Reputation: 45
I'm compiling the following code however it isn't working as expected.
Can someone explain why the following code doesn't work and how to correct it so it does?
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]
}
}
Upvotes: 0
Views: 174
Reputation: 365277
[data_location]
is the same thing as data_location
in MASM syntax. Square brackets are optional, not the extra level of indirection you need to deref a pointer from static storage.
Remember that in C, data_location
gives you the value from memory, and your C is then dereferencing that. But inline asm uses asm syntax.
If you want it to assemble with the address hard-coded into the instruction, you need to make the address a preprocessor constant, not just a DWORD
variable in static storage.
#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
}
}
Apparently a ds:
is necessary to make MASM/MSVC treat [0x12345]
as a memory operand, not an immediate. But it also has the downside of actually emit a redundant ds
prefix byte in the machine code.
Obviously you could make this much more efficient by actually using
++*(DWORD*)data_location;
and letting the compiler inline the add
or inc
instruction. Forcing a caller to actually call this stub function will just slow you down.
add [mem], immediate
is only 2 uops, vs. 3 for memory-destination inc
on Intel CPUs. It only costs 1 extra byte of code-size.
jmp [ret]
with DWORD ret = ...;
will work, but is an unfortunate choice. You don't really need to load the target address from static storage. Ideally you'd jmp 0x1002FFA
and let the assembler calculate a relative offset to that absolute destination. But unfortunately MASM syntax and/or Windows .obj
files don't support that.
If you can use a tmp register, mov
-immediate of the address into the register avoids needing any static data, potentially allowing the front-end to sort out a branch mispredict sooner. It's still an indirect branch, though.
Also, if you ever actually call
this function, remember that the caller will have pushed a return address which you leave on the stack, so this is like a tailcall.
In fact, you could get the compiler to emit a jmp
for you if you simply made a normal function call with no args at the end of a void
function.
Upvotes: 2
Reputation: 28839
If I'm understanding you correctly, you want something along the lines of
DWORD data_location = 0x0100579C;
DWORD ret = 0x1002FFA;
void __declspec(naked) inc()
{
__asm
{
mov eax, [data_location]
inc dword ptr [eax]
jmp [ret]
}
}
Upvotes: 2