Seitenleiste

Tutorial

Infodatenbank

Community

Das Linken

In diesem Kapitel soll es nur kurz um das Linkerskript und das Linken im allgemeinen gehen.

Das Linkerskript

ENTRY(start)
OUTPUT_FORMAT(elf32-i386)

SECTIONS
{
    . = 0x100000;
    __kernel_start = .;
    .multiboot_data :
{
        *(.multiboot_data)
}

    .text :
{
        *(.text)
}

    .data :
{
        *(.data)
        *(.rodata)
}

    .bss :
{
        *(.bss)
}
    __kernel_end = .;
    end = .;
}

Wozu das nun? Sinn eines Linkerskript ist es, dem Linker mitzuteilen, wie das Programm gelinkt werden soll.

Wir teilen dem Linker hier mit, dass der Einsprungspunkt in das Programm „start“ heißt. Der Linker wird nun im Programm nach einer Marke „start“ suchen und diese als Einsprungspunkt verwenden.
„start“ wird er in unserer Assemblerdatei finden. Das ist auch dort, wo wir unser Programm beginnen lassen wollen.

Wir geben außerdem das Ausgabeformat an. ld beherrscht sehr viele Formate, wir können also aus einer breiten Spanne auswählen.
Ich nehme hier „elf32-i386“, denn der Kernel soll i386-kompatibel sein und muss von GRUB geladen werden können. GRUB kann auch unterschiedliche Formate laden, „elf“ ist aber daher gut, da wir uns dabei unangenehme Angelegenheiten um den Multibootheader ersparen.

Als nächstes definieren wir die einzelnen Bereiche. Als erstes definieren wir einen Bereich für den Multibootheader, damit sich dieser auch wirklich am Beginn der fertigen Datei befinden wird. Dann gibt es denn „text“-Bereich, in ihn kommt der Code. Wir legen fest, dass der Kernel an der Stelle 0x100000 beginnen soll (das ist die 1MB-Marke). Wir setzen auch eine Variable an diese Stelle. Damit können wir später aus unserem Kernel heraus bestimmen, wohin der Kernel geladen wurde.

Hinter den Text packen wir die „data“-Sektion. In ihr werden Daten (globale Variablen etc) gespeichert.

Danach kommt noch der „bss“-Bereich. Dieser Bereich enthält alle uninitialisierten Daten. Dazu gehört z.B. der Stack. Zuletzt setzen wir auch wieder eine Variable am Ende. Mit ihr können wir später erfahren, bis wohin unser Kernel im Speicher reicht.

Nun wird gelinkt

Wir wissen nun, wie unser Linkerskript auszusehen hat. Außerdem sollten wir aus jeder einzelnen C-Datei eine Object-Datei kompiliert haben (siehe diesen Abschnitt). Um diese ganzen *.o-Dateien zu einer Datei zusammenzufügen, benutzen wir den Linker.

Mit ld und dem obigen Linkerskript funktioniert folgender Aufruf, um einen korrekt gelinkten Kernel zu erhalten:

ld -m elf_i386 -Map linker-output-map.txt -T linkerscript.ld -o kernel.bin <ALLE KOMPILIERTEN OBJEKTDATEIEN>
Parameter Wirkung & Warum
-m elf_i386 Dieser Parameter gibt an, welche Art von Ausgabe der Linker erzeugen soll. Bei mir handelt es sich dabei um ein ELF-Format für i386-basierte Computer.
-Map <datei> In die angegebene Datei werden jede Menge Informationen über den fertig gelinkten Kernel geschrieben. Dies kann bei der Fehlersuche nützlich sein. Dem Verständnis des Linkens kann es auch ganz gut helfen …
-T <datei> Durch diese Datei wird der Link-Vorgang gesteuert. Hier geben wir das zuvor erstellte Linkerskript an.
-o <datei> Hier geben wir noch den Dateinamen an, den unser fertig gelinkter Kernel haben soll.

-TODO: Weiter