GCC: почему глобальная переменная отсутствует в динамической таблице символов?
Код:
//test.c
#include <stdio.h>
int v_flag = 0xCACA;
void main(int argc, char* argv[]){
printf("v_flag = %d, &v_flag=%p \n", v_flag, &v_flag);
v_flag++;
printf("v_flag = %d\n", v_flag);
}
Обобщение:
$ gcc -fPIC -o test test.c
Run: (не важно)
$./test v_flag = 51914, & v_flag = 0x601034 v_flag = 51915
Прочитайте таблицы символов:
$ gcc - версия gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-8) ... $ ld - версия GNU ld версия 2.23.52.0.1-16.el7 20130226 ... тест $ readelf -s Таблица символов ".dynsym" содержит 4 записи: Num: Значение Размер Тип Bind Vis Ndx Имя 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2) 2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) 3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ Таблица символов ".symtab" содержит 65 записей: Num: Значение Размер Тип Bind Vis Ndx Имя... 58: 0000000000601048 0 NOTYPE GLOBAL DEFAULT 25 _end 59: 0000000000400450 0 FUNC GLOBAL DEFAULT 13 _start 60: 0000000000601038 0 NOTYPE GLOBAL DEFAULT 25 __bss_start 61: 0000000000400514 89 FUNC GLOBAL DEFAULT 13 main 62: 0000000000601034 4 ОБЪЕКТА ГЛОБАЛЬНЫЙ ПО УМОЛЧАНИЮ 24 v_flag ...
Вопрос 1: Почему глобальная переменная v_flag появляется в symtab, а не в dynsym? (примечание: отключить оптимизацию "-O0" не помогает)
В ответ на вопрос 1 добавление флага " -rdynamic " приведет к тому, что v_flag (а также другие) появятся в dynsym:
$ gcc -rdynamic -o test test.c тест $ readelf -s Таблица символов ".dynsym" содержит 18 записей: Num: Значение Размер Тип Bind Vis Ndx Имя 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2) 2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) 3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ ... 11: 0000000000400670 0 FUNC GLOBAL DEFAULT 13 _start 12: 0000000000601038 0 NOTYPE GLOBAL DEFAULT 25 __bss_start 13: 0000000000400734 89 FUNC GLOBAL DEFAULT 13 main 14: 0000000000400600 0 FUNC GLOBAL DEFAULT 11 _init 15: 0000000000400800 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini 16: 0000000000400848 0 FUNC GLOBAL DEFAULT 14 _fini 17: 0000000000601034 4 ОБЪЕКТ ГЛОБАЛЬНЫЙ ПО УМОЛЧАНИЮ 24 v_flag Таблица символов ".symtab" содержит 65 записей:...
Однако, согласно странице руководства
-rdynamic Передать флаг -export-dynamic в компоновщик ELF для целей, которые его поддерживают. Это указывает компоновщику добавлять все символы, а не только используемые, в таблицу динамических символов.
Следовательно, вопрос 2, можем ли мы сказать, что v_flag не используется (следовательно, он не появляется в dynsym)? Если так, то почему?
Обновление 1:
Эта проблема не отображается в ld версии 2.20.* (Спасибо Константину Владимирову за то, что указал на это).
1 ответ
Сначала вы должны понять, что даже с rdynamic
вы делаете здесь что-то действительно неуклюжее - экспорт зависит от позиции v_flag
для динамического конкретного загрузчика dynsym
раздел.
Отвечая на ваши вопросы - он отбрасывается, потому что он не используется. И он не используется, потому что он не может быть использован в любом разумном динамическом контексте.
Я думаю, что вы действительно хотите - это скомпилировать код, чтобы быть позиционно независимым:
gcc -o test test.c -fPIC
Теперь без каких-либо динамических взломов у вас есть:
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2)
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
4: 0000000000601020 4 OBJECT GLOBAL DEFAULT 25 v_flag
Я предлагаю вам прочитать несколько документов по написанию общих библиотек. Это мой любимый.
В сборе:
.globl v_flag
.data
.align 4
.type v_flag, @object
.size v_flag, 4
v_flag:
.long 51914
Протестировано: GCC 4.4.3, GCC 4.7.2, GCC 4.8.2, GCC 4.9.2, линкер ld 2.20.1
Не мог комментировать, поэтому пришлось написать это здесь.
Такое же поведение (т.е. не показывает v_flag в таблице dynsym) происходит в GNU ld version 2.20.51.0.2-5.36.el6 20100205
.
Поэтому я думаю, отредактируйте рассматриваемое обновление, так как не все 2.20.* Работают.
Так что пока единственный способ - использовать -rdynamic, кто-нибудь, пожалуйста, добавьте ответ, если есть другой способ, потому что -rdynamic выглядит как взлом.
Также я видел случаи, когда работает без rdynamic, а также ld-version > 2.23, но я не могу понять причину или воспроизвести, почему это работает.