Forum: Compiler & IDEs Segger Embedded Studio: Memory (map) problem


von Markus M. (adrock)


Angehängte Dateien:

Lesenswert?

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
int main(void) {
6
  int i;
7
  int r;
8
9
  static char some_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:
1
 10000000-10000003  __SEGGER_RTL_rand_next              4   4  Init  RW  intops.o (libc_v7em_fpv4_sp_d16_hard_t_le_eabi_balanced.a)
2
  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?

: Bearbeitet durch User
von olaf (Gast)


Lesenswert?

> 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

von Markus M. (adrock)


Lesenswert?

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.

: Bearbeitet durch User
von Nop (Gast)


Lesenswert?

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.

von Markus M. (adrock)



Lesenswert?

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...

: Bearbeitet durch User
von Markus M. (adrock)


Lesenswert?

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.

: Bearbeitet durch User
von Programmer (Gast)


Lesenswert?

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 ?

von Markus M. (adrock)


Lesenswert?

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.

: Bearbeitet durch User
von Programmer (Gast)


Angehängte Dateien:

Lesenswert?

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 :-)

von Markus M. (adrock)


Lesenswert?

Ja, bei mir sieht im map File auch alles gut aus.
1
 20002bf8-20002bfb  __SEGGER_RTL_rand_next              4   4  Init  RW  intops.o (libc_v7em_t_le_eabi_balanced.a)

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.

: Bearbeitet durch User
von Programmer (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

habs mir im Detail nochmal angeschaut und es ist absolut perfekt :-)
Habe Dir den Screenshot anghängt.

von Markus M. (adrock)



Lesenswert?

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.

von Programmer (Gast)


Lesenswert?

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 ?

von Markus M. (adrock)


Angehängte Dateien:

Lesenswert?

Hier mal das Projekt, im "output" Ordner habe ich mal alles gelöscht.

von Markus M. (adrock)


Lesenswert?

...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.

von Programmer (Gast)


Lesenswert?

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.

von Markus M. (adrock)


Lesenswert?

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.

: Bearbeitet durch User
von Programmer (Gast)


Lesenswert?

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.

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.