如何对 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 语法时汇编程序崩溃 [重复]

AT&T 语法中的 3 或 4 参数 x86 程序集[重复]

如何解决错误:我的代码中出现分段错误(核心转储)? AT&T 语法

x86 AT&T 语法程序集的注释语法

x86-64 汇编中的数组元素比较(AT&T 语法)

JL 在 at&t 语法中是啥意思?