Schreibe schon länger Programme für diverse AVRs mit dem GCC. Nun frage ich mich aber was der für einen Code erzeugt welcher vor main aufgerufen wird. Habe hierzu testweise ein Programm erzeugt was eigentlich nix macht g. Einiges ist mir klar - doch vieles auch unbegreiflich. Vielleicht weis ja jemand was hier passiert: Mich interressier besonders das ab Adresse 1B --> Hier beginnt die Interrupt Vektor Table +00000000: C014 RJMP PC+0x0015 Relative jump +00000001: C02D RJMP PC+0x002E Relative jump +00000002: C02C RJMP PC+0x002D Relative jump +00000003: C02B RJMP PC+0x002C Relative jump +00000004: C02A RJMP PC+0x002B Relative jump +00000005: C029 RJMP PC+0x002A Relative jump +00000006: C028 RJMP PC+0x0029 Relative jump +00000007: C027 RJMP PC+0x0028 Relative jump +00000008: C026 RJMP PC+0x0027 Relative jump +00000009: C025 RJMP PC+0x0026 Relative jump +0000000A: C024 RJMP PC+0x0025 Relative jump +0000000B: C023 RJMP PC+0x0024 Relative jump +0000000C: C022 RJMP PC+0x0023 Relative jump +0000000D: C021 RJMP PC+0x0022 Relative jump +0000000E: C020 RJMP PC+0x0021 Relative jump +0000000F: C01F RJMP PC+0x0020 Relative jump +00000010: C01E RJMP PC+0x001F Relative jump +00000011: C01D RJMP PC+0x001E Relative jump +00000012: C01C RJMP PC+0x001D Relative jump +00000013: C01B RJMP PC+0x001C Relative jump +00000014: C01A RJMP PC+0x001B Relative jump --> Hier endet die Interrupt Vektor Table --> Hier wird das Status Register gelöscht, aber warum?? +00000015: 2411 CLR R1 Clear Register +00000016: BE1F OUT 0x3F,R1 Out to I/O location --> Er setzt den Stack-Pointer, OK! +00000017: E5CF LDI R28,0x5F Load immediate +00000018: E0D2 LDI R29,0x02 Load immediate +00000019: BFDE OUT 0x3E,R29 Out to I/O location +0000001A: BFCD OUT 0x3D,R28 Out to I/O location --> und das folgende ist mir total schleierhaft.... +0000001B: E010 LDI R17,0x00 Load immediate +0000001C: E6A0 LDI R26,0x60 Load immediate +0000001D: E0B0 LDI R27,0x00 Load immediate +0000001E: E6EC LDI R30,0x6C Load immediate +0000001F: E0F0 LDI R31,0x00 Load immediate +00000020: C002 RJMP PC+0x0003 Relative jump +00000021: 9005 LPM R0,Z+ Load program memory and postincrement +00000022: 920D ST X+,R0 Store indirect and postincrement +00000023: 36A0 CPI R26,0x60 Compare with immediate +00000024: 07B1 CPC R27,R17 Compare with carry +00000025: F7D9 BRNE PC-0x04 Branch if not equal +00000026: E010 LDI R17,0x00 Load immediate +00000027: E6A0 LDI R26,0x60 Load immediate +00000028: E0B0 LDI R27,0x00 Load immediate +00000029: C001 RJMP PC+0x0002 Relative jump +0000002A: 921D ST X+,R1 Store indirect and postincrement +0000002B: 36A0 CPI R26,0x60 Compare with immediate +0000002C: 07B1 CPC R27,R17 Compare with carry +0000002D: F7E1 BRNE PC-0x03 Branch if not equal --> Dies ist der Jump nach main! +0000002E: C001 RJMP PC+0x0002 Relative jump +0000002F: CFD0 RJMP PC-0x002F Relative jump @00000030: main
Das ist der sogenannte "startup-Code", der den Prozessor soweit initialisiert, daß main aufgerufen werden kann. Wie Du schon herausgefunden hast, initialisiert das beispielsweise den Stack und die Interrupttabelle. Der Quelltext dieses Startupcodes sollte beim Compiler eigentlich dabei sein; da ich gcc nicht einsetze, kann ich Dir da leider keine genaueren Hinweise geben.
Der Quelltext dafür ist bei der avr-libc mit dabei. Natürlich nur, wenn man sich den Sourcecode mit installiert.
@Jörg Wunsch OK, aber wo...? Sind für eine zufällige Suche einfach zuviele Dateien
Ich habe eine Vollinstallation gemacht, finde bei mir aber keine einzige C Datei im WinAVR Ordner...
Den Sourcecode gibt's separat, ansonsten wäre WinAVR ja noch x-mal größer als es sowieso schon ist. Meiner Erinnerung nach hat Eric im README auch beschrieben, wo's den gibt. Für avr-libc: http://download.savannah.nongnu.org/releases/avr-libc/avr-libc-1.4.3.tar.bz2 Keine Angst vor .tar.bz2, erstens kann man das mit dem mitgelieferten tar-Kommando auspacken: tar -xvj -f avr-libc-1.4.3.tar.bz2 und außerdem sollten auch aktuelle WinZips das können. Die fragliche Datei heißt crt1/gcrt1.S.
Um code vor "main()" aufzurufen, braucht er den Quelltext der lib nicht anfassen, das ist schon eingebaut. Schau mal hier: http://www.nongnu.org/avr-libc/user-manual/mem_sections.html Abschnitt über ".initN" sections. Die werden sequenziell abgearbeitet, code in der init1 section z.B. bereits bevor der Stack initialisiert wurde. also einfach in den C code eine funktion mit attribute "naked" und "section .init1" anlegen, den Rest erledigt der Linker. /Ernst
Habe mir eben die "gcrt1.S" angeschaut. Glaube sogar meine Stackpointer inizialisierungs-Routine gefunden wiedergefunden zu haben, nur was der Code macht, bzw. was sonst in der Datei steht ist mir immernoch ein Rätsel. Kann das jemand mit eigenen Worten "beschreiben" was da geschieht?
Der grossteil ist: - init stack - init zero_reg (register mit 0 vorbelegen) - Kopieren von Flash->RAM um vorinitialisierte Variablen zu belegen, also sachen wie: unit16_t xxx=123; char * string="Hallo Welt"; usw. - Löschen (füllen mit 0x00) von Speicherbereichen mit unititialisierten Variablen - default Interrupt-Handler deklarieren, der einen Reset auslöst. Bei C++ kommt dann noch Code für Konstruktoren von globalen Objekten hinzu. /Ernst
Na der Beitrag von Ernst war mal ein Anfang in die Richtige Richtung -Danke. Nur ich frage mich immernoch wozu, denn mein Beispielprogramm beinhaltet ja praktisch nichts ausser Main also auch keine Variablen.
> Nur ich frage mich immernoch wozu, denn mein Beispielprogramm > beinhaltet ja praktisch nichts ausser Main also auch keine > Variablen. Die Initialisierungsfunktionen sind mehr theoretisch optional. Praktisch generiert der Compiler stets ungelöste Referenzen auf diese Funktionen, sodass der Linker sie immer mit einbindet. Das ist wohl mal 'ne Idee von Marek Michalkiewicz gewesen, dass der Compiler das tatsächlich feststellt, was gebraucht wird, die aber nie wirklich zu Ende gebaut worden ist. Für die meisten ,,richtigen'' Programme ist es eher belanglos, da sie in irgendeiner Form natürlich Variablen benutzen. ;-) Am ehesten passiert es noch, dass jemand keinerlei initialisierte Variablen braucht und daher diese Funktion weggelassen werden könnte.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.