Что такое символы типа R_386_32 в библиотеке времени выполнения C? - PullRequest
0 голосов
/ 03 октября 2018

Я прочитал Здесь .
Насколько я понимаю, R_386_32 для статических данных, а R_386_PC32 для функции.да?

Однако я все еще не понимаю, как использовать символ типа R_386_32.
См. пример ниже.

Пример 1

readelf -a --wide /usr/lib/i386-linux-gnu/crt1.o | grep R_386_32
0000000c  00000901 R_386_32               00000000   __libc_csu_fini
00000011  00000b01 R_386_32               00000000   __libc_csu_init
00000018  00000c01 R_386_32               00000000   main

Пример 2

readelf -a --wide /usr/local/lib/gcc/i686-pc-linux-gnu/5.5.0/crtbegin.o 
00000001  00001501 R_386_32               00000000   __TMC_END__
00000010  00001601 R_386_32               00000000   _ITM_deregisterTMCloneTable
00000031  00001501 R_386_32               00000000   __TMC_END__
00000049  00001701 R_386_32               00000000   _ITM_registerTMCloneTable
000000a1  00001901 R_386_32               00000000   _Jv_RegisterClasses


Вопрос

  1. В Пример 2 , R_386_32 напечатаноданные автоматически добавляются в приложение
    во время компиляции?
  2. Если да, могу ли я ссылаться на эти данные в своем коде?
    Например, могу ли я создать приложение , которое напечатает значение _Jv_RegisterClasses?
  3. В Пример 1 , Почему main имеет тип R_386_32?
    Я думаю, что это должно быть R_386_PC32, потому что это не статические данные, этоэто функция.

1 Ответ

0 голосов
/ 03 октября 2018

Вы смотрите на перемещения, , а не символы. Перемещения - это то, что генерирует ассемблер, когда хочет обратиться к символу, значение которого неизвестно;это инструкция для компоновщика, чтобы заполнить правильное значение во время ссылки.Перемещения не являются типами символов;на каждый символ можно ссылаться через произвольное количество перемещений произвольного типа.Также обратите внимание, что таблица символов не знает, к какому типу данных относится символ, если вообще существует.Символ - это просто адрес и имя.

Тип перемещения R_386_32 просто означает «вставьте здесь значение символа как 32-битное». Невозможно сказать, используется ли символ для данных.или текст.Это используется, например, если вы загружаете адрес символа или выполняете абсолютный доступ к памяти.Обе эти инструкции генерируют перемещение R_386_32:

mov $foo, %eax       # move value of symbol to register
mov foo, %eax        # perform absolute memory access

С другой стороны, тип перемещения R_386_PC32 вычитает значение указателя инструкции ( p rogram c Унтер) от символа и вставляет его.Этот тип перемещения в основном используется для прямого перехода и инструкций вызова:

jmp foo              # jump to foo
call foo             # call foo

В общем, нет способа угадать, в каком разделе определен символ, по просмотру перемещений.Действительно, перемещения вообще не дают никакой информации об этом, и объектный файл не может требовать, чтобы внешний символ ссылался на данные или текст.Для определенных символов вы можете узнать, в каком разделе они находятся, запустив утилиту nm.Символы, отмеченные t или T, представляют собой текст, d или D представляют собой данные, r или R представляют собой данные только для чтения, а b или B представляют собой BSS.

На ваш второй вопрос: да, вы можете.Используйте код C, как это, чтобы напечатать значение _Jv_RegisterClasses.Обратите внимание, что значение символа является адресом переменной, к которой он относится.

extern const void _Jv_RegisterClasses;  /* or any other type */

printf("%p\n", &_Jv_RegisterClasses);   /* print value of symbol */
...