Linker — Änderungen 10003 → 10755

Zeile 1: Zeile 1:
 
{{Stub}}
 
{{Stub}}
−
Ein '''Linker''' ist ein Programm, welches Objektdateien "zusammenkopiert" und mit anderen nötigen Dateien verbindet.
+
Ein '''Linker''' ist ein Programm, das die vom Compiler generierten Objektdateien mit anderen Objektdateien und/oder Libraries verknüpft.
  
  
 
== Funktionsweise ==
 
== Funktionsweise ==
−
Beispiel: Wir haben ein simples "Hallo-Welt"-Programm in C, welches Gebrauch von der Funktion printf() macht. Diese ist bekanntlich Teil der libc, also der Standardbibliothek von C. Beim Kompillieren wird das C-Programm in Maschinencode übersetzt.  
+
Ein Beispiel: Das gute, alte "Hello, world!"-Programm soll kompiliert, aber noch nicht gelinkt werden.
  
−
Das erreicht man mit dem [[gcc]] so:
+
<c>
 +
#include <stdio.h>
 +
 
 +
int main()
 +
{
 +
    printf("Hello, world!\n");
 +
}
 +
</c>
 +
 
 +
Kompilieren kann man das Programm mit folgendem Befehl:
  
 
<code>
 
<code>
Zeile 12: Zeile 21:
 
</code>
 
</code>
  
−
Nun wurde eine Objektdatei erstellt. Diese enthält sogenannte Referenzen auch Objekte, Funktionen usw..  
+
Das "-c" sorgt dafür, dass der gcc vorerst nur kompiliert und noch nicht linkt.
−
Wenn wir uns also die erzeugte Datei per objdump -t anschauen, bekommen wir die Symboltabelle:
+
 
 +
Nun wurde eine Objektdatei erstellt. Diese enthält zwar bereits den übersetzten Code aus hello.c, aber man könnte sie noch nicht ausführen:
  
 
<code>
 
<code>
−
hello.o:    file format elf32-i386
+
$ gcc -c -o hello hello.c
−
 
+
$ ./hello
−
SYMBOL TABLE:
+
bash: ./hello: Keine Berechtigung
−
00000000 l    df *ABS* 00000000 hello.c
+
$ chmod u+x hello
−
00000000 l    d  .text 00000000 .text
+
$ ./hello
−
00000000 l    d  .data 00000000 .data
+
bash: ./hello: Kann die Datei nicht ausführen.
−
00000000 l    d  .bss 00000000 .bss
 
−
00000000 l    d  .rodata 00000000 .rodata
 
−
00000000 l    d  .note.GNU-stack 00000000 .note.GNU-stack
 
−
00000000 l    d  .comment 00000000 .comment
 
−
00000000 g    F .text 0000002b main
 
−
00000000        *UND* 00000000 puts
 
−
 
 
 
</code>
 
</code>
  
−
Hier sehen wir die Referenzen, die noch nicht in der Datei enthalten sind: puts z.B..
+
Woran liegt das? Nun, wir benutzen in hello.c die Funktion printf() aus stdio.h. Allerdings genügt es nicht, stdio.h einfach zu inkludieren, wie man sieht. Zur Erklärung ein Auszug aus stdio.h:
  
−
Erst durch das Zusammenlinken mit anderen Objektdateien (hier: die der libc) wird der nötige Code in die Datei
+
<c>
−
eingelinkt und die Datei ausführbar gemacht:
+
extern int printf (__const char *__restrict __format, ...);
 +
</c>
  
 +
Die Parameterliste soll uns hier nicht interessieren. Deutlich wichtiger (zumindest im Zusammenhang mit diesem Artikel) ist das Schlüsselwort "extern" vor der eigentlichen Funktionsdeklaration. Dieses Schlüsselwort besagt, dass die Funktion existiert (jedoch nicht in der aktuellen Quelldatei) und beruhigt somit den Compiler, der sonst eine Fehlermeldung oder zumindest eine Warnung ausgegeben hätte, wenn man printf() ohne diese Deklaration verwendet hätte.
  
−
== Linkerdatei ==
+
Nun kommt der Linker ins Spiel. Dessen Aufgabe ist es, die Objektdatei (bzw. in diesem Fall Library), die die Funktion enthält, so mit dem Programm zu verknüpfen, dass die Funktion auch tatsächlich aufgerufen werden kann. Dazu genügt folgender Befehl:
−
Eine Linkerdatei definiert, wo welche Sektionen des Codes liegen.
 
−
 
 
−
Hier ein Beispiel aus dem Betriebssystem Qultics:
 
  
 
<code>
 
<code>
−
OUTPUT_FORMAT(elf32-i386)
+
$ gcc -c -o hello.o hello.c
−
OUTPUT_ARCH(i386:i386)
+
$ gcc hello.o -o hello
−
ENTRY(start)
+
$ ./hello
−
phys = 0x00100000;
+
Hello, world!
−
SECTIONS
 
−
{
 
−
kernel_start = phys;
 
−
 
 
−
  .text phys : AT(phys) {
 
−
    code = .;
 
−
    *(.text)
 
−
    *(.rodata)
 
−
    . = ALIGN(4096);
 
−
  }
 
−
  .data : AT(phys + (data - code))
 
−
  {
 
−
    data = .;
 
−
    *(.data)
 
−
    . = ALIGN(4096);
 
−
  }
 
−
  .bss : AT(phys + (bss - code))
 
−
  {
 
−
    bss = .;
 
−
    *(.bss)
 
−
    . = ALIGN(4096);
 
−
  }
 
−
  end = .;
 
−
 
 
−
  kernel_end = end;
 
−
  kernel_size = kernel_end - kernel_start;
 
−
}
 
 
</code>
 
</code>
  
 +
Der gcc ruft selbstständig den Linker mit allen benötigten Libraries auf und erzeugt eine ausführbare Datei, die nun auch die Funktion printf() (sowie alle anderen Funktionen, die in stdio.h als extern deklariert wurden) enthält.
  
 
[[Kategorie:Werkzeuge]]
 
[[Kategorie:Werkzeuge]]
  
 
[[en:Linkers]]
 
[[en:Linkers]]