I'm trying to create a dispatch table which changes the location of some instruction in another address which is allocated by AllocateMemoryOnRemoteProcess
.
One of the problems that I encountered was almost all of Calls
and all kind of Jumps
are near
and relative
and as long as I load the assemblies in new location, then these instructions won't work.
As I know I should convert these instructions to far jump
or far call
one of the solutions that I saw during my googling was using push
and ret
like :
push 0xdeadbeef
ret
or someone suggests using registers for absolute addressing like :
mov %eax,0xdeadbeef
jmp %eax
These solutions won't work in my case because as long as I'm in a function routine, changing the stack state or in the second case changing a register like %eax
causes failure.
Someone in this question wrote :
- call far (with opcode 9A) jumps to an absolute segment and offset. ie, it's like setting CS and ?IP at once.
So it seems I should use opcode with 9A
for far calls
, but this just works for the calls and I have no idea about converting all kinds of Jumps with this method!
I regularly use objdump
to disassemble a binary, then use clang
as the assembler by using the following command :
clang -c MyAsm.asm -m32
But when I assemble with the above command then the result is relative.
For example when MyAsm.asm
is :
call 0x402af2
The result of objdump
is :
MyAsm.o: file format Mach-O 32-bit i386
Disassembly of section __TEXT,__text:
__text:
0: e8 ed 2a 40 00 calll 4205293 <__text+0x402AF2>
These results are relative.
So my questions are :
far calls
or far jumps
(j*
instructions) with clang
or any other tools (which of course, work for both 80x86 and Amd64 structures)?If you can spare a register, I advise you to use
movabs $addr,%rax
jmp *%rax
or, if you can ensure that the address is within the first 2 GB of address space,
mov $addr,%eax
jmp *%eax
I strongly advise you against using
push $addr
ret
as this trashes the return prediction, making the next few function returns slower than necessary. Far jumps and calls (ljmp
and lcall
) are a red herring. While they could technically be used, they won't help you achieve your goal and are actually meant for a different purpose (changing cs
) and are implemented as slow, micro-coded instructions on modern processors.
If you cannot spare a register, you can use this sort of trick instead:
jmp *0f(%rip)
...
0: .quad addr
The second line can be anywhere in the program and should be in the data segment for ideal performance. However, if needed, it can also be right after the jump instruction.
This should just work and in addition doesn't require you to use an extra register. It is slower than using a register though.
Note that conditional jumps strictly require the jump target to be immediate. If you want to do a conditional jump to an absolute address, use an idiom like this:
# for jz addr
jnz 1f
jmp *0f(%rip)
0: .quad addr
1: ...
Note that in 16 and 32 bit mode, there is no rip-relative addressing mode. So you'll have to use an absolute address and write
jmp *0f
0: .long addr
instead. However, that kind of defeats the purpose as if you could use an absolute addressing mode to reach 0f
, you could also just use a relative addressing mode to reach addr
. So it seems like you'll have to resort to a push
+ ret
sequence, even if it is slow.
In 16 bit modes, most likely using a far jump is fine. If not, the push
+ ret
sequence is idiomatic (processors of that vintage did not have return prediction).