Forum: Compiler & IDEs AT91SAM7S: einheitlicher Startup-Code


von Clemens H. (sum)


Angehängte Dateien:

Lesenswert?

Guten Abend,

in den verschiedenen Foren/Softwarepaketen/Beispielen kursieren die
unterschiedlichsten Startup-Codes für die AT91SAM7S-Familie von Atmel
herum. In der Gnuarm Gruppe wurde erwähnt, dass bei vielen der
Startup-Codes der Kommentar nicht zum Code passt, der Code nicht tut
was er soll, etc. etc.

Dies habe ich nun zum Anlass genommen, meinen eigenen Startup-Code zu
schreiben. Ich habe versucht, den Code möglichst genau und treffend zu
dokumentieren. Da ich annähernd alles neu geschrieben - und per
JTAG-Debugging getestet - habe, passen die Kommentare auf jeden Fall
zum Code und die Funktionalität ist hoffentlich korrekt.

Derzeit werden folgende Funktionen unterstützt:
- Initialisierung der Daten im RAM (.bss, .data)
- Initialisierung der verschiedenen Taktgeber (Oszillator, PLL,
Divider)
- Initialisierung aller Stacks (User, Supervisor, Abort, Undefined,
IRQ, FIQ)
- Interruptbehandlung (IRQ), Ausführung der Interruptroutine im User
Mode
- Software Interruptbehandlung (SWI), Ausführung der C-Routine zum SWI
im System Mode (Priviligiert)
- Ausführen der main() im User Mode

Eine Behandlung der Undefined Instruction, Prefetch-Abort und
Data-Abort ist geplant.

Zur Einbindung in ein Projekt müssen nur die Dateien fiq.S, startup.h,
main.c, swi_c.c angepasst werden. Zur verwendung des Remap-Commands
muss das Linker-script mem.ld angepasst werden. Zusätzlich zum
Quellcode ist noch ein Makefile mit der Möglichkeit per OpenOCD zu
flashen enthalten. Die OpenOCD-Version muss geringfügig modifiziert
werden.

Hoffentlich lässt sich mit einem solchen Code ein einheitliches
Startup-Verfahren - ähnlich wie bei dem avr-gcc - einrichten.

Ich bitte ausdrücklich um Anregungen/Kritik/Fehlerberichte - und vor
allem auch Erfolgsberichte!

Clemens

von mthomas (Gast)


Lesenswert?

Habe nicht alles genau durchgelesen, also nur vom kurz drueberschauen
ein paar Anmerkungen/Fragen:
- einige Kommentare passen nicht zum Code oder sind etwas
missverstaendlich. ("clear register" statt push regsiter, initBSS
statt init_DATA_and_BSS), remapping in Kommentaren erwaehnt aber keine
Option und kein code fuer remap
- Funktioniert der Code mit thumb/thumb-interwork?
- Redundanz in section und ".org" und linker-script-Einstellungen.
.org sollte vermieden werden und laesst sich auch vermeiden.
- Zur Plazierung der vordefinierten Sektionen fuer libgcc scheinen im
Linker-Skript Eintraege zu fehlen
- Der IRQ-Handler und vor allem swi darin sieht sehr ungewoehnlich aus,
warum so?

Martin Thomas

von A.K. (Gast)


Lesenswert?

Weshalb User-Mode statt Sys-Mode für die IRQ-Handler? Im Sys-Mode wird
auch der seltsame SWI überflüssig.

von A.K. (Gast)


Lesenswert?

Setzt du interworking bei thumb code zwingend voraus?

Wirklich universell wird's nur, wenn ein komplett als thumb code
geschriebenes Programm ohne interworking arbeiten kann (spart Platz).
Da solcherart Funktionen allerdings nicht freiwillig in den native mode
zurückkehren (Konstruktionsfehler in LDM, in späteren ARMs repariert),
ist es mit einem einfachen BX nicht getan. Da wird ein explizier
Moduswechsel fällig.

