x86中的jmpl指令是什么? [英] what is jmpl instruction in x86?
问题描述
x86组件设计具有指令后缀,例如l(long)
,w(word)
,b(byte)
.
所以我认为jmpl
是long jmp
但是当我编译它时,它工作得很奇怪.
请参见下面的示例.
x86 assembly design has instruction suffix, such as l(long)
, w(word)
, b(byte)
.
So I thought that jmpl
to be long jmp
But it worked quite weird when I compile it.
See below example.
Test1 :程序集
main:
jmp main
Test1 :编译结果
eb fe jmp 0x0804839b <main>
Test2 :程序集
main:
jmpl main # added l suffix
Test2 :编译结果
ff 25 9b 83 04 08 jmp *0x0804839b
与Test1相比, Test2 结果出乎意料.
我认为它应该与Test1一样编译.
问题:
jmpl
在8086设计中是否有不同的说明?
(根据此处,SPARK中的jmpl
表示jmp链接.是这样吗?)
...或者这仅仅是gnu汇编器上的错误?
Compared to Test1, Test2 result is unexpected.
I think It should be compiled as same as Test1.
Question:
Is jmpl
something different instruction in 8086 design?
(according to here, jmpl
in SPARK means jmp link. is it something like this?)
...Or is this just bug on gnu assembler?
推荐答案
与calll main
不同的是,l
操作数大小的后缀表示间接jmp
-称呼. 这种不一致是AT& T语法设计中的纯粹精神错乱.
An l
operand-size suffix implies an indirect jmp
, unlike with calll main
which is still a relative near-call. This inconsistency is pure insanity in AT&T syntax design.
(而且,由于您将其与main
之类的操作数一起使用,因此它成为内存间接跳转,从main
进行数据加载并将其用作新的EIP值.)
(And since you're using it with an operand like main
, it becomes a memory-indirect jump, doing a data load from main
and using that as the new EIP value.)
您永远不需要使用jmpl
助记符,可以并且应该在操作数上使用*
指示间接跳转.类似于jmp *%eax
设置EIP = EAX,或者jmp *4(%edi, %ecx, 4)
索引跳转表,或者jmp *func_pointer
.在所有这些中,使用jmpl
是可选的.
You never need to use the jmpl
mnemonic, you can and should indicate indirect jumps using *
on the operand. Like jmp *%eax
to set EIP = EAX, or jmp *4(%edi, %ecx, 4)
to index a jump table, or jmp *func_pointer
. Using jmpl
is optional in all of these.
您可以使用jmpw *%ax
将EIP截断为16位值.汇编为66 ff e0 jmpw *%ax
)
You could use jmpw *%ax
to truncate EIP to a 16-bit value. That assembles to 66 ff e0 jmpw *%ax
)
比较什么是callq指令?和 retq和ret有什么区别?,这只是操作数大小的后缀,与您预期的一样,与普通call
或普通ret
相同.但是jmp
是不同的.
Compare What is callq instruction? and What is the difference between retq and ret?, that's just the operand-size suffix behaving like you expected it would, same as plain call
or plain ret
. But jmp
is different.
半相关:AT& T语法中的远jmp或呼叫(到新的CS:[ER] IP)是ljmp/lcall.这些是非常不同的.
semi-related: far jmp or call (to a new CS:[ER]IP) in AT&T syntax is ljmp / lcall. These are very different.
GAS接受jmpl main
等同于jmpl *main
也是疯狂的.它只会警告而不是错误.
It's also insane that GAS accepts jmpl main
as equivalent to jmpl *main
. It only warns instead of erroring.
$ gcc -no-pie -fno-pie -m32 jmp.s
jmp.s: Assembler messages:
jmp.s:3: Warning: indirect jmp without `*'
然后使用objdump -drwC a.out
拆解它,看看我们得到了什么:
And then disassembling it to see what we got, with objdump -drwC a.out
:
08049156 <main>: # corresponding source line (added by hand)
8049156: ff 25 56 91 04 08 jmp *0x8049156 # jmpl main
804915c: ff 25 56 91 04 08 jmp *0x8049156 # jmp *main
8049162: ff 25 56 91 04 08 jmp *0x8049156 # jmpl *main
08049168 <foo>:
8049168: e8 fb ff ff ff call 8049168 <foo> # calll foo
804916d: ff 15 68 91 04 08 call *0x8049168 # calll *foo
8049173: ff 15 68 91 04 08 call *0x8049168 # call *foo
如果在源代码中将l
替换为q
,并且在没有-m32
的情况下进行构建(使用默认的-m64
),则会得到相同的结果.包括有关缺少*
的相同警告.但是反汇编在每条指令上都有一个显式的jmpq
和callq
. (除了我添加的相对直接jmp
外,它在反汇编中使用jmp
助记符.)
We get the same thing if we replace l
with q
in the source, and built without -m32
(using the default -m64
). Including the same warning about a missing *
. But the disassembly has an explicit jmpq
and callq
on every instruction. (Except for a relative direct jmp
I added, which uses the jmp
mnemonic in the disassembly.)
就像objdump认为32位是32位和64位模式下jmp/call的默认操作数大小,因此它希望始终使用64位的q
后缀,但将其保留为隐式32位模式.无论如何,那只是在隐式/显式后缀之间的反汇编选择,对于程序员编写源代码没有怪异.
It's like objdump thinks 32-bit is the default operand-size for jmp/call in both 32 and 64-bit mode, so it wants to always use a q
suffix in 64-bit, but leaves it implicit in 32-bit mode. Anyway, that's just disassembly choice between implicit / explicit size suffixes, no weirdness for a programmer writing source code.
-
Clang的内置汇编器确实拒绝了
jmpl main
,需要jmpl *main
.
Clang's built-in assembler does reject
jmpl main
, requiringjmpl *main
.
$ clang -m32 jmp.s
jmp.s:3:8: error: invalid operand for instruction
jmpl main
^~~~
calll main
与call main
相同.间接跳转均使用call *main
和calll *main
.
calll main
is the same as call main
. call *main
and calll *main
are both accepted for indirect jumps.
YASM的GAS语法模式将jmpl main
组装为一个相对相对的jmp,例如jmp main
!.因此,它与gcc/clang关于jmpl
暗示间接不同意. (很少有人在GAS模式下使用YASM;如今,对于AVX512这样的新指令,它的维护一直没有跟NASM保持一致.我喜欢YASM对于长NOP的良好默认设置,但否则,我建议使用NASM.)
YASM's GAS-syntax mode assembles jmpl main
to a near relative jmp, like jmp main
! So it disagrees with gcc/clang about jmpl
implying indirect. (Very few people use YASM in GAS mode; and these days its maintenance hasn't kept up with NASM for new instructions like AVX512. I like YASM's good defaults for long NOPs, but otherwise I'd recommend NASM.)
这篇关于x86中的jmpl指令是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!