Что означает KEEP в скрипте компоновщика? - PullRequest
43 голосов
/ 22 марта 2012

Руководство LD не объясняет, что делает команда KEEP. Ниже приведен фрагмент стороннего линкерного скрипта с KEEP. Что делает команда KEEP в ld?

SECTIONS
{  
    .text :
    {
        . = ALIGN(4);
        _text = .;
        PROVIDE(stext = .);
        KEEP(*(.isr_vector))
        KEEP(*(.init))
        *(.text .text.*)        
        *(.rodata .rodata.*)        
        *(.gnu.linkonce.t.*)
        *(.glue_7)
        *(.glue_7t)
        *(.gcc_except_table)
        *(.gnu.linkonce.r.*)
        . = ALIGN(4);
        _etext = .;
        _sidata = _etext;
        PROVIDE(etext = .);   
            _fini = . ;
                *(.fini)

    } >flash

Ответы [ 3 ]

42 голосов
/ 23 марта 2012

Afaik LD сохраняет символы в разделе, даже если на символы нет ссылок.(--gc-section).

Обычно используется для разделов, имеющих какое-то особое значение в процессе запуска двоичного кода, более или менее для обозначения корней дерева зависимостей.


(Для Sabuncu ниже)

Дерево зависимостей :

Если вы удаляете неиспользуемый код, вы анализируете код и помечаете все доступные области (код + глобальные переменные + константы).

Таким образом, вы выбираете раздел, помечаете его как «использованный» и смотрите, на какой другой раздел он ссылается, затем вы отмечаете этот раздел как «использованный» и проверяете, на что они ссылаются и т. Д.

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

Поскольку раздел может ссылаться на несколько других разделов (например, одна процедура вызывает три разных других), если вы получите результат, который вы получитедерево.

Корни:

Однако вышеприведенный принцип ставит нас перед проблемой: какой «первый» раздел используется всегда?Первый узел (корень) дерева так сказать?Это то, что делает «keep ()», оно сообщает компоновщику, какие разделы (если они есть) являются первыми, на которые нужно обратить внимание.Как следствие, они всегда связаны между собой.

Обычно это разделы, которые вызываются из загрузчика программы для выполнения задач, связанных с динамическим связыванием (может быть необязательным и зависит от ОС / формата файла), и точка входапрограмма.

10 голосов

Пример минимального Linux IA-32, иллюстрирующий его использование

main.S

.section .text
.global _start
_start:
    /* Dummy access so that after will be referenced and kept. */
    mov after, %eax
    /*mov keep, %eax*/

    /* Exit system call. */
    mov $1, %eax

    /* Take the exit status 4 bytes after before. */
    mov $4, %ebx
    mov before(%ebx), %ebx

    int $0x80

.section .before
    before: .long 0
/* TODO why is the `"a"` required? */
.section .keep, "a"
    keep: .long 1
.section .after
    after: .long 2

link.ld :

ENTRY(_start)
SECTIONS
{
    . = 0x400000;
    .text :
    {
        *(.text)
        *(.before)
        KEEP(*(.keep));
        *(.keep)
        *(.after)
    }
}

Скомпилируйте и запустите :

as --32 -o main.o main.S
ld --gc-sections -m elf_i386 -o main.out -T link.ld main.o
./main.out
echo $?

выход

1

Если мы закомментируем строку KEEP, получится:

2

Если мы либо:

  • добавить манекен mov keep, %eax
  • удалить --gc-sections

Выход возвращается к 1.

Проверено на Ubuntu 14.04, Binutils 2.25.

Объяснение

Нет ссылки на символ keep, и, следовательно, содержащий его раздел .keep.

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

Так как мы добавляем 4 к адресу before, если раздел keep отсутствует, то статус выхода будет 2, который присутствует в следующем разделе .after.

TODO: ничего не произойдет, если мы удалим "a" из .keep, что делает его размещаемым. Я не понимаю, почему это так: этот раздел будет помещен в сегмент .text, который из-за его магического имени будет выделяться.

1 голос
/ 20 февраля 2019

Заставить компоновщика сохранить некоторые специфические разделы

SECTIONS 
{
....
....

*(.rodata .rodata.*)

KEEP(*(SORT(.scattered_array*)));
}
...