www.mikrocontroller.net

Forum: Compiler & IDEs Merkwürdiges Verhalten bei Variablen und for-schleifen


Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich arbeite an einem Projekt für einen ARM9 mit gcc. Es treten 
merkwürdige Phänomene auf:

1. Globale Variablen lassen sich nicht mit 0 initialisieren, sie 
enthalten stattdessen einen undefinierten Wert. Andere Werte gehen aber.

2. Eine For-Schleife zählt manchmal bis ins Unendliche. Wenn ich eine 
Code-Zeile davor setze, egal was, geht es teilweise. Hier ein Beispiel:
unsigned short ip_chksum (int header_length)
{
    unsigned short u16;
    unsigned long sum = 0;
    int i;

    for (i = 0; i < 10; i++) {
        sum += endians(ip.shorts[i]);
    }

    while (sum >> 16)
        sum = (sum & 0xFFFF) + (sum >> 16);

    return (unsigned short)~sum;
}
Habe diese Funktion schon mehrfach umgeschrieben und immer wieder bleibt 
das Programm darin hängen. In der Ursprünglichen Variante dieser 
Funktion funktionierte sie nur, wenn ich das IP-Checksum Feld des 
IP-Header-Structs nicht vor der Funktion auf null setzte. Somit wurde 
zwar eine falsche Checksumme berechnet, aber immerhin lief das Programm 
weiter.

Das umfangreiche Programm funktioniert sonst gut, nur manchmal stolpere 
ich über die genannten Probleme. Ich hoffe jemand hat einen Tipp für 
mich.

Viele Grüße
Daniel

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Probleme der genannten Art sind des öfteren Folgen von Out-Of-Bounds 
Array Zugriffen, also Fehlern in deinem Code

zb
int i;
int j[5];
int k;

int main()
{
  i = 4;
  k = 5;
  j[5] = 8;
}

Hier wird auf j out-of-bounds zugegriffen. j ist ein Array mit 5 
Elementen, durchnummeriert von 0 bis 4. Ein Element 5 existiert schlicht 
und ergreifend nicht. Wird es im obigen Code trotzdem beschrieben, 
ändert entweder i oder k (je nachdem wie sie der Compiler im Speicher 
angeordnet hat) scheinbar unmotiviert seinen Wert.

Nun ist obiger Fall trivial zu detektieren. Interessanter wird es, wenn 
derartige Fehler bei funktionslokal angelegten Arrays passieren. Dann 
kann manchmal alles mögliche passieren, weil man sich unter Umständen 
den Return-Stack komplett zerschiesst.

Eine andere Variante (oder eigentlich dasselbe Problem nur anders 
verpackt) ist ein Zugriff über Pointer die 'in den Wald zeigen'.

Kurz und gut: Solche Phenomäne wie du sie bechreibst sind meistens ein 
Hinweis darauf, dass man Speicher beschreibt, an denen man nichts zu 
suchen hat.

Viel Spass beim Suchen. Solche Probleme sind schwer zu finden.
Erster Schritt: reproduzierbar machen. Die Aussage 'manchmal passiert 
dieses' muss ersetzt werden durch 'wenn ich zuerst A mache, dann B, dann 
C, dann passiert dieses und jenes'

Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich beobachte diese Phänomene seit ich vor Monaten mit dem Projekt 
begonnen habe. Leider konnte ich trotz vielen rumprobierens bisher 
nichts eingrenzen. Das IP-Feld besteht aus 20 bytes, also 10 
16-bit-worten. Die angegebene For-Schleife sollte also nicht über das 
Array hinaus laufen.

Ich habe schon etwas programmiererfahrung in C, kenne die Probleme die 
du beschrieben hast und bin daher darauf sensibilisiert. Im gesamten 
Programm wird ständig mit Pointern hantiert und empfangene 
Netzwerkheader werden auseinandergenommen um an gewünschte Werte zu 
kommen. Alles funktioniert sonst.

Aber warum werden dann globale Variablen nicht richtig mit 0 
initialisiert? Folgender Code würde ein Error liefern:
int i = 0;
int test () {
    if(i != 0)
        return error;
}
Eine 1 statt einer 0 geht wiederrum. Dabei wäre ja nicht mal das '=0' 
nötig bei globalen Variablen, wie ich im Forum gelesen habe.

Vielleicht gibt es noch andere Ursachen für so ein Problem. Wenn nicht 
muss ich eben weiter und weiter suchen...

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mögliche Gründe gibt es im Dutzend. Stacküberlauf ist einer davon.

Wenn du mal einen Code beisammen hast, bei dem du genau identifizieren 
kannst welche Variable offensichtlich irgendwann versehentlich 
überschrieben wird, dann hilft dir ein Data Watchpoint im Debugger.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel G. schrieb:

> 1. Globale Variablen lassen sich nicht mit 0 initialisieren, sie
> enthalten stattdessen einen undefinierten Wert. Andere Werte gehen aber.

Klingt nach einem Problem mit dem Startup-Code deiner Bibliothek
(oder wo auch immer er her kommt -- ich kenne mich mit ARMs nicht
so aus).

Eine nicht initialisierte globale (oder statische) Variable wird
implizit mit 0 initialisiert.  Dies erfolgt, indem der Compiler
sie in eine section namens .bss steckt.  Alle diese Variablen werden
vom Linker dann zusammengefasst, und es ist die Verantwortung des
Startup-Codes, den gesamten BSS-Bereich beim Start auszunullen.

Eine initialisierte globale Variable landet in der section .data.
Der Startup-Code muss beim Start hier die Initialwerte aus externem
Speicher (Festplatte, ROM, ...) laden.

Eine globale Variable, die überflüssigerweise mit 0 initialisiert
wird, wird vom Compiler (als kleine Optimierung) ebenfalls nach .bss
gesteckt.

Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Stack Pointer liegt etwa 62MB hinter dem letzten Image-Byte. Der 
läuft nicht so schnell über. Zudem benutzt die Funktion den Stack gar 
nicht, wie ich eben aus dem Assembler Code entnommen habe.

Was den Startup Code angeht: ich werde jetzt erstmal meine Toolchain neu 
installieren und dabei alle Optionen überprüfen. vielleicht ist etwas 
nicht richtig eingestellt oder installiert.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel G. schrieb:
> Der Stack Pointer liegt etwa 62MB hinter dem letzten Image-Byte. Der
> läuft nicht so schnell über. Zudem benutzt die Funktion den Stack gar
> nicht, wie ich eben aus dem Assembler Code entnommen habe.

Du solltest auch berücksichtigen, dass du nur die Symptome siehst und 
nicht die Ursache. Die Ursache muss nicht in der Funktion zu finden 
sein, die Probleme macht. Eigentlich ist die Ursache für solche Probleme 
meistens ganz weit von der Stelle entfernt an der man auf das Problem 
aufmerksam wird. Auch deshalb sind solche Probleme oft so schwer zu 
identifizieren.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es gibt auf ARMs mehrere Stacks. Einen für das Hauptprogramm, einen für 
normale Interrupts, usw. Je nachdem wie die konfiguriert werden, können 
die also auch bei massig Speicher schnell ineinander laufen.

Wenn beispielsweise der IRQ-Stack direkt hinter dem normalen Stack liegt 
und zu klein konfiguriert ist, dann plättet dir jeder Interrupt die 
lokalen Daten der obersten Level des Hauptprogramms weg. Allerdings auch 
die Return-Adressen, weshalb man das meistens daran merkt, dass er bei 
Return über die Wupper geht.

Für sowas hilft eine Analyse des Mapfiles in Verbindung mit dem 
Verständnis des Startup-Codes.

Autor: tuppes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eins kann man aber wohl in Stein meißeln: Es ist (gerade beim gcc) mit 
ganz ganz großer Wahrscheinlichkeit kein Compiler-Fehler oder etwas 
ähnliches. Umformulieren von Code wird das Problem daher nur 
verschleiern.

Ich würde folgendes versuchen:

1. Am Anfang von main() müssen alle globalen Daten korrekt initialisiert 
sein. Die, die nicht explizit initialisiert wurden, müssen auf 0 stehen. 
Das zuerst im Debugger prüfen. Wenn nicht, dann ist der Startupcode 
faul. Woher stammt der überhaupt?

2. Wenn OK, dann Schritt für Schritt weitergehen und darauf achten, 
durch welche Aktion sich die globalen Daten unerwartet ändern. Diesen 
Punkt möglichst eng eingrenzen.

