Forum: Compiler & IDEs Globale Variablen für Datenaustausch


von Leif U. (boing)


Lesenswert?

Hallo,

ich benutze globale variablen um werte aus C-Programmen heraus an
Assemblerfunktionen zu übergeben. (z.B. volatile uint8_t swap1)
Zum Debuggen nehme ich das AVRStudio.
Setzt man nun swap1 in die Watchlist behauptet das Studio diese
Variable würde sich an einer Adresse oberhalb 0x800000 (8388608) also
jenseits der 8KByte befinden und gibt als Value "Invalid location"
an. Meines erachtens hat der ATMEga128 aber nur 4Kbyte SRAM.
Wie kommt das?

Desweiteren habe ich das Problem, dass der Austausch zwischen c und
Assembler auf diese Weise mal funktioniert und mal fehlschlägt.
In einem kleinem Testproblem funktioniert es fehlerfrei. In einem
anderen Programm, habe ich die globalen Variablen zum Datenaustausch
nachträglich eingebaut, allerdings kommt bei der hälfte davon nicht der
korrekt wert im Assembler an. Ausserdem will es mir nicht gelingen, den
Fehler in dem Testprogramm zu reproduzieren...
Ich würde gern, die seltsamen Adressen als Fehlerquelle ausschliessen.

Cheers,

Leif

von Leif U. (boing)


Angehängte Dateien:

Lesenswert?

Ich habe die "Fehlerquelle" durch systematisches auskommentieren
lokalisiert. Allerdings werde ich nicht recht schlau daraus.
Alles unwichtige habe weggeschnitten. Hier die kleinen Häufchen Code,
die den Fehler festhalten:


////// dasproblem.c //////////
#include <avr/io.h>
volatile uint8_t dummy;
volatile uint8_t swap1;
volatile uint8_t swap2;
volatile uint8_t swap3;
volatile uint8_t swap4;
volatile uint8_t swap5;
volatile uint8_t swap6;
volatile uint8_t  startadresshA0;
volatile uint8_t  startadresslA0;
volatile uint8_t  startadresshA1;  //<--- HERE !!!!!!!!!!!!!!
volatile uint8_t  startadresslA1;
volatile uint8_t  startadresshB0;
volatile uint8_t  startadresslB0;
volatile uint8_t  startadresshB1;
volatile uint8_t  startadresslB1;
volatile uint8_t  startadresshC0;
volatile uint8_t  startadresslC0;
volatile uint8_t  startadresshC1;
volatile uint8_t  startadresslC1;
volatile uint8_t  startadresshC2;
volatile uint8_t  startadresslC2;
volatile uint8_t  startadresshC3;
volatile uint8_t  startadresslC3;

extern void swapit();
extern void multi();
int main (void){

swap1 = 0xAF;
swap2 = 0xFA;
swap3 = 0xCF;
swap4 = 0xCF;
swap5 = 0xDA;
swap6 = 0xDB;
multi();
return(0);
}



;;;;;;;;mul.S;;;;;;;;;;;;;;;;;;;;
.stabs  "",100,0,0,multi
.stabs  "mul.S",100,0,0,multi
;;#include "avr/io.h"
.extern dummy
.extern swap1
.extern swap2
.extern swap3
.extern swap4
.extern swap5
.extern swap6
.extern startadresshA0
.extern startadresslA0

.extern startadresshA1

.extern startadresslA1
.extern startadresshB0
.extern startadresslB0
.extern startadresshB1
.extern startadresslB1
.extern startadresshC0
.extern startadresslC0
.extern startadresshC1
.extern startadresslC1
.extern startadresshC2
.extern startadresslC2
.extern startadresshC3
.extern startadresslC3

.global multi
.func multi
multi:
;;;;;;;;Initialise;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
cli ; disable interrupts
push 18
push 19
push 20
push 21
push 22
push 23
push 24
in 24,0x3F ;SREG
push 24
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lds 18, swap1
lds 19, swap2
lds 20, swap3
lds 22, swap4
lds 23, swap5
lds 24, swap6
;;;;;;;;;;;;;;;;;cleanup;;;;;;;;;;;;;;;;;;;;;;;;
pop 24
out 0x3F, 24 ;SREG
pop 24
pop 23
pop 22
pop 21
pop 20
pop 19
pop 18
sei ; Enable interrupts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ret
.endfunc


Compilen und linken übernimmt die Stapelverabrbeitung im Anhang.

Der Fehler im Detail:
Die Variable swap4, wird mit 0xCF initialisiert. Da sich die Variable
nicht mit der "watchlist" überwachen lässt, lade ich sie testhalber
in das Register 22. Dort erscheint leider der wert 0xC0.
Alle anderen swaps geben die korrekten werte in die Register. Tauschen
der Register oder der Reihenfolge ändert nichts: swap4 liefert den
falschen wert.
Der Fehler lässt sich beheben indem man die mit "HERE !!!!!!!!!"
Kommentierte Zeile auskommentiert.

