条件跳转到寄存器

5

我想获取这些命令:

jl some_label(%rip)
# or
jl *%rax

我正在为英特尔x64架构编写汇编程序。

当我尝试编译此代码时,GCC会提示“jl操作数类型不匹配”。

2个回答

7

在x86上,条件跳转是相对的。您可以使用“倒置”的条件跳转,然后是一个无条件跳转:

  jge   skip_jump
  jmp   *%rax       # AT&T syntax
skip_jump:

相应的NASM语法是jmp rax。两种写法都将RIP设置为RAX,因此这是一次寄存器间接跳转。

我必须将我的二进制代码插入到另一个二进制文件中,当我尝试运行我的代码时,它无法使用任何标签,因为它们是使用其他地址计算的。这就是为什么我不能在我的代码中使用任何标签。 - Roman Kovtuh
汇编器将条件跳转的目标标签转换为相对偏移量。我不知道你所说的“与其他地址计算”的意思。例如,如果jmp %rax指令的大小为4个字节,则jge skip_jump将简单地变成7D 04(或者按最低有效位先写的04 7D)。 - Michael
我明白你的意思,但在实践中,当程序链接到可执行文件时,我可以看到绝对地址。如果标签可以表示为相对偏移量,我就不会有任何问题,但每次我想要使用标签进行跳转时,我都必须计算标签的偏移量。 - Roman Kovtuh
反汇编器可能会将地址显示为绝对地址,但没有“Jxx absolute”指令。计算用于跳过代码片段的前向跳转的跳转偏移量很简单;它等于要跳过的代码的大小。 - Michael
谢谢。我忘记了在obj文件中跳转地址是以相对偏移量存储的,而不是在可执行文件中。现在我使用obj文件将其加载到其他二进制文件中,它可以正常工作。 - Roman Kovtuh
显示剩余2条评论

1

有条件地跳过间接的 jmp rax 通常是正确的方法。

另一个选择是使用 cmov 修改目标地址:

  ## Normally worse than jge, but worth considering
    lea       stay_here(%rip), %rdx         # pick any register
    cmovge    %rdx, %rax
    jmp       *%rax
stay_here:

这会导致更大的代码大小和更多的uops,但在taken path上只有一个总分支。此外,对于间接分支目标的默认预测通常是+0(即下一条指令),如果BTB没有其历史记录,则可能在预测冷启动时正确预测。

除此之外,跳转到下一条指令并没有特殊处理,仍然需要正确的预测,并且仍然可能减慢前端速度。

在某些具有简单/弱间接分支预测的CPU上,将条件合并到间接分支中几乎肯定会造成损失,因为它是一个额外的可能分支目标。

但是,如果您发现jge / jmp组合的预测效果不佳,这将是值得尝试的一种混合方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接