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, но я не могу понять причину или воспроизвести, почему это работает.

Другие вопросы по тегам