2012-01-08 5 views
1

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

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

#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 

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

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 <[email protected]> 
    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 <[email protected]> 
    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 <[email protected]> 
    40057d: b8 00 00 00 00  mov $0x0,%eax 
} 

Похоже адрес функции PRINTF дается в callq линия: 400410. Но когда я

addr2line -e a.out 0x400410 

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

??:0 

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

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

+1

N.B: stdio.h содержит * объявление * 'printf()' not a * definition *. В чем проблема * реального *, которую вы пытаетесь решить (и почему вы используете g ++ для компиляции C)? – Johnsyweb

+0

Реальная проблема, которую я хочу решить, находится в большой базе кода. Существует вызов функции (скажем, xyz()), и функция содержится в одном из 100 или около того включенных файлов. Я хочу определить, где находится функция (декларация). –

+0

@Johnsyweb, если стандартная библиотека была скомпилирована с '-g', мы увидели бы соответствующий номер строки? Я думаю, что все. –

ответ

3

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

EDIT: На втором взгляде на параметры вашего компилятора я вижу, что исполняемый файл связан вместе. Если у вас есть встроенные символы отладки, вам может потребоваться указать, какой раздел вы хотите использовать с addr2line.

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

+0

Joshua K: [http://wiki.linuxquestions.org/wiki/Addr2line], похоже, указывает на то, что расположение функций из внешних библиотек также записывается в исполняемый файл, но это, похоже, не работает для меня. –

+0

В этих примерах '_init' встроен в программу через время выполнения C в качестве объектного кода компилятором. 'printf' с другой стороны находится внутри glibc. – jmkeyes

2

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

g++ -E test.cpp | less 

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

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

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

Не требуется компиляция, связывание или захоронение объектов!

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


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

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

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

Удачи вам!

+1

Похоже, что мы должны искать определение - см. Последние комментарии по этому вопросу. (Хороший ответ в противном случае). –

+0

@AaronMcDaid: Ах. Я отправил свой ответ после того, как Йоги прокомментировал: «Я хочу определить, где находится функция (декларация)». В этом случае мой последний абзац, вероятно, лучший совет, который я могу предложить. Это и учиться различать C и C++ и декларации, определения и призывы. – Johnsyweb

1

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 
[email protected] 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

Спасибо Рафал. Какую дополнительную информацию дает gdb в этом примере. Информация из [info symbol] также появляется в файле objdump. Может быть, я чего-то не хватает. –

+0

GDB запускает исполняемый файл, который связывает его в памяти. Когда вы вызываете 'info 0x400448', он ищет символ по этому адресу (который разрешает' printf') и отмечает, что он находится в секции PLT исполняемого файла. – jmkeyes

0

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

g++ -g -static test.cpp 

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

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

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

Смежные вопросы