Какая функция вызывается в программе на C? - PullRequest
1 голос
/ 08 января 2012

Я пытаюсь выяснить, какая именно функция вызывается (из какого включаемого файла), когда я вызываю библиотечную функцию.

Итак, у меня есть эта программа,

#include <stdio.h>
#include <math.h>

int twice(int input) {
  int output;
  output = input * 2;
  return output;
}

int main(int argc, char **argv) {
  printf("Hello World and %f\n", sin(1));
  printf("Output: %d\n", twice(3));
  printf("Here is the end of the program... %d\n", 3);
}

Я хочу увидеть, какой printf вызывается.(Я знаю, что в данном случае это тот, что в stdio.h, но это только пример.)

Я скомпилирую файл:

g++ -g test.cpp

, а затем сделаю дамп сборкиcode

objdump --source a.out > test.objdump

В test.objdump я вижу строки вроде

int main(int argc, char **argv) {
  400528: 55                    push   %rbp
  400529: 48 89 e5              mov    %rsp,%rbp
  40052c: 48 83 ec 10           sub    $0x10,%rsp
  400530: 89 7d fc              mov    %edi,-0x4(%rbp)
  400533: 48 89 75 f0           mov    %rsi,-0x10(%rbp)
  printf("Hello World and %f\n", sin(1));
  400537: f2 0f 10 05 91 01 00  movsd  0x191(%rip),%xmm0   #4006d0<__dso_handle+0x50>
  40053e: 00
  40053f: bf 88 06 40 00        mov    $0x400688,%edi
  400544: b8 01 00 00 00        mov    $0x1,%eax
  400549: e8 c2 fe ff ff        callq  400410 <printf@plt>
  printf("Output: %d\n", twice(3));
  40054e: bf 03 00 00 00        mov    $0x3,%edi
  400553: e8 bc ff ff ff        callq  400514 <_Z5twicei>
  400558: 89 c6                 mov    %eax,%esi
  40055a: bf 9c 06 40 00        mov    $0x40069c,%edi
  40055f: b8 00 00 00 00        mov    $0x0,%eax
  400564: e8 a7 fe ff ff        callq  400410 <printf@plt>
  printf("Here is the end of the program... %d\n", 3);
  400569: be 03 00 00 00        mov    $0x3,%esi
  40056e: bf a8 06 40 00        mov    $0x4006a8,%edi
  400573: b8 00 00 00 00        mov    $0x0,%eax
  400578: e8 93 fe ff ff        callq  400410 <printf@plt>
  40057d: b8 00 00 00 00        mov    $0x0,%eax
}

Кажется, что адрес функции printf указан в строке callq: 400410. Но когда я делаю

addr2line -e a.out 0x400410 

(я тоже пробовал 400410 без 0x), я получаю

??:0

, который не дает мне местоположение функции printf.Может кто-нибудь указать на ошибку в моем процессе.Есть ли какая-то опция для g ++, которую я не передаю?

Действительно признателен за помощь.Спасибо!

Ответы [ 4 ]

3 голосов
/ 08 января 2012

Вы компилируете свой код в объектный код, а затем выгружаете код сборки из объектного кода.В этот момент код не был связан компоновщиком, и поэтому printf является просто символом в таблице процедурных связей.Только когда программа будет связана, это определение появится.

РЕДАКТИРОВАТЬ: На второй взгляд на параметры вашего компилятора, я вижу, что исполняемый файл связан вместе.Если у вас есть встроенные символы отладки, вам может потребоваться указать, какой раздел вы хотите использовать с addr2line.

Что касается использования printf, я считаю, что addr2line может найти только определения функцийлокальный для вашего исполняемого файла, а не функции, определенные внешними библиотеками.С точки зрения test.cpp, printf существует вне себя и не может иметь строки, под которой он был определен, потому что это будет записано только связываемой библиотекой.Если эта библиотека (в данном случае glibc) не была скомпилирована как отладочная сборка, вы не можете знать, для какого файла и номера строки она была определена.

2 голосов
/ 08 января 2012

Если вы просто хотите найти объявление из printf() (в C или C ++ не ясно из вашего вопроса, который вы используете), вы можете сделать:

g++ -E test.cpp | less

Где -E означает:

-E только препроцесс; не компилировать, не собирать и не ссылаться

Затем выполните поиск вперед / для printf, чтобы найти объявление (оно должно быть объявлено до его использования и, следовательно, должно быть первым попаданием). Затем выполните поиск в обратном направлении ? для ^#, чтобы найти, из какого файла это было включено.

Компиляция, компоновка или дамп объекта не требуются!

Я также рекомендую проверить ack и ctags, оба из которых могут быть использованы для нахождения символов в больших исходных деревьях с большой эффективностью.


После дальнейших комментариев ...

Поиск определения путем компиляции и связывания вашего кода не всегда возможен. Вы видели это с printf(), который вы не создали и, возможно, не существует на вашем компьютере. Также обратите внимание на определения, написанные на других языках, или определения, которые должны быть разрешены во время выполнения.

ack и ctags, вероятно, будут лучшим подходом для вас.

Удачи!

1 голос
/ 08 января 2012

addr2line может найти только определения, содержащиеся в данном исполняемом файле, поэтому он ничего не скажет о printf ответе:

rafal:~/test$ addr2line -f 0x400448
??
??:0
rafal:~/test$ addr2line -f 0x400554
_Z5twicei
/home/rafal/test/c.cpp:4

Также для поиска информации о функциях в общих библиотеках вы можетеиспользовать GDB

gdb a.out
(gdb) info symbol 0x400448
printf@plt in section .plt of /home/rafal/test/a.out
(gdb) info symbol 0x400554
twice(int) in section .text of /home/rafal/test/a.out
0 голосов
/ 09 января 2012

Попробуйте это:

g++ -g -static test.cpp

Это должно устранить всю путаницу для вас.

Без -static ссылок gcc против общих библиотек.Это означает, что такие функции, как printf, вообще отсутствуют в вашей программе, но загружаются из / lib во время выполнения.Это более экономно, но, возможно, немного медленнее (хотя ваша система в целом будет работать быстрее).Вы можете проверить содержимое работающей программы с помощью GDB, но имейте в виду, что совместное использование кода означает, что существует множество путаниц, таких как GOT и PLT, и тому подобное.

Компиляция в виде статического двоичного файла тянет во всю системуфункции и помещает их в вашу программу.Обратите внимание, что это не работает со всеми возможными библиотеками (если они не предоставляют статическую альтернативу).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...