3. In was für einem Speicher liegen die fraglichen Daten? Internes RAM 
oder externer Speicher, für den ein Businterface konfiguriert werden 
muss? Wenns extern ist, ist das Interface evtl. falsch aufgesetzt und 
liefert Unsinn.

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
tuppes schrieb:
> Eins kann man aber wohl in Stein meißeln: Es ist (gerade beim gcc) mit
> ganz ganz großer Wahrscheinlichkeit kein Compiler-Fehler oder etwas
> ähnliches.

Mal abgesehen davon, dass man mit der Fehlerbeschreibung kaum erraten 
kann, wo der Fehler liegen könnte (bedeutet "immer wieder" das gleiche 
wie "ausnahmslos, jedes Mal"?), entbehrt die Betonung auf "gerade beim 
gcc" nicht einer gewissen Ironie :-)

Wenn man den Fehler mit der vom OP genannten Funktion zuverlässig 
reproduzieren kann, dann würde sich ein Disassembly durchaus lohnen.

Gruß
Marcus
http://www.doulos.com/arm/

Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für die vielen Antworten!

Die Antwort von A.K. kam gerade noch rechtzeitig um mich vor einer 
Neuinstallation der Toolchain zu bewahren. :-)

Folgende Dinge sind auf jeden Fall schief gelaufen:

1. Ich dachte den Code für die Variableninitialisierung gegeriert der 
Compiler von sich aus. Somit hatte ich in meinem (selbstgeschriebenen) 
Startupcode keinen derartigen Code.

2. Der Hinweis, dass ARMs mehrere Stacks haben, war ein Treffer! Ich 
habe gar nicht daran gedacht auch die Stackpointer der anderen 
Prozessormodi zu initialisieren.

Wenn ich jetzt so drüber nachdenke, passen diese Versäumnisse genau auf 
die aufgetretenen Verhaltensweisen des Programms.

Ich werde nun entweder meinen Startupcode erweitern oder einen fertigen 
nehmen. Libgloss soll, wie ich gestern gelesen habe, Startupcode für 
verschiedene Targets beinhalten.

Wenn ich Resultate habe melde ich mich wieder. Viele Grüße,
Daniel

Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, habe nun Folgendes in meinen Startup Code aufgenommen:

1. .bss und COMMON Section wird mit Nullen überschrieben

2. Stackpointer werden korrekt initialisiert

Bisher traten keine weiteren Probleme (der beschiebenen Art) auf. Danke 
nochmal für eure Hilfe!

Ich habe aber noch Fragen:

1. Kann es sein, dass die Option -nostartfiles für den Linker 
verhindert, dass der Compiler eine C-Runtime mit einbringt?

2. Wieso liegen meine globalen uninitialisierten Variablen in COMMON und 
nicht in .bss?

3. Wenn ich ein Struct einer Funktion übergebe, wird es dann wirklich im 
Stack übergeben? Wenn das Struct sehr groß ist, dann ist der Stack ja 
schnell voll, meiner beispielsweise hat eine Größe von 4kB. Laut C-Buch 
soll es so sein, und ich nutze daher nur Pointer auf Structs als 
Parameter.

Viele Grüße
Daniel

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel G. schrieb:

> 1. Kann es sein, dass die Option -nostartfiles für den Linker
> verhindert, dass der Compiler eine C-Runtime mit einbringt?

Ja.

> 3. Wenn ich ein Struct einer Funktion übergebe, wird es dann wirklich im
> Stack übergeben? Wenn das Struct sehr groß ist, dann ist der Stack ja
> schnell voll, meiner beispielsweise hat eine Größe von 4kB.

Weshalb man komplette structs auch nur selten als Wert übergibt, 
allenfalls wenn sehr klein.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel G. schrieb:

> 2. Wieso liegen meine globalen uninitialisierten Variablen in COMMON und
> nicht in .bss?

Historisches Unix-C-Compiler-Verhalten.  Damit musste man eine
Deklaration einer nicht initialisierten globalen Variablen nicht
von einer Definition unterscheiden, sondern kann bspw. in einer
Headerdatei stehen haben:
int someglobal;

Alle Quelldateien, die sich das reinziehen, legen dann eine identische
Deklaration dafür im Objektcode ab, die als COMMON deklariert ist.
Wer noch FORTRAN lernen durfte weiß, wofür der Linker sowas mal können
musste. :-)  Der Linker überlagert nämlich all diese COMMON-Blöcke,
sodass gleichartige Definitionen auch wirklich auf das gleiche Objekt
zeigen.

