Forum: Compiler & IDEs Yagarto: unnötige Includes?


von Sascha M. (siddhartha)


Lesenswert?

Hallo zusammen

ich schreibe gerade einen Bootloader für einen AT91SAM7S256 und benutze 
die Yagarto-Toolchain (mit der Eclipse Integration). Im Bootloader 
selber brauche ich jedoch keine der C-Standard-Funktionen und include 
auch keine Header-Files wie stdio.h, stdlib.h oder ähnliche (die brauche 
ich nur in der Hauptapplikation).
Da ich unterdessen der 16kB Grenze, die ich mir für den Bootloader 
gesetzt habe, sehr nahe gekommen bin (das Binary ist nurnoch 4 Byte 
kleiner ;-)) habe ich mir mal aus dem Map-File zusammengerechnet, wie 
gross die einzelnen Dateien genau sind, damit ich sehen kann, wo ich 
eventuell noch abspecken muss. Dabei ist mir aufgefallen, dass sehr 
viele Header-Files von Yagarto included werden z.B.

1
x:/xxx/yagarto/bin/../lib/gcc/arm-elf/4.2.2/../../../../arm-elf/lib/interwork\libc.a(lib_a-malloc.o)

welches die malloc() und free() Funktionen beinhaltet! Der ganze "Spass" 
benötigt schlussendlich etwa 10.5 kB (hab einfach die Size-Angaben aus 
dem Map-File addiert).

Kann mir jemand erklären, warum das genau so ist? Ich benutze weder die 
malloc() noch die free() Funktion. Eigentlich benutze ich ja gar keine 
Funktionen der C-Standard-Library. Dass da n'paar Funktionen vom 
Compiler gebraucht werden, hatte ich schon erwartet, aber 10.5 kB????
Gibt es eine Möglichkeit diese Includes zu umgehen oder muss das so 
sein, damit der Compiler überhaupt richtig kompilieren kann?

In der Hauptapplikation sind sogar über 50 kB aus der Yagarto-Lib, aber 
da verwende ich auch des öfteren Funktionen aus der Standard-Library 
(trotzdem scheinen mir über 50 kB doch relativ viel...).

Wäre froh wenn mich jemand "aufklären" könnte, ob das normal ist (und 
wenn ja warum) oder ob man was dagegen machen kann.

Tausend Dank.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Die Includes spielen später keine Rolle.

Du solltest in der MAP-Datei oder dem ASM-Listing nachsehen, ob die 
fraglichen Funktionen drin sind.

Dort siehst du generell welche Variablen und Funktionen im Endprodukt 
drin sind und wieviel Platz jedes einzelne Symbol benötigt.

von Sascha M. (siddhartha)


Lesenswert?

Ähm aus der MAP-Datei hab ich die Grösse etc ja erst ausgerechnet. Und 
von dort kommt auch die oben aufgeführte Beispiel-Zeile eines Includes.

Sonst wüsste ich gar keine Möglichkeit wo ich nachsehen könnte, was 
genau alles included wird. Kann man irgendwo sehen, welche Header-Files 
genau von welchem File included werden? Habe bisher immer mit dem 
MAP-File gearbeitet, weil da ja Grösse und Dateien in der (mehr oder 
weniger) korrekten Reihenfolge drinstehen, wie sie später im Speicher 
vorkommen werden.

von Sascha M. (siddhartha)


Lesenswert?

OK ich hab den "Übeltäter" gefunden. Ich hab ne eigene crt0.S etc 
geschrieben und in der steht (wie meines Wissens ungefähr üblich):

1
/* --- Now enter the C code */
2
   ldr   r0, =exit
3
   mov   lr, r0               /* Return address = exit */
4
   ldr   r0, =main
5
   bx    r0

Sobald ich die ersten beiden Zeilen, die die exit-Routine laden, 
auskommentiere, sinkt die Grösse meines Binaries auf 5.5 kB. Mir ist 
klar, dass die newlib Library mit libc sehr stark "verdrahtet" ist also 
dass viele Dateien von anderen abhängen, aber dass das einfach mal so 
mehr als 10 kB ausmacht?

Da es aber unschön ist, diese beiden Zeilen einfach wegzulassen (was 
passiert, wenn main aus irgendwelchen Gründen (trotz while(1)) beendet 
wird und dann da nicht zu exit gesprungen wird?) wollte ich fragen, ob 
es eine Möglichkeit gibt, sowas irgendwie einfach selbst 
sicherzustellen.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Dein Sprachgebrauch von included ist ungewöhnlich und kann 
Diskussionen erschweren. Du meinst, was aus den Libraries gelinkt 
wird.

Um den Startupcode in Ruhe zu lassen, könntest du eine eigene, 
Schmalhans exit() Funktion schreiben, die zur Not nur ein while(1); 
enthält bzw. beim Bootloader u.U. garnix, weil der anders den geladenen 
Code anspringt. Dann wird die fette exit() aus der Library nicht mehr 
dazugelinkt.

von Sascha M. (siddhartha)


Lesenswert?

Ja sorry, ich geh mit diesen Begriffen manchmal zu "leichtsinnig" um ;-) 
Natürlich meine ich gelinkt.
Eigentlich ist es auch gar nicht möglich aus der main-Funktion des 
Bootloaders rauszukommen, da da am Ende sowieso ein

