ELF-Tutorial — Änderungen 6913 → 9373

Zeile 1: Zeile 1:
 +
{{Tutorial
 +
|Titel=ELF-Tutorial
 +
|Schwierigkeit=1
 +
|Vorwissen=[[Paging]]
 +
|Sprache=FreeBasic
 +
}}
 +
 
Und wieder einmal schreibe ich ein Tutorial für euch. Diesmal geht es um ELF, ein Format für ausführbare Dateien. Sich mit ELF zu beschäftigen ist sinnvoll, denn irgendwann braucht man eben ein gescheites Dateiformat für seine Treiber und sonstigen Programme.
 
Und wieder einmal schreibe ich ein Tutorial für euch. Diesmal geht es um ELF, ein Format für ausführbare Dateien. Sich mit ELF zu beschäftigen ist sinnvoll, denn irgendwann braucht man eben ein gescheites Dateiformat für seine Treiber und sonstigen Programme.
  
Zeile 21: Zeile 28:
  
  
−
'''Kümmern wir uns einmal um die erste Frage:'''
+
'''Kümmern wir uns einmal um die erste Frage: Wie ist eine ELF-Datei aufgebaut?'''
  
 
ELF-Dateien haben einen ELF-Header, der Dinge wie eine "Magic-Number" (zur Identifizierung) enthält. Da ELF ein plattformübergreifendes Format ist, sind hier auch einige wichtige Angaben gespeichert, z. B. für welche Architektur diese Datei gedacht ist. Der ELF-Header liegt immer direkt am Anfang einer ELF-Datei.
 
ELF-Dateien haben einen ELF-Header, der Dinge wie eine "Magic-Number" (zur Identifizierung) enthält. Da ELF ein plattformübergreifendes Format ist, sind hier auch einige wichtige Angaben gespeichert, z. B. für welche Architektur diese Datei gedacht ist. Der ELF-Header liegt immer direkt am Anfang einer ELF-Datei.
  
  
−
'''Nun zur zweiten Frage:'''
+
'''Nun zur zweiten Frage: Wie lade ich die Daten korrekt in den Speicher?'''
  
 
Die Daten einer ELF-Datei liegen in einzelnen Abschnitten vor, die in die "Programmheader-Tabelle" eingetragen sind. Der ELF-Header enthält Einträge, die angeben, wo diese Tabelle liegt, wie groß die Einträge sind usw. Die Einträge dieser Tabelle enthalten die Angaben, wo der Speicherbereich liegt, wie groß er in der Datei ist, wie groß er im Speicher sein sollte, wo dieser Speicherbereich im Speicher liegen soll und noch einiges mehr.
 
Die Daten einer ELF-Datei liegen in einzelnen Abschnitten vor, die in die "Programmheader-Tabelle" eingetragen sind. Der ELF-Header enthält Einträge, die angeben, wo diese Tabelle liegt, wie groß die Einträge sind usw. Die Einträge dieser Tabelle enthalten die Angaben, wo der Speicherbereich liegt, wie groß er in der Datei ist, wie groß er im Speicher sein sollte, wo dieser Speicherbereich im Speicher liegen soll und noch einiges mehr.
−
 
 
ELF-Dateien können auch einen Section-Header haben, der ist für uns aber uninteressant.
 
ELF-Dateien können auch einen Section-Header haben, der ist für uns aber uninteressant.
  
  
−
'''Und jetzt die dritte Frage:'''
+
'''Und jetzt die dritte Frage: Wo liegt der ausführbare Code?'''
  
 
Das Feld "e_entry" im ELF-Header gibt die virtuelle Adresse an, an der der ausführbare Code später liegt. Wenn wir einen Task erstellen, geben wir ihm einfach diesen Wert als EIP-Register. Bei Linux beträgt dieser Wert meist 0x805F540, der ausführbare Code liegt also ungefähr bei 128 MB. Aber dank Paging braucht der PC gar nicht so viel RAM.
 
Das Feld "e_entry" im ELF-Header gibt die virtuelle Adresse an, an der der ausführbare Code später liegt. Wenn wir einen Task erstellen, geben wir ihm einfach diesen Wert als EIP-Register. Bei Linux beträgt dieser Wert meist 0x805F540, der ausführbare Code liegt also ungefähr bei 128 MB. Aber dank Paging braucht der PC gar nicht so viel RAM.
Zeile 67: Zeile 73:
 
</freebasic>
 
</freebasic>
  
−
In C:
 
−
<c>
 
−
typedef uint32_t Elf32_Addr;
 
−
typedef uint16_t ELF32_Half;
 
−
typedef uint32_t ELF32_Off;
 
−
typedef int32_t  ELF32_Sword;
 
−
typedef uint32_t ELF32_Word;
 
−
typedef unsigned char ELF_Uchar;
 
−
</c>
 
  
 
Beginnen wir nun mal mit dem ELF-Header.
 
Beginnen wir nun mal mit dem ELF-Header.
Zeile 108: Zeile 105:
 
  end type
 
  end type
 
</freebasic>
 
</freebasic>
−
 
−
Und in C:
 
−
<c>
 
−
struct ELF_IDENT_HEADER
 
−
{
 
−
    uint32_t EI_MAGIC
 
−
    uint8_t  EI_CLASS
 
−
    uint8_t  EI_DATA
 
−
    uint8_t  EI_VERSION
 
−
    uint32_t EI_PAD
 
−
    uint32_t EI_PAD2
 
−
    uint8_t  EI_NIDENT
 
−
}
 
−
</c>
 
−
 
  
 
So. Wofür ist jetzt "ELF_IDENT_HEADER" gut? Ganz einfach, er gibt uns erst mal ein paar grundlegende Infos, z.&nbsp;B. ob die Datei Little oder Big Endian ist. Das ist wichtig, da der Rest der Datei diesen Regeln folgt! (Eigentlich ist dieser Header etwas anders eingeteilt, aber der Einfachheit halber habe ich das mal so gelöst. Wie es wirklich richtig ist, kann man in den ELF-Spezifikationen nachlesen)
 
So. Wofür ist jetzt "ELF_IDENT_HEADER" gut? Ganz einfach, er gibt uns erst mal ein paar grundlegende Infos, z.&nbsp;B. ob die Datei Little oder Big Endian ist. Das ist wichtig, da der Rest der Datei diesen Regeln folgt! (Eigentlich ist dieser Header etwas anders eingeteilt, aber der Einfachheit halber habe ich das mal so gelöst. Wie es wirklich richtig ist, kann man in den ELF-Spezifikationen nachlesen)