Что такое раздел * ABS * и когда его использовать? - PullRequest
4 голосов
/ 08 мая 2019
// foo.c
int main() { return 0; }

Когда я скомпилировал приведенный выше код, я заметил некоторые символы, расположенные в *ABS*:

$ gcc foo.c
$ objdump -t a.out | grep ABS
0000000000000000 l    df *ABS*  0000000000000000              crtstuff.c
0000000000000000 l    df *ABS*  0000000000000000              foo.c
0000000000000000 l    df *ABS*  0000000000000000              crtstuff.c
0000000000000000 l    df *ABS*  0000000000000000              

Похоже, что они являются некоторыми символами отладки, но информация об отладке не хранится где-то вроде.debug_info раздел?

Согласно man objdump:

* ABS *, если секция абсолютна (т.е. не связана с какой-либо секцией)

Я непоймите это, поскольку здесь не приводится ни одного примера.

Вопрос здесь показывает интересный способ передачи некоторых дополнительных символов в *ABS* с помощью --defsym.Но я думаю, что это может быть проще, передавая макросы.

Так что же это за раздел *ABS* и когда кто-то будет его использовать?

РЕДАКТИРОВАТЬ :

Абсолютные символы не перемещаются, их виртуальные адреса (0000000000000000 в приведенном вами примере) фиксированы.

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

// foo.c

#include <stdio.h>

extern char foo;

int main()
{
  printf("%p\n", &foo);
  return 0;
}
$ gcc foo.c -Wl,--defsym,foo=0xbeef -g

$ objdump -t a.out | grep ABS
0000000000000000 l    df *ABS*  0000000000000000              crtstuff.c
0000000000000000 l    df *ABS*  0000000000000000              foo.c
0000000000000000 l    df *ABS*  0000000000000000              crtstuff.c
0000000000000000 l    df *ABS*  0000000000000000
000000000000beef g       *ABS*  0000000000000000              foo

# the addresses are not fixed
$ ./a.out
0x556e06629eef
$ ./a.out
0x564f0d7aeeef
$ ./a.out
0x55c2608dceef

# gdb shows that before entering main(), &foo == 0xbeef
$ gdb a.out
(gdb) p &foo
$1 = 0xbeef <error: Cannot access memory at address 0xbeef>
(gdb) br main
Breakpoint 1 at 0x6b4: file foo.c, line 7.
(gdb) r
Starting program: /home/user/a.out

Breakpoint 1, main () at foo.c:7
7         printf("%p", &foo);
(gdb) p &foo
$2 = 0x55555555feef <error: Cannot access memory at address 0x55555555feef>

1 Ответ

1 голос
/ 08 мая 2019

Если вы посмотрите на другие символы, вы можете найти индекс (или название раздела, если читатель выполняет сопоставление для вас) вместо *ABS*. Это индекс раздела в таблице заголовков разделов. Он указывает на заголовок раздела, в котором определен символ (или SHN_UNDEF (ноль), если он не определен в объекте, который вы просматриваете). Таким образом, значение (виртуальный адрес) символа будет корректироваться на то же значение, что его содержащий раздел корректируется во время загрузки. (Этот процесс называется перемещение .) Не так для абсолютных символов (имеющих специальное значение SHN_ABS в качестве их st_shndx). Абсолютные символы не перемещаются, их виртуальные адреса (0000000000000000 в приведенном вами примере) являются фиксированными.

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

Что касается вашего вопроса с той причиной, по которой он не хранится в разделе .debug_info (и почему эта информация выводится, даже если не были указаны переключатели отладки), ответ заключается в том, что это отдельная вещь; это просто таблица символов (.symtab). Конечно, он также необходим для отладки, но его основная цель - связать файлы объектов (.o). По умолчанию он сохраняется в связанных исполняемых файлах / библиотеках. Вы можете избавиться от него с помощью strip.

Многое из того, что я написал здесь, находится в man 5 elf.


Я не думаю, что выполнение того, что вы делаете (с --defsym), поддерживается / должно работать с динамическим связыванием. Глядя на вывод компилятора (gcc -S -masm=intel), я вижу это

lea     rsi, foo[rip]

Или, если мы посмотрим на objdump -M intel -rD a.out (связь с -q для сохранения перемещений), мы увидим то же самое: rip -относительная адресация используется для получения адреса foo.

113d:       48 8d 35 ab ad 00 00    lea    rsi,[rip+0xadab]        # beef <foo>
                    1140: R_X86_64_PC32     foo-0x4

Компилятор не знает, что это будет абсолютный символ, поэтому он генерирует код, который он делает (как для обычного символа). rip - указатель инструкции, поэтому он зависит от базового адреса сегмента, содержащего .text после того, как программа отображается в память с помощью ld.so.

Я нашел этот ответ , проливающий свет на правильный вариант использования абсолютных символов.

...