von Clemens H. (sum)


Angehängte Dateien:

Lesenswert?

Hallo,

nachdem ich nun zum zweiten mal tippe... mein browser ist abgestürzt
... bitte ich um verzicht eurerseits auf etwas komfort:

zu Martin Thomas:
- Ja, die Bezeichnungen waren nicht exakt - nun geändert.
- Remap funktioniert noch nicht, da das Linkerscript dafür noch nicht
geeignet ist. Mir ist noch keine elegante Lösung dafür untergekommen.
- .org ist beseitigt. hatte in dieser Konfiguration sooderso keinen
Effekt.
- die libgcc habe ich noch nicht angeschaut. Ich bin leider kein
Linker-script experte. damit tu ich mich noch ein bisschen schwer.
- Da der IRQ-Handler im User mode ausgeführt wird, muss anschließend
wieder in den IRQ-Mode gewechselt werden. Dies darf nur aus einem
Priviligierten Modus heraus geschehen. Dafür wird SWI benötigt.

zu A.K.:
- Der UserMode ist "weniger gefährlich". Allerdings habe ich noch
keine Hardware im AT91SAM7S gefunden, die den Zugriff aus dem Usermode
heraus verweigert. Also begrenzt sinnvoll. Im Interrupt hingegen ist es
unter Umständen sinnvoll, da dort ein zurückkehren in den IRQ-Mode
zwingend erforderlich ist (SPSR wird benötigt). Also würde - selbst bei
System Mode - der SWI nur dann entfallen dürfen, wenn 100% sicher ist,
dass der IRQ-Handler (in C) nicht in den User-Mode wechselt (weswegen
sei mal dahingestellt).

Thumb-Interwork ist nun eingebunden. Hierfür war im Makefile schon
entsprechendes vorhanden, im Assembler startupcode ist aus B ein BX
geworden. Laut Atmel-DB und ARM-DB ist dies die sichere Methode in den
Thumb mode zu wechseln. Ein Wechsel über MSR ist nicht erlaubt
(ARM-DB). Hat zu diesem Thema noch jemand mehr Informationen? Ich werde
es auf jeden Fall einmal testen.

Derzeit ergibt sich im Thumb-Compilermodus noch ein Problem: die
Schleife zum Kopieren der .data Section wird falsch kompiliert. Hier
wird bcc verwendet, was aber weiterhin in der Schleife bleibt, wenn
beide Werte gleich sind (Zero=1, Carry=0). Dann sollte aber die
Schleife abbrechen. Folglich funktioniert der Thumb-Code noch nicht.

Mein Compiler (von uc.net):
Ziel: arm-elf
Konfiguriert mit: ../../src/gcc-4.1.0/configure --target=arm-elf
--prefix=/usr/local/arm --enable-interwork --enable-multilib
--enable-languages=c,c++ --with-newlib
--with-headers=../../src/newlib-1.14.0/newlib/libc/include
Thread-Modell: single
gcc-Version 4.1.0

Wer dazu Informationen hat, bitte bescheidsagen!

Schöne Grüße, Clemens

von A.K. (Gast)


Lesenswert?

Du bist dir ganz ganz sicher, dass du einen ARM7 nicht mit einem Pentium
verwechselst?

Deine Sorgen möchte ich mal haben. Der Interrupt-Handler wie auch jeder
andere Code kann den Speicher plätten, das Flash löschen und die PLL
verstellen damit der Chip final abraucht (zumindest bei LPC2000 soll
das möglich sein). Und sich auch ganz normal daneben benehmen, wie etwa
den Stack vernichten und solche Kleinigkeiten.

Dieser User Mode ist sinnvoll, wenn du einen ARM mit MMU nimmst und ein
Linux oder etwas ähnliches drauf laufen lässt. Aber dann wirst du einen
Start-Code ohnehin noch ein kleines bischen erweitern müssen ;-).

von A.K. (Gast)


Lesenswert?

Nochmal zu thumb: Was ist denn dein Ziel? Soll es möglich sein, reine
thumb Programme damit zu nutzen, z.B. auch als interrupt handler?

Wenn ja: Ich sehe z.B. immer noch BX in irq.S, womit ein interrupt
handler nur dann im thumb mode laufen kann, wenn das Programm mit
interworking übersetzt wird. Das aber kostet Platz und Zeit, und ist in
diesem Fall ausschliesslich deshalb nötig, weil der zentrale IRQ handler
das nicht vorsieht.

Alternative: Moduswechsel ggf. selber durchführen, handler aufrufen und
wieder zurück wechseln.

Sicher kann man sich das auch sparen. Aber du selbst hast den Anspruch
gestellt, einen einheitlichen Startup-Code zu bauen, also nicht bloss
einen für dich persönlich.

Ich habe nicht ausführlich danach gesucht, aber C++ Support ist mir bei
dir jedenfalls nicht aufgefallen. Es gibt dazu nicht viel zu tun, es
geht nur um die constructor calls und die entsprechenden sections im
linker definition file. Sicher, für viele hier klingt C++ nach
"Igitt", aber ich mach das ganz gerne, auch auf AVR. Wenn Interesse
besteht, kann ich was dazu liefern.

von Roland Schmidt (Gast)


Lesenswert?

A.K. Interesse an Neuem besteht immer.
Und wenn's dazu noch was zu lernen gibt?
Immer her damit.

von A.K. (Gast)


Lesenswert?

Ins ROM müssen zusammen mit dem normalen Code mindestens noch:
    .gnu.linkonce.t.*        G++ 4.0x
    .text.*                  G++ 4.1x
und vorsichtshalber auch
    .gcc_except_table        vermutlich für C++ exceptions
    .glue_7                  aus LPC2000 samples, weiss nicht wozu
    .glue_7t                 dito

Separate Gruppe für die C++ constructors:

.ctors :
{
    _ctors_start_ = . ;
    KEEP(*(SORT(.ctors.*)))
    KEEP(*(.ctors))
    _ctors_end_ = . ;
} >ROM

Code dazu im Startup, zwischen Speicherinitialisierung und Aufruf von
main() anzusiedeln:

    ldr     r4, =__ctors_start__
    ldr     r5, =__ctors_end__
1:  cmp     r4, r5
    beq     2f
    ldr     r12, [r4],#4
    mov     lr, pc
    bx      r12
    b      1b
2:

Kann man natürlich auch in C machen, wenn's unbedingt sein muss.

Wobei die Initialisierung von .bss und .rodata rein garnichts mit der
Controller-Familie zu tun hat. Warum also Namen wie AT91F_Init_BSS_DATA
verwenden, die genau dies suggerieren?

Ist in Assembler zudem einfacher, kürzer und vermeidet das schon
skizzierte thumb code Problem. Entstammt den LPC2000 Samples.

    ldr    r1, =_etext
    ldr    r2, =_data
    ldr    r3, =_edata
1:  cmp    r2, r3
    ldrlo  r0, [r1],#4
    strlo  r0, [r2],#4
    blo    1b
2:

    mov    r0, #0
    ldr    r1, =__bss_start
    ldr    r2, =__bss_end__
3:  cmp    r1, r2
    strlo  r0, [r1],#4
    blo    3b

von A.K. (Gast)


Lesenswert?

Mein support für thumb-only Programme ohne interworking:

Unterprogrammaufruf, Adresse in R12:
        .macro  callR12
        mov     lr, pc
#if ...support thumb code w/o interworking...
        b       callstub
#else
        bx      r12
#endif
        .endm

