Ответ 1
Согласно документам:
Это дает ссылку компоновщику добавлять все символы, а не только используемые, в таблицу динамических символов.
Это не символы отладки, они являются динамическими символами-линкерами. Они не удаляются с помощью strip
, поскольку он (в большинстве случаев) прерывает исполняемый файл - они используются компоновщиком времени выполнения для выполнения заключительной стадии ссылки вашего исполняемого файла.
Пример:
$ cat t.c
void foo() {}
int main() { foo(); return 0; }
Компилировать и связывать без -rdynamic
(и без оптимизации, очевидно)
$ gcc -O0 -o t t.c
$ readelf -s t
Symbol table '.dynsym' contains 3 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
Symbol table '.symtab' contains 50 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000400270 0 SECTION LOCAL DEFAULT 1
....
27: 0000000000000000 0 FILE LOCAL DEFAULT ABS t.c
28: 0000000000600e14 0 NOTYPE LOCAL DEFAULT 18 __init_array_end
29: 0000000000600e40 0 OBJECT LOCAL DEFAULT 21 _DYNAMIC
Таким образом, исполняемый файл имеет .symtab
со всем. Но обратите внимание, что .dynsym
вообще не упоминает foo
- в нем есть простые вещи. Для работы backtrace_symbols
недостаточно информации. Он опирается на информацию, представленную в этом разделе, для соответствия кодовых адресов с именами функций.
Теперь скомпилируйте с помощью -rdynamic
:
$ gcc -O0 -o t t.c -rdynamic
$ readelf -s t
Symbol table '.dynsym' contains 17 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
4: 0000000000601018 0 NOTYPE GLOBAL DEFAULT ABS _edata
5: 0000000000601008 0 NOTYPE GLOBAL DEFAULT 24 __data_start
6: 0000000000400734 6 FUNC GLOBAL DEFAULT 13 foo
7: 0000000000601028 0 NOTYPE GLOBAL DEFAULT ABS _end
8: 0000000000601008 0 NOTYPE WEAK DEFAULT 24 data_start
9: 0000000000400838 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used
10: 0000000000400750 136 FUNC GLOBAL DEFAULT 13 __libc_csu_init
11: 0000000000400650 0 FUNC GLOBAL DEFAULT 13 _start
12: 0000000000601018 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
13: 000000000040073a 16 FUNC GLOBAL DEFAULT 13 main
14: 0000000000400618 0 FUNC GLOBAL DEFAULT 11 _init
15: 00000000004007e0 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini
16: 0000000000400828 0 FUNC GLOBAL DEFAULT 14 _fini
Symbol table '.symtab' contains 50 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000400270 0 SECTION LOCAL DEFAULT 1
....
27: 0000000000000000 0 FILE LOCAL DEFAULT ABS t.c
28: 0000000000600e14 0 NOTYPE LOCAL DEFAULT 18 __init_array_end
29: 0000000000600e40 0 OBJECT LOCAL DEFAULT 21 _DYNAMIC
То же самое для символов в .symtab
, но теперь foo
имеет символ в разделе динамического символа (и там появляется и ряд других символов). Это делает работу backtrace_symbols
- теперь у нее достаточно информации (в большинстве случаев) для сопоставления кодовых адресов с именами функций.
Разделите это:
$ strip --strip-all t
$ readelf -s t
Symbol table '.dynsym' contains 17 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2)
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
4: 0000000000601018 0 NOTYPE GLOBAL DEFAULT ABS _edata
5: 0000000000601008 0 NOTYPE GLOBAL DEFAULT 24 __data_start
6: 0000000000400734 6 FUNC GLOBAL DEFAULT 13 foo
7: 0000000000601028 0 NOTYPE GLOBAL DEFAULT ABS _end
8: 0000000000601008 0 NOTYPE WEAK DEFAULT 24 data_start
9: 0000000000400838 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used
10: 0000000000400750 136 FUNC GLOBAL DEFAULT 13 __libc_csu_init
11: 0000000000400650 0 FUNC GLOBAL DEFAULT 13 _start
12: 0000000000601018 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
13: 000000000040073a 16 FUNC GLOBAL DEFAULT 13 main
14: 0000000000400618 0 FUNC GLOBAL DEFAULT 11 _init
15: 00000000004007e0 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini
16: 0000000000400828 0 FUNC GLOBAL DEFAULT 14 _fini
$ ./t
$
Нет .symtab
, но динамическая таблица символов все еще существует, и выполняется исполняемый файл. Так что backtrace_symbols
все еще работает.
Разделите таблицу динамических символов:
$ strip -R .dynsym t
$ ./t
./t: relocation error: ./t: symbol , version GLIBC_2.2.5 not defined in file libc.so.6 with link time reference
... и вы получите сломанный исполняемый файл.
Интересно, для чего используются .symtab
и .dynsym
: Внутри таблиц символов ELF. Одной из замечаний является то, что .symtab
не требуется во время выполнения, поэтому он отбрасывается загрузчиком. Этот раздел не сохраняется в памяти процесса. .dynsym
, с другой стороны, необходим во время выполнения, поэтому он сохраняется в образе процесса. Таким образом, он доступен для таких вещей, как backtrace_symbols
для сбора информации о текущем процессе изнутри.
Короче говоря:
- динамические символы не делятся на
strip
, так как это сделает исполняемый невыгружаемый -
backtrace_symbols
нужны динамические символы, чтобы выяснить, какой код принадлежит той функции -
backtrace_symbols
не использует отладочные символы
Следовательно, поведение, которое вы заметили.
По вашим конкретным вопросам:
-
gdb
- отладчик. Он использует отладочную информацию в исполняемом файле и библиотеках для отображения соответствующей информации. Он намного сложнее, чемbacktrace_symbols
, и проверяет фактические файлы на вашем диске в дополнение к текущему процессу.backtrace_symbols
нет, он полностью находится в процессе - поэтому он не может обращаться к разделам, которые не загружаются в исполняемый образ. Отладочные разделы не загружаются в образ среды выполнения, поэтому они не могут их использовать. -
.dynsym
не является частью отладки. Это раздел, используемый динамическим компоновщиком..symbtab
также не является частью отладки, но он может использоваться отладчиком, имеющим доступ к исполняемым (и библиотечным) файлам.-rdynamic
не генерирует отладочные разделы, а только эту расширенную таблицу динамических символов. Выполняемый рост из-rdynamic
полностью зависит от количества символов в этом исполняемом (и соображениях выравнивания/дополнения). Он должен быть значительно меньше-g
. - За исключением статически связанных двоичных файлов, исполняемым файлам требуются внешние зависимости, разрешенные во время загрузки. Как ссылка
printf
и некоторые процедуры запуска приложений из библиотеки C. Эти внешние символы должны быть указаны где-то в исполняемом файле: для этого используется.dynsym
, и поэтому exe имеет.dynsym
, даже если вы не указали-rdynamic
. Когда вы это укажете, компоновщик добавляет другие символы, которые не нужны для работы процесса, но могут использоваться такими вещами, какbacktrace_symbols
. -
backtrace_symbols
не будет разрешать имена функций, если вы статически ссылаетесь. Даже если вы укажете-rdynamic
, раздел.dynsym
не будет отправлен в исполняемый файл. Таблицы символов не загружаются в исполняемый образ, поэтомуbacktrace_symbols
не может сопоставлять кодовые адреса с символами.