x86 asm中的调用指令的编码之间有什么区别? [英] What is the difference between the encodings for the call instruction in x86 asm?
问题描述
供参考: call
指令的英特尔文档的HTML摘录.
For reference: an HTML extract of Intel's documentation for the call
instruction.
我知道第3.1.1.3节对此进行了解释,但是我在理解手册时遇到了麻烦,可能是因为它太技术性了.
I am aware that section 3.1.1.3 explains this but I am having trouble understanding the manual, probably because it is too technical.
-
FF /2
和FF /3
中的/2
和/3
是什么?
r/m32
和m16:32
有什么区别? r/m32
涵盖了32位寄存器和内存操作数,所以这不会使m16:32
变得多余吗?
What is the difference between r/m32
and m16:32
? r/m32
covers both 32-bit registers and memory operands so wouldn't that make m16:32
redundant?
根据手册call ptr16:32
是调用操作数中给出的绝对绝对地址".如果我理解正确,这将允许我在给定的绝对32位地址处调用函数.如何在绝对地址0x717A60
处调用函数(我在MSVC中使用内联汇编器)? call 0x717A60
给我一个错误,并且call ds:0x717A60
被组装到call [0x717A60]
.
According to the manual call ptr16:32
is a "Call far, absolute, address given in operand". If I understood correctly, this will allow me to call a function at a given absolute 32-bit address. How can I call the function at the absolute address 0x717A60
(I'm using the inline assembler in MSVC)? call 0x717A60
gives me an error and call ds:0x717A60
is assembled to call [0x717A60]
.
以下机器代码对应于哪个操作码? FF 15 90 98 76 70
Which opcode does the following machine code correspond to? FF 15 90 98 76 70
推荐答案
-
/2
与/3
:请参见指令摘要表中的第3.1.1.1O节操作码"列:
- The
/2
vs./3
: See Section 3.1.1.1O Opcode Column in the Instruction Summary Table:
/digit — 0到7之间的数字表示指令的ModR/M字节仅使用r/m(寄存器 或内存)操作数. reg字段包含用于扩展指令操作码的数字.
/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
)之类的指令相同.
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以这种方式用多个单操作数指令重载了一些操作码字节. 3位的/r
字段变为另外3个操作码位,而不是操作数.对此有更多详细信息:
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:
- 如何阅读Intel Opcode表示法
- /4在FF/4中意味着什么?
- x64指令编码和ModRM字节-有关字段中的字段.
- How to read the Intel Opcode notation
- What does the /4 mean in FF /4?
- x64 instruction encoding and the ModRM byte - details about the fields in the modrm byte.
另请参见 x86函数调用类型
远"一个call
装入CS
段寄存器以及IP
/EIP
/RIP
.正常的靠近"呼叫仅需要一个32位(或64位)地址,并且不会修改CS
.
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
从未在正常"状态下使用.普通操作系统上的32位或64位用户空间代码,因为它们都使用平面内存模型.
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
是立即数,具有16位段值和32位绝对地址编码到指令中(小尾数,先偏移32位,然后是新的CS值). 这是far call
.请参阅此问题与解答.汇编程序将为far call some_symbol
生成此指令编码,并从段some_symbol
中定义段中获取段值.同样,您实际上不太可能在16位代码之外使用此代码.但是,如果您这样做,请参阅此问题与解答有关如何使MASM发出的信息.
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
是一个6字节的内存操作数,从ModR/M字节编码的有效地址加载. 这是另一个遥远的联系.因此call far [eax]
从eax
中的地址进行48位加载.对于ModR/M字节,只有存储器寻址模式才是合法的,因为该指令需要的数据比寄存器的宽度还要多. (即call far eax
不合法)
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
是用于近距离呼叫的内存或寄存器操作数.您可以从call eax
或call [eax]
中获得它.当然,任何寻址方式都是合法的,例如call FS:[edi + esi*4 + some_table]
. FS segment-override前缀适用于函数指针从中加载的位置,而不是其跳转到的段. (即,它不会更改CS,因为它仍然是近距离通话.)
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.)
如何在绝对地址0x717A60处调用该函数
How can I call the function at the absolute address 0x717A60
如果您的代码不必与位置无关,那么到目前为止,最好的选择是将其组装到call rel32
并以正确的相对位移到达该地址.使用NASM和AT& T语法,您可以简单地编写call 0x717A60
,而汇编程序+链接程序将对其进行处理.我不确定如何用MASM编写它; MSVC内联汇编不接受call 123456h
.
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
.
在call
编码附近没有绝对直接的编码,因此,如果您确实需要PIC,则应该执行类似mov eax, 0x717A60
/call eax
的操作.
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
.
您不想使用call far
绝对直接调用,因为它可能慢得多,并且将CS:EIP而不只是EIP作为返回地址.您还必须知道要在细分字段中输入什么.
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
这将反汇编为call DWORD PTR ds:0x70769890
(使用GNU objdump -Mintel
语法),即call r/m32
,其中操作数是[disp32]
绝对寻址模式.
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.
(或者在64位代码中,它是具有rel32
的RIP相对寻址模式,但仍然是从内存中静态位置加载功能指针的内存间接call
.)
(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.)
另请参见 x86 标签Wiki的问题,以了解更多信息链接到文档.
See also the x86 tag wiki for more links to docs.
这篇关于x86 asm中的调用指令的编码之间有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!