#if ...support thumb code w/o interworking...
callstub:
        tst     r12, #1         // ARM or thumb?
        moveq   pc, r12         // ARM: jump to R12
        stmfd   sp!, {lr}       // Thumb: save LR
        adr     lr, 1f+1        // odd return address for thumb call
        orr     r1, pc, #1      // switch to thumb mode
        bx      r1
        .thumb
        mov     pc, r12         // call thumb function
1:      pop     {r1}            // switch back to ARM and return
        bx      r1
        .align  2
        .arm
#endif

Beispiel:

    ldr     r4, =__ctors_start__
    ldr     r5, =__ctors_end__
1:  cmp     r4, r5
    beq     2f
    ldr     r12, [r4],#4
    callR12
    b       1b
2:

von Clemens H. (sum)


Lesenswert?

Hallo A.K.

ich verwechsele meinen arm definitv nicht mit einem Pentium - wie
gesagt, hat er ja keine mmu. aber in irgendeiner weise ist es denke ich
schon sinnvoll, das konzept des ARMs an sich beizuhalten - also die
trennung von User und Priviligierten Modi. Allerdings hast du recht,
das Programm wird wohl gleichermaßen in System mode gut laufen können.
Möchte man eine Art betriebssystem vorsehen und "Programme" von einem
externen Speicher (z.B. MMC) nachladen, so wird man nicht um die SWI
oder um eine Funktionen-Tabelle herumkommen. Deshalb habe ich diese
gleich implementiert - und verwendet.

Was ich bei dir noch nicht ganz verstanden habe, ist, wie du den
Moduswechsel vollziehst? Du benutzt in deinem Code auch "nur" eine
BX-Instruktion mit garantiert niedrigem Bit gesetzt. Nur: ist die
Addresse einer Thumb-Funktion nicht automatisch ungerade? Oder braucht
man dafür das Interworking? Darüber - muss ich gestehen - habe ich mir
noch keine Gedanken gemacht, nachdem ich das ganze für Thumb compiliert
habe, war die Addresse der Funktion ungerade.

Der Interrupt handler wird immer im ARM-Mode aufgerufen. Demnach ist
ein Aufruf eines Thumb-Handlers auch wieder über BX nötig.

Zu C++: Ja, gerne sollten wir das reinpacken. Schließlich ist C++ eine
in meiner Sicht gute Alternative zu C. Ich werde micht die Tage mal
darum Kümmern, dass der Code auf C++ erweitert wird.

Die Bezeichnung der Nicht-AT91-spezifischen Funktionen wird geändert.

Dass man die Initialisierung auch in ASM vorshene kann, ist definitiv
korrekt, wahrscheinlich auch besser optimierbar. Damit würde man
allerdings die schönere Lesbarkeit deutlich herabsetzten. Das Problem
ist wohl eher dort zu suchen, wo der Compiler einen Fehler hat.
Schließlich träfe das ja auf alle Schleifen zu. Demnach kann man den
Thumb-Modus mehr oder minder vergessen.

Schöne Grüße, Clemens

von Clemens H. (sum)


Lesenswert?

Vielleicht sollte man auch - zur besseren Trennung der verschiedenen
Controller - den Startup-Code der Controllerspezifisch ist - in eine
extra Datei packen. Das könnte die Übersicht etwas verbessern.

von A.K. (Gast)


Lesenswert?

"das konzept des ARMs an sich beizuhalten"

Sorry, aber das Konzept des ARM ist eben dieser Pentium.
Gewissermassen.

Die ARM Architektur entstand in den 80-ern als Kern eines BBC
Computers. Sowas Richtung C64 oder Atari ST nur mit weitaus besserem
Betriebssystem, was ebendiese Unterscheidung zwischen User und SVC-Mode
mit sich brachte (der System Mode ist neueren Datums). Die Verwendung in
embedded Systems lag zwar auf der Hand, kam indes erst danach.

