Hallo Community,
die Frage hier baut auf meiner anderen Frage in diesem Thread auf
(Beitrag "Re: Probleme beim Linken mit arm-none-eabi-gcc (yagarto)"), ist aber jetzt
etwas spezifischer geworden, weswegen ich sie noch mal neu formuliere.
Das erwähnte Problem habe ich nun zwar einfach umgangen, aber ich weiß
nicht wieso es überhaupt da ist. Um es noch mal kurz zu beschreiben:
Ich versuche Code für einen Cortex-M3 zu kompilieren und verwende dazu
die yagarto-Toolchain und die newlibc. Nachdem ich einige Änderungen an
meinem Code vorgenommen hatte, wollte ich wieder kompilieren und bekam
dann diese Linker-Fehler:
1 | arm-none-eabi-gcc -T ../../cpu/arm//atsam3s4/atsam3s4-flash.ld -L../../cpu/arm//atsam3s4 -march=armv7-m -mcpu=cortex-m3 -mthumb -Wl,-Map=mapfile -nostartfiles hello-world.co obj_deRFusb-13E00/contiki-main.o contiki-deRFusb-13E00.a -o hello-world.deRFusb-13E00
|
2 | c:/yagarto-20121222/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/thumb/v7m\libc.a(lib_a-impure.o):(.data+0x0): multiple definition of `_impure_ptr'
|
3 | contiki-deRFusb-13E00.a(stdio.o):(.data+0x428): first defined here
|
4 | c:/yagarto-20121222/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/thumb/v7m\libc.a(lib_a-sbrkr.o): In function `_sbrk_r':
|
5 | C:\msys\1.0\home\yagarto\newlib-build\arm-none-eabi\thumb\v7m\newlib\libc\reent/../../../../../../../newlib-1.20.0/newlib/libc/reent/sbrkr.c:58: undefined reference to `_sbrk'
|
6 | c:/yagarto-20121222/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/thumb/v7m\libc.a(lib_a-writer.o): In function `_write_r':
|
7 | C:\msys\1.0\home\yagarto\newlib-build\arm-none-eabi\thumb\v7m\newlib\libc\reent/../../../../../../../newlib-1.20.0/newlib/libc/reent/writer.c:58: undefined reference to `_write'
|
8 | c:/yagarto-20121222/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/thumb/v7m\libc.a(lib_a-closer.o): In function `_close_r':
|
9 | C:\msys\1.0\home\yagarto\newlib-build\arm-none-eabi\thumb\v7m\newlib\libc\reent/../../../../../../../newlib-1.20.0/newlib/libc/reent/closer.c:53: undefined reference to `_close'
|
10 | c:/yagarto-20121222/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/thumb/v7m\libc.a(lib_a-fstatr.o): In function `_fstat_r':
|
11 | C:\msys\1.0\home\yagarto\newlib-build\arm-none-eabi\thumb\v7m\newlib\libc\reent/../../../../../../../newlib-1.20.0/newlib/libc/reent/fstatr.c:62: undefined reference to `_fstat'
|
12 | c:/yagarto-20121222/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/thumb/v7m\libc.a(lib_a-isattyr.o): In function `_isatty_r':
|
13 | C:\msys\1.0\home\yagarto\newlib-build\arm-none-eabi\thumb\v7m\newlib\libc\reent/../../../../../../../newlib-1.20.0/newlib/libc/reent/isattyr.c:58: undefined reference to `_isatty'
|
14 | c:/yagarto-20121222/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/thumb/v7m\libc.a(lib_a-lseekr.o): In function `_lseek_r':
|
15 | rm hello-world.co
|
16 | C:\msys\1.0\home\yagarto\newlib-build\arm-none-eabi\thumb\v7m\newlib\libc\reent/../../../../../../../newlib-1.20.0/newlib/libc/reent/lseekr.c:58: undefined reference to `_lseek'
|
17 | c:/yagarto-20121222/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/thumb/v7m\libc.a(lib_a-readr.o): In function `_read_r':
|
18 | C:\msys\1.0\home\yagarto\newlib-build\arm-none-eabi\thumb\v7m\newlib\libc\reent/../../../../../../../newlib-1.20.0/newlib/libc/reent/readr.c:58: undefined reference to `_read'
|
19 | collect2.exe: error: ld returned 1 exit status
|
20 | make: *** [hello-world.deRFusb-13E00] Error 1
|
Nach Stunden der Problemsuche hab ich dann einfach eine ältere
kompilierbare Version wieder hergestellt und nach und nach die
Neuerungen eingebaut, bis ich den Grund für die Fehler gefunden hatte
und letztendlich lag es an einem Aufruf von putchar, was ich an manchen
Stellen als ein schnelles printf zu Debuggingzwecken verwende. Mit
printf hat der Compiler respeketive Linker übrigens kein Problem.
Nachdem ich das putchar auskommentiert habe, hat er wieder kompiliert
und ich verstehe nicht warum. Als eine ‚Besonderheit’ muss ich wohl noch
hinzufügen, dass ich verschiedene Quelldateien mit in meinem Projekt
habe, die C-Standardfunktionen ‚überschreiben’, unter anderem printf,
fputc, putchar und so weiter. Ich schätze, dass das vielleicht nicht
ganz sauber ist, aber zum einen habe ich das Projekt auch nur so
übernommen. Und zum anderen sind die Quelldateien laut der Kommentare
auch direkt von Atmel und erzeugen auch wesentlich schlankeren Code als
die newlib mit dem ganzen Reent-Zeug und brauchen auch kein malloc.
Insgesamt macht das für mich einen Unterschied von knapp 24kB, weswegen
ich auch sicher nicht auf die newlib-Implementierung umsteigen werde.
Wie dem auch sei. Das Komische ist eben, dass putchar in derselben Datei
implementiert ist wie fputc, nämlich uart_console.c. Aber fputc kann ich
ohne Probleme verwenden. Und die Implementierung von putchar macht auch
nichts anderes als fputc mit stdio als Argument aufzurufen:
1 | signed int putchar(signed int c)
|
2 | {
|
3 | return fputc(c, stdout);
|
4 | }
|
Die printf-Funktion ist in einer anderen Datei implementiert, nämlich in
stdio.c, ruft aber irgendwann über vprintf, vfprintf und fputs auch
wieder fputc auf. Ein Aufruf von printf im Code kompiliert problemlos
und tut zur Laufzeit auch genau das, was sie soll. fputc ruft dann
übrigens Funktionen auf, die auf die serielle Schnittstelle schreiben,
ebenfalls in uart_console.c implementiert.
Jetzt verstehe ich nicht, wieso es mit printf und fputc kompiliert und
mit putchar nicht, obwohl putchar in derselben Datei wie fputc
implementiert ist und auch nichts weiter tut als fputc aufzurufen. Ein
Auszug aus dem mapfile zeigt auch, dass auf jeden Fall die richtige
putchar-Implementierung genommen wird:
1 | .text 0x0040a65c 0x3a8 contiki-deRFusb-13E00.a(uart_console.o)
|
2 | 0x0040a694 UART_Configure
|
3 | 0x0040a730 UART_PutChar
|
4 | 0x0040a780 UART_GetChar
|
5 | 0x0040a7cc UART_IsRxReady
|
6 | 0x0040a818 UART_SetInputHandler
|
7 | 0x0040a854 UART0_IrqHandler
|
8 | 0x0040a888 fputc
|
9 | 0x0040a8e0 fputs
|
10 | 0x0040a930 putchar
|
11 | 0x0040a958 fgetc
|
12 | 0x0040a98c getchar
|
Was hat die newlib bzw. der Linker da für ein Problem mit putchar?!
Der Linker beschwert sich ja, dass z.B. in der newlib-Funktion _sbrk_r
_sbrk verwendet wird, was aber nicht referenziert werden kann. Nehme ich
putchar raus, wird auch _sbrk_r nicht mehr benötigt und daher kommt der
Fehler auch nicht. Gleiches gilt für _write_r, _close_r und so weiter.
Aber in der Implementierung von putchar passiert ja auch nichts weiter,
weswegen ich nicht verstehe, wieso dann auf einmal die ganzen
newlib-Funktionen gebraucht werden. Gibt es auch eine Möglichkeit zu
sehen, wieso er jetzt auf einmal die newlib-Funktionen braucht? Die
müssen ja irgendwo aufgerufen werden jetzt. Also quasi so eine Art „Open
Call Hierachry“, nur eben auf Object-Code-Ebene.
Vielen Dank für eure Hilfe.