[data_location]
与 MASM 语法中的相同data_location
。方括号是可选的,而不是从静态存储中取消引用指针所需的额外间接级别。
请记住,在 C 中,data_location
为您提供内存中的值,然后您的 C 将取消引用该. 但是内联 asm 使用 asm 语法。
如果您希望它与硬编码到指令中的地址一起汇编,则需要使地址成为预处理器常量,而不仅仅是DWORD
静态存储中的变量。
#define data_location 0x0100579C
#define ret_addr 0x1002FFA
void __declspec(naked) inc()
{
//++*(DWORD*)data_location;
//((void (*)(void))ret)();
__asm
{
add dword ptr ds:[data_location], 1
// add dword ptr ds:[0x0100579C], 1 // after C preprocessor
mov eax, ret_addr
jmp eax
}
}
显然 ads:
是使 MASM/MSVC 被[0x12345]
视为内存操作数而不是立即数所必需的。但它也有在机器代码中实际发出冗余ds
前缀字节的缺点。
++*(DWORD*)data_location;
显然,您可以通过实际使用并让编译器内联add
orinc
指令来提高效率。强制调用者实际调用此存根函数只会减慢您的速度。
add [mem], immediate
只有 2 微指令,而inc
英特尔 CPU 上的内存目标为 3。它只需要 1 个额外字节的代码大小。
jmp [ret]
withDWORD ret = ...;
会起作用,但这是一个不幸的选择。您实际上并不需要从静态存储中加载目标地址。理想情况下,您应该jmp 0x1002FFA
让汇编器计算到该绝对目的地的相对偏移量。但不幸的是 MASM 语法和/或 Windows.obj
文件不支持它。
如果您可以使用 tmp 寄存器,mov
则 -immediate 将地址放入寄存器可避免需要任何静态数据,从而可能允许前端更快地解决分支错误预测。不过,它仍然是一个间接分支。
此外,如果你真的使用过call
这个函数,请记住调用者将推送一个返回地址,你留在堆栈上,所以这就像一个尾调用。
事实上,jmp
如果您只是在函数末尾不带 args 的普通函数调用,您可以让编译器为您发出 a void
。