关于汇编:x86 asm中调用指令的编码之间有什么区别?

What is the difference between the encodings for the call instruction in x86 asm?

供参考:call指令的英特尔文档的HTML摘录。

我知道第3.1.1.3节对此进行了解释,但是我在理解手册时遇到了麻烦,可能是因为它太技术性了。

  • FF /2FF /3中的/2/3是什么?

  • r/m32m16:32有什么区别? r/m32涵盖了32位寄存器和内存操作数,所以这不会使m16:32冗余吗?

  • 根据手册,call ptr16:32是"调用操作数中给出的绝对绝对地址"。 如果我理解正确,这将允许我在给定的绝对32位地址处调用函数。 如何在绝对地址0x717A60处调用函数(我在MSVC中使用内联汇编器)? call 0x717A60给我一个错误,并且call ds:0x717A60被组装到call [0x717A60]

  • 以下机器代码对应于哪个操作码? FF 15 90 98 76 70


  • /2 vs. /3:请参见指令摘要表中的第3.1.1.1O节"操作码"列:
  • /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.

    在这里使用单操作数指令的mod / rm字节的/r字段与inc r/m32(FF /0)之类的指令相同。

    x86以这种方式用多个单操作数指令重载了一些操作码字节。 3位/r字段变为另外3个操作码位,而不是操作数。关于此的更多细节:

    • 如何阅读英特尔操作码表示法
    • / 4在FF / 4中是什么意思?
    • x64指令编码和ModRM字节-有关modrm字节中字段的详细信息。

    r/m32m16:32ptr16:32

    另请参见x86函数调用类型

    "远" call装入CS段寄存器以及IP / EIP / RIP。普通的" near"调用仅需要一个32位(或64位)地址,而不修改CS

    far call从未在普通OS的"普通" 32或64位用户空间代码中使用,因为它们都使用平面内存模型。

    ptr16:32是立即数,具有16位段值和32位绝对地址编码到指令中(小尾数,先偏移32位,然后是新的CS值)。这是far call。请参阅此问答。汇编器将为far call some_symbol生成此指令编码,并从其中定义段some_symbol中获取段值。同样,您实际上不太可能在16位代码之外使用此代码。但是,如果您这样做,请参阅此问答以获取如何使MASM发出它的信息。

    m16:32是一个6字节的内存操作数,从ModR / M字节编码的有效地址加载。这是另一个遥不可及的地方。因此call far [eax]eax中的地址进行48位加载。对于ModR / M字节,只有存储器寻址模式才是合法的,因为该指令需要的数据要多于寄存器的宽度。 (即call far eax不合法)

    r/m32是用于Near调用的内存或寄存器操作数。您是从call eaxcall [eax]获得的。当然,任何寻址方式都是合法的,例如call FS:[edi + esi*4 + some_table]。 FS segment-override前缀适用于函数指针从中加载的位置,而不是其跳转到的段。 (即,它不会更改CS,因为它仍然是临近通话。)


    How can I call the function at the absolute address 0x717A60

    请参阅在x86机器代码中调用绝对指针。

    如果您的代码不必与位置无关,那么到目前为止,最好的选择是将其组装到call rel32并以正确的相对位移到达该地址。使用NASM和AT&T语法,您只需编写call 0x717A60,然后由汇编程序+链接程序进行处理。我不确定如何用MASM编写它; MSVC内联汇编不接受call 123456h

    call编码附近没有绝对直接的编码,因此,如果您确实需要PIC,则应该执行类似mov eax, 0x717A60 / call eax的操作。

    您不希望使用call far绝对直接调用,因为它可能要慢得多,并且将CS:EIP而不只是EIP作为返回地址。您还必须知道要在细分字段中输入什么。


    FF 15 90 98 76 70

    它反汇编为call DWORD PTR ds:0x70769890(使用GNU objdump -Mintel语法),即call r/m32,其中操作数为[disp32]绝对寻址模式。

    (或者在64位代码中,它是具有rel32的RIP相对寻址模式,但仍然是从内存中的静态位置加载功能指针的内存间接call。)


    另请参阅x86标签Wiki,以获取更多指向文档的链接。