Betriebssysteme Teil 2: Übersetzung von C

Werbung
Betriebssysteme
Teil 2: Übersetzung von C-Programmen
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
09.10.15 1
Übersicht
•
•
•
•
•
Übersetzungsprozess
gcc(I) als Steuerprogramm
Assembler
Binder
Hauptprogramme in C
In dieser Einheit werden nur die Grundprinzipien dargestellt,
dies ist keine Beschreibung konkreter Formate etc.
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
2
Übersetzungsprozess von C I – Überblick
Syntax Analyse (Parser)
Compiler
Ableitungsbaum
Optimierung
Compiler
Ableitungsbaum
Codegenerierung
Compiler
Sequenz Zwischensprache
Sequenz Assembler
Assemblieren
Assembler
Module als
Object-Files
Sequenz Tabellen
Zusammensetzen
Linker/Linkage Editor
Object-File
Sequenz Tabellen
Laden
ProzessImage
Lader/Loader
Daten im RAM
Ausführung
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
3
Übersetzungsprozess von C II
C-Programm
Beispiel.c
Preprozessor
C-Programm mit
expandierten Makros
Übersetztes Programm
ohne Bibliotheksroutinen
Beispiel.i
(Eigentlicher)
Übersetzer
Beispiel.o
Binder
Fertiges ausführbares
Programm
Include-Dateien
Hauptprogramm
Bibliotheken
Beispiel
Lader in Linux
Programm in
Ausführung
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
4
Durchlauf (Pass)
• Das Übersetzen erfolgt in mehreren Durchläufen (Pass), in
denen das gesamte Programm vollständig gelesen und
interpretiert wird.
• Nach jedem Durchlauf wird das Programm in überarbeiteter
Form neu in einer speziellen Datei angelegt; diese wird bei
dem nächsten Durchlauf benutzt.
• Die Steuerung der Durchläufe übernimmt gcc(I).
• Bei Compilern sind 4 bis 5 Durchläufe üblich, es können auch
erheblich mehr sein, z. B. PL/1 hatte bis zu 60 Durchläufe.
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
5
Kommando gcc(I) I
gcc [-c] [-g] [-o ofile] [-E] [-M] [-S] file1 file2 ... fileN
Die angegeben Dateien file1 bis fileN werden als C-Programme angesehen
und entsprechend den Flags übersetzt.
Flag -c bewirkt, dass vor dem Linken der Vorgang beendet wird, d.h. dass
lediglich *.o-Dateien erzeugt werden.
Flag -g bewirkt, dass Debugging-Informationen den Binärdateien hinzugefügt
werden.
Flag -o dient der Benennung der Ausgabedatei als ofile.
Flag -E bewirkt einen Stopp nach der Preprozessor (Generieren von *.iDateien).
Flag -M bewirkt die Ausgabe einer Regel zur Benutzung in make(1); es wird
nicht übersetzt.
Flag -S bewirkt die Erzeugung des Assemblers.
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
6
Kommando gcc(I) II
• gcc (GNU C) ist ein Programm, das alle Schritte der
Übersetzung durch Starten von weiteren Programmen
veranlasst und steuert.
• Per Parameter kann der globale Ablauf nach jedem Schritt
abgebrochen werden, z.B.
– Parameter -E: nur bis *.i-Datei
– Parameter -c: nur bis *.o-Datei
• Anhand der Dateinamen-Endung erkennt gcc(I) wie weit der
Übersetzungsvorgang vorangeschritten ist und veranlasst
entsprechend die nächsten Schritte, so dass am Ende das
fertig gebundene und ausführbare Programm vorhanden ist.
Beispiel: "gcc a.o b.c c.o" führt für b.c alle, für a.o und c.o nur
den letzten Schritt (Binden) durch.
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
7
Übersetzungsprozess von C III – Syntaxanalyse
1. Durchlauf: Makroexpansion
Es werden die Makrodefinitionen (C hat die Möglichkeit von
Makros, in Programmiersprachen ohne Makros wird dieser
Schritt ausgelassen) vermerkt und alle Makro-Aufrufe mit
den Makrokörpern samt Parametern ersetzt.
2. Durchlauf: Syntaktische Prüfung
Entspricht der entstandene Text den Regeln der Sprache?
Z.B. Hat jede öffnende Klammer (rund oder geschweift) eine
korrespondierende schließende? Wird jedes Statement durch
ein Semikolon abgeschlossen?
3. Durchlauf: Semantische Prüfung
Sind alle Variablen und Funktionen deklariert? Werden sie
übereinstimmend damit benutzt?
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
8
Übersetzungsprozess von C IV
4. Durchlauf: Optimierung (optional)
Können Deklarationen weggelassen werden, da die Variablen
nicht benutzt werden? Lassen sich Schleifen verkürzen?
5. Durchlauf: Erzeugung von Assembler-Code
Für jedes Statement wird der entsprechende Assemblercode
generiert, so dass das generierte Programm das tut, was es
laut Sprachdefinition tun sollte.
6. Durchlauf: Assemblieren
Der Compiler ist jetzt fertig; es wird ein Assembler gestartet,
der das generierte Assembler-Programm in eine Objektdatei
übersetzt.
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
9
Übersetzungsprozess von C V
• Die generierte Objektdatei ist aus folgenden Gründen nicht
ausführbar:
– Es fehlen aufgerufene und nicht programmierte Routinen,
z. B. System.out.println() in Java oder printf() in C.
– Globale Variablen haben noch keine feste Position
(Adresse), sie könnten an verschiedenen Stellen angelegt
werden.
• Der Binder (Linker, Linkage Editor) setzt das endgültige
Programm unter Verwendung von Bibliotheken zusammen
und positioniert die globalen Variablen. Erst dessen Ergebnis
kann ausgeführt werden.
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
10
Übersetzungsprozess von C V
7. Durchlauf: Binden
Der Binder durchsucht Objektbibliotheken, um ein
unvollständiges Programm mit den nicht selbst
programmierten, aber aufgerufenen Subroutinen zu
ergänzen.
Am Ende ist eine direkt ausführbare Datei entstanden.
Jetzt erst kann die Datei mit Maschinencode vom Betriebssystem
in den RAM geladen und ausgeführt werden.
Java wird etwas anders realisiert: es wird nicht bis zum
Maschinencode übersetzt, sondern in eine Zwischensprache: Java-Byte-Code.
Dieser wird in einem Interpreter (Virtuelle Maschine) ausgeführt.
Bei Linux ist es meistens auch etwas anders.
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
11
Assembler I
• Assembler = Übersetzer für Programme in einer symbolischen
Maschinensprache
• Die Sprache Assembler ist für jeden CPU-Typ anders und spiegelt
die Eigenarten der CPU-Architektur wieder.
• Zur Assembler-Sprache gehören u.a.:
– Befehle (Instruktionen) der CPU.
– Makros als Zusammenfassungen mehrerer Befehle.
– Anweisungen zur Reservierung von Speicherplatz.
– Anweisungen zur Belegung von Speicherplatz.
• Der Assembler übersetzt das Assembler-Programm in ein
maschinen-codiertes Format, dem Objektformat.
• Diese Dateien heißen daher Objektdateien.
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
12
Assembler II – Fiktives Beispiel
Assembler
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
Objekt-Datei
13
Assembler III
• Assemblersprachen sind in der Regel spalten-orientiert, d.h. die
Zeilen haben ein festes Format, das einzuhalten ist.
• Ein wichtiges Charakteristikum eines Assemblers ist, dass die
Assembler-Befehle fast immer 1:1 zu Maschinenbefehlen
umgesetzt werden (Ausnahme: Verwendung von Makros).
• Sprungmarken = Label = Namen für Speicherstellen
(symbolische Adressen) von bestimmten Instruktionen, z. B.
Beginn einer Subroutine
• Das Programmieren in Assembler ist sehr mühselig, da:
– es viel Zeit kostet,
– viele Fehler gemacht werden können.
Aber: In Assembler sind die effizientesten Programme
realisierbar
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
14
Compiler vs. Assembler
• Höhere Programmiersprachen, wie z. B. C oder Java, werden
durch Compiler in Maschinensprache übersetzt.
• Compiler = Übersetzer für Programme in einer höheren
Programmiersprache, die sich dadurch auszeichnet, dass ein
Statement ("Befehl") dieser Sprache in mehrere Befehle in der
Maschinensprache übersetzt werden muss.
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
15
Reales Beispiel I
W
F
STATUS
……
TRISC
EQU
EQU
EQU
0
1
0x003
; Bit für Working Register
; Bit für File Register
; Adresse Statusregister
EQU
0x087
; Adresse Tristatekontrolle PORT C
ORG
goto
ORG
goto
ORG
start bsf
movlw
movwf
clrf
bcf
; unendliche
loop
movf
movwf
goto
END
0
;
start
;
4
;
start
;
5
;
STATUS,RPO
;
Oxff
;
TRISB
;
TRISC
;
STATUS,RPO
;
Arbeitsschleife
PORTB,w
;
PORTC
;
loop
;
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
Beginn
Sprung zum Programmanfang
Interrupt-Einsprung
nicht besetzt
Anfang des Programms
RPO <- 1: Registerbank 1
1111 1111 nach W-Register
W-Register nach Steuerung Eingang
0000 0000 Port C ist Ausgang
RPO <- 0: Registerbank 0
speichere Eingabe nach W-Register
speichere W-Register nach Ausgabe
springe immer (Schleife)
Aus [8-3] S.44
16
Reales Beispiel II – Pseudo-Instruktionen
Instruktion
Erläuterung
EQU
Equivalence
Definition von Konstanten
ORG
Origin
Fiktive Speicherzellen-Adresse, an der die folgenden
Instruktionen platziert werden
END
Ende des Assembler-Programms bzw. Moduls
Erläuterungen der (Pseudo-)Befehle von einem Assembler für
PIC-Microcontroller.
• Pseudo-Befehl = Anweisung an den Assembler zu dessen
Steuerung
• Pseudo-Befehle entsprechend keinen Anweisungen des
Prozessors – sie sind Anweisungen an den Assembler.
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
17
Aufbau von Befehlen
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
18
Arten von Operanden (Adressierungsarten)
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
19
Aufbau von Befehlen (fiktives Beispiel)
Adressierungsart = Art und Weise der Bestimmung bzw. Adresse des Operanden
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
20
Beispiel: Objekt-Fileformat (a.out) I
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
21
Beispiel: Objekt-Fileformat (a.out) II
Header = Deskriptor für den Aufbau der Datei
Text = Tabelle mit dem übersetzten Code
Data = Tabelle mit den vorbelegten globalen Daten (static)
Relocation Information = Verschiebungsinformation = Tabelle mit
der Beschreibung der Stellen im Code, die durch den Linker
korrigiert werden müssen
• Symbol-Tabelle = Tabelle mit den Deskriptoren von Symbolen, z.B.
Namen von Variablen oder Routinen
• String-Tabelle = Feld mit de Zeichenketten (Strings), die die
Symbole ausmachen
Da dieselben Symbole mehrfach vorkommen können, werden die
Strings in der String-Tabelle und die Verweise darauf in der
Symbol-Tabelle abgelegt.
•
•
•
•
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
22
Verschiebungsinformation (Relocation Info)
• Wenn ein Modul auf eine static-Variable zugreift, dann muss der
Ort, also dessen Adresse zum Zeitpunkt des Bindens berechnet
werden, denn der Ort hängt von der Position des betreffenden
Moduls innerhalb der Binärdatei ab.
• In der Tabelle Relocation Information stehen Deskriptoren, die
festlegen, an welchen Stellen im Code die zu korrigierende
Adressen stehen.
• Wenn die CPU mit einer relativen Adressierungsart darauf zugreift,
ist die Korrektur zwingend erforderlich.
• Wenn die CPU relativ zu einem Register, z.B. PC, darauf zugreift, so
steht im Code lediglich die Differenz der Adressen zwischen
Register und dem Ort. Dann ist eine Verschiebung nicht nötig.
• Dasselbe gilt analog für Zugriffe auf absolute Adressen.
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
23
Bemerkungen
• Die beiden vorgestellten Formate sind nur Beispiele.
• Für Objekt-Dateien gibt es unter Linux folgende Formate:
– Klassisches a.out-Format (siehe oben, veraltet)
– COFF (Common Object File Format), veraltet
Siehe z.B. http://de.wikipedia.org/wiki/COFF
– ELF (Executable and Linking Format)
Siehe z.B.
http://de.wikipedia.org/wiki/Executable_and_Linking_
Format
http://www.linux-kernel.de/appendix/ap05.pdf
Heutige Systeme benutzen nur noch das ELF-Format.
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
24
Binden I
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
25
Binden II - Binärcode (Objectcode)
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
26
Binden III - Bibliotheken
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
27
Begriffe
• Bibliothek = Archiv = Library = Datei mit mehreren
benannten Informationsblöcken einschließlich eines
Verzeichnisses; jeder Block kann eine eigenständige Datei
aufnehmen, z. B. Zip-Archive
• Beispielstruktur:
Header Index
Datei
1
Datei
2
...
Datei
N
• Objektbibliothek = Bibliothek für Objektdateien
• Binärprogramm = Aus vielen Objektdateien bzw.
Bibliotheken zusammengesetztes ausführbares Programm
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
28
Beispiel: Bibliothek (ar-Format)
Siehe http://sourceware.org/binutils/docs/binutils/ranlib.html
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
29
Binden IV
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
30
Binden V
•
•
Jede übersetzte, ungebundene Objekt-Datei wird Modul
genannt.
Der Linker arbeitet pro Modul in folgenden Schritten:
1. Kopieren des aktuellen Moduls ans Ende der bisherigen
2. Feststellen, was dieses neue Modul an Symbole definiert
3. Diese aus der Tabelle der Unbekannten entfernen und in die
Tabelle der Bekannten eintragen
4. Alle Verweise (Aufrufe etc.) im bisher geladenen Teil mit
dem neuen Modul verbinden
5. Alle Verweise auf noch nicht geladene Routinen bzw. in
Tabelle der Unbekannten bringen.
6. Ist die Tabelle der Unbekannten leer, so terminiert das
Laden, ansonsten werden die Bibliotheken nach der
Definition der Unbekannten durchsucht; wird ein Modul dazu
gefunden, geht es mit Schritt 1 weiter, ansonsten wird eine
Fehlermeldung produziert.
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
31
Zeitpunkte des Bindens
• Direkt während der Übersetzung des Programm
Dadurch entsteht eine ausführbare Datei mit allen Teilen.
• Erst zum Zeitpunkt des Ladens in den RAM
Es entstehen kleine nicht-ausführbare Programme, die während
des Startens mit aktuellen Versionen der fehlenden Teile
verbunden werden.
– Der Linker ist dann Teil des Laders.
– Dies wird meist bei Linux gemacht.
• Während der Laufzeit des Programms
Der Binder läuft parallel zum Programm und verbindet nur die
Routinen, die aufgerufen werden.
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
32
Hauptprogramm
• C kennt keine Hauptprogramme, alle Routinen sind
gleichwertige Funktionen, die Werte liefern (und deshalb
einen Aufrufer benötigen).
• Es wird ein in Assembler geschriebenes Hauptprogramm
dazu gebunden, das eine C-Routine Namens "main" aufruft,
so dass main() wie ein Hauptprogramm erscheint.
Pseudocode des Hauptprogramms
Initialize Register
Initialize Stack
Push(Parameter)
call _main(argc,arv,env) /* Haupt-Programm */
call _exit(0)
/* für return in main() */
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
33
Nach dieser Anstrengung etwas Entspannung....
Betriebssysteme – WS 2015/16 - Teil 2/Übersetzung
34
Herunterladen