2015-10-15 17 views
1

我有一個爲X64寫的ASM文件。它提供了一個葉函數。該文件與MASM64/ML64組裝。尋址變量(或什麼是ML64生成?)

與簽名的C-pseduo代碼是:

int GenerateBlock(byte* ptr, size_t size, unsigned int safety) 
{ 
    if (ptr == NUL) return 0; /*FAIL*/ 
    ... 
} 

下面是ASM代碼相同的部分:

;; RCX (in): byte* buffer 
;; RDX (in): size_t bsize 
;; R8d (in): unsigned int safety 
;; RAX (out): bool, success (1), failure (0) 

ASM_GenerateBlock PROC buffer:QWORD,bsize:QWORD,safety:DWORD 
    LOCAL val:QWORD   ;; local variables 
    MWSIZE EQU 8   ;; machine word size 

      ;; Validate pointer 
    cmp  buffer, 0 
    je  ASM_GenerateBlock_Cleanup 
      ;; Cleanup will set RAX to 0 and return 
    ... 
ENDP 

當我步驟呼叫,似乎fastcall是正在使用,這與文檔一致。前兩個參數出現在RCXRDX之間,這也是一致的。

但是帶有NULL指針的測試用例產生了意想不到的結果。這裏是一個的正在使用的測試案例:

ASM_GenerateBlock(NULL /*ptr*/, 64 /*size*/, 20 /*safety*/); 

當我步驟的代碼,RCX似乎是buffer(其NULL),RDX似乎是bsize(其0x40),但比較cmp buffer, 0發生針對這是我未知的價值。從即時窗口:

buffer 
0x000000013f82bcd0 
*(__int64*)buffer 
0x000000013f62aba8 
bsize 
0x000000013f14871b 
*(__int64*)bsize 
0xccccccc348c48348 

13f82bcd0大體類似的指令指針地址(EIP是13F50D268)。它看起來不像ESPEBP

我有幾個問題...

  • 什麼尋址ML64使用可變buffer模式?
  • 變量buffer的值來自哪裏?
  • 爲什麼ML64不使用ECX的變量buffer
  • 我該如何解決這個問題?

相同的代碼,縮短到32位,組裝並執行精細。然而,ML將bufferbsize放在堆棧上並且相對於EBP解決它們。

我也嘗試更改爲cmp QWORD PTR buffer, 0,但它沒有幫助。


enter image description here

回答

2

從在最後的屏幕截圖中的拆卸,

cmp buffer, 0 

被組裝到

cmp qword ptr [buffer], 0 # memory operand. rip-relative? or stack-relative? Not enough insn bytes for an absolute 32bit address 

代替

cmp RCX, 0 

因此,您正在使用的彙編語法仍然聲明buffer作爲符號或內存偏移等,而不是寄存器的別名。是的,x86-64 Windows ABI使用寄存器調用約定(不幸的是與Linux不同)。我猜這跟ABI的32bit fastcall相似。 Agner Fog有一個文檔解釋了32位和64位操作系統的各種調用約定。


請注意,立即爲零的cmp幾乎總是比test rcx, rcx更差的選擇。較短的insn編碼,並且在Intel和AMD上仍然具有以下jcc的宏保險絲。

+0

謝謝彼得。你知道我該如何解決這個問題嗎? MASM/MASM64有一個['ALIAS'](https://msdn.microsoft.com/en-us/library/b07c5b4f.aspx),但它在MASM64/ML64下不起作用。請參閱從ML(X86)移植到ML64(X64)時的[A2008錯誤?](http://stackoverflow.com/q/33118452)我可以說最好的,MASM64/ML64幾乎沒有用於符號開發(與MASM/ML)。它所做的就是與MASM共享相同的名字(這對MASM來說是一種恥辱,因爲它是一個非常好的工具)。 – jww

+0

@jww:對不起,沒有線索。我不使用MSVC,只使用yasm和GNU。即使在亞洲,我也沒有做過太多的宏觀工作。有人在你最近的另一個問題上發佈的鏈接聽起來像MSVC只是放棄了支持將'IF EAX == 1'這樣的東西變成64位的實際insns。有時你可以通過'cmp eax,1'和'jb'來保存一條指令,對於== 0和'je'對於== 1。這樣可以節省幾個insn字節,並且在CPU上不能宏塊融合同一塊insn中的兩個比較和分支對。 –

0

我該如何解決這個問題?

我無法回答一些問題,但我知道如何解決它。下面,基本要求是對X86(MASM/ML)和X64(MASM64/ML64)進行相同的源代碼工作,只需進行很少的更改。

這裏是原來的C函數簽名:

int GenerateBlock(byte* ptr, size_t size, unsigned int safety) 

在X86 MASM,相對用來尋址,和ASM代碼將如下所示:

;; Base relative (in): byte* buffer 
;; Base relative (in): size_t bsize 
;; Base relative (in): unsigned int safety 

ASM_GenerateBlock PROC buffer:DWORD,bsize:DWORD,safety:DWORD 
    LOCAL val:DWORD   ;; local variables 
    MWSIZE EQU 4   ;; machine word size 

      ;; Validate pointer 
    cmp  buffer, 0 
    je  MSC_ASM_GenerateBlock_Cleanup  
    ... 

    ;; Write byte to buffer from AL 
    mov  BYTE PTR [buffer], al 
    inc  buffer 
    ... 

對於X64與fastcall,一個需要一些小的黑客:

;; RCX (in): byte* buffer 
;; RDX (in): size_t bsize 
;; R8d (in): unsigned int safety 

ASM_GenerateBlock PROC bufferX:QWORD,bsizeX:QWORD,safetyX:DWORD 
    LOCAL val:QWORD   ;; local variables 
    MWSIZE EQU 8   ;; machine word size 

      ;; Fastcall workaround 
    buffer EQU ecx 
    bsize EQU edx 
    safety EQU r8d 

      ;; Validate pointer 
    cmp  buffer, 0 
    je  MSC_ASM_GenerateBlock_Cleanup  
    ... 

      ;; Write byte to buffer from AL 
    mov  BYTE PTR [buffer], al 
    inc  buffer 
    ... 

上面,發生了兩個修復程序。首先是過程原型中變量的名稱。 Buffer改爲bufferX等。第二個EQU像C語言#define一樣使用以將buffer等同於ecx