- The
/2
vs. /3
: See Section 3.1.1.1O Opcode Column in the Instruction Summary Table:
/digit — A digit between 0 and 7 indicates that the ModR/M byte of the instruction uses only the r/m (register
or memory) operand. The reg field contains the digit that provides an extension to the instruction's opcode.
Using the /r
field of the mod/rm byte of one-operand instructions is the same here as for instructions like inc r/m32
(FF /0
).
x86 overloads a few opcode bytes with multiple one-operand instructions this way. The 3-bit /r
field becomes another 3 opcode bits instead of an operand. More detail about that:
r/m32
vs. m16:32
vs. ptr16:32
See also x86 function call types
A "far" call
loads the CS
segment register as well as IP
/EIP
/RIP
. A normal "near" call only needs a 32-bit (or 64-bit) address, and doesn't modify CS
.
far call
is never used in "normal" 32 or 64-bit user-space code on normal OSes, because they all use a flat memory model.
ptr16:32
is an immediate, with the 16-bit segment value and the 32-bit absolute address encoded into the instruction (little-endian, with the 32-bit offset first then the new CS value). This is a far call
. See this Q&A. Assemblers will generate this instruction encoding for far call some_symbol
, taking the segment value from the segment some_symbol
is defined in. Again, you're really unlikely to ever use this outside of 16-bit code. But if you do, see this Q&A for how to get MASM to emit it.
m16:32
is a 6-byte memory operand, loaded from the effective address encoded by the ModR/M byte. This is another far call. So call far [eax]
does a 48-bit load from the address in eax
. Only memory addressing modes are legal for the ModR/M byte, because the instruction needs more data than the width of a register. (i.e. call far eax
isn't legal)
r/m32
is a memory or register operand for a near call. You get this from call eax
or call [eax]
. Of course any addressing mode is legal, e.g. call FS:[edi + esi*4 + some_table]
. The FS segment-override prefix applies to the location the function pointer is loaded from, not the segment that it jumps to. (i.e. it doesn't change CS because it's still a near call.)
How can I call the function at the absolute address 0x717A60
See Call an absolute pointer in x86 machine code.
If your code doesn't have to be position-independent, by far the best choice is something that assembles to call rel32
with the right relative displacement to reach that address. In NASM and AT&T syntax, you can simply write call 0x717A60
and the assembler + linker take care of it. I'm not sure how to write it in MASM; MSVC inline asm doesn't accept call 123456h
.
There is no absolute direct near call
encoding, so if you do need PIC then you should do something like mov eax, 0x717A60
/ call eax
.
You don't want to use a call far
absolute direct call, because it's probably much slower, and pushes CS:EIP instead of just EIP as the return address. You'd also have to know what to put in the segment field.
FF 15 90 98 76 70
That disassembles to call DWORD PTR ds:0x70769890
(in GNU objdump -Mintel
syntax), which is a call r/m32
, where the operand is a [disp32]
absolute addressing mode.
(Or in 64-bit code, it's a RIP-relative addressing mode with that rel32
, but still a memory-indirect call
that loads a function-pointer from a static location.)
See also the x86 tag wiki for more links to docs.
far call
that loadsCS
. You don't want that. – Ebbycall
to an absolute address using msvc inline asm buried as part of item 3. I didn't notice that until I was mostly done writing an answer to the obvious parts of the question. This is a great example of why SO has a one question per Question-post guideline. – Ebby