Заголовки разделов файла ELF

Последнее обновление: 08.07.2023

Заголовки разделов (section headers) обеспечивают разбивку файла ELF на логические единицы. Заголовок файла содержит количество и расположение таблицы заголовков разделов в файле ELF. Для получения заголовков разделов передадим утилите readelf опцию -S или -SW

Например, возьмем простейшую программу:

.global _start          // устанавливаем стартовый адрес программы
 
_start: mov X0, #1          // 1 = StdOut - поток вывода
 ldr X1, =hello             // строка для вывода на экран
 mov X2, #19                // длина строки
 mov X8, #64                // устанавливаем функцию Linux
 svc 0                      // вызываем функцию Linux для вывода строки
 
 mov X0, #0                 // Устанавливаем 0 как код возврата
 mov X8, #93                // код 93 представляет завершение программы
 svc 0                      // вызываем функцию Linux для выхода из программы
 
.data
hello: .ascii "Hello METANIT.COM!\n"    // данные для вывода

Пусть она скомпилирована в файл hello.so. Выведем ее заголовки разделов:

c:\arm>aarch64-none-elf-readelf hello.so -SW
There are 6 section headers, starting at offset 0x10268:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        0000000000400000 010000 000028 00  AX  0   0  8
  [ 2] .data             PROGBITS        0000000000410028 010028 000013 00  WA  0   0  1
  [ 3] .symtab           SYMTAB          0000000000000000 010040 000198 18      4   7  8
  [ 4] .strtab           STRTAB          0000000000000000 0101d8 000063 00      0   0  1
  [ 5] .shstrtab         STRTAB          0000000000000000 01023b 000027 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), p (processor specific)

c:\arm>

Другой способ вывода заголовков разделов представляет утилита objdump с передачей ей опции -h:

c:\arm>aarch64-none-elf-objdump hello.so -h

hello.so:     file format elf64-littleaarch64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         00000028  0000000000400000  0000000000400000  00010000  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000013  0000000000410028  0000000000410028  00010028  2**0
                  CONTENTS, ALLOC, LOAD, DATA

c:\arm>

Заголовок каждого раздела содержит адрес раздела и размер, который он занимает. У каждого заголовка раздела также есть имя, тип и ряд полей вспомогательных флагов, которые описывают, как следует интерпретировать заголовок раздела. Например, раздел .text помечен как код, доступный только для чтения, а раздел .data помечен как данные и доступен для чтения/записи.

Для просмотра конкретного раздела утилите objdump передаются параметры -s -j. Например, просмотрим секцию .data:

c:\arm>aarch64-none-elf-objdump hello.so -s -j .data

hello.so:     file format elf64-littleaarch64

Contents of section .data:
 410028 48656c6c 6f204d45 54414e49 542e434f  Hello METANIT.CO
 410038 4d210a                               M!.

c:\arm>

Рассмотрим вкратце основные разделы.

Раздел .text

По соглашению все инструкции машинного кода, сгенерированные компилятором, помещаюься в секцию .text бинарного файла программы. Раздел .text помечен как доступный для чтения и выполнения, но не для записи. Это означает, что если программа попытается случайно изменить свой программный код, программа вызовет ошибку сегментации.

Раздел .data

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

Раздел .data обычно доступен для чтения/записи. И программа может свободно читать и перезаписывать глобальные переменные в разделе .data во время выполнения программы.

.bss

Для глобальных переменных, которые либо не инициализированы, либо инициализированы нулем, в файле ELF предусмотрен раздел Block Starting Symbol или .bss. Этот раздел работает так же, как и раздел .data, за исключением того, что переменные внутри него автоматически обнуляются перед запуском программы.

.rodata

Раздел .rodata (read-only data - данные только для чтения) используется для хранения глобальных данных в программе, которые не должны изменяться во время выполнения программы. В этом разделе хранятся глобальные переменные, помеченные как const, то есть константы, а также обычно хранятся константные литералы C-строки, используемые в данной программе.

Метаразделы

Два раздела файла ELF являются метаразделами, которые используются для поиска в других таблицах разделов. Это таблица строк (string table), которая определяет строки, используемые файлом ELF, и таблица символов (symbol table), которая определяет символы, на которые ссылаются в других разделах ELF.

Таблица строк

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

Таблица строк используется различными структурами в файле ELF, которые имеют строковое поле. Эти структуры определяют значение строки с помощью смещения в таблице строк. Таблица разделов является одной из таких структур. Каждому разделу дается имя, например .text, .data или .strtab. Заголовок файла ELF предоставляет прямой указатель на таблицу строк. Это позволяет загрузчику отслеживать таблицу строк перед тем, как анализировать другие разделы ELF.

Таблица символов

