INC 操作码编译到错误的地址

INC opcode compiles to wrong address

本文关键字:地址 错误 操作码 编译 INC      更新时间:2023-10-16

我正在编译以下代码,但它没有按预期工作。

有人可以解释为什么以下代码不起作用以及如何纠正它吗?

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]
}
}

[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
}
}

显然,为了使MASM/MSVC将[0x12345]视为记忆操作数而不是即时操作数,需要ds:。 但它也有在机器代码中实际发出冗余ds前缀字节的缺点。

显然,您可以通过实际使用
++*(DWORD*)data_location;并让编译器内联addinc指令来提高效率。 强制调用方实际调用此存根函数只会减慢您的速度。

add [mem], immediate仅为 2 uops,而英特尔 CPU 上的内存目标inc为 3 uops。 它只需要 1 个额外的代码大小字节。

jmp [ret]DWORD ret = ...;会起作用,但这是一个不幸的选择。 您实际上不需要从静态存储加载目标地址。 理想情况下,您会jmp 0x1002FFA并让汇编程序计算到该绝对目标的相对偏移量。 但不幸的是,MASM 语法和/或 Windows.obj文件不支持这一点。

如果您可以使用 tmp 寄存器,则将地址的 -立即mov到寄存器中,避免需要任何静态数据,从而可能允许前端更快地整理分支错误预测。 不过,它仍然是一个间接分支。


此外,如果您实际call此函数,请记住,调用方将推送您留在堆栈上的返回地址,因此这就像尾调用一样。

事实上,如果你只是在void函数的末尾进行没有参数的普通函数调用,你可以让编译器为你发出一个jmp

如果我理解正确的话,你想要一些类似的东西

DWORD data_location = 0x0100579C;
DWORD ret = 0x1002FFA;
void __declspec(naked) inc()
{
__asm
{   
mov eax, [data_location]
inc dword ptr [eax]
jmp [ret]
}
}