我正在编译以下代码,但未按预期工作。
有人可以解释为什么以下代码不起作用以及如何更正它吗?
DWORD data_location = 0x0100579C;
DWORD ret = 0x1002FFA;
void __declspec(naked) inc()
{
// The following is what I'm trying to accomplish which works
*(DWORD*)data_location = *(DWORD*)data_location + 1;
__asm
{
inc [data_location] //Should compile as FF 05 9C570001, instead compiles to the address containing the pointer to data_location
// inc data_location also compiles to the same thing above
jmp [ret]
}
}
答案 0 :(得分:2)
如果我对您的理解正确,那么您希望获得类似的东西
DWORD data_location = 0x0100579C;
DWORD ret = 0x1002FFA;
void __declspec(naked) inc()
{
__asm
{
mov eax, [data_location]
inc dword ptr [eax]
jmp [ret]
}
}
答案 1 :(得分:2)
[data_location]
与MASM语法中的data_location
相同。方括号是可选的,而不是您需要从静态存储中取消引用指针的额外级别的间接操作。
请记住,在C中,data_location
为您提供了来自内存的值,然后您的C取消引用了那个。但是内联asm使用asm语法。
如果您希望它与硬编码到指令中的地址组合在一起,您需要将地址设置为预处理器常量,而不仅仅是静态存储中的DWORD
变量。< / p>
#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
}
}
显然,使MASM / MSVC将ds:
视为内存操作数而不是立即数,[0x12345]
是必需的。但是它也有一个缺点,就是实际上会在机器代码中发出一个冗余的ds
前缀字节。
很显然,您可以通过实际使用来提高效率
++*(DWORD*)data_location;
,然后让编译器内联add
或inc
指令。强制调用者实际调用此存根函数只会降低您的速度。
add [mem], immediate
仅2块,而Intel CPU上的内存目标inc
仅3片。它仅花费1个额外的代码大小字节。
jmp [ret]
一起使用的 DWORD ret = ...;
可以使用,但这是一个不幸的选择。您实际上并不需要从静态存储中加载目标地址。理想情况下,您会jmp 0x1002FFA
并让汇编器计算相对于该绝对目标的相对偏移。但是不幸的是,MASM语法和/或Windows .obj
文件不支持。
如果可以使用tmp寄存器,则将地址mov
立即放入寄存器中可以避免需要任何静态数据,从而可能使前端更快地整理出错误的分支。不过,它仍然是一个间接分支。
此外,如果您实际上使用过call
这个函数,请记住,调用方将推送您留在堆栈中的返回地址,所以这就像一个尾调用。
实际上,如果您只是在jmp
函数末尾简单地进行了不带参数的普通函数调用,则可以使编译器为您发出void
。