Таблица символов или .symtab определяет символы, используемые или определяемые двоичным кодом программы. Символ представляет собой именованное место в программе или внешне определенный символ. Символы, определенные в программе, указываются в основной таблице символов файла ELF. И функции, и глобальные объекты данных могут иметь имена символов, связанные с ними, но символы также могут быть назначены локальным переменным потока, внутренним объектам среды выполнения, таким как глобальная таблица смещений, и даже меткам внутри данной функции. Для просмотра таблицы символов утилите readelf передается флаг -s:

c:\arm>aarch64-none-elf-readelf hello.so -s

Symbol table '.symtab' contains 17 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000400000     0 SECTION LOCAL  DEFAULT    1 .text
     2: 0000000000410028     0 SECTION LOCAL  DEFAULT    2 .data
     3: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS hello.o
     4: 0000000000400000     0 NOTYPE  LOCAL  DEFAULT    1 $x
     5: 0000000000410028     0 NOTYPE  LOCAL  DEFAULT    2 hello
     6: 0000000000400020     0 NOTYPE  LOCAL  DEFAULT    1 $d
     7: 000000000041003b     0 NOTYPE  GLOBAL DEFAULT    2 _bss_end__
     8: 000000000041003b     0 NOTYPE  GLOBAL DEFAULT    2 __bss_start__
     9: 000000000041003b     0 NOTYPE  GLOBAL DEFAULT    2 __bss_end__
    10: 0000000000400000     0 NOTYPE  GLOBAL DEFAULT    1 _start
    11: 000000000041003b     0 NOTYPE  GLOBAL DEFAULT    2 __bss_start
    12: 0000000000410040     0 NOTYPE  GLOBAL DEFAULT    2 __end__
    13: 000000000041003b     0 NOTYPE  GLOBAL DEFAULT    2 _edata
    14: 0000000000410040     0 NOTYPE  GLOBAL DEFAULT    2 _end
    15: 0000000000080000     0 NOTYPE  GLOBAL DEFAULT    2 _stack
    16: 0000000000410028     0 NOTYPE  GLOBAL DEFAULT    2 __data_start

c:\arm>

Каждая запись символа в таблице символов определяет следующие атрибуты:

  • Num: номер символа.

  • Name: имя символа.

  • Value: значение символа, которое обычно является его адресом в памяти.

  • Size: размер символа. Для объектов данных это обычно размер объекта данных в байтах, а для функций — длина функции в байтах.

  • Type: тип символа, который обычно является одним из следующих значений:

    • STT_NOTYPE: тип символа не указан

    • STT_OBJECT: cимвол соответствует глобальной переменной

    • STT_FUNC: cимвол соответствует функции

    • STT_SECTION: cимвол соответствует разделу

    • STT_FILE: cимвол соответствует файлу исходного кода. Эти символы иногда используются при отладке программы.

    • STT_TLS: cимвол соответствует локальной переменной данных потока, определенной в заголовке TLS

    • STT_GNU_IFUNC: cимвол представляет собой специфичную для GNU косвенную функцию

  • Bind: атрибуты привязки символа. Они определяют, должен ли символ быть видимым для других программ в процессе связывания/компоновки. Символ может быть локальным (значение STB_LOCAL), глобальным (STB_GLOBAL) или ни тем, ни другим. Локальные символы не видны программам за пределами текущего ELF-файла. Загрузчик игнорирует эти символы в процессе динамической компоновки. Глобальные символы, напротив, могут использоваться вне программы или разделяемой библиотеки.

    Символы также можно могут быть слабыми (weak). Слабые символы полезны для создания стандартных реализаций функций, которые могут быть переопределены другими библиотеками. Программы на C и C++, скомпилированные с использованием GCC, могут помечать функции и данные как слабые с помощью атрибута __attribute__((weak)) или с помощью директивы #pragma weak. Например, функция malloc и ряд других функций выделения памяти часто определяются с использованием слабых символов. Это позволяет программам переопределить подобные реализации по умолчанию без перехвата функций.

  • Ndx: номер раздела, в котором находится символ. Значение ABS указывает, что символ не привязан к определенному разделу

В колонке имени символов можно встретить специальные символы - $x и $d. Это символы сопоставления (mapping symbols) — специальные символы, которые используются, чтобы помочь отладчикам и дизассемблерам определить, как следует интерпретировать байты в разделе .text. Эти символы носят только информативный характер и не влияют на то, как процессор интерпретирует данные в разделе. Могут применяться следующие символы сопоставления:

  • $a: последовательность, следующая за этим символом, представляет собой инструкции, закодированные в набор инструкций A32.

  • $t: последовательность, следующая за этим символом, представляет собой инструкции, закодированные в набор инструкций T32 (Thumb).

  • $x: последовательность, следующая за этим символом, представляет собой инструкции, закодированные в набор инструкций A64.

  • $d: последовательность, следующая за этим символом, представляет собой константные данные

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850