Kann sich da Jemand einen Reim draus machen?!

Cheers,
Leif

von Leif U. (boing)


Lesenswert?

Anstelle die Zeile auszukommentieren kann man auch der Variablen dort
einen anderen Namen geben.
Ich werd einfach nicht schlau daraus...

Ich hoffe Irgendjemand hat eine Idee.


Cheers,
Leif

von Karsten Brandt (Gast)


Lesenswert?

Nur ne Idee:

Evtl. doppelte Deklaration der startadresshA1-Variablen im Code?

von Karsten Brandt (Gast)


Lesenswert?

In welchem Zusammenhang stehen startadresshA1 und swap4?
Oder gibt es keinen und das ist das Problem?

von Karsten Brandt (Gast)


Lesenswert?

Aber wie gesagt, man kann hiernur raten.
Ich denke Du würdest mehr Info's bekommen, wenn Du das ganze Projekt
zur Verfügung stellst.

von Leif U. (boing)


Angehängte Dateien:

Lesenswert?

Es gibt keinen Zusammenhang zwischen den Variablen. Ich kann zumindest
keinen erkennen. Die obigen quelltexte sind das Projekt. Der einfach
halt halber habe ich die entsprechenden Dateien angehängt.

doit.bat compiliert, linkt und wandelt anschliessen ins COFF Format,
vorausgesetzt WinAVR ist installiert. (Einfach mit Enter bestätigen, es
sind pausen dabei um eventuelle Ausgaben lesen zu können)
Das .cof lässt sich dann mit dem Studio debuggen.

von Karsten Brandt (Gast)


Lesenswert?

Ok, nur die Sourcen betrachtet sehe ich den Fehler auch nicht.
Da ich mit der WinArm-Umgebung für einen anderen µC programmiere, kann
ich Dein Beispiel nicht direkt kompilieren.
Ich könnte es zwar mit dem arm-elf-gcc probieren.
Fraglich ist nur, ob wir dann das gleiche Ergebnis erhalten.

Eine Möglichkeit ist evtl. noch, dass Du mir die elf.Datei zukommen
läßt. Diese kann ich dann mal mit objdump und Co. analysieren.
Vielleicht sehe ich ja dann was.

von Karsten Brandt (Gast)


Lesenswert?

Oder Du linkst mal mit der Option -Xlinker -Map=dasproblem.map und
schickst dann die map-Datei.

von Leif U. (boing)


Angehängte Dateien:

Lesenswert?

Ok ich bin ein wenig weiter.
Die Zeile lds 22, swap4;
sieht im Disassembler wie folgt aus:
35:       swap4 = 0xCF;
+00000057:   EC8F        LDI     R24,0xCF         Load immediate
+00000058:   93800068    STS     0x0068,R24       Store direct to data
space
Im extenden I/O Memory kann man die geschrieben werte beobachten.
swap4 wird zunächst mit 0xCF korrekt in den SRAM geschrieben.
Der übernächste Befehl ist swap5 = 0xDA;
im Disassembler zu sehen als:
38:       startadresshC3= 0xDE;
+0000005D:   ED8E        LDI     R24,0xDE         Load immediate
+0000005E:   93800067    STS     0x0067,R24       Store direct to data
space

STS     0x0067,R24 Überschriebt 0xCF mit 0xC0

Deshalb verschwindet das Problem wenn man etwas an den Variablem
rumspielt: Die variablen stehen an anderen Stellen im Speicher. Bei
bestimmten kombinationen überschreiben sie sich nicht gegenseitig.
(Umbenennen von startadresshA1 in startaaaaadresshA1 hilft zum
Beispiel)
Nur warum geschieht die überhaupt?!

Zum selbernachschauen habe ich das .elf angehängt.

Sind die GNU-Tools buggy oder habe ich da bösen C-Code geschrieben?!

Cheers,
Leif

von Leif U. (boing)


Angehängte Dateien:

Lesenswert?

Hier noch die .map Datei

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ist das auf einem realen AVR oder auf einem Simulanten^H^H^H^Htor?

Wenn letzteres, ist dir schon mal in den Sinn gekommen, dass sowas
auch nur Software ist, die Bugs haben kann?

Der (Dis-)Assemblercode sieht jedenfalls OK aus.

von Karsten Brandt (Gast)


Lesenswert?

So ich hab mal einen Blick in Dein Map-File geworfen.

Das Deine Variablen oberhalb von 0x00800000 liegen ist korrekt und
hat nichts mit der Speicher-Kapazität des ATMEGA zu tun.
Sondern mit dem eingestellten Speicher-Mapping.
Siehe Dazu Auszug aus Deinem Map-File:

Memory Configuration

Name             Origin             Length             Attributes
text             0x00000000         0x00002000         xr
data             0x00800060         0x0000ffa0         rw !x
eeprom           0x00810000         0x00010000         rw !x
default        0x00000000         0xffffffff

