Hi,
habe hier ein sehr obskures Problem mit Segger Embedded Studio (habe
schon ein Supportticket geöffnet, aber vlt. bin ich ja nur zu dumm und
jmd. hatte das Problem schonmal).
Es fing damit an, dass ich ein Projekt welches ich seit Jahren nur ab
und zu anfasse um ein paar Parameter zu ändern nicht mehr übersetzen
konnte, da die neueren Libs die mit ES kommen offenbar nicht mehr zu
meinen alten Startup-Files passten, und somit Symbole fehlten etc. Okay,
also mit ES ein neues leeres Projekt für einen STM32F405RG erzeugt und
die Startup-Files von da in mein altes Projekt übernommen.
Mit dem GNU Linker dann noch weitere Fehlermeldungen erhalten und auf
den SEGGER Linker umgeschaltet. Okay, Projekt übersetzt nun, aber es
gibt offenbar einen Fehler in der Memory map. Es ist selbst mit einem
leeren (Beispiel-)Projekt nachvollziehbar, welches ich aus dem
"STM32F4xx" Package generiere.
Beispielcode:
1
#include<stdio.h>
2
#include<stdlib.h>
3
#include<string.h>
4
5
intmain(void){
6
inti;
7
intr;
8
9
staticcharsome_data[10000];
10
11
for(i=0;i<100;i++){
12
memset(some_data,0,10000);
13
r=rand();
14
printf("Hello World %d!\n",r);
15
}
16
}
Wir sind uns wohl alle einig, dass der Code Zufallszahlen ausgeben
sollte. Die Ausgabe ist aber:
1
Hello World 0!
2
Hello World 0!
3
...
Das Problem kommt durch einen Speicherkonflikt zustande.
Im MAP File habe ich:
10000004-10002713 some_data.0 10 000 4 Zero ZI main.o
Also man sieht hier, dass an der Adresse 0x10000000 4 Bytes für die
rand() Funktion der Segger RunTimeLibrary verwendet werden, dahinter
kommt ein Buffer aus meinem Code.
Wenn man sich nun aber den Code von rand() im Debugger ansieht, sieht
man, dass die Funtkion fälschlicherweise die Adresse 0x10000004
verwendet, was dann mit dem Buffer (some_data) kollidiert (siehe
Screenshot).
Das Problem tritt unabhängig vom verwendeten Compiler GCC/SEGGER auf,
sowohl mit ES 6.40 als auch 7.10a.
Irgendeine Idee woher dieses obskure "Speicherversatz" kommen könnte?
Mache ich etwas falsch?
> Mache ich etwas falsch?
Klar. :-)
Es koennte nicht schaden uns mal die Ausgaben deines Compile und Link
laufs zu zeigen.
Dann ist es IMHO ein Problem wenn du neue und alte Dateien mischt. Wer
weiss ob Segger nicht mittlerweile andere Vorstellungen hat was in einem
Linkerscript stehen sollte?
Es ist grundsaetzlich schlecht Projekte die man nur alle paar Jahre mal
anfasst mit neuen Versionen eines Compilers zu uebersetzen. Man bleibt
entweder immer bei der letzten Version mit der man entwickelt hat, oder
aber man macht einmal ein Upgrade und zieht dann alle Tests nochmal
durch.
Es ist allgemein besser fuer ernsthafte Projekte ein Makefile zu nutzen
und wenn man unbedingt eine schicke Oberflaeche haben will von dort das
make aufzurufen. Damit du halt notfalls ohne den ganzen klimbim schauen
kannst wie es laeuft und nicht raten musst.
Olaf
olaf schrieb:>> Mache ich etwas falsch?>> Es koennte nicht schaden uns mal die Ausgaben deines Compile und Link> laufs zu zeigen.
Ich schrieb ja bereits: "Es ist selbst mit einem leeren
(Beispiel-)Projekt nachvollziehbar welches ich aus der aktuellen
Embedded Studio / aus dem "STM32F4xx" Package generiere."
Das "Package" ist quasi ein Template, welches ebenfalls von Segger
kommt. Also alles auf dem jeweils aktuellen Stand. Inklusive Libraries
und Startup-Files.
> Dann ist es IMHO ein Problem wenn du neue und alte Dateien mischt. Wer
Das war auch erst mein Verdacht, aber, siehe oben.
> anfasst mit neuen Versionen eines Compilers zu uebersetzen. Man bleibt> entweder immer bei der letzten Version mit der man entwickelt hat, oder> aber man macht einmal ein Upgrade und zieht dann alle Tests nochmal> durch.
Das stimmt, es handelt sich allerdings um ein reines Hobbyprojekt, daher
habe ich das natürlich nicht so durchgezogen.
Compiler und Linker laufen ohne Fehler durch.
Die Konfiguration der Linkersections etc. habe ich mir auch angesehen,
da ist nichts zu beanstanden.
Was rand() hier laden will, muß ja der Zustand des PRNG sein.
Aufgerufen wird erstmal aebi_read_tp, und dazu finde ich einen
Google-Treffer:
https://codebrowser.dev/glibc/glibc/sysdeps/unix/sysv/linux/arm/aeabi_read_tp.S.html
Laut Kommentar wurde also wohl die Standardlib mit mtp=soft übersetzt:
https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html
rand() versucht also, etwas mit thread local storage zu laden. Du
könntest mal in aebi_read_tp mit dem Debugger reinsteppen, was da
eigentlich übersetzt wurde. Zurückgegeben wird dafür jedenfalls r0 mit
0x0ffffffc.
Das ist schonmal merkwürdig, weil das nicht in einen gültigen
RAM-Bereich zeigt, aber vielleicht soll das ja mit einem Offet von
mindestens 4 genutzt werden. Allerdings nimmt rand() in r1 stattdessen
einen Offset von 8 an.
Sieht nach einem Problem entweder im Startup-File oder in den
Linker-Einstellungen aus, also daß die Linker-Einstellungen nicht zu dem
passen, wie die Standardlib übersetzt wurde.
Nop schrieb:> Was rand() hier laden will, muß ja der Zustand des PRNG sein.
Ja, richtig.
> Laut Kommentar wurde also wohl die Standardlib mit mtp=soft übersetzt:> https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html
Richtig, so ist auch meine Einstellung in den Code-Optionen. Die C-Lib
kommt allerdings als .a vorübersetzt von Segger (in allen möglichen
Ausprägungen für die unterstützten Cores).
Aber man sollte ja erwarten, dass das Projekt in den
Default-Einstellungen korrekten Code erzeugt - wenn es denn schon so
automatisch konfiguriert wird.
> rand() versucht also, etwas mit thread local storage zu laden. Du> könntest mal in aebi_read_tp mit dem Debugger reinsteppen, was da> eigentlich übersetzt wurde. Zurückgegeben wird dafür jedenfalls r0 mit> 0x0ffffffc.
Das habe ich schon getan, es liest diesen Wert 0x0ffffffc direkt aus dem
Flash-Speicher. Scheint also irgendwie falsch initialisiert bzw. gefüllt
zu werden.
> Das ist schonmal merkwürdig, weil das nicht in einen gültigen> RAM-Bereich zeigt, aber vielleicht soll das ja mit einem Offet von
Wenn ich das ganze mit dem GNU-Linker baue, ist der Code korrekt. Dann
verwende ich aber auch einen anderen Startup-Code (dieser ist abhängig
vom verwendeten Linker).
Es scheint so als ob dort der Fehler liegt, da im Startup-Code für den
GNU-Linker die Basisadresse korrekt gesetzt wird (siehe Screenshot), so
wie im .map File angegeben:
1
.tdata.__SEGGER_RTL_rand_next
2
0x00000000200008d4 0x4 C:/Program Files/SEGGER/SEGGER Embedded Studio for ARM 6.40/lib/libc_v7em_fpv4_sp_d16_hard_t_le_eabi_balanced.a(intops.o)
Jetzt schaue ich mir nochmal den Startup-Code für den Segger-Linker
an...
Für den GNU-Linker muss ich ein Startup-Code
thumb_crt0.s
verwenden, dort wird die Funktion (korrekt) gebaut:
HELPER __aeabi_read_tp
ldr r0, =__tbss_start__-8
bx lr
Für den Segger-Linker wird der Startup-Code
SEGGER_THUMB_Startup.s
verwendet, dort ist diese Funktion allerdings garnicht definiert, kommt
also von irgendwo anders her, vermutlich mit "weak" irgendwo noch
definiert.
EDIT: Selbst wenn ich die Funktion in den Segger Startupcode kopiere und
sie auch entsprechend übersetzt wird, sehe ich im Debugger das
_tbss_start_ offenbar einen "falschen" Wert 0x10000004 anstelle von
0x10000000 hat.
Also irgendwas läuft da mit dem Memory placement mit dem Segger-Linker
schief.
Hallo,
verstehe nicht wirklich das Problem. Habe ein Standardprojekt unter SES
angelegt, Deinen Code hineinkopiert und es funktioniert.
Liegt es nicht möglicherweise an irgendwelchen Fragmenten Deines alten
Projekts ?
Programmer schrieb:> Hallo,>> verstehe nicht wirklich das Problem. Habe ein Standardprojekt unter SES> angelegt, Deinen Code hineinkopiert und es funktioniert.> Liegt es nicht möglicherweise an irgendwelchen Fragmenten Deines alten> Projekts ?
Ja, es funktioniert wenn Du den SEGGER Compiler nimmst, weil dort hinter
den 4 Bytes der rand() Funktion offenbar unbenutzte Bytes stehen - das
Placement der Daten ist etwas unterschiedlich. Der generierte Code ist
aber (bei mir) genauso falsch mit dem Offset 4 gewesen.
Wenn Du den Compiler auf GNU umstellst (nicht den Linker, mit dem GNU
Linker existiert der Fehler nicht) müsstest Du den gleichen Fehler
haben.
Ich habe das Projekt bereits mehrfach in einem jeweils frischen
Verzeichnis erstellt und konnte es immer reproduzieren.
Also:
Compiler: Segger, Linker: Segger -> Falscher Code, funktioniert aber
weil der Buffer nicht direkt nach __SEGGER_RTL_rand_next platziert wird
Compiler: Gnu, Linker: Segger -> Falscher Code, Problem lässt sich
direkt wie o.g. reproduzieren
Compiler: Gnu, Linker: Gnu -> Erzeugter Code ist korrekt
Compiler: Segger, Linker: Gnu -> Nicht getestet, vermute aber der Code
ist dann ebenfalls i.O.
Hallo,
erst einmal Danke für die Ausführungen.
Trotzdem erkenne ich nicht, warum die Variante Segger Compiler + Segger
Linker. Der Linker macht das, was er soll. Es gibt keinerlei
Auffälligkeiten im MAP-File.
Bei Deiner Ausführung ist für mich eher merkwürdig, daß Code und RAM bei
0x10000000 beginnt, was ja so nicht paßt
Ich habe mal mein MAP-File angehängt
Vielleicht verstehe ich aber aller falsch :-)
Dann schaue Dir doch mal den Code der rand() Funktion im Debugger an
(F11 um in die Funktion zu steppen) und an der Stelle wo das
ldr r2, [r0, r1]
kommt schau Dir den Inhalt von r0 und r1 an. Die Summe ist interessant.
Diese sollte ja genau 20002bf8 ergeben, da sie für die indirekte
Adressierung verwendet wird.
Am Ende der rand() Funktion wird dann wieder was zurückgeschrieben mit
str r2, [r0, r1]
das müsste ja dann an der Speicherstelle 20002bf8 landen.
Bin auf Dein Ergebnis gespannt.
Das ist wirklich merkwürdig, ich hatte es ja nicht nur einmal
ausprobiert.
Hier nochmal der walkthrough mit allen Änderungen die ich gemacht habe,
und dem Ergebnis: Symbol in map hat Adresse 0x10000000, der Zugriff
findet aber auf 0x10000004 statt, siehe Summe von r0+r1.
Hallo,
was mir natürlich bei Dir auffällt ist die RAM-Adresse bei 0x10000000,
was dem CCM-RAM im STM32F4 entspricht.
Kannst Du Dein Projekt mal zippen und mir senden ?
...gerade nochmal mit der 7.10a getestet, vorher Tools -> Admin ->
"Delete all user data", dann 7.10a neu installiert, Packages erneut
runtergeladen und meine o.g. Schritte ausgeführt. Das Ergebnis ist wie
vorher, lt. map müsste der Code für rand() 0x10000000 verwenden, er
nimmt aber 0x10000004.
Hallo,
es ist ein Problem im Linker-File "STM32F4xx_Flash_CCM.icf"
Ändere Zeile 62 zu:
define block tls with fixed order { block tbss, block tdata };
Ich kann im Detail aber nicht sagen, warum es ohne "with fixed order"
nicht funktioniert. Jedenfalls wird ohne die Anweisung die Adresse
für den Block "tbss" um 4 Byten verschoben. In diesem Block sind
Variablen der Run-Time -Library abgelegt.
Programmer schrieb:> Ich kann im Detail aber nicht sagen, warum es ohne "with fixed order"> nicht funktioniert. Jedenfalls wird ohne die Anweisung die Adresse> für den Block "tbss" um 4 Byten verschoben. In diesem Block sind> Variablen der Run-Time -Library abgelegt.
Danke. Ja, das mit dem verschobenen tbss_start hatte ich auch gesehen,
dachte aber das müsste so sein. Ist aber schon sehr merkwürdig und ein
wirklich subtiler Fehler, den man erstmal ggfs. garnicht merkt und der
einem dann später auf die Füße fällt. Bin mal gespannt was im Segger
Forum dazu rauskommt.
Hallo,
ja, das ganze ist ziemlich tückisch, da ja keinerlei
Fehler-/Warnmmeldung kommt. Bei Segger hat man eben leider vergessen in
dem STM32F4 Board-Support-Package die Linker-Scripte anzupassen, nachdem
diese Erweiterung hinzukam.
Sollte Segger also auf die ToDo-Liste schreiben.