x86中的jmpl指令是什么? [英] what is jmpl instruction in x86?

查看:454
本文介绍了x86中的jmpl指令是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

x86组件设计具有指令后缀,例如l(long)w(word)b(byte).
所以我认为jmpllong 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),则会得到相同的结果.包括有关缺少*的相同警告.但是反汇编在每条指令上都有一个显式的jmpqcallq. (除了我添加的相对直接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, requiring jmpl *main.

$ clang -m32 jmp.s
jmp.s:3:8: error: invalid operand for instruction
  jmpl main
       ^~~~

calll maincall main相同.间接跳转均使用call *maincalll *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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