Wie Du dort sehen kannst beginnt der Speicherbereich für Deine Daten ab
der Adresse 0x00800060 und hat die Länge 0x0000ffa0.

Deine Variablen liegen an folgenden Adressen:

                0x00800060                swap3
                0x00800061                startadresslC2
                0x00800062                startadresshA1
                0x00800063                swap5
                0x00800064                startadresshC1
                0x00800065                startadresslC1
                0x00800066                swap6
                0x00800067                startadresshC3
                0x00800068                swap4
                0x00800069                startadresslC3
                0x0080006a                startadresslA1
                0x0080006b                startadresshA0
                0x0080006c                swap1
                0x0080006d                startadresslB1
                0x0080006e                startadresshB0
                0x0080006f                startadresslA0
                0x00800070                startadresslC0
                0x00800071                swap2
                0x00800072                startadresshC2
                0x00800073                startadresslB0
                0x00800074                dummy
                0x00800075                startadresshB1
                0x00800076                startadresshC0

und somit auch korrekt im Speicherbereich für Daten.
Wenn Dein Debugger nun der Meinung ist, dass sich die Daten an einer
ungültigen Position befinden, dann ist dies doch schon sehr
fragwürdig.

Außerdem habe ich versucht mit arm-elf-objdump den DisassemblerCode
Deines Programmes anzuschauen. Ist jedoch scheinbar nicht möglich.
arm-elf-objdump stieg mit der Fehlermeldung aus:

Can't disassemble for architecture UNKNOWN!

Ist auch nachvollziehbar!

Es wäre jetzt noch möglich mit der Option -S zu kompilieren um nur den
Assembler-Code zu sehen und hier reinzustellen.
Aber wie Jörg schon sagte, scheint das hier wirklich ein Problem Deiner
Entwicklungsumgebung zu sein.

von Leif U. (boing)


Lesenswert?

Simulator des AvrStudios...
Könnte natürlich auch daran liegen. Das Problem besteht dann jedoch
weiterhin :(
Ich werde mal bei Atmel nachfrqagen.

Danke soweit!

von Leif U. (boing)


Angehängte Dateien:

Lesenswert?

Hmm Atmel nach dem AVRStudio fragen...
Das Studio wird von SourceForge gehostet. Dort stehen Eric Weddington
und Jörg Wunsch als Admins. Da bin ich hier doch gar nicht so schelcht
aufgehoben.

Weil es schon ein paar Tage her ist, fasse ich nochmal zusammen:
Ich habe ein Assemblerprogramm, welches mittels volatile/extern
deklarierten variablen adressen übergeben bekommt.
Leider überschreiben sich die Zeiger gegenseitig wenn sie in den SRAM
geladen werden.
(Im angehängten Code wird swap4 überschrieben, wenn swap6 in den SRAM
geladen wird.)
Gibt man den Zeigern neue Namen oder lässt einen weg (z.b. bei
startadresshA1) verändern sich beim nächsten compilieren die adressen
der Zeiger. Das kann dazu führen, daß sich zufällig eine verteilung
ergibt in der sich die Zeiger nicht überschreiben. Leider führt auch
Weiterstricken des Codes dazu, daß bei nächsten Compilieren andere
Adressen verteilt werden und das Problem taucht irgendwann wieder auf.

Gegenseitig überschreiben sich nur Variablen mit dem qualifier
"volatile".
Das Problem lässt sich zweifelsfrei reproduzieren, auch auf anderen
Computern mit einer älteren Version des Studios.

Um zweifelsfrei zu klären ob es, wie von Karsten und Jörg vermutet
tatsächlich am Simulator liegt, würde ich mich freuen wenn Jemand das
programm in einem anderem Simulator laufen lassen könnte.

Im anhang ist das Programm in Form von Quellcode, als .cof und als
.elf. Ein .map file liegt auch bei.

Gruß,   Leif

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Das Studio wird von SourceForge gehostet.

Nein, das ist ein Atmel-Produkt.  Du meinst WinAVR.

von Leif U. (boing)


Lesenswert?

Stimmt!
Trotzdem wäre mir wohler wenn ich genau wüsste, daß es am Studio
liegt...

von Leif U. (boing)


Lesenswert?

Überlässt man complilieren und linken dem Studio, verfliegt das Problem
anscheinend.
Die volatile variablen landen dann auch in einem ganz anderen
Speicherbereich.

Warum bringt der Linker bei händischem Aufruf meinerseits die volatlie
variablen (und nur diese) eigentlich an den 0x800.. adressen unter?
Für alle andere Variablen beginnt der SRAM bei 0x100.
Und wie kann ich darauf einfluß nehmen?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Die 0x800000 ist der Offset, den der RAM-Bereich intern bekommt.
Der EEPROM bekommt 0x810000.  Damit werden die drei Speicherbereiche
des AVR sozusagen virtuell in einen flachen Adressraum abgebildet,
weil das das Einzige ist, was die GNU-Tools derzeit verstehen.

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.