Merkwürdiges Verhalten bei Variablen und for-schleifen

#1283657
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:
1
unsigned short ip_chksum (int header_length)
2
{
3
    unsigned short u16;
4
    unsigned long sum = 0;
5
    int i;
6

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

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

14
    return (unsigned short)~sum;
15
}
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
#1283673
Lesenswert?

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

zb
1
int i;
2
int j[5];
3
int k;
4

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

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'
#1283703
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:
1
int i = 0;
2
int test () {
3
    if(i != 0)
4
        return error;
5
}
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...
Moderator Persönliche Seite #1283812
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.
#1283980
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.
#1284016
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.
#1284017
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.
Gast #1284201
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.
Persönliche Seite #1284316
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/
#1284955
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
#1286517
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
#1286526
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.
Moderator Persönliche Seite #1286592
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:
1
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.
#1286614
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.
#1293652
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
#1294060
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?
#1294064
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.
#1294180
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?
Persönliche Seite #1294769
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/
#1294781
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
#1300595
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
1
/************************************************
2

3
 * DEFINITIONS                                  *
4

5
 ************************************************/
6

7

8

9
#define STACK_SIZE   0x1000
10

11

12

13
#define ARM_MODE_USER    0b10000
14

15
#define ARM_MODE_ABORT   0b10111
16

17
#define ARM_MODE_FIQ     0b10001
18

19
#define ARM_MODE_IRQ     0b10010
20

21
#define ARM_MODE_SVC     0b10011
22

23
#define ARM_MODE_SYSTEM  0b11111
24

25
#define ARM_MODE_UDEF    0b11011
26

27

28

29
#define I_BIT            0x80
30

31
#define F_BIT            0x40
32

33

34

35
/************************************************
36

37
 * VECTOR TABLE                                 *
38

39
 ************************************************/
40

41

42

43
  .section ".vectortable"
44

45

46

47
/* Exception vectors */
48

49
  b   reset_vector    /* reset */
50

51
  b   undef_vector   /* Undefined Instruction */
52

53
  b   swi_vector     /* Software Interrupt */
54

55
  b   pabt_vector    /* Prefetch Abort */
56

57
  b   dabt_vector    /* Data Abort */
58

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

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

63
  b   fiq_vector      /* FIQ */
64

65

66

67
undef_vector:
68

69
  b   undef_vector
70

71
swi_vector:
72

73
  b   swi_vector
74

75
pabt_vector:
76

77
  b   pabt_vector
78

79
dabt_vector:
80

81
  b   dabt_vector
82

83
rsvd_vector:
84

85
  b   rsvd_vector
86

87
irq_vector:
88

89
    ldr     pc, [pc, #-0xf20]
90

91
fiq_vector:
92

93
  b   fiq_vector
94

95
reset_vector:
96

97
  b  reset_vector
98

99

100

101

102

103
/************************************************
104

105
 * INITIALIZE STACK POINTER                     *
106

107
 ************************************************/
108

109

110

111
  .text
112

113
  .globl start
114

115

116

117
start:
118

119

120

121
/* SUPERVISOR Mode */
122

123
  ldr     sp,=TOP_OF_MEM
124

125

126

127
/* IRQ Mode */
128

129
  sub     r0, sp, #STACK_SIZE
130

131
  mov     r1, #ARM_MODE_IRQ | I_BIT | F_BIT
132

133
  msr     cpsr_c, r1
134

135
  mov     sp, r0
136

137

138

139
/* FIQ Mode */
140

141
  sub     r0, sp, #STACK_SIZE
142

143
  mov     r1, #ARM_MODE_FIQ | I_BIT | F_BIT
144

145
  msr     cpsr_c, r1
146

147
  mov     sp, r0
148

149

150

151
/* ABORT Mode */
152

153
  sub     r0, sp, #STACK_SIZE
154

155
  mov     r1, #ARM_MODE_ABORT | I_BIT | F_BIT
156

157
  msr     cpsr_c, r1
158

159
  mov     sp, r0
160

161

162

163
/* UDEF Mode */
164

165
  sub     r0, sp, #STACK_SIZE
166

167
  mov     r1, #ARM_MODE_UDEF | I_BIT | F_BIT
168

169
  msr     cpsr_c, r1
170

171
  mov     sp, r0
172

173

174

175
/* USER/SYSTEM Mode, enable IRQ */
176

177
  sub     r0, sp, #STACK_SIZE
178

179
  mov     r1, #ARM_MODE_USER | F_BIT
180

181
  msr     cpsr_c, r1
182

183
  mov     sp, r0
184

185

186

187
/************************************************
188

189
 * COPY VECTOR TABLE                            *
190

191
 ************************************************/
192

193

194

195
    ldr     r0, =_svec
196

197
    ldr     r1, =_evec
198

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

201
1:
202

203
    cmp     r0, r1
204

205
    ldrcc   r3, [r0], #4
206

207
    strcc   r3, [r2], #4
208

209
    bcc     1b
210

211

212

213
/************************************************
214

215
 * zero the .bss section                        *
216

217
 ************************************************/
218

219

220

221
        ldr     r1, =_sbss
222

223
        ldr     r2, =_ebss
224

225
        mov     r0, #0
226

227
1:
228

229
        cmp     r1, r2
230

231
        strcc   r0, [r1], #4
232

233
        bcc     1b
234

235

236

237
/************************************************
238

239
 * BRANCH TO MAIN                               *
240

241
 ************************************************/
242

243

244

245
/* branch to main funktion */
246

247
  b       main
#1343261
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
#1343271
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.
#1343287
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
#1343329
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.
#1343347
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?
#1343368
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.
Persönliche Seite #1349024
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.ddi0198e/I1039296.html
Allerdings bieten ARMv6/7 noch mehr Konfigurationsmöglichkeiten.

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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren