Forum: Compiler & IDEs aligned_alloc in gcc für ARM


von J. S. (jojos)


Lesenswert?

Das aligned_alloc() liefert einen undefined Fehler im gcc Linker, es 
sollte seit C11 unterstützt sein: 
https://en.cppreference.com/w/c/memory/aligned_alloc
Warum ist es im arm-eabi-none noch nicht drin? Das (veraltete?) 
memalign() gibt es und tut es auch, ist aber doch irgendwie unschön weil 
nicht portabel?

von Daniel (Gast)


Lesenswert?

Da wird nicht vom Compiler bereitgestellt, sondern von der C-Bibliothek. 
Welche benutzt du? Glibc (seit 2.16)? Musl (seit 0.9.5)? Newlib (seit 
2.3.0)? ...

Es hängt auch davon ab ob du mit -std=c11 (oder neuer) baust, ob die 
Header die Funktion deklarieren. Das Fehlen der Deklaration sollte aber 
keinen Linkerfehler hervorrufen, außer du baust in Wirklichkeit C++ 
Code.

von J. S. (jojos)


Lesenswert?

Daniel schrieb:
> außer du baust in Wirklichkeit C++
> Code.

doch, das schon, es ist ein .cpp Modul. Aber warum soll das einen 
Unterschied machen, im header ist die Funktion vorhanden, sonst hätte 
der Compiler ja schon gemeckert.
Newlib-nano oder Newlib, die Version muss ich nochmal kontrollieren. War 
gcc 10.irgendwas

von Daniel (Gast)


Lesenswert?

Hätte ja sein können, dass du dir selbst eine Deklaration gebastelt 
hast, bei der dann das extern "C" fehlt. Dann stimmt der Symbolname bei 
Linken nicht.

Wie gesagt, hat nix mit der Version von GCC zu tun.

von J. S. (jojos)


Lesenswert?

aber ich installiere ja keine *lib getrennt, die wird mit der Toolchain 
installiert die mit der jeweiligen gcc Version kommt. Es geht um ARM 
embedded, arm-eabi-none für die Cortex-M.

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


Lesenswert?

J. S. schrieb:
> die wird mit der Toolchain installiert die mit der jeweiligen gcc
> Version kommt

GCC pflegt keine Bibliotheken. Der verlässt sich nur darauf, dass die 
mit ihm ausgelieferten Bibliotheken sich entsprechend dem Standard 
verhalten.

Insofern gibt es nicht "die Toolchain", die mit dem GCC ausgeliefert 
wird. Du musst schon Ross und Reiter benennen.

von J. S. (jojos)


Lesenswert?

na das was man von arm developer als toolchan runterlädt,
ich habe noch die Version gcc-arm-none-eabi-10-2020-q4-major-win32.zip
Dann probiere ich es mal mit einer neueren Version.

Aber ARM schreibt auch dazu:
1
6.5.5 Alignment of C heap storage
2
The standard C allocation functions C99 (7.20.3), such as malloc(), return storage aligned to the normal maximal
3
alignment, i.e. the largest alignment of any (standard) type.
4
Implementations may, but are not required to, provide a function to return heap storage of greater alignment. Suitable
5
functions are:
6
int posix_memalign(void **memptr, size_t alignment, size_t size );
7
as defined in POSIX, or:
8
void *aligned_alloc(size_t alignment, size_t size);
9
as defined in C11 (7.22.3.1)

also alles kann, nix muss?

: Bearbeitet durch User
von piffpoff (Gast)


Lesenswert?

Erstmal kannst du dich ja generell nicht auf den C standard berufen wenn 
du C++ schreibst. Da kannst du dich genau so gut auf einen Java standard 
oder so berufen.

Wenn du C++ schreibst ist der von dir gewählte C++ standard relevant 
also:
 *C++98
 *C++03
 *C++11
 *C++14
 *C++17
 *C++20

Wenn du C schreibst der entsprechende C standard:
 *C89
 *C90
 *C95
 *C99
 *C11
 *C17

Wenn du Annahmen aus c in c++ triffst und andersrum, dann wirst du oft 
solche Probleme haben... Wenn du willst dass sich alles genau so wie im 
C11 Standard verhält, dann solltest du das explizit mit angeben also 
-std=c11, aber das hat natürlich nicht zwingend den gewünschten effekt 
wenn du c++ schreibst.

von Daniel (Gast)


Lesenswert?

Das was ARM als gcc-arm-none-eabi-10-2020-q4-major-win32.zip zum 
Download anbietet ist eine von ARM zusammengestellte Kombination aus

 - gcc 10.2.1
 - binutils 2.34.1
 - gdb 10.1.90
 - newlib 3.3.0

Es ist die Aufgabe von newlib sowohl den Header als auch die Library für 
aligned_alloc bereitzustellen.

Alle 132 libc.a, libg.a, libc_nano.a und libg_nano.a Libraries in dem 
Paket enthalten eine Implementation von aligned_alloc. Mit welcher 
Kommandozeile linkst du und wie lautet die genaue Fehlermeldung?

von Programmierer (Gast)


Lesenswert?

Wenn du schon C++ benutzt, warum dann nicht den C++ Mechanismus für 
Alignment?

https://en.cppreference.com/w/cpp/types/aligned_storage

von J. S. (jojos)


Lesenswert?

Daniel schrieb:
> Paket enthalten eine Implementation von aligned_alloc.

ja, es wurde auch nicht genau aligned_alloc angemeckert, sondern das 
benutzt posix_memalign und das fehlte.

Ich compiliere mit gnu++17 oder c++17, im C++17 ist aligned_alloc 
übernommen worden.

Habe jetzt die aktuelle Version gcc 10.3.1 installiert, damit 
funktioniert es ohne weitere Änderungen.
In C++ sollte allerdings aligned_alloc im std namespace liegen, aber 
wenn ich std::aligned_alloc() aufrufe, dann gibts Mecker das es nicht im 
std namespace gefunden wird.

Programmierer schrieb:
> Wenn du schon C++ benutzt, warum dann nicht den C++ Mechanismus für
> Alignment?

schon wieder veraltet:
(deprecated in C++23)

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Naja, posix_memalign ist Bestandteil des gesamten malloc-Pakets.
1
       The posix_memalign() function allocates size bytes of memory such that
2
       the allocation's base address is a multiple of alignment, and returns
3
       the allocation in the value pointed to by ptr. The requested alignment
4
       must be a power of 2 at least as large as sizeof(void *).

Das Backend für malloc muss man in der newlib eh selbst implementieren 
(sbrk).

Warum sie aber dann für posix_memalign keine Implementierung haben, ist 
verwunderlich. Müsstest du schauen, wie du etwas bauen kannst, das zu 
dem passt, was da schon als malloc-Implementierung drin ist.

von Mombert H. (mh_mh)


Lesenswert?

J. S. schrieb:
> Daniel schrieb:
>> Paket enthalten eine Implementation von aligned_alloc.
> ja, es wurde auch nicht genau aligned_alloc angemeckert, sondern das
> benutzt posix_memalign und das fehlte.
Willst du uns vielleicht noch etwas mitteilen?

von Rolf M. (rmagnus)


Lesenswert?

J. S. schrieb:
> aber ich installiere ja keine *lib getrennt, die wird mit der Toolchain
> installiert die mit der jeweiligen gcc Version kommt.

Umgekehrt: gcc kommt als Teil der installierten Toolchain. Die 
Standard-Bibliothek auch. Es gibt auch keinen:

J. S. schrieb:
> gcc Linker

denn der Linker ist ein weiterer Teil der Toolchain, aber nicht des 
Compilers.

von J. S. (jojos)


Lesenswert?

Ich bin das Problem nochmal angegangen weil ich mit dem F7 Disco meine 
Heizungsüberwachung bauen möchte.
Auf dem Disco F769 verhielt sich Ethernet anders duch einen Fehler in 
der Chip Rev. A, zum Test habe ich das Programm dann auf das Disco F746 
portiert. Das hat diesen Fehler nicht, zickt jetzt aber bei 
aligned_alloc.
Beim gcc 10.2 war die Funktion nicht passend für µC implementiert, 
danach wurde die Funktion geändert und verwendet jetzt intern 
_memalign_r() statt posix_align().
Ich habe jetzt die neuere gcc 11.3.1 installiert, mit newlib von 
2022/08. Damit liefert aligned_alloc einen hardfault. Mit gcc 10.3.1 
funktioniert es, auf dem F769 funktioniert es mit beiden gcc Versionen. 
Was kann da faul sein?
Den Code der newlib habe ich heruntergeladen, der ist sehr mühselig zu 
lesen, die Funktionen werden per define hin und her umbenannt.

Mein Testcode:
1
#include "mbed.h"
2
3
DigitalOut led(LED1);
4
5
int main()
6
{
7
    size_t size = 1024;
8
9
    void *p1 = malloc(size);
10
    printf("pointer p1: %p\n", p1);
11
    fflush(stdout);
12
13
    void *p2 = aligned_alloc(32, size);
14
    printf("pointer p2: %p\n", p2);
15
    fflush(stdout);
16
17
18
    while(true) {
19
        led = !led;
20
        ThisThread::sleep_for(1s);
21
    }
22
    return 0;
23
}

Speicher ist satt vorhanden, das malloc funktioniert, das aligned_alloc 
führt zum hardfault mit Crashdump:
1
pointer p1: 0x200030d8
2
3
++ MbedOS Fault Handler ++
4
5
FaultType: HardFault
6
7
Context:
8
R0   : 00000000
9
R1   : FEADF7DC
10
R2   : 00000028
11
R3   : DEADBEC5
12
R4   : 00000020
13
R5   : 00000408
14
R6   : 200038F8
15
R7   : 20000A10
16
R8   : 20003918
17
R9   : 00000000
18
R10  : 00000000
19
R11  : 00000000
20
R12  : 08006D1D
21
SP   : 20002E70
22
LR   : 08007C17
23
PC   : 08008938
24
xPSR : A10F0000
25
PSP  : 20002E08
26
MSP  : 2004FFC0
27
CPUID: 410FC271
28
HFSR : 40000000
29
MMFSR: 00000000
30
BFSR : 00000082
31
UFSR : 00000000
32
DFSR : 00000000
33
AFSR : 00000000
34
BFAR : FEADF7E0
35
Mode : Thread
36
Priv : Privileged
37
Stack: PSP
38
39
-- MbedOS Fault Handler --
40
41
42
43
++ MbedOS Error Info ++
44
Error Status: 0x80FF013D Code: 317 Module: 255
45
Error Message: Fault exception
46
Location: 0x8008938
47
Error Value: 0x20001130
48
Current Thread: main Id: 0x20002ECC Entry: 0x8007C71 StackSize: 0x1000 StackMem: 0x20001EA8 SP: 0x20002E70 
49
For more info, visit: https://mbed.com/s/error?error=0x80FF013D&osver=61600&core=0x410FC271&comp=2&ver=110300&tgt=DISCO_F746NG
50
-- MbedOS Error Info --

: Bearbeitet durch User
von Nop (Gast)


Lesenswert?

Nimm doch einfach das normale alloc, das ist ausreichend aligned für 
alle Standard-Typen.

von J. S. (jojos)


Lesenswert?

Die Cache Lines vom F7 möchten 32 Byte Alignment haben.

von Nop (Gast)


Lesenswert?

J. S. schrieb:
> Die Cache Lines vom F7 möchten 32 Byte Alignment haben.

Interessanter Punkt, wußte ich noch gar nicht. Und da Du Ethernet 
erwähntest, wird das dynamische Speichermanagement wohl für die 
IP-Pakete sein, die erst zur Laufzeit anfallen, weswegen die sonst 
übliche statische Allokation nicht so einfach wäre.

Aber ob das Cache-Alignment da wirklich der Flaschenhals einer 
Heizungssteuerung wird, zumal Du ohnehin die Line-Grenzen 
überschreitest, sobald mehr als 32 Bytes im Paket sind? IP alleine hat 
ja schon 20 Bytes, plus nochmal 20 für TCP oder 8 für UDP.

von J. S. (jojos)


Lesenswert?

Der crash jetzt ist im FatFS passiert, da wird ein Buffer angelegt der 
für das Lesen/Schreiben einiger Sektoren per DMA benutzt wird. Das 
Filesystem kann man mehrfach instanziieren, deshalb ist der Buffer da 
per malloc drin. Für den Cache mit den 32 Byte lines sollte der eben 
auch 32 Byte aligned sein, beim Cache clean kann sonst benachbarter 
Speicher überschrieben werden. Ist schon eine komplizierte Kiste.

Jetzt habe ich es nochmal für den F769 übersetzt und da gibts nun auch 
einen Hardfault. Hmmm.... Alignment 16 und andere size beim alloc habe 
ich auch probiert, gleicher Fehler.

von Nop (Gast)


Lesenswert?

Oha. Macht das FS auch einen free() auf den Buffer? Wenn nicht, könntest 
Du ja rein zum Testen einen alloc-wrapper machen, der 32 Byte mehr 
alloziert und den ersten Pointer mit 32er-Alignment zurückgibt. free() 
geht darauf dann natürlich nicht, aber es wäre immerhin klar, daß es al 
Alignment liegt.

von J. S. (jojos)


Lesenswert?

Ich kann den Fehler ja mit dem minimal Programm reproduzieren, deshalb 
ist mir die Anwendung von aligned_alloc jetzt erstmal egal. Wenn es die 
Funktion gibt, dann soll die auch funktionieren.
So workarounds für aligned_alloc hatte ich schon probiert und war 
glücklich das es eine Funktion im Standard gibt. Nur scheint es mit der 
Implementierung zu hapern. In der newlib ist die jetzt drin, Keil hat 
eine eigene Lib und kennt die immer noch nicht.

: Bearbeitet durch User
von J. S. (jojos)


Lesenswert?

Die newlib ist unschuldig wie es aussieht, Mbed hat eine Statistik für 
malloc und die kommt durcheinander wenn memalign/aligned_alloc die 
Adresse des Blocks vom heap manipulieren.
Schöner Fehler...

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.