为什么我在反汇编输出中看到条件跳转到相对偏移量零(也称为跳转到下一条指令)?

问题描述 投票:0回答:1

上下文:我知道——或者至少,an——这个问题的答案;我将其发布在这里是因为几个小时前,当我没有这样做时,我无法通过搜索这些关键字找到任何内容。


有时,当我查看反汇编输出时,我会看到一个条件跳转到下一行,这是没有意义的——要么你去那里因为检查失败而你没有跳转,要么你去那里因为检查通过并且你确实跳到那里了。

例如,如果我编译以下小型 C++ 程序

#include <stdexcept>

bool f(int x, int y, int z)
{
  switch(x)
  {
    case 0: return z < y;
    case 1: return y < z;
    default: throw std::runtime_error("bad x");
  }
}

下到一个

.o
文件,然后使用
objdump -C -d
对其进行反汇编,部分反汇编如下所示:

0000000000000000 <f(int, int, int)>:
   0:   f3 0f 1e fa             endbr64
   4:   39 d6                   cmp    %edx,%esi
   6:   0f 9f c0                setg   %al
   9:   85 ff                   test   %edi,%edi
   b:   75 03                   jne    10 <f(int, int, int)+0x10>
   d:   c3                      ret
   e:   66 90                   xchg   %ax,%ax
  10:   83 ff 01                cmp    $0x1,%edi
  13:   0f 85 00 00 00 00       jne    19 <f(int, int, int)+0x19>
  19:   39 d6                   cmp    %edx,%esi
  1b:   0f 9c c0                setl   %al
  1e:   c3                      ret

指令

0f 85 00 00 00 00
,条件跳转到相对偏移量0,在反汇编中显示为
jne 19
。这似乎毫无意义,因为无论条件如何,它似乎都分支到下一条指令。

这里到底发生了什么?

assembly x86-64 objdump
1个回答
0
投票

如果我们查看更多的反汇编,我们会注意到一些事情;

Disassembly of section .text:

0000000000000000 <f(int, int, int)>:
   0:   f3 0f 1e fa             endbr64
   4:   39 d6                   cmp    %edx,%esi
   6:   0f 9f c0                setg   %al
   9:   85 ff                   test   %edi,%edi
   b:   75 03                   jne    10 <f(int, int, int)+0x10>
   d:   c3                      ret
   e:   66 90                   xchg   %ax,%ax
  10:   83 ff 01                cmp    $0x1,%edi
  13:   0f 85 00 00 00 00       jne    19 <f(int, int, int)+0x19>
  19:   39 d6                   cmp    %edx,%esi
  1b:   0f 9c c0                setl   %al
  1e:   c3                      ret

Disassembly of section .text.unlikely:

0000000000000000 <f(int, int, int) [clone .cold]>:
   0:   55                      push   %rbp
   1:   bf 10 00 00 00          mov    $0x10,%edi
   6:   53                      push   %rbx
   7:   50                      push   %rax
   8:   e8 00 00 00 00          call   d <f(int, int, int) [clone .cold]+0xd>
   d:   48 8d 35 00 00 00 00    lea    0x0(%rip),%rsi        # 14 <f(int, int, int) [clone .cold]+0x14>

[snip]

我们应该在单独的部分中跳转到的代码,.text.unlikely。

跳转的

00 00 00 00
相对地址是一个占位符,链接器将填充该占位符,以指向最终放置 .text.unlikely 中的代码的位置。
.o
文件中有一些
objdump
未显示的元数据告诉它执行此操作。

如果您不是编译为

.o
文件,而是在反汇编之前一直编译为可执行文件,则不会出现此问题,因为链接器已经完成其工作并填写了地址。

您还可以通过简单地将

g++
停止在汇编代码级别来绕过此问题,而无需使用
.o
标志生成
-S
文件。 然而,与使用
objdump
相比,这有一个缺点,即
objdump
可以对名称进行分解,而
g++ -S
显然不能。

© www.soinside.com 2019 - 2024. All rights reserved.