Question

Out of curiosity, I decided to hand-assemble some x86 code. I'm doing all right so far, but I just cannot figure out the proper encoding for the call instruction.

I get that it's basically supposed to be E8 xx xx xx xx, where xx xx xx xx is the address I want to jump to.

The way that I tried encoding this is like so (NASM):

extern _printf

; ...

db 0xe8
dd _printf

That assembles and links just fine, but the program crashes.

I looked at how NASM assembles the instruction call _printf, and it generates a different xx xx xx xx than mine does. I wondered if I was specifying the address incorrectly or something, but the code

times 512 nop
dd _printf
times 512 nop

yields a gazillion 90s surrounding the same address I got from my hand-assembled call, which means the actual address of _printf isn't what I'm supposed to be passing.

What am I missing here?

(Also: I was curious about the other encoding for call, the one that starts with FF. What's the difference?)

Was it helpful?

Solution

0xE8 is used with relative address. So the following instruction is encoded as E8 00 00 00 00

  call label
label:

Some encodings starting with 0xFF can be used for indirect calls where address of the destination is stored in register or memory. If you want to call procedure at specific address, you can do the following:

  mov  eax, 0x12345678 ; address of procedure (not relative)
  call eax

0x9A encoding allows you to make far calls that update CS-register as well. So for example:

  call 0x1234:0x55667788

updates value of the CS-register to 0x1234 and the value of the instruction pointer to 0x55667788. Return address is also pushed to stack with values for both CS and instruction pointer.

For more information about different encodings I recommend this reference.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top