Comme un exercice pour apprendre plus précisément comment fonctionnent les programmes c et quel niveau minimum de contenu doit exister pour qu'un programme puisse utiliser libc, j'ai pris l'initiative de programmer principalement l'assemblage x86 en utilisant gas et ld . Comme un petit défi amusant, j'ai assemblé et lié avec succès plusieurs programmes liés à différentes bibliothèques dynamiques, mais je n'ai pas réussi à coder un programme à partir de zéro pour utiliser les appels de fonction libc sans utiliser directement gcc . Je comprends les conventions d'appel des différentes fonctions de la bibliothèque c, et ai inspecté minutieusement les programmes compilés à partir de gcc en utilisant objdump et readelf, mais je n'ai rien trouvé concernant les informations à inclure dans un fichier d'assemblage de gaz et quels paramètres invoquer dans ld pour établir un lien avec libc. Quelqu'un a un aperçu de cela? Je suis sous Linux, sur un ordinateur x86.Comment lier un programme d'assemblage de gaz qui utilise la bibliothèque standard C avec ld sans utiliser gcc?
Répondre
Il y a au moins trois choses à faire o utiliser avec succès libc avec liaison dynamique:
- Lien
/usr/lib/crt1.o
, qui contient_start
, qui sera le point d'entrée pour le fichier binaire ELF; - Lien
/usr/lib/crti.o
(avant libc) et/usr/lib/crtn.o
(après), qui fournissent un certain code d'initialisation et de finalisation; - Indiquez au lieur que le binaire utilisera le lieur dynamique,
/lib/ld-linux.so
.
Par exemple:
$ cat hello.s
.text
.globl main
main:
push %ebp
mov %esp, %ebp
pushl $hw_str
call puts
add $4, %esp
xor %eax, %eax
leave
ret
.data
hw_str:
.asciz "Hello world!"
$ as -o hello.o hello.s
$ ld -o hello -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o -lc hello.o /usr/lib/crtn.o
$ ./hello
Hello world!
$
Je pense que quelque chose comme cela devrait fonctionner:
- faire un programme simple C
- gcc -S file.c
- modifier file.s
- file.s de gaz
- ld file.o -lc crt1.o -o myprog
Si vous définissez main
dans l'assemblage
réponse de Matthieu fait un excellent travail de vous dire les exigences minimales. Permettez-moi de vous montrer comment trouver ces chemins dans votre système. Exécuter:
gcc -v hello_world.c |& grep 'collect2' | tr ' ' '\n'
puis de récupérer les fichiers mentionnés par Matthew.
gcc -v
vous donne la commande de liaison exacte utilisée par GCC.
collect2 est l'exécutable interne que GCC utilise en tant que frontal de liaison, qui a une interface similaire à ld
.
Sous Ubuntu 14.04 64 bits (GCC 4.8), je me suis retrouvé avec:
ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 \
/usr/lib/x86_64-linux-gnu/crt1.o \
/usr/lib/x86_64-linux-gnu/crti.o \
-lc hello_world.o \
/usr/lib/x86_64-linux-gnu/crtn.o
Vous pourriez aussi avoir besoin -lgcc
et -lgcc_s
. Voir aussi: Do I really need libgcc?
Si vous définissez _start
dans l'assemblage
Si je définissais le _start
, le monde bonjour de glibc a travaillé avec juste:
ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc hello_world.o
Je ne sais pas si cela est robuste, c'est-à-dire si les initialisations crt
peuvent être ignorées en toute sécurité pour appeler les fonctions de la glibc. Voir aussi: Why does an assembly program only work when linked with crt1.o crti.o and crtn.o?
Ceci est extrêmement utile, cela clarifie beaucoup d'informations. en appliquant cela à mon code, j'obtiens 2 erreurs, "référence indéfinie à '__libc_csu_fini'" et "référence non définie à '__libc_csu_init'" après avoir fait un vidage de symbole sur tous les fichiers objet, je n'ai pas réussi à trouver les symboles, et crt1.o semble appeler les symboles. Y at-il quelque chose qui pourrait avoir ces symboles à l'intérieur de leur fichier objet? – Cyro
Ceux-ci proviennent d'une partie non partagée de la bibliothèque C; Lier avec '-lc' devrait tirer dans'/usr/lib/libc.so', qui est en fait un fragment de script de l'éditeur de liens référençant le bon fichier ('/ usr/lib/libc_nonshared.a'). Peut-être un problème avec l'ordre de lien? Je suis assez sûr que vous voulez 'crt1.o' suivi par' crti.o 'd'abord, puis vos objets et bibliothèques, puis 'crtn.o' juste à la fin - mais peut-être' -lc' devrait venir après vos objets (juste avant 'crtn.o'), pas avant. –
Je suis allé de l'avant et simplement lié avec /usr/lib/libc_nonshared.a juste après avoir tapé -lc et tout a fonctionné! merci un million! – Cyro