Wie ein Gasmontage Programm zu verknüpfen, die die C-Standardbibliothek mit ld verwendet, ohne Verwendung von gcc?

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

  •  01-10-2019
  •  | 
  •  

Frage

Als Übung genauer zu erfahren, wie c-Programme funktionieren und was Mindestmaß an Inhalt für ein Programm existieren muss in der Lage sein, libc zu verwenden, ich habe es auf mich genommen, um Programm zu versuchen, in erster Linie in x86-Assembler Gas und ld.

Als wenig Spaß Herausforderung, habe ich erfolgreich zusammengebaut und mehrere Programme im Zusammenhang mit verschiedenen selbstgemachten verknüpft dynamischen Bibliotheken, aber ich habe versagt ein Programm von Grund auf neu Code in der Lage sein zu verwenden libc Funktionsaufrufe ohne gcc direkt zu verwenden.

Ich verstehe die Aufrufkonventionen der einzelnen C-Bibliotheksfunktionen und gründlich Programme von gcc zusammengestellt aus durch die Verwendung von objdump und readelf kontrolliert, aber nicht überall so weit wie welche Informationen bekam in einer Gasbaugruppendatei aufzunehmen und was Parameter in ld erfolgreich Link zu libc aufzurufen. Wer noch keine Einsicht dazu?

Ich bin mit Linux, auf einem x86-Computer.

War es hilfreich?

Lösung

Es gibt mindestens drei Dinge, die Sie erfolgreich tun müssen, um verwenden libc mit dynamischer Verknüpfung:

  1. Link /usr/lib/crt1.o, die _start enthält, die der Einstiegspunkt für den ELF-Binaries sein wird;
  2. Link /usr/lib/crti.o (vor libc) und /usr/lib/crtn.o (nach), die eine Initialisierung und Finalisierung Code bereitzustellen;
  3. Sagen Sie den Linker, dass die binäre den dynamischen Linker verwenden, /lib/ld-linux.so.

Zum Beispiel:

$ 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!
$

Andere Tipps

Wenn Sie definieren main in der Montage

Matthew Antwort hat eine große Aufgabe, um die Mindestanforderungen zu erzählen.

Lassen Sie mich Ihnen zeigen, wie wie diese Pfade in Ihrem System zu finden. Führen Sie:

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

und dann die Dateien abholen Matthew erwähnt.

gcc -v gibt Ihnen die genauen Linker Befehl GCC Anwendungen.

collect2 ist die internen ausführbaren GCC Anwendungen als Linker-Front-End, die eine ähnliche Schnittstelle zu ld hat.

In Ubuntu 14.04 64-Bit (GCC 4.8), landete ich mit:

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

Sie können auch -lgcc und -lgcc_s braucht. Siehe auch: brauche ich wirklich libgcc

Wenn Sie definieren _start in der Montage

Wenn ich die _start definiert, arbeitete die Hallo Welt von glibc mit nur:

ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc hello_world.o

Ich bin sicher nicht, ob das robust ist, das heißt, wenn die crt Initialisierungen sicher übersprungen werden glibc Funktionen aufzurufen. Siehe auch: Warum funktioniert ein Assembler-Programm nur, wenn sie mit crt1.o crti.o und crtn.o verknüpft?

Wenn Sie _start tun statt main (wie in einigen der Kommentare oben erwähnt), werden Sie auch das Programm beendet die Art und Weise ändern müssen, oder du wirst eine seg Fehler bekommen:

            .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!"

Auf 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

Auch eine einfache Möglichkeit, um herauszufinden, was der dynamische Linker auf Ihrem System ist ein kleines C-Programm zu kompilieren und dann ldd auf dem binären laufen:

test.c:

int main() { return 0; }

Kompilieren und Ausführen LDD gegen ausführbar:

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

Ich denke, so etwas wie dies funktionieren soll:

  1. ein einfaches C-Programm machen
  2. gcc -S file.c
  3. bearbeiten file.s
  4. Gas file.s
  5. ld file.o -lc crt1.o -o myprog
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top