【问题标题】:What are the meanings of callq command parameters?callq命令参数的含义是什么?
【发布时间】:2019-05-14 02:02:10
【问题描述】:

我知道callq 指令的作用;它在this answer 中有描述。指令应该有一个参数,应该是被调用函数的地址。

然而,当反汇编一个目标文件时,我看到下面一行显示了一条callq 指令,其中包含两个值而不是一个参数:

  1e:   e8 00 00 00 00          callq  23 <main+0x19>

我假设23 是返回地址,&lt;main+0x19&gt; 是要调用的函数的地址。但是,被调用的函数不在地址main+0x19

callq指令反汇编显示的23main+0x19这两个值是什么意思?


原始C代码:

#include <stdio.h>

void fun(int a)
{
}

int main()
{
    int a = 1234;
    fun(a);
}

objdump -D main.o main.asm 反汇编代码:

0000000000000000 <fun>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   89 7d fc                mov    %edi,-0x4(%rbp)
   7:   90                      nop
   8:   5d                      pop    %rbp
   9:   c3                      retq   

000000000000000a <main>:
   a:   55                      push   %rbp
   b:   48 89 e5                mov    %rsp,%rbp
   e:   48 83 ec 10             sub    $0x10,%rsp
  12:   c7 45 fc 03 00 00 00    movl   $0x3,-0x4(%rbp)
  19:   8b 45 fc                mov    -0x4(%rbp),%eax
  1c:   89 c7                   mov    %eax,%edi
  1e:   e8 00 00 00 00          callq  23 <main+0x19>
  23:   b8 00 00 00 00          mov    $0x0,%eax
  28:   c9                      leaveq 
  29:   c3                      retq   

【问题讨论】:

  • 我不认为这是重复的,因为我认为这些答案中没有解决问题中的误解。
  • 我投票支持重新开放,因为所谓的“重复”问题既没有询问指令的参数,也没有一个答案回答它。
  • 我还以某种方式修改了这个问题 -- 理解它。 @Edward:我希望我正确理解了你的问题,问题仍然是问你想问什么。
  • @MartinRosenau:同意。这不是关于callqcall,而是首先要了解x86 call rel32 的工作原理以及反汇编程序如何帮助从相对偏移量计算绝对目标。以及未链接的目标文件如何工作。
  • @PeterCordes 我认为用户在理解23main+0x19 这两个值时存在问题。所以我相应地修改了这个问题。用户无法理解地址 0x1F 处有一些重定位。 ...以及理解objdump -D 不显示重定位的问题。

标签: linux assembly x86-64 disassembly object-files


【解决方案1】:

callq 指令只有一个操作数,而不是问题中暗示的两个操作数。反汇编器以两种形式显示它,作为地址和作为符号+偏移量。

您正在查看 unlinked 对象文件的反汇编。由于被反汇编的文件没有链接,所以显示的目标地址不是fun的地址。汇编器将 0 放在指令的操作数字段中,并为链接器创建一个重定位记录,以填充到目标最终地址的偏移量。

调用指令的操作数是一个偏移量,相对于调用后下一条指令的地址。因此,操作数字段中的值 0 会导致反汇编程序将下一条指令的地址显示为调用的目标。在所示的反汇编中,即地址 23。

如果您将fun 设为静态函数,则汇编器可能会填写函数的真实偏移量,因为它不需要重定位,并且您会在反汇编中看到它。 (这可能取决于您使用的确切工具和选项。)

如果您反汇编一个链接的可执行文件,反汇编程序将显示调用的真实目标地址。

【讨论】:

  • 反汇编链接的 PIE 可执行文件,较新的 Ubuntu 上的默认值,而不是 OP 的 16.04,仍将假定整个可执行文件的基地址为 0。但是,是的,将正确填写相对偏移量。当你实际运行它时,整个事情的基地址会改变,但不会改变相对偏移量或 symbol+x 显示跳转目标的方式。
  • 我使用 objdump -DrwC -Mintel main.o 的 asm 代码变成了: 1e: e8 00 00 00 00 call 23
    1f: R_X86_64_PC32 fun-0x4 23: b8 00 00 00 00 mov eax,0x0 为什么是重定位地址“fun-0x4”而不是“fun”
  • @Edward 该目标文件尚未重新定位。如您所见,call 的所有操作数字节都是00 00 00 00,即它们的值尚未填写。观察链接的二进制文件以查看正确的值。
  • 链接器填写重定位符号相对于正在填写的字段的第一个字节的相对偏移量,但是指令需要相对于下一条指令到目标的偏移量,这是一个区别4 个字节。
  • @prl 谢谢,我在《计算机系统:程序员的视角》中找到了我所有问题的答案
猜你喜欢
  • 2018-03-26
  • 2014-09-12
  • 1970-01-01
  • 1970-01-01
  • 2017-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多