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

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

我有一个为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
;; 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块中宏融合两个比较和分支对。