1
while(1);

steht, aber ich werde wohl noch eine Endlos-Schleife in die crt0.S Datei 
einbauen, sicher ist sicher.

Danke für deine Hilfe.

von Sascha M. (siddhartha)


Lesenswert?

Jetzt merke ich gerade, dass ich deinen Beitrag nicht ganz verstanden 
habe.
Ja eine eigene exit() Funktion zu schreiben, wäre auch eine Alternative.
Vor allem liesse sich das dann besser anpassen, falls das mal nötig 
wäre.
Den Startup-Code zu ändern ist nicht so tragisch, da ich den sowieso 
selber zusammengestellt und geschrieben habe (mit Vorlage).

von Heiko_S (Gast)


Lesenswert?

@Sascha M.: Kannst Du mir evtl. Informationen zur Verfügung stellen, wie 
Dein Bootloader funktionieren soll?
Ich selber habe keine Vorstellungen, wie ich solch ein Code anspringen 
sollte, bzw. den Stack und C-Code (Variablen, Interrupt,...) initiieren 
sollte.

von Tilo Lutz (Gast)


Lesenswert?

Im Howto von J. Lynch ist ein Startupcode vorhanden, der auf vielen ARM7 
Modellen auf anhieb läuft. Afaik bezieht es sogar explizit auf den 
AT91SAM7S256.

Um den Einsprung in den Startupcode muss man sich normalerweise nicht 
kümmern.
Der Code ist so geschrieben, dass bei Adresse 0x0 ein Sprungbefehl zur 
Adresse mit dem eigentlichen Resethandler steht. Ab 0x1 sind die 
Vektoren für Interrupts etc. zu finden.

Nach dem der Resethandler ausgeführt wurde, springt dieser normalerweise 
zur Funktion main. Von dort aus beginnt das Hauptprogramm

Ich kenne mich mit Assembler usw. noch nicht so gut aus, deshalb kann 
ich dir zur Stackbehandlung usw. nicht so viel sagen. Ansonsten kann ich 
noch auf mein Howto verweisen. Das ist zwar für einen anderen uC, der 
ARM-Teil ist jedoch fast identisch.

von Sascha M. (siddhartha)


Lesenswert?

@Heiko_S: Tilo hat ja schon einige deiner Fragen beantwortet.
Ich persönliche hatte mich am crt0.S File der newlib orientiert. Dort 
findet man für viele verschiedene Plattformen die jeweiligen 
Startup-Files.

Falls du weitere Fragen hast, einfach raus damit ;-)

von Heiko_S (Gast)


Lesenswert?

Da ist vielleicht die Frage schlecht formuliert worden!
Den StartUpCode kenne ich zur genüge (schon einige Tage damit 
verbracht). Aber ein Bootloader aus einem laufenden Programm-, oder 
Bootloader grundsätzlich anspringen?
Dann, wenn kein Programm übertragen werden soll, das eigentliche 
Hauptprogramm anspringen?
Wohin ist dieses dann gelinkt, da bei PowerUp immer der Flash auf 
Adresse 0 zeigt.

Beim AVR ist mit einem BootLoaderFlag automatisch erst der Bootloader 
aktiv, aber beim ARM?

Aus diesem Grunde (kein BootLoaderFlag beim ARM) stellen sich bei mir so 
viele Fragen, wie überhaupt solch ein BootLoader funktionieren soll.

von Tilo Lutz (Gast)


Lesenswert?

Ok, jetzt wird es etwas klarer.

Ich kann jetzt nur etws zum ADUC schreiben. In dessen Flash liegt ein 
2kb großer Bootloder von ADI. Dieser wird vor dem Startup Code 
ausgeführt. In diesem sind zum einen Kalibrierwerte gespeichert. Zum 
anderen wird der Pegel des DWN-Pin überprüft. Ist der Pegel high, wird 
über Uart neue Firmware geladen. Ist der Pegel low, wird der 
Startprozess an Adresse 0x0 fortgesetzt.

Dies sollte bei anderen uCs ähnlich sein.

von Sascha M. (siddhartha)


Lesenswert?

Also ich linke den Bootloader auf die Adresse 0x0 und die 
Hauptapplikation auf 0x4000 => es bleiben 16 kB für den Bootloader 
(relativ viel, wird vielleicht noch verkleinert). In den Bootloader kann 
man einfach mit einem Sprung nach 0x0 kommen. Oder halt, wenn das Geräte 
eingeschaltet wird.

Dadurch ist der Bootloader immer vorhanden und muss nicht erst wie bei 
SAM-BA durch setzen von Jumper ins interne Flash kopiert werden. Der 
Nachteil ist halt, dass dieser Speicherbereich für die Hauptapplikation 
nicht zur Verfügung steht.

Ein Knackpunkt sind dann noch die Interrupt-Vektoren (sofern du die 
nicht ins RAM kopierst). Ich mache es so, dass bei 0x0 die 
Interrupt-Vektoren des Bootloaders sind, diese aber einfach aus einem 
Branch zu den Interrupt-Vektoren der Hauptapplikation bestehen, welche 
bei 0x4000 liegen. Dadurch musst du im Bootloader halt auf 
Interrupt-Vektoren verzichten und des Öfteren mal auf Flag-Polling 
zurückgreifen.

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.