我有一个为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
,这与文档一致。前两个参数显示在RCX
和RDX
中,这也是一致的。
但是带有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
)。它似乎与ESP
或EBP
不相似。
我有几个问题......
buffer
?buffer
的值来自何处?ML64
不 使用ECX
作为变量buffer
?相同的代码,缩写为32位,汇编并执行正常。但是,ML会将buffer
和bsize
放在堆栈上,并相对于EBP
解决它们。
我也尝试过更改为cmp QWORD PTR buffer, 0
,但没有帮助。
答案 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
。