Wenn du das nun auch in einem simplen Controller verewigen willst,
bitteschön. Aber nimm's mir dann auch nicht übel, wenn ich es für ein
bischen zweifelhaft halte, Interrupts im User Mode auszuführen. Das ist
nämlich in der Geschichte der Computerarchitekturen ein ziemliches Novum
und definitiv nicht das Konzept von ARM.

"Demnach ist ein Aufruf eines Thumb-Handlers auch wieder über BX
nötig."

Yep. Was den Aufruf angeht klappt das auch noch. Nur wird der Rückweg
scheitern. Thumb Funktionen ohne interworking pflegen das mit einem POP
{PC} abzuhandeln, mit interworking wird POP {LR}, BX LR draus. Oder so
ähnlich.

Grund: Erst ab Architektur ARMv5 kehrt POP {PC} wieder zum ARM Mode
zurück. ARM7 ist aber Architektur ARMv4, da geht das nur mit BX.

Und deshalb mein Stub. Der erste BX wechselt in den thumb mode, der
zweite retour. Der eigentliche Funktionsaufruf steckt im MOV PC.

von A.K. (Gast)


Lesenswert?

"Damit würde man allerdings die schönere Lesbarkeit deutlich
herabsetzten."

Dein Kommentar in ebendiesem C Code konterkariert diese Aussage etwas
;-).

"Das Problem ist wohl eher dort zu suchen, wo der Compiler einen
Fehler hat."

Wo hat der einen Fehler?

"Nur: ist die Addresse einer Thumb-Funktion nicht automatisch
ungerade?"

Ich weiss nicht recht, ob es Sinn ergibt, diesen Code haarklein zu
erklären. Der startup code ist ARM, der vom SAM7 bevorzugte Code Thumb.
Diese Kombination erzwingt interworking, es sei denn man kümmert sich an
allen Schnittstellen zwischen ARM und Thumb selber darum. Wenn du also
Thumb ohne interworking unterstützen willst, dann wird dir kaum etwas
anderes übrig bleiben, als dich in diese Materie etwas einzuarbeiten.
Ansonsten solltest du dich auf interworking beschränken (und das so
dokumentieren).

von A.K. (Gast)


Lesenswert?

Apropos Compilerfehler: Ich kann im erzeugten Code keinen Fehler
erkennen. BCC ist da völlig korrekt.

Aber vielleicht muss man mit 6502 aufgewachsen sein, um das natürlich
zu finden: Wie 6502 hat auch ARM keine echte Subtraktion sondern statt
dessen eine Addition des Einerkomplements. Das aber hat eine inverse
Logik des Carry-Flags zur Folge.

von Clemens H. (sum)


Angehängte Dateien:

Lesenswert?

Hallo,

die Prozeduren im Thumb-modus werden bei mir alle mit einem "BX lr"
abgeschlossen. Vielleicht liegt das auch am Compiler oder daran, dass
die Funktionen das Link-register nicht für andere Zwecke benutzen. Ich
werde in Zukunft nochmals darauf achten.

Den "Fehler" im GCC habe ich mal dokumentiert. Mir scheint, der
Fehler liegt nicht im GCC sondern im ARM?!? Aber den Rest der
Interpretation überlasse ich mal euch. Da der Log ziemlich lang ist,
habe ich ihn angehangen.

Schöne Grüße, Clemens

von A.K. (Gast)


Lesenswert?

void g(void);
void f(void)
{
    g();
}

GCC 4.1.0: -mthumb

f:      push    {lr}
        bl      g
        pop     {pc}

GCC 4.1.0: -mthumb -mthumb-interwork

f:      push    {lr}
        bl      g
        pop     {r0}
        bx      r0

von Clemens H. (sum)


Lesenswert?

Komisch, dass das bei mir (GCC 4.1.0) nicht passiert. Ich nehme gleich
mal ein Beispiel aus dem Code direkt:

