web-dev-qa-db-fra.com

Que signifie KEEP dans un script de l'éditeur de liens?

Le manuel LD n'explique pas ce que fait la commande KEEP. Vous trouverez ci-dessous un extrait d'un script de l'éditeur de liens tiers qui comprend KEEP. Que fait la commande KEEP dans 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
43
Randomblue

Afaik LD conserve les symboles dans la section même si les symboles ne sont pas référencés. (--Gc-sections).

Habituellement utilisé pour les sections qui ont une signification particulière dans le processus de démarrage binaire, plus ou moins pour marquer les racines de l'arbre de dépendance.


(Pour Sabuncu ci-dessous)

Arbre de dépendance:

Si vous éliminez le code inutilisé, vous analysez le code et marquez toutes les sections accessibles (code + variables globales + constantes).

Vous choisissez donc une section, la marquez comme "utilisée" et voyez à quelle autre section elle fait référence, puis vous marquez cette section comme "utilisée" et vérifiez à quoi elle fait référence, etc.

Les sections qui ne sont pas marquées "utilisées" sont alors redondantes et peuvent être supprimées.

Puisqu'une section peut référencer plusieurs autres sections (par exemple, une procédure appelant trois autres différentes), si vous voulez dessiner le résultat, vous obtenez un arbre.

Racines:

Le principe ci-dessus nous pose cependant un problème: quelle est la "première" section qui est toujours utilisée? Le premier nœud (racine) de l'arbre pour ainsi dire? C'est ce que fait "keep ()", il indique à l'éditeur de liens quelles sections (si disponibles) sont les premières à regarder. En conséquence, ceux-ci sont toujours liés.

Il s'agit généralement de sections appelées à partir du chargeur de programme pour effectuer des tâches liées à la liaison dynamique (peut être facultative et dépendante du système d'exploitation/du format de fichier) et du point d'entrée du programme.

42
Marco van de Voort

exemple Linux IA-32 minimal qui illustre son utilisation

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)
    }
}

Compiler et exécuter:

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

Sortie:

1

Si nous commentons la ligne KEEP, la sortie est:

2

Si nous non plus:

  • ajouter un mannequin mov keep, %eax
  • retirer --gc-sections

La sortie revient à 1.

Testé sur Ubuntu 14.04, Binutils 2.25.

Explication:

Il n'y a aucune référence au symbole keep, et donc à sa section contenant .keep.

Par conséquent, si la récupération de place est activée et que nous n'utilisons pas KEEP pour faire une exception, cette section ne sera pas placée dans l'exécutable.

Puisque nous ajoutons 4 à l'adresse de before, si la section keep n'est pas présente, l'état de sortie sera 2, qui sera présent le prochain .after section.

TODO: rien ne se passe si nous supprimons le "a" de .keep, ce qui le rend attribuable. Je ne comprends pas pourquoi il en est ainsi: cette section sera placée dans le .text segment, qui à cause de son nom magique sera attribuable.

Forcer l'éditeur de liens à conserver certaines sections spécifiques

SECTIONS 
{
....
....

*(.rodata .rodata.*)

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