寻址变量(或者,什么是ML64生成?)

时间:2015-10-15 01:12:54

标签: visual-studio assembly x86-64 masm fastcall

我有一个为X64编写的ASM文件。它提供了叶子功能。该文件与MASM64 / 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似乎是bufferNULL},RDX似乎是bsize0x40 }),但比较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 个答案:

答案 0 :(得分: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不同)。我猜它类似于32位fastcall ABI。 Agner Fog有一个文档,解释了32位和64位操作系统的各种调用约定。

请注意,即时为零的cmp几乎总是比test rcx, rcx更糟糕的选择。更短的insn编码,以及仍然在Intel和AMD上具有以下jcc的宏保险。

答案 1 :(得分: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
    ...

对于fastcall的X64,需要一些小的黑客攻击:

;; 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