Dieses Verhalten ist vom C-Standard explizit gestattet und als eine
von zwei (glaub' ich) möglichen Alternativen spezifiziert.

Mittels -fno-common schaltet man beim GCC auf die andere Alternative
um.

Normalerweise sollte der Linkerscript die COMMON-Dinger auflösen und
dann mit .bss zusammenführen.

Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zuvor hatte ich Folgendes im Linker Script stehen:

    /* collect all uninitialized .bss sections */
    .bss (NOLOAD) : {
        . = ALIGN(4);
        _sbss = .;
        *(.bss)
        _ebss = .;
    }>ram

Damit lagen alle COMMON Objekte hinter .bss und eben nicht zwischen 
_sbss und _ebss (laut map file).

Nach hinzufügen von *(COMMON) hinter *(.bss) wurden dann alle COMMON 
Objekte in die Section .bss aufgenommen.

Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Leider muss ich den Thread fortsetzen: Zwar konnte ich die Probleme 
größtenteils lösen aber ein weiteres und ähnliches Problem tauchte auf.

Ich habe mehrere verschachtelte if-Abfragen. Je nachdem ob ich eine 
Codezeile vor einer bestimmten if-Abfrage einfüge, wird die nachfolgende 
if-Abfrage korrekt behandelt oder (beides, if und else) einfach 
übersprungen.

1. Das dürfte wohl auch auf Speichersalat zurückzuführen sein, aber ich 
weiß nicht wo ich noch suchen soll oder wo zuerst. Die beiden 
Stackpointer (SVC und IRQ) sind initialisiert, andere Prozessormodi 
nutzt das Programm nicht. Die Fehler tritt im IRQ Modus auf.

2. Die Stacks sind riesig und ich habe sie testweise noch riesiger 
gemacht. Zudem übergeben ich höchstens 32Bit Variablen an Funktionen. 
Also Stacküberlauf schließe ich aus.

3. Natürlich habe ich vielfach den C-Code auf fehlerhafte Pointer, 
Kopierroutinen etc. durchgesehen und verschiedenes testweise 
auskommentiert.

Ich komme langsam in Zeitnot und bin über jeden Hinweis dankbar, der 
mich den Fehler schneller finden lässt!

Ich hatte noch zwei Vermutungen:
V1. Linker Script nicht korrekt. Dazu habe ich mir das ld manual 
durchgelesen und das Linkerscript nach meinem ermessen umgeschrieben. Es 
hat sich nichts verändert.
V2. Irgendein Problem mit THUMB und ARM Code bzw. Interworking. Kann das 
sein?

Grüße,
Daniel

Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe gerade noch rausgefunden, dass je nach Optimierungseinstellung 
des Compilers sich das Verhalten des Codes ändert. Vielleicht deutet das 
ja auf etwas hin?

Danke und Gruß,
Daniel

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Könnte einfach nur ein fehlendes "volatile" sein.

Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das habe ich aus anderen Gründen schon mehrmals überprüft. Alle von 
Exceptions und Task-Code gemeinsam verwendeten Variablen sind als 
volatile gekennzeichnet.

Aber dieses shared data Problem kann doch nicht solch fehlerhaftes 
Verhalten herbeirufen!?

Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht fehlt ja noch was in meinem Startup File. Ich lese immer 
wieder, dass initialisierte Variablen geladen oder kopiert werden 
müssen. Entsprechend meines Linker Scripts sollten die aber bereits im 
Image liegen:

    .data : {
        _sdata = .;
        *(.vectors)
        *(.data)
        _edata = .;
    } > ram

Oder habe ich was falsch verstanden?

Nebenbei, weiss jemand, was .vectors zu bedeuten hat?

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel G. schrieb:

> Aber dieses shared data Problem kann doch nicht solch fehlerhaftes
> Verhalten herbeirufen!?

Klar. Wenn du z.B. in dem if eine Variable abfragst, die eigentlich 
volatile sein müsste, dann kann zusätzlicher Code vor diesem if dazu 
führen, dass die Variable nicht mehr dauerhaft in Registern gehalten 
werden kann, und somit beim if neu aus dem Speicher gelesen werden muss.

Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habs nochmal überprüft, alles volatile was benutzt wird.

Aber das Problem ist ja folgendes:
if (a)
    func1();
else
    func2();

Weder func1() noch func2() wird ausgeführt, solange vor dem if nicht 
eine zusätzliche Code-Zeile eingefügt ist.

Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe noch etwas rausgefunden:

Der Fehler tritt auf, egal an welcher Stelle die Funktion im Speicher 
liegt. Es muss also etwas mit der Funktion an sich zu tun haben.

Ich habe langsam den Verdacht, dass mit lokalen Variablen nicht richtig 
umgegangen wird. Muss ich im Linker Script irgendetwas beachten, dass 
lokalen Variablen auch Platz eingeräumt wird?

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel G. schrieb:
> Ich habe gerade noch rausgefunden, dass je nach Optimierungseinstellung
> des Compilers sich das Verhalten des Codes ändert. Vielleicht deutet das
> ja auf etwas hin?

Würdest Du uns auch verraten, wie sich das Verhalten ändert? 
Funktioniert das Programm wenn Du optimierst, oder wenn Du nicht 
optimierst? Im letzteren Fall, könnte das auf weitere Probleme mit dem 
Stack hinweisen.

Bei geringer Optimierung scheint GCC keine Register für lokale Variablen 
zu verwenden, sondern nur den Stack. Wenn der nicht richtig aufgesetzt 
wurde, dann knallts. Sobald bei höheren Optimierungsstufen für lokale 
Variablen Register verwendet werden, kann das Problem verschwinden.

Ich denke an weitere Stackprobleme, da Du erwähntest, dass nur SVC und 
IRQ stack verwendet werden. Läuft Dein Programm nur im SVC mode oder 
wird irgendwann auch mal in den USR/SYS mode umgeschaltet? Dann musst Du 
dessen Stack natürlich auch noch initialisieren.

Gruß
Marcus
http://www.doulos.com/arm/

Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

habs vergessen dazu zu schreiben: in allen Optimierungsroutinen läuft 
der Code fehlerhaft, nur eben unterschiedlich fehlerhaft. Ohne 
Optimierung geht garnichts mehr.

Ich habe die Initialisierung bereits für alle anderen Modi in meinen 
Startup Code übernommen. Nun Arbeitet der Prozessor im User-Mode und 
IRQ.

Wenn ich den Stack verschiebe oder die Anordnung der Unterprogramme im 
Speicherimage, ändert sich nichts, gleiche Fehler.

Reicht es, wenn ich die Stackpointer initialisiere oder muss ich mehr 
machen? Habe mal was gelesen, dass der Stackbereich mit Nullen 
überschrieben wird. Halte das bisher für unnötig.

Gruß,
Daniel

Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich bin leider immer noch nicht weiter und hoffe auf Hilfe! Vielleicht 
kann sich ja jemand meine c-runtime ansehen ob dort ein Fehler ist. Ich 
wäre sehr dankbar!

Der Vectortable liegt nicht am Anfang des Speichers. Start ist .start 
von wo aus der table dann kopiert wird und den Vectortable der Bootstrap 
routine überschreibt. Das funktioniert immerhin.

Wie gesagt: unterschiedliches fehlerhaftes Verhalten je nach 
Optimierungsgrad. Ohne Optimierung geht nichts mehr, da wird nicht mal 
die erste Zeile der main-funktion ausgeführt.

Viele Grüße
Daniel
/************************************************

 * DEFINITIONS                                  *

 ************************************************/



#define STACK_SIZE   0x1000



#define ARM_MODE_USER    0b10000

#define ARM_MODE_ABORT   0b10111

#define ARM_MODE_FIQ     0b10001

#define ARM_MODE_IRQ     0b10010

#define ARM_MODE_SVC     0b10011

#define ARM_MODE_SYSTEM  0b11111

#define ARM_MODE_UDEF    0b11011



#define I_BIT            0x80

#define F_BIT            0x40



/************************************************

 * VECTOR TABLE                                 *

 ************************************************/



  .section ".vectortable"



/* Exception vectors */

  b   reset_vector    /* reset */

  b   undef_vector   /* Undefined Instruction */

  b   swi_vector     /* Software Interrupt */

  b   pabt_vector    /* Prefetch Abort */

  b   dabt_vector    /* Data Abort */

  .word  _edata    /* Size of the image for SAM-BA */

  ldr pc, [pc, #-0xf20]   /* IRQ : read the AIC */

  b   fiq_vector      /* FIQ */



undef_vector:

  b   undef_vector

swi_vector:

  b   swi_vector

pabt_vector:

  b   pabt_vector

dabt_vector:

  b   dabt_vector

rsvd_vector:

  b   rsvd_vector

irq_vector:

    ldr     pc, [pc, #-0xf20]

fiq_vector:

  b   fiq_vector

reset_vector:

  b  reset_vector





/************************************************

 * INITIALIZE STACK POINTER                     *

 ************************************************/



  .text

  .globl start



start:



/* SUPERVISOR Mode */

  ldr     sp,=TOP_OF_MEM



/* IRQ Mode */

  sub     r0, sp, #STACK_SIZE

  mov     r1, #ARM_MODE_IRQ | I_BIT | F_BIT

  msr     cpsr_c, r1

  mov     sp, r0



/* FIQ Mode */

  sub     r0, sp, #STACK_SIZE

  mov     r1, #ARM_MODE_FIQ | I_BIT | F_BIT

  msr     cpsr_c, r1

  mov     sp, r0



/* ABORT Mode */

  sub     r0, sp, #STACK_SIZE

  mov     r1, #ARM_MODE_ABORT | I_BIT | F_BIT

  msr     cpsr_c, r1

  mov     sp, r0



/* UDEF Mode */

  sub     r0, sp, #STACK_SIZE

  mov     r1, #ARM_MODE_UDEF | I_BIT | F_BIT

  msr     cpsr_c, r1

  mov     sp, r0



/* USER/SYSTEM Mode, enable IRQ */

  sub     r0, sp, #STACK_SIZE

  mov     r1, #ARM_MODE_USER | F_BIT

  msr     cpsr_c, r1

  mov     sp, r0



/************************************************

 * COPY VECTOR TABLE                            *

 ************************************************/



    ldr     r0, =_svec

    ldr     r1, =_evec

    mov     r2, #0    /* destination for the vector table */

1:

    cmp     r0, r1

    ldrcc   r3, [r0], #4

    strcc   r3, [r2], #4

    bcc     1b



/************************************************

 * zero the .bss section                        *

 ************************************************/



        ldr     r1, =_sbss

        ldr     r2, =_ebss

        mov     r0, #0

1:

        cmp     r1, r2

        strcc   r0, [r1], #4

        bcc     1b



/************************************************

 * BRANCH TO MAIN                               *

 ************************************************/



/* branch to main funktion */

  b       main


Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe einen Thread hier gepostet mit dem gleichen Problem. Hast du es 
gelöst?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der gezeigte Startupcode jedefalls vergisst, die initialisierten Daten 
zu initialisieren (aus dem Flash zu kopieren).

Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein, es ist leider nicht gelöst. Ich habe daher kürzlich einen neuen 
Thread gestartet "Ohne Optimierung gehts nichts mehr" oder so ähnlich. 
Aber auch dort leider kein Ergebnis.

Das Image mit allen Daten wird durch AT91Bootstrap in RAM kopiert.

Grüße
Daniel

Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe das Problem möglicherweise gelöst:

Ich habe mir die Stackpointer Initialisierung von der Atmel 
at91bootstrap Routine abgeschaut, wo der benutzte Stackpointer auf 
0x23ffffff, also Ende des Speichers gesetzt wird.

Ist das OK? Es ist ein full stack und somit wird der erste Wert 
unaligned mit drei bytes im Nirgendwo gespeichert. Wie verhält sich STM 
bei unaligned data? Wird überhaupt etwas gespeichert? Und wieso macht 
Atmel sowas?

Grüße,
Daniel Gering

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Full" heisst, dass SP auf das unterste belegte Byte zeigt, also erst 
dekrementiert und dann gespeichert wird. Daher wäre 0x24000000 kein 
Problem, sondern vielmehr der klassische Anfangswert eines 
Stackpointers.

Aber 0x23ffffff für einen Stackpointer wäre wirklich äusserst seltsam, 
denn das wäre eben unaligned und sowas ist bei Stacks ziemlich verboten, 
selbst wenn eine Maschine sowas erlauben sollte, was beim ARM m.W. nicht 
der Fall ist. Allerdings meckert ARM zumindest in Standardeinstellung 
wohl auch nicht, was zu allerlei Unfug führen kann.

Wenn das tatsächlich der Fall ist, dass besteht möglicherweise ein 
Missverständnis zwischen Startup-Code und den Werten/Namen vom 
Linker-Script.

Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh ja, bei full stack hab ich mich geirrt. Dann liegt es wohl nur am 
alignment. Und es war auch vorschnell und falsch zu sagen, dass Atmel es 
unaligned gemacht hat. Das muss ich wohl wo anders her oder selbst 
falsch gemacht haben.

Ich nehme an, dass mit steigender Optimierung der Stack weniger benutzt 
wird und das Programm somit immer besser lief.

Compiler (codesourcery) hat übrigens nicht gewarnt bei -Wall.

Danke A.K., ihre kompetenten Beiträge sind wirklich ein Gewinn für 
dieses Forum!

Dann kann ich mich ja jetzt endlich wieder um die eigentliche 
Programmentwicklung kümmern.

Viele Grüße
Daniel Gering

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel G. schrieb:

> Compiler (codesourcery) hat übrigens nicht gewarnt bei -Wall.

Der Stackpointer wird in deinem handgebauten Startupcode definiert und 
aus einer externen Adresse abgeleitet, die wohl dem Linker-Script 
entstammt.

Also woher sollte der Compiler die exakte Adresse des Stacks kennen?

Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dem Compiler wird die Adresse über die Option -DTOP_OF_MEMORY 
mitgeteilt. TOP_OF_MEMORY ist dabei eine im Makefile initialisierte 
Variable.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die wird auch in dieser Form nicht dem Compiler mitgeteilt, sondern dem 
Präprozessor vor dem Assembler, der deinen Startup-Code verarbeitet. 
Assemblerprogrammierung heisst bekanntlich Schrott-rein-Schrott-raus. 
Sorry, aber du kannst nicht den Compiler für deinen Fehler in Haftung 
nehmen, der hat von solchen absoluten Adressen keine Ahnung.

Autor: Daniel G. (motello)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Allerdings meckert ARM zumindest in Standardeinstellung
> wohl auch nicht, was zu allerlei Unfug führen kann.

Ich habe den Satz wohl falsch verstanden, ich dachte du meintest den 
Compiler und dessen Warnungen. Natürlich ist es schön wenn ein Compiler 
bei Bugs warnt, aber ich geben selbstverständlich nicht dem Compiler 
schuld wenn ich einen Fehler mache und er nicht warnt.

Was meinst du mit dem obigen Satz? Wie soll er meckern? Exception?

Also bekommt der Compiler nichts weiter als eine Referenz auf die 
Speicheradresse in der der TOP_OF_MEM Wert steht?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel G. schrieb:

> Was meinst du mit dem obigen Satz? Wie soll er meckern? Exception?

Es gibt Prozessoren mit unaligned trap. In ARMv6 (ARM11) besteht 
offenbar die Möglichkeit, solche Zugriffe entweder einen Trap laufen zu 
lassen, oder korrekt auszuführen.

> Also bekommt der Compiler nichts weiter als eine Referenz auf die
> Speicheradresse in der der TOP_OF_MEM Wert steht?

Der Compiler kriegt davon garnichts mit. Der verlässt sich darauf, dass
am Anfang einer Funktion der SP einen sinnvollen Wert enthält und sorgt 
dafür, dass was ihn angeht aus einem korrekten SP kein unkorrekter wird. 
Optional wird Code eingebaut, der auf Stacküberlauf testet. Das wär's 
dann aber auch. Den absoluten Wert kennt er nicht. Der 
Präprozessor-Makro TOP_OF_MEM ist für den Compiler völlig uninteressant.

Autor: Marcus Harnisch (mharnisch) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel G. schrieb:
> Ich nehme an, dass mit steigender Optimierung der Stack weniger benutzt
> wird und das Programm somit immer besser lief.

Sach' ich ja.

A. K. schrieb:
> Es gibt Prozessoren mit unaligned trap. In ARMv6 (ARM11) besteht
> offenbar die Möglichkeit, solche Zugriffe entweder einen Trap laufen zu
> lassen, oder korrekt auszuführen.

Geht auch bei einigen ARM9E basierten Systemen. Siehe z.B. 
http://infocenter.arm.com/help/topic/com.arm.doc.d...
Allerdings bieten ARMv6/7 noch mehr Konfigurationsmöglichkeiten.

Gruß
Marcus
http://www.doulos.com/arm/

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.