Segger Embedded Studio: Memory (map) problem

OP #7302519
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?

Angehängte Dateien:
Gast #7303307
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

OP #7303393
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.

Gast #7303512
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.

OP #7303656
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...

OP #7303687
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.

Gast #7305483
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 ?

OP #7305535
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.

Gast #7305726
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 :-)

Angehängte Dateien:
OP #7306007
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.

OP #7306371
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.

OP #7306793
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.

Gast #7306924
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.

OP #7307291
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.

Gast #7307379
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.

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