INC 操作码编译到错误的地址
INC opcode compiles to wrong address
我正在编译以下代码,但它没有按预期工作。
有人可以解释为什么以下代码不起作用以及如何更正它吗?
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]
}
}
如果我没理解错的话,你想要的是
DWORD data_location = 0x0100579C;
DWORD ret = 0x1002FFA;
void __declspec(naked) inc()
{
__asm
{
mov eax, [data_location]
inc dword ptr [eax]
jmp [ret]
}
}
[data_location]
与 MASM 语法中的 data_location
相同。方括号是可选的,不是从静态存储中取消引用指针所需的额外间接级别。
请记住,在 C 中,data_location
为您提供内存中的值,然后您的 C 将取消引用 that。但是内联 asm 使用 asm 语法。
如果你想让它assemble和地址hard-coded进入指令,你需要使地址成为预处理器常量,而不仅仅是一个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
}
}
显然 ds:
是使 MASM/MSVC 将 [0x12345]
视为内存操作数而不是立即数所必需的。但它也有缺点,实际上会在机器代码中发出冗余的 ds
前缀字节。
显然你可以通过实际使用
来提高效率
++*(DWORD*)data_location;
并让编译器内联 add
或 inc
指令。强制调用者实际调用这个存根函数只会减慢你的速度。
add [mem], immediate
只有 2 微指令,而在英特尔 CPU 上 memory-destination inc
为 3 微指令。它只需要 code-size.
的 1 个额外字节
jmp [ret]
和 DWORD ret = ...;
都可以,但这是一个不幸的选择。您实际上并不需要从静态存储中加载目标地址。理想情况下,您 jmp 0x1002FFA
并让 assembler 计算到该绝对目的地的相对偏移量。但不幸的是,MASM 语法 and/or Windows .obj
文件不支持。
如果您可以使用 tmp 寄存器,mov
-直接进入寄存器的地址避免需要任何静态数据,可能允许 front-end 更快地解决分支预测错误。不过,它仍然是一个间接分支。
另外,如果你真的 call
这个函数,请记住调用者将压入一个你留在堆栈上的 return 地址,所以这就像一个尾调用。
事实上,如果您只是在 void
函数末尾进行不带参数的普通函数调用,您可以让编译器为您发出 jmp
。
我正在编译以下代码,但它没有按预期工作。
有人可以解释为什么以下代码不起作用以及如何更正它吗?
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]
}
}
如果我没理解错的话,你想要的是
DWORD data_location = 0x0100579C;
DWORD ret = 0x1002FFA;
void __declspec(naked) inc()
{
__asm
{
mov eax, [data_location]
inc dword ptr [eax]
jmp [ret]
}
}
[data_location]
与 MASM 语法中的 data_location
相同。方括号是可选的,不是从静态存储中取消引用指针所需的额外间接级别。
请记住,在 C 中,data_location
为您提供内存中的值,然后您的 C 将取消引用 that。但是内联 asm 使用 asm 语法。
如果你想让它assemble和地址hard-coded进入指令,你需要使地址成为预处理器常量,而不仅仅是一个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
}
}
显然 ds:
是使 MASM/MSVC 将 [0x12345]
视为内存操作数而不是立即数所必需的。但它也有缺点,实际上会在机器代码中发出冗余的 ds
前缀字节。
显然你可以通过实际使用
来提高效率
++*(DWORD*)data_location;
并让编译器内联 add
或 inc
指令。强制调用者实际调用这个存根函数只会减慢你的速度。
add [mem], immediate
只有 2 微指令,而在英特尔 CPU 上 memory-destination inc
为 3 微指令。它只需要 code-size.
jmp [ret]
和 DWORD ret = ...;
都可以,但这是一个不幸的选择。您实际上并不需要从静态存储中加载目标地址。理想情况下,您 jmp 0x1002FFA
并让 assembler 计算到该绝对目的地的相对偏移量。但不幸的是,MASM 语法 and/or Windows .obj
文件不支持。
如果您可以使用 tmp 寄存器,mov
-直接进入寄存器的地址避免需要任何静态数据,可能允许 front-end 更快地解决分支预测错误。不过,它仍然是一个间接分支。
另外,如果你真的 call
这个函数,请记住调用者将压入一个你留在堆栈上的 return 地址,所以这就像一个尾调用。
事实上,如果您只是在 void
函数末尾进行不带参数的普通函数调用,您可以让编译器为您发出 jmp
。