ltrace 和 objdump 中显示的不同指令地址

Different instruction address shown in ltrace and objdump

我使用ltrace和objdump来分析下面的简单代码。但是我发现 ltrace 和 objdump 显示的指令地址不同。

#include <iostream>
int main() {
    std::cout << "Hello";
    return 0;
}

如下信息,在ltrace中可以看到[call std::basic_ostream]的地址是[0x400789]。 (0x400789是call指令的地址,不是std::basic_ostream)

binary@binary-VirtualBox:~/code/chapter5/test$ ltrace -i -C ./a.out
[0x4006a9] __libc_start_main(0x400776, 1, 0x7fff06c6ad28, 0x4007f0 <unfinished ...>
[0x4007b7] std::ios_base::Init::Init()(0x601171, 0xffff, 0x7fff06c6ad38, 160)             = 0
[0x4007cb] __cxa_atexit(0x400650, 0x601171, 0x601048, 0x7fff06c6ab00)                     = 0
[0x400789] std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)(0x601060, 0x400874, 0x7fff06c6ad38, 192) = 0x601060
[0x7f220180aff8] std::ios_base::Init::~Init()(0x601171, 0, 0x400650, 0x7f2201b96d10Hello)      = 0x7f2201f19880
[0xffffffffffffffff] +++ exited (status 0) +++

然而,objdump中显示的[call std::basic_ostream]的地址是[0x400784]并且 另一条指令 [mov eax,0x0] 在 [0x400789] 上。其他“调用”指令也是如此。

0000000000400776 <main>:
  400776:       55                      push   rbp
  400777:       48 89 e5                mov    rbp,rsp
  40077a:       be 74 08 40 00          mov    esi,0x400874
  40077f:       bf 60 10 60 00          mov    edi,0x601060
  400784:       e8 d7 fe ff ff          call   400660 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
  400789:       b8 00 00 00 00          mov    eax,0x0
  40078e:       5d                      pop    rbp
  40078f:       c3                      ret    

我真的很想知道造成差距的原因。 非常感谢。

那些是return地址(在父call之后的指令,call压入堆栈的地址)。

ltrace 无法知道调用函数的指令有多长,例如带有函数指针的 call reg 只有 2 个字节,call rel32 为 5 个字节,call [RIP + rel32] 为 6 个字节(如果使用 [=16= 编译,GCC 将使用 memory-indirect 调用].)

或者如果它是 tail-called,执行将从 jmp 或其他东西到达它,所以即使在具有 fixed-length 指令的 ISA 上,如 MIPS 或 AArch64,ltrace 仍然无法可靠地打印调用它的位置。最好不要试图编造太多东西并保持简单,打印它在调用堆栈上实际看到的地址。