Comment lier un programme d'assemblage de gaz qui utilise la bibliothèque standard C avec ld sans utiliser gcc?

StackOverflow https://stackoverflow.com/questions/3577922

  •  01-10-2019
  •  | 
  •  

Question

En guise d'exercice pour en savoir plus précisément comment les programmes c travail et quel niveau minimum de contenu doit exister pour un programme pour pouvoir utiliser libc, je l'ai pris sur moi pour tenter de programme principalement dans x86 ensemble à l'aide de gaz et ld.

Comme un peu amusant défi, je l'ai assemblé et relié avec succès plusieurs programmes liés à différentes bibliothèques dynamiques self-made, mais je n'ai pas être en mesure de coder un programme à partir de zéro pour utiliser les appels de fonction libc sans directement gcc.

Je comprends les conventions des fonctions de bibliothèque individuelle c, et ont soigneusement les programmes inspectés appelant compilés sur gcc par l'utilisation de objdump et readelf, mais ne l'ai pas eu nulle part dans la mesure où les informations à inclure dans un fichier d'assemblage de gaz et ce paramètres pouvant être invoquées dans ld pour relier avec succès à libc. Quelqu'un at-il une idée à ce sujet?

Je suis sous Linux, sur une machine x86.

Était-ce utile?

La solution

Il y a au moins trois choses que vous devez faire pour utiliser avec succès libc avec dynamique liant:

  1. Lien /usr/lib/crt1.o, qui contient _start, qui sera le point d'entrée pour le fichier binaire ELF;
  2. Lien /usr/lib/crti.o (avant libc) et /usr/lib/crtn.o (après), qui fournissent un code d'initialisation et de finalisation;
  3. Dites l'éditeur de liens que le binaire utilisera l'éditeur de liens 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!
$

Autres conseils

Si vous définissez main dans l'assemblage

La réponse de Matthieu fait un excellent travail de vous dire les exigences minimales.

Permettez-moi de vous montrer comment comment trouver ces chemins dans votre système. Exécuter:

gcc -v hello_world.c |& grep 'collect2' | tr ' ' '\n'

et puis choisissez les fichiers Matthieu mentionnés.

gcc -v vous donne la commande linker exacte des utilisations du CCG.

collect2 est l'utilisation de GCC internes exécutables comme un agent de liaison frontal, qui dispose d'une interface similaire à ld.

Ubuntu 14.04 64 bits (GCC 4.8), je fini 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: Ai-je vraiment besoin 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, à savoir si les initialisations crt peuvent être en toute sécurité sautais pour appeler des fonctions glibc. Voir aussi: Pourquoi un programme de montage ne fonctionne que lorsqu'il est lié avec crt1.o crti.o et crtn.o

Si vous utilisez _start au lieu de main (comme mentionné dans certains des commentaires ci-dessus), vous aurez également besoin de changer la façon dont le programme se termine, ou vous aurez une faute de SEG:

            .text
            .globl    _start
_start:     
            mov       $hw_str, %rdi
            call      puts
            movl      $0,%ebx   # first argument: exit code.
            movl      $1,%eax   # system call number: sys_exit.
            int       $0x80     # call kernel.

            .data
hw_str:     .asciz "Hello world!"

Kubuntu 18.04.2 (gcc (Ubuntu 7.3.0-27ubuntu1 ~ 18,04) 7.3.0):

$ as -o hello.o hello.s
$ ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o hello hello.o -lc

En outre, un moyen facile de savoir ce que l'éditeur de liens de dynamique est sur votre système est de compiler un petit programme C puis exécutez ldd sur le binaire:

test.c:

int main() { return 0; }

compilez et exécutez ldd contre exécutable:

$ gcc -o test test.c
$ ldd test
    linux-vdso.so.1 (0x00007ffd0a182000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff24d8e6000)
    /lib64/ld-linux-x86-64.so.2 (0x00007ff24ded9000)

Je pense que quelque chose comme cela devrait fonctionner:

  1. faire un programme simple C
  2. gcc -S file.c
  3. modifier file.s
  4. file.s de gaz
  5. ld file.o -lc crt1.o -o myprog
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top