Я использую ltrace и objdump для анализа простого кода ниже. Но я обнаружил, что есть разница в адресах инструкций, показанных между ltrace и objdump.
#include <iostream>
int main() {
std::cout << "Hello";
return 0;
}
Из следующей информации видно, что адрес [call std::basic_ostream] равен [0x400789] в ltrace. (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) +++
Однако адрес [call std::basic_ostream], показанный в objdump, равен [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
Я действительно хочу знать, что вызывает разрыв. Спасибо большое.
Это адреса возврата (инструкция после call в родительском элементе; ltrace не может знать, как долго длилась инструкция, вызвавшая функцию, только адрес возврата, который она получила. Или, если бы она была вызвана хвостом, выполнение достигло бы ее из jmp или что-то в этом роде.





Это адреса возврата (инструкция после call в родительском адресе, который call помещает в стек).
ltrace не может знать, как долго длилась инструкция, вызывающая функцию, например. call reg с указателем на функцию составляет всего 2 байта против 5 для call rel32 против 6 для call [RIP + rel32] (косвенный вызов памяти, который будет использовать GCC, если вы компилируете с -fno-plt.)
Или, если бы он был вызван хвостом, выполнение достигло бы его из jmp или чего-то еще, поэтому даже на ISA с инструкциями фиксированной длины, такими как MIPS или AArch64, ltrace все еще не мог надежно печатать, откуда он был вызван. Лучше не пытаться делать слишком много вещей и сохранять простоту, печатая адрес, который он действительно может видеть в стеке вызовов.
Например, почему адрес функции и адрес, который вы видите в
ltrace, не совпадают? Это, вероятно, в середине функции.