如何对 AT&T 语法中的标签进行相对 jmp?
Posted
技术标签:
【中文标题】如何对 AT&T 语法中的标签进行相对 jmp?【英文标题】:How to do a relative jmp to a label in AT&T syntax? 【发布时间】:2021-10-06 16:04:58 【问题描述】:如果我在汇编中编写(at&t 语法,x86-64):
jmpq 0x4(%rip)
然后跳转到4+rip
但是如果我写的话它会跳到哪里:
jmpq label(%rip)
其中标签 = 4?
我很困惑,因为它可能是相同的答案,也可能与我们移动标签和 NOT 标签 + rip 的 movq 相同。
【问题讨论】:
如果label
被定义为常量,例如使用.equ
那么它的行为就像你使用4
一样。否则汇编器将调整偏移量。请注意,这对mov
的作用相同。
@Jester 对不起,我的意思是如果 label 是这样的标签:in .text
@CherryDT 为什么你同时添加了这两个?在 mov 它忽略 rip...
【参考方案1】:
要执行导致 RIP = 标签的正常相对跳转,使用jmp label
。
汇编器计算相对位移。
(是的,你必须使用jmp
而不是jmpq
。An operand-size suffix for jmp
implies an indirect jump in AT&T syntax,不像calll
/ callq
,这是一个疯狂且令人困惑的糟糕设计。)
相对直接跳转与自 8086 以来的工作方式相同,并且与 x86-64 中新增的 RIP 相对数据寻址模式没有任何关系。 (How do RIP-relative variable references like "[RIP + _a]" in x86-64 GAS Intel-syntax work? 还介绍了 AT&T 语法如何用于4(%rip)
与label(%rip)
用于数据寻址。)
您不想从函数指针加载新的 RIP,所以不要使用内存寻址模式。亲戚jmp
本身不访问内存; label
的内存只有在 jmp
完成后才能通过代码获取访问。 (真正的 CPU 是通过分支预测和其他东西流水线化的,但仍然保持指令在下一个开始之前完全执行的 错觉,例如,相对于未映射页面的 jmp
可以完全执行而不会出现自身故障,只有保存 RIP = 新位置的下一个代码提取操作出错。)
然后
jmpq 0x4(%rip)
跳转到4+rip
不,它没有。如果你真的组装它,它会警告indirect jmp without '*'
。拆解展示
ff 25 04 00 00 00 jmp *0x4(%rip)
即它从jmp
指令结束后4 个字节开始的qword 将指针从内存中加载 到RIP。它没有设置 RIP = RIP+4,那将是 jmp .+2 + 4
(因为短跳转是 2 个字节长,或者如果你在 jmp 后面加上标签,jmp end_of_insn + 4
)
【讨论】:
所以总结一下这将跳转到什么:jmpq my_int_var(%rip)? my_int_var=4? @Dan:你的意思是如果你在asm源码中使用my_int_var=4
,和.equ my_int_var, 4
一样把符号地址设置为4
?事实证明,这与执行jmpq 4(%rip)
相同,而不是使用 RIP 相对寻址模式来到达绝对地址 4。您可以并且应该自己尝试使用 gcc -c foo.s
&& objdump -drwC foo.o
。它会警告没有*
的间接跳转。
@Dan: 除非my_int_var=4
的定义出现在源代码中的jmp
之后,在这种情况下,您会在目标文件中获得重定位,并且在链接时您确实会获得401000: ff 25 fe ef bf ff jmp *-0x401002(%rip) # 4 <my_int_var>
从地址4
加载一个指针,它使用RIP 相对寻址模式到达该地址。我猜 GAS 很奇怪,因为它是一个 1-pass (over the source) 汇编程序。 Distinguishing memory from constant in GNU as .intel_syntax 基本上是同一个问题。以上是关于如何对 AT&T 语法中的标签进行相对 jmp?的主要内容,如果未能解决你的问题,请参考以下文章
AT&T 语法中的 3 或 4 参数 x86 程序集[重复]