000000a8 <Init_BSS_DATA>:
  a8:  4a07        ldr  r2, [pc, #28]  (c8 <.text+0xc8>)
 * The routine pretends, all addresses are 4-Byte-aligned. Insert ". =
ALIGN( 4 );" before
 * the definition of the PROVIDE( ... ); statement in the linker file
to achieve this.
 * this procedure is executed in System Mode
 */
void  Init_BSS_DATA( void ) {
  aa:  4908        ldr  r1, [pc, #32]  (cc <.text+0xcc>)
  ac:  4808        ldr  r0, [pc, #32]  (d0 <.text+0xd0>)
  ae:  e001        b  b4 <Init_BSS_DATA+0xc>
  b0:  c908        ldmia  r1!,{r3}
  unsigned int *dp, *sp;
  /* load the .data section into ram: */
  dp = &_data_start;
  sp = &_data_load_start;
  while (dp < &_data_end)
    *dp++ = *sp++;
  b2:  c208        stmia  r2!,{r3}
  b4:  4282        cmp  r2, r0
  b6:  d3fb        bcc  b0 <Init_BSS_DATA+0x8>
  b8:  4a06        ldr  r2, [pc, #24]  (d4 <.text+0xd4>)
  ba:  4907        ldr  r1, [pc, #28]  (d8 <.text+0xd8>)
  bc:  e001        b  c2 <Init_BSS_DATA+0x1a>
  be:  2300        mov  r3, #0
  /* zero out the .bss section */
  dp = &_bss_start;
  while (dp < &_bss_end)
    *dp++ = 0;
  c0:  c208        stmia  r2!,{r3}
  c2:  428a        cmp  r2, r1
  c4:  d3fb        bcc  be <Init_BSS_DATA+0x16>
  c6:  4770        bx  lr
}

von A.K. (Gast)


Lesenswert?

CPSR im Thumb Code: 400000df
CPSR im ARM Code:   600000df

Fällt dir da was auf? Bit 5, das T Bit, sollte im Thumb Code gesetzt
sein, ist es aber nicht. Da läuft ganz was anderes schief.

von A.K. (Gast)


Lesenswert?

Klar dass das bei dir nicht passiert. Weil LR in der Routine nicht
angefasst wird. Hattest du oben ganz richtig vermutet. Drum habe ich ja
in meinem Beispiel einen Funktionsaufruf drin.

von A.K. (Gast)


Lesenswert?

Nebenbei eine Kleinigkeit aus deinem Startup-Code:

  ldr  r0, =AT91F_Init_BSS_DATA
  bx  r0

  ldr  r0, =AT91F_InitLowLevel
  bx  r0

BX ist jedoch kein Unterprogrammaufruf, das wäre BLX und den gibt's
erst ab ARMv5. Was du hier brauchst:

  ldr  r0, =AT91F_Init_BSS_DATA
      mov   lr, pc
  bx  r0

  ldr  r0, =AT91F_InitLowLevel
      mov   lr, pc
  bx  r0

von Clemens H. (sum)


Angehängte Dateien:

Lesenswert?

Hallo A.K.

komisch, dass das T-Flag nicht gesetzt ist. Dennoch sagt OpenOCD ja,
dass der Prozessor im Thumb-State angehalten wurde. Also sollte der
Status schon korrekt sein. Das Auslesen der Register/CPSR ist leider
etwas buggy, das hab ich schon gefunden.

Als eindeutigen Beweis dafür, dass das C-Flag gelöscht ist, nehme ich
allerdings den Programmablauf. Dieser wird dann nämlich in der Schleife
fortgesetzt. Dies geschieht allerdings nur im Thumb-State. Ich finds
irgendwie komisch.

Ja, Unterprogrammaufrufe habe ich noch nicht. werde ich mir bei
Gelegenheit mal ansehen. Eventuell kann man ja eine Define setzten, die
den Code je nach Support von Interworking anders kompiliert.

Danke für den Hinweis des Funktionsaufrufes in ASM. Habe ich geändert.

Im Anhang befindet sich nun eine etwas neuere Version. Hier
geändert/hinzugekommen ist:
- Aufteilung des SAM7S-Codes auf extra Dateien, im Makefile per
Variable einstellbar, ob SAM7S oder anderer Code (noch zu schreiben)
genommen werden soll.
- Define zum Support der SWI-Instruktion (startup_config.h) und zum
Einstellen des Modes, in dem die Main läuft. Hier ist ARM_MODE_User
oder ARM_MODE_System möglich. Wenn System-Mode gewählt wird, so braucht
das SWI nicht kompiliert zu werden - und auch im Interrupt nicht
verwendet werden. Ist alles per Define geregelt (hoffentlich korrekt).
System-Mode spart etwa 144Byte...
- ein README, das hoffentlich aktuell bleibt.

Schöne Grüße, Clemens

von A.K. (Gast)


Lesenswert?

"komisch, dass das T-Flag nicht gesetzt ist. Dennoch sagt OpenOCD ja,
dass der Prozessor im Thumb-State angehalten wurde. Also sollte der
Status schon korrekt sein."

Wir haben 3 Fakten:
- OpenOCD sagt, er sei im Thumb Modus.
- Prozessor sagt, er sei im ARM Modus.
- Programm verhält sich falsch.
Neben der alten Regel, dass der Prozessor immer Recht hat, ist hier
auch die Mehrheit gegen dich.

Es gibt übrigens mehrere Quellen der Erkenntnis zu Thumb. Zum OpenOCD
gibt's irgendwo einen Hinweis, dass dort Bit 0 aus der Adresse benutzt
wird. Evtl. die Adresse der Funktion in der er sich befindet. Daher
können OpenOCD und Prozessor dazu sehr wohl unterschiedlicher Ansicht
sein.

Merkregel: 99% aller sogenannten Compilerfehler sind erfahrungsgemäss
Benutzerfehler oder Fehlinterpretationen. Ebenso wie 99,99% aller
sogenannten Prozessorfehler. Das heisst also, dass man sich mit dem Ruf
"Compilerfehler!" oder "Prozessorfehler!" mit an Sicherheit
grenzender Wahrscheinlichkeit blamiert.

von Clemens H. (sum)


Lesenswert?

Das heisst also, dass man sich mit dem Ruf
"Compilerfehler!" oder "Prozessorfehler!" mit an Sicherheit
grenzender Wahrscheinlichkeit blamiert."

Da hast du gewissermaßen recht! Allerdings habe ich ja schon
geschrieben, dass der Prozessor - wenn im ARM-Mode Compilier - normal
läuft. Wenn allerdings im Thumb-Mode Compiliert, im DataAbort
"hängt".

Erklärung dafür ist, dass der Zurücksprung aus der C-Routine (die im
Thumb-Mode läuft), nur korrekt sein kann, wenn vor dem Aufruf "mov pc,
lr" geschieht. Jetzt läuft also beides.

Vielen Dank, Clemens

von Clemens H. (sum)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe jetzt einmal versucht, den Code für C++-Support einzubauen. Im
Linkerscript sind entsprechende Einträge hinzugekommen und im
startup_c.c ist der Aufruf der Konstruktoren implementiert. Die
Konstruktoren werden direkt vor dem Aufruf der main() aufgerufen.

Im Makefile ist noch kein Support für C++-Dateien, ich habe leider noch
keinen Code um das zu testen.

Falls ihr Fehler/Verbesserungsvorschläge im Code/Linkerscript seht,
bitte melden!

Clemens

von Clemens H. (sum)


Lesenswert?

Nun habe ich zwar geschafft, das Makefile anzupassen, allerdings fehlt
in allen *.o-Dateien die aus *.cc Dateien erstellt wurden, die .ctors
und .dtors Sections:
test.h:
class TestClass {
        unsigned int TestInt;
public:
        int execute( void );
        TestClass() {};
        TestClass( unsigned int i );
        ~TestClass( void );
};
-------------------------------------------
test.cc:
#include "test.h"
TestClass::TestClass( unsigned int i ) {
        TestInt = 2*i;
}
TestClass::~TestClass( void ) {
        TestInt = 0;
}
int TestClass::execute( void ) {
        do {
                TestInt++;
        } while (TestInt < 1000);
        return TestInt;
}
-------------------------------------------------------

Kompilierung mit arm-elf-gcc -c test.cc -o test.o
arm-elf-objdump -h test.o

test.o:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         000000f8  00000000  00000000  00000034  2**2
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 .data         00000000  00000000  00000000  0000012c  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  0000012c  2**0
                  ALLOC
  3 .comment      00000012  00000000  00000000  0000012c  2**0
                  CONTENTS, READONLY
--------------------------------------------------------------

Selbst beim Linken aller Files wird keine .ctors und .dtors Section
erzeugt (schließlich kommen da ja auch nur die .ctors und .dtors aus
den Objectfiles rein, und die gibt es ja nicht).

Kann mir jemand weiterhelfen?

von mthomas (Gast)


Lesenswert?

Moeglicherweise uebersehen, aber wo wird ein Objekt der Klasse im
"global scope" angelegt? CTORS/DTORS fuer Objekte im "local scope"
werden m.W. intern anders verwaltet (aber auch ein Objekt im
local-scope sehe ich nicht). Vielleicht hilft ein Blick in mein
arm-elf-gcc C++-Beispiel:
http://www.siwawi.arubi.uni-kl.de/avr_projects/arm_projects/index.html#lpc_cpp1

Martin Thomas

von A.K. (Gast)


Lesenswert?

@mthomas: Etwas off-topic, aber vielleicht interessiert es: Mit ging
beim GCC auf die Nerven, dass Aufrufe von Template-Funktionen höchst
ineffizient implementiert werden, da sie als "weak externals" erkannt
werden und der Compiler daraus "long calls" macht. Was immer sich
jemand dabei gedacht hatte - ich hab's ihm jedenfalls wieder
abgewöhnt.

von mthomas (Gast)


Lesenswert?

@A.K.: Klar interessiert es. Nutze bisher selbst zwar C++ kaum auf µC,
aber man kann nie "zuviel" wissen. Die unzulaengliche Optimierung ist
mir bisher nicht aufgefallen.

Das Interesse an "C++ mit arm-elf-gcc" ist realtiv gross
(Forenbeitraege, e-mails). Am Einfachsten duerfte es sein,
"Vorher/schlecht" und "Nachher/gut" an einem kleinen Beispiel zu
demonstrieren und die notwendigen Aenderungen zur Optimierung in einer
readme-Datei festzuhalten. Werde das Beispiel dann auf der WinARM-Seite
bereitstellen (natuerlich mit Nennung der Quelle). Die WinARM-Seite wird
realtiv oft besucht und die Information ist dort - denke ich - gut
aufgehoben.

Martin Thomas

von A.K. (Gast)


Angehängte Dateien:

Lesenswert?

OK, steht alles im Source-Code drin.

von Clemens H. (sum)


Angehängte Dateien:

Lesenswert?

Hallo Martin und A.K.

ich habe nun wieder etwas Zeit gefunden am Code weiterzubasteln:

der C++-Support geht nun, das Problem war, dass er nicht vollständig
kompilierte am Anfang. Ich habe den Fehler gemacht und eine Variable
als Klasse deklariert und initialisiert und dies in eine *.c-Datei
geschrieben. Nun ist es in eine .cc Datei und es geht gut.
Konstruktoren werden erzeugt.

Leider konnte ich den Code noch nicht In-Situ testen, da meine Hardware
noch nicht fertig aufgebaut ist.

schöne Grüße, Clemens

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.