1

我有一个为 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正在被使用,这与文档一致。前两个参数出现在RCXandRDX中,这也是一致的。

但是带有NULL指针的测试用例会产生意想不到的结果。这是正在使用的测试用例:

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

当我执行代码时,RCX似乎是buffer(its NULL),RDX似乎是bsize(its 0x40),但比较cmp buffer, 0是针对我未知的值进行的。从即时窗口:

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

13f82bcd0看起来大致像一个指令指针地址(EIP 是13F50D268)。它似乎与ESPor不相似EBP

我有几个问题...

  • ML64 对变量使用什么寻址模式buffer
  • 变量的值buffer从何而来?
  • 为什么ML64 使用ECX变量buffer
  • 我怎样才能解决这个问题?

相同的代码,缩短为 32 位,可以很好地汇编和执行。但是,ML 将buffer和放入bsize堆栈并相对于EBP.

我也尝试更改为cmp QWORD PTR buffer, 0,但没有帮助。


在此处输入图像描述

4

2 回答 2

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 位fastcallABI。 Agner Fog有一个文档解释了 32 位和 64 位操作系统的各种调用约定。


请注意,立即为零的 cmp 几乎总是比test rcx, rcx. jcc更短的 insn 编码,并且仍然与Intel 和 AMD的后续宏融合。

于 2015-10-15T01:35:09.743 回答
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等。 SecondEQU像 C 语言一样#define用于等同bufferecx.

于 2015-10-15T23:41:41.897 回答