значение R_386_32 / R_386_PC32 в разделе .rel.text эльфа

чтобы понять концепцию переseleniumия, я написал простую программу chk.c следующим образом:

1 #include 2 main(){ 3 int x,y,sum; 4 x = 3; 5 y = 4; 6 sum = x + y; 7 printf("sum = %d\n",sum); 8 } 

его эквивалентный код сборки с использованием «objdump -d chk.o»:

 00000000 : 0: 55 push %ebp 1: 89 e5 mov %esp,%ebp 3: 83 e4 f0 and $0xfffffff0,%esp 6: 83 ec 20 sub $0x20,%esp 9: c7 44 24 1c 03 00 00 movl $0x3,0x1c(%esp) 10: 00 11: c7 44 24 18 04 00 00 movl $0x4,0x18(%esp) 18: 00 19: 8b 44 24 18 mov 0x18(%esp),%eax 1d: 8b 54 24 1c mov 0x1c(%esp),%edx 21: 8d 04 02 lea (%edx,%eax,1),%eax 24: 89 44 24 14 mov %eax,0x14(%esp) 28: b8 00 00 00 00 mov $0x0,%eax 2d: 8b 54 24 14 mov 0x14(%esp),%edx 31: 89 54 24 04 mov %edx,0x4(%esp) 35: 89 04 24 mov %eax,(%esp) 38: e8 fc ff ff ff call 39  3d: c9 leave 3e: c3 ret 

и секция .rel.text, видимая с использованием readelf, выглядит следующим образом:

 Relocation section '.rel.text' at offset 0x360 contains 2 entries: Offset Info Type Sym.Value Sym. Name 00000029 00000501 R_386_32 00000000 .rodata 00000039 00000902 R_386_PC32 00000000 printf 

У меня есть следующие вопросы, основанные на этом:

1) из второй записи в разделе .rel.text, я могу понять, что значение в смещении 0x39 в .text-разделе (которое здесь равно 0xfffffffff) должно быть заменено адресом символа, связанного с индексом 9 таблицы символов (& который выходит printf). Но я не могу четко понять смысл 0x02 (ELF32_R_TYPE) здесь. Что здесь задает R_386_PC32? Может кто-нибудь объяснить его смысл ясно.

2) Я также не могу понять первую запись. что нужно заменить при смещении 0x29 в разделе .text и почему здесь неясно. Снова я хочу знать значение R_386_32 здесь. Я нашел один файл pdf elf_format.pdf, но я не могу четко понять значение «Тип» в разделе .rel.text.

3) Также я хочу знать значение сборки inst “lea (% edx,% eax, 1),% eax”. Хотя я нашел очень хорошую ссылку ( какова цель инструкции LEA? ), Описывающая значение lea, но формат lea (то есть 3 скобки внутри arg) не ясен.

если кто-либо может четко объяснить ответы на вышеуказанные вопросы, он будет весьма признателен. Я все еще пытаюсь найти ответы на эти вопросы, хотя я много пробовал с Google.

еще один вопрос. Я показал записи таблицы символов для обоих смещений 5 и 9 ниже.

  Num: Value Size Type Bind Vis Ndx Name 5: 00000000 0 SECTION LOCAL DEFAULT 5 9: 00000000 0 NOTYPE GLOBAL DEFAULT UND printf' 

Информационное поле для первой записи в таблице .rel.text равно 0x05, которая указывает индекс таблицы символов. Я показал запись таблицы символов для индекса 5 выше, но не могу понять, как это говорит нам о том, что это для .rodata.

1), 2): R_386_32 – это перемещение, которое помещает абсолютный 32-разрядный адрес символа в указанную ячейку памяти. R_386_PC32 – это перемещение, которое помещает 32-разрядный адрес символа, соответствующего ПК, в указанную ячейку памяти. R_386_32 полезен для статических данных, как показано здесь, поскольку компилятор просто загружает перемещенный адрес символа в некоторый регистр, а затем обрабатывает его как указатель. R_386_PC32 полезен для ссылок на функции, поскольку он может использоваться как непосредственный аргумент для call . См. Elf_machdep.c для примера того, как обрабатываются перестановки.

3) lea (%edx,%eax,1),%eax означает просто %eax = %edx + 1*%eax если выражено синтаксисом C. Здесь он в основном используется в качестве замены кода операции add .

EDIT: Вот пример.

Предположим, что ваш код загружается в память, начиная с 0x401000, что строка "sum = %d\n" заканчивается на 0x401800 (в начале раздела .rodata ) и что printf находится в 0x1400ab80, в libc.

Затем, перемещение R_386_32 в 0x29 поместит байты 00 18 40 00 на 0x401029 (просто копируя абсолютный адрес символа), делая команду на 0x401028

  401028: b8 00 18 40 00 mov $0x401800,%eax 

R_386_PC32 в 0x39 помещает байты 43 9b c0 13 на 0x401039 (значение 0x1400ab80 – 0x40103d = 0x13c09b43 в шестнадцатеричном формате), что делает эту инструкцию

  401038: e8 43 9b c0 13 call $0x1400ab80  

Мы вычитаем 0x40103d для учета значения% pc (который является адресом инструкции после call ).

Первая запись перемещения – это получить указатель на строку формата ( "sum = ..." ) в процессе настройки вызова printf . Поскольку раздел .rodata перемещается, а также раздел .text , ссылки на строки и другие постоянные данные нуждаются в исправлениях.

Имея это в виду, похоже, что перераспределение R_386_32 связано с данными, а R_386_PC32 с кодовыми адресами, но спецификация ELF (у которой у меня нет удобной копии), вероятно, объясняет различные детали.

Команда lea – это то, что компилятор решил выполнить дополнение для этой процедуры. Он мог бы выбрать add или пару других возможностей, но эта форма lea , по-видимому, используется довольно часто для определенных случаев, поскольку она может сочетать добавление с умножением. Результатом команды является lea (%edx,%eax,1),%eax – это то, что %eax получит значение %edx + 1 * %eax . 1 можно заменить ограниченным набором малых целых чисел. Первоначальной целью команды lea был «Load Effective Address» – взять базовый указатель, индекс и размер и присвоить адрес элемента в массиве. Но, как вы можете видеть, компиляторы могут использовать его для других вещей, а также …