Visual studio 寻址变量(或者,ML64生成什么?)
我有一个为X64编写的ASM文件。它提供了一个叶函数。该文件是用MASM64/ML64组装的 带有签名的C-PSEDOU代码为:Visual studio 寻址变量(或者,ML64生成什么?),visual-studio,assembly,x86-64,masm,fastcall,Visual Studio,Assembly,X86 64,Masm,Fastcall,我有一个为X64编写的ASM文件。它提供了一个叶函数。该文件是用MASM64/ML64组装的 带有签名的C-PSEDOU代码为: 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 ;;
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
不相似
我有几个问题
- ML64对变量
缓冲区使用什么寻址模式
- 变量
的值来自哪里buffer
- 为什么
没有使用ML64
作为变量ECX
buffer
- 我怎样才能解决这个问题
同样的代码,缩短为32位,可以很好地进行汇编和执行。但是,ML将
buffer
和bsize
放在堆栈上,并相对于EBP
对它们进行寻址
我还尝试更改为cmpqwordptr缓冲区,0
,但没有帮助
来自最终屏幕截图中的拆解
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
因此,您正在使用的汇编语法仍然将缓冲区
声明为符号或内存偏移量或其他内容,而不是作为寄存器的别名。是的,x86-64 Windows ABI使用了一种寄存器调用约定(不幸的是,它与Linux不同)。我猜它类似于32位fastcall
ABI。有一个文档解释32位和64位操作系统的各种调用约定
请注意,立即为零的cmp几乎总是比
测试rcx、rcx
更糟糕的选择。更短的insn编码,并且仍然与Intel和AMD上的以下jcc
宏融合
我怎样才能解决这个问题
有些问题我无法回答,但我知道如何解决。下面,底层需求是针对X86(MASM/ML)和X64(MASM64/ML64)的相同源代码工作,只需很少的更改
这是原始的C函数签名:
int-GenerateBlock(字节*ptr,大小\u t size,无符号int-safety)
在X86 MASM下,使用相对寻址,ASM代码如下所示:
;;基本相对(in):字节*缓冲区
;; 基准相对(英寸):大小
;; 基本相对(in):无符号整数安全
ASM_GenerateBlock进程缓冲区:DWORD,bsize:DWORD,safety:DWORD
本地val:DWORD;;局部变量
Mw尺寸等于4;;机器字大小
;; 验证指针
cmp缓冲区,0
je MSC_ASM_GenerateBlock_清理
...
;; 将字节从AL写入缓冲区
mov字节PTR[缓冲区],al
公司缓冲区
...
对于带有fastcall
的X64,需要进行一些小技巧:
;;RCX(in):字节*缓冲区
;; RDX(英寸):大小
;; R8d(in):无符号整数安全
ASM_GenerateBlock PROC bufferX:QWORD,bsizeX:QWORD,safetyX:DWORD
本地val:QWORD;;局部变量
Mw尺寸等于8;;机器字大小
;; 快速呼叫解决方案
缓冲区均衡
bsize EQU edx
安全设备r8d
;; 验证指针
cmp缓冲区,0
je MSC_ASM_GenerateBlock_清理
...
;; 将字节从AL写入缓冲区
mov字节PTR[缓冲区],al
公司缓冲区
...
在上面,出现了两个修复。首先是过程原型中变量的名称<代码>缓冲区更改为
bufferX
,等等。第二个eq
像C语言一样使用#define
将缓冲区
等同于ecx。你知道我怎样才能解决这个问题吗?MASM/MASM64具有,但在MASM64/ML64下不工作。看看我能说的,MASM64/ML64对于符号开发几乎是无用的(与MASM/ML不同)。它所做的只是与MASM同名(这是MASM的耻辱,因为它是一个非常好的工具)。@jww:对不起,没有线索。我不使用MSVC,只使用yasm和GNU作为。即使在yasm中,我也没有对宏做太多的工作。有人在你最近的另一个问题上发布的链接听起来像MSVC刚刚放弃了对将EAX==1的转换为64位的实际INSN的支持。有时可以通过执行cmp eax,1
,然后执行jb
for==0和je
for==1来保存指令。这样就节省了几个insn字节,并且CPU上的uop不能在同一个insn块中宏融合两个比较和分支对。