Forum: Mikrocontroller und Digitale Elektronik Verständnisproblem des Linkers bei mehreren .c-Dateien


von Christian O. (hightec)


Lesenswert?

Guten Morgen liebe Gemeinschaft,

ich bin ein blutiger Einsteiger in Sachen uC Programmierung, habe aber 
dennoch gute Erfahrungen in Sachen Programmierung bzw. das Verständnis 
dahinter.

Ich lese mich seit ca. 4 Wochen quer durch sämtliche Artikel und 
Tutorials und habe schon recht gute Fortschritte gemacht.

Momentan beschäftige ich mich mit dem Verständnis der Funktions- und 
Arbeitsweise des Compilers.

Soweit so gut auch alles einfach zu verstehen. Nur eine Sache ist mir 
bisher schleierhaft und ich habe auch noch keine wirklich 
zufriedenstellende Antwort gefunden:

Die AVR-Testprogramme die ich bisher geschrieben habe spielten sich 
immer in einer einzigen .c-Datei ab. (Ebenfalls soweit so gut)

Nun las ich das der Linker beim Kompillieren mehrere .c-Dateien zu einem 
Programm zusammenfügt.
Wie genau sieht dies denn aus?

Kann ich mir das so vorstellen, dass die verschiedenen Quelltextdateien 
zu einer einzigen zusammengefügt, heißt die Quelltexte praktisch 
hintereinander geschrieben werden?
Oder werden wirklich mehrere Dateien auf den uC geflasht und vom Linker 
verlinkt?

Ich hoffe ich konnte euch mein Defizit erklären. Bin dankbar für jede 
brauchbare Antwort ;-)

Gruß

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Christian O. schrieb:

> Momentan beschäftige ich mich mit dem Verständnis der Funktions- und
> Arbeitsweise des Compilers.
>
> Soweit so gut auch alles einfach zu verstehen. Nur eine Sache ist mir
> bisher schleierhaft und ich habe auch noch keine wirklich
> zufriedenstellende Antwort gefunden:
>
> Die AVR-Testprogramme die ich bisher geschrieben habe spielten sich
> immer in einer einzigen .c-Datei ab. (Ebenfalls soweit so gut)
>
> Nun las ich das der Linker beim Kompillieren mehrere .c-Dateien zu einem
> Programm zusammenfügt.
> Wie genau sieht dies denn aus?


Jede C-Datei wird einzeln und für sich compiliert. Das Ergebnis davon 
ist ein Object-File für jede C-Datei. Ein Object-File enthält bereits 
Maschinencode, so wie er vom Prozessor ausgeführt werden kann.

Aber: da fehlt ja noch einiges. Zum einen müssen die Aufruf-Querverweise 
für die einzelnen Funktionen hergestellt werden, zum anderen hast du ja 
nicht alle Funktionen selber geschrieben. Da sind zb Hilfsfunktionen, 
die arithmetische Operationen durchführen (zb Multiplikation, zb 
Division), oder auch Standard-C Funktionen wie zb Stringverarbeitung 
oder sprintf oder ...

Alle diese Funktionen wurden mal von jemandem geschrieben und 
vorübersetzt. Diese Einzelteile sind gesammelt worden und in einer 
Library verpackt worden.

Und jetzt kommt der Linker ins Spiel.
Er kriegt die einzelnen übersetzten Object-Files vorgesetzt, nimmt noch 
die System-Library dazu und versucht das jetzt aufzulösen:
Er kopiert alle Einzelteile zum kompletten Programm zusammen, fügt die 
Aufrufadressen der Funktionen an der aufrufenden Stelle ein (die kennt 
er ja jetzt, denn jetzt gibt es ja erstmals ein komplettes Programm), 
ergänzt die fehlenden Teile aus der Systembibliothek und bindet auch 
deren Aufrufe korrekt ein.

Als Ergebnis hast du dann das fertige Programm.

>
> Kann ich mir das so vorstellen, dass die verschiedenen Quelltextdateien
> zu einer einzigen zusammengefügt, heißt die Quelltexte praktisch
> hintereinander geschrieben werden?

Nicht die Quelltexte.
Die vorübersetzten Einheiten. Maschinencode. Mit deinem Programmtext, 
geschrieben in C, hat der Linker nur noch insofern zu tun, als ihm der 
Compiler die Einzelteile in Maschinencode übersetzt hat. Aber ansonsten 
hat der Linker mit C nichts mehr am Hut.

: Bearbeitet durch User
von Stephan B. (matrixstorm)


Lesenswert?

Danke Karl fuer die schoene Erklaerung.

Fuer Christian hier nocheinmal im Detail und mit Bild: 
http://www.tenouk.com/ModuleW.html

MfG

von Christian O. (hightec)


Lesenswert?

Vielen Dank für die ausführliche Antwort,

ok dass der Linker keinen Quelltext sondern Maschinencode vorgesetzt 
bekommt ist recht einleuchtend.

Also zusammengefasst: Der Linker bekommt die kompillierten Programmcodes 
und die Funktionen aus der Standard-libary, und und und. Dies alles 
kopiert er dann in eine einzige Maschinencode-Datei (Hex?) zusammen.

Also wird aus:

Beispiel:

Main.o -> 11100101000101
Nichtmain.o -> 101001011110101
Auchnichtmain.o -> 101010111010
Standard-Libary-Funktionen -> 110100010010001100111

dann folgendes:

11100101000101101001011110101101010111010110100010010001100111

(ja ich weiss das ist kein Hex ;-) .Die Speicheradressierung und das 
drumherum mal ausser acht gelassen)

Hab ich das so richtig verstanden?

: Bearbeitet durch User
von Garden (Gast)


Lesenswert?

Was machen Compiler und Linker?

Vielleicht hilft dieses Video:

http://et-tutorials.de/938/was-machen-compiler-und-linker/

von Karl H. (kbuchegg)


Lesenswert?

Christian O. schrieb:
> Vielen Dank für die ausführliche Antwort,
>
> ok dass der Linker keinen Quelltext sondern Maschinencode vorgesetzt
> bekommt ist recht einleuchtend.
>
> Also zusammengefasst: Der Linker bekommt die kompillierten Programmcodes
> und die Funktionen aus der Standard-libary, und und und. Dies alles
> kopiert er dann in eine einzige Maschinencode-Datei (Hex?) zusammen.

Ja.
Wobei nicht gesagt ist, dass das 'Hex' (was auch immer das sein soll) 
sein muss. Es ist ein Binärfile, welches zb im Falle eines 
Windows-Programms dann auch gleich direkt auf einem Windows-System 
ausführbar ist. Im konkreten Fall eines Cross-Compilers (also 
Compiler/Linker die ein Programm erzeugen, welches dann auf einem ganz 
anderen System läuft), muss dann natürlich das ganze so aufbereitet 
werden, dass es dann auch tatsächlich in den AVR gebrannt werden kann.


> Beispiel:
>
> Main.o -> 11100101000101
> Nichtmain.o -> 101001011110101
> Auchnichtmain.o -> 101010111010
> Standard-Libary-Funktionen -> 110100010010001100111
>
> dann folgendes:
>
> 11100101000101101001011110101101010111010110100010010001100111
>
> (Die Speicheradressierung und das drumherum mal ausser acht gelassen)
>
> Hab ich das so richtig verstanden?

So in etwa.
Die Details sind zwar völlig anders, aber vom Prinzip her kommt das 
schon hin.

: Bearbeitet durch User
von Christian O. (hightec)


Lesenswert?

Sehr gut,
Vielen Dank euch für die Hilfe...nun hab ich es gerafft ;-)

@ Karl
Mit Hex meinte ich, dass in fast sämtlichen Artikeln stand, dass die auf 
den AVR zu übertragende Datei eine .hex-Datei ist. So eine Hex-Datei 
habe ich auch immer auf den AVR geschrieben. Dachte dass der Code der 
übertragen wird dann auch im Hexadezimalformat ist.

Aber nun hab ich die Informationen die ich suchte. Danke für die 
schnellen Antworten und Links...Werde mir die Artikel von Stephan und 
Garden nochmal zur Gemüte führen, die sehen recht interessant aus.

Gruß

: Bearbeitet durch User
von ich (Gast)


Lesenswert?

Christian O. schrieb:
> Mit Hex meinte ich, dass in fast sämtlichen Artikeln stand, dass die auf
> den AVR zu übertragende Datei eine .hex-Datei ist. So eine Hex-Datei
> habe ich auch immer auf den AVR geschrieben. Dachte dass der Code der
> übertragen wird dann auch im Hexadezimalformat ist.
>
Hier mal noch eine Erläuterung des Intel-Hex-Formates, das für die 
Programmierfiles (*.hex) in der Regel verwendet wird. Das sind nicht nur 
die Inhalte des eigentlichen Maschinenprogrammes, sondern auch noch 
Adressinformationen, Segmentadressen usw. Außerdem ist das ganze auch 
noch in ASCII codiert, also als Textdatei.

http://de.wikipedia.org/wiki/Intel_HEX

von Axel S. (a-za-z0-9)


Lesenswert?

Christian O. schrieb:
> Mit Hex meinte ich, dass in fast sämtlichen Artikeln stand, dass die auf
> den AVR zu übertragende Datei eine .hex-Datei ist. So eine Hex-Datei
> habe ich auch immer auf den AVR geschrieben. Dachte dass der Code der
> übertragen wird dann auch im Hexadezimalformat ist.

Jein. Das Intel-Hex Format ist nur ein Transportformat.

Wenn du mit avr-gcc ein Programm für einen AVR compilierst, dann fällt 
aus dem Linker ein File im ELF Format raus. Das heißt dann z.B. 
main.elf. Darin steht dann der ausführbare Maschinencode (Section 
.text), initialisierte Variablen (Section .data) etc. Ebenfalls drin 
sein können aber auch Debugging-Informationen.

Wenn du ein Programm nun in den AVR flashen willst, dann brauchst du 
dazu mindestens die Teile aus dem ELF File, die in den Flash gehen. Die 
werden in einem typischen Makefile mit den Programm avr-objcopy aus dem 
ELF File extrahiert und im Intel HEX Format zwischenspeichert. Das sieht 
z.B. so aus:
1
avr-objcopy -O ihex -R .eeprom main.elf main.hex

Im Prinzip kann das ELF File auch weitere Daten enthalten, die 
unabhängig vom Flash in den AVR geschrieben werden:

- initialisierte EEMEM Variablen
- Fuses

das braucht dann jeweils andere Aufrufe von avr-objcopy, um die Daten 
aus dem ELF zu extrahieren.

Technisch ist dieser Zwischenschritt mit den HEX Files übrigens nicht 
nötig. Man könnte auch dem Brennprogramm (z.B. avrdude) beibringen, wie 
es das ELF File zu zerlegen hat. Allerdings würde man avdude damit 
wieder fest mit der GNU Toolchain verbandeln. Und da es avr-objcopy 
ohnehin gibt, hat man sich entschieden, diese Funktionalität nicht zu 
duplizieren. Ich habe aber auch schon Brennprogramme gesehen, die direkt 
.elf fressen.


XL

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.