Думаю, вам, возможно, потребуется прочитать немного больше о динамической компоновке. Давайте возьмем strlen
в качестве примера символа, так как printf
немного особенный (фортификационный материал).
Ваша проблема (я думаю), что вы хотите взять адрес символа и перевести его обратно в адрес. Вы пытаетесь это сделать, анализируя ELF-файл программы, которую вы отлаживаете. Это работает с символами, которые находятся в вашей программе, но не с динамически связанными символами, такими как strlen
. И вы хотите знать, как это решить.
Причина в том, что адрес символов, таких как strlen
, не содержится в вашей программе ELF. Вместо этого они являются нерешенными ссылками, которые динамически разрешаются , когда программа загружает. Действительно, современный Linux (я полагаю) загружает динамические библиотеки (которые содержат перемещаемый или независимый от позиции код) в рандомизированном порядке и рандомизированных адресах, поэтому расположение этих символов будет неизвестно до загрузки программы.
Для библиотек, которые вы открыли с помощью dlopen()
(т. Е. Где вы загружаете себя в программу), вы можете получить адрес таких символов, используя dlsym()
; это не очень хорошо, если они связаны с программой во время компиляции/ссылки.
На gcc, чтобы разрешить положение символов в общем, используйте расширение gcc dladdr()
. Со страницы руководства:
The function dladdr() takes a function pointer and tries to
resolve name and file where it is located. Information is
stored in the Dl_info structure:
typedef struct {
const char *dli_fname; /* Pathname of shared object that
contains address */
void *dli_fbase; /* Address at which shared object
is loaded */
const char *dli_sname; /* Name of nearest symbol with address
lower than addr */
void *dli_saddr; /* Exact address of symbol named
in dli_sname */
} Dl_info;
If no symbol matching addr could be found, then dli_sname and
dli_saddr are set to NULL.
dladdr() returns 0 on error, and nonzero on success.
Я считаю, что это сработает для вас.
Для получения дополнительной информации, я предлагаю вам посмотреть на source к ltrace
, который отслеживает библиотечные вызовы, и как backtrace_symbols
(и here) работ; обратите внимание, что особенно для неглобальных символов это будет ненадежным, и обратите внимание на комментарий, добавляющий -r dynamic
к линии ссылок.
Возможно, вы также захотите посмотреть addr2line и его source.
Включена ли динамическая связь? – fuz
В glibc символ 'printf' на самом деле называется' __printf_chk' из-за фортификационного патча. Запустите 'nm' в объектном файле, который вызывает' printf', и вы увидите. Как правило, посмотрите на libelf как на то, как разбирать файлы эльфа. Я рекомендую вам не разбирать их вручную. – fuz
Я уже использую libelf. И на самом деле, если я использую nm, я могу видеть символ «printf», но не его адрес, а символ помечен буквой «U» для «Undefined». Это моя проблема, я использую адрес функции для извлечения ее имени. Но если адрес не заполнен эльфом, я не могу получить имя. И да, libc динамически связан. Думаю, –