Forum: Compiler & IDEs [ARM] Nützliches newlib-nano float printf


von Lukas K. (carrotindustries)


Lesenswert?

Hallo Zusammen,

mal ausnahmsweise keine Frage, sondern (hoffentlich) nützliche Hinweise 
Leute, die vor ähnlichem Problem stehen: Auf dicken µCs, wie den STM32 
kann man sich ja durchaus Dinge wie printf gönnen, auch für floats.

Wie zu erwarten tut's mit den notwendigen Linker-Optionen -u 
_printf_float --specs=nano.specs -lnosys nicht auf anhieb. Aus der 
mapfile geht hervor, dass sprintf aus der 'normalen' libc kommt, nicht 
aus der 'nano'.
Lösung: GROUP(-lc_nano) im Linkerscript angeben (Quelle: Google). Jetzt 
wird immerhin _printf_float aufgerufen, aber sprintf schreibt immer noch 
0.000 in den Buffer.

Reichlich debuggen (inkl. neu bauen von der newlib mit debug-symbolen) 
hat dann gezeigt, dass die Übergabe von double mit vararg nicht 
funktioniert (kommt immer 0 raus).
Lösung: Damit double (8byte lang) (variadisch?) übergeben werden kann, 
muss der Stack auf 8bytes aligned sein (Quelle: Google). Floats in 
varargs werden automatisch zu double befördert. In dem Linkerscript von 
Atollic Truestudio, das den Beispielen von ST beiliegt, wird der Stack 
an die Adresse 0x2001FFFF gelegt, was natürlich kein ganzzahliges 
Vielfaches von 8 ist. Mit 0x2001FFF8 als Stack-anfang/ende tut nun 
printf für floats.

Vielleicht findet's wer und spart sich langwieriges debuggen...

Lukas

von Jim M. (turboj)


Lesenswert?

Lukas K. schrieb:
> In dem Linkerscript von
> Atollic Truestudio, das den Beispielen von ST beiliegt, wird der Stack
> an die Adresse 0x2001FFFF gelegt, was natürlich kein ganzzahliges
> Vielfaches von 8 ist.

Schick das mal als Bugreport an den Hersteller. Das würde nicht nur bei 
Floats Probleme machen: Der GCC generiert auch schon mal LDRD Befehle 
wenn er 64 Bits auf einmal laden kann. Diese Instruktion besteht auf 
Alignment, anders als da normale LDR (wo das von einem normalerweise 
nicht gesetztem Bit anhängt).

von Schaulus Tiger (Gast)


Lesenswert?

Jim Meba schrieb:

> Der GCC generiert auch schon mal LDRD Befehle wenn er 64 Bits
> auf einmal laden kann. Diese Instruktion besteht auf Alignment,
> anders als da normale LDR (wo das von einem normalerweise
> nicht gesetztem Bit anhängt).

Lukas K. schrieb:

> Mit 0x2001FFF8 als Stack-anfang/ende tut nun printf für floats.

Bist du sicher? Hängt das nicht auch von so einem Bit ab?

Damit er 64-Bit aligned bleibt, muss er ja bei jedem push usw. bei 
Bedarf justiert werden. Das kostet RAM und ist deshalb bestimmt 
abschaltbar. Ich fürchte, der Default nach Reset ist von Chip zu Chip 
unterschiedlich.

von Karl H. (kbuchegg)


Lesenswert?

Lukas K. schrieb:

> Lösung: Damit double (8byte lang) (variadisch?) übergeben werden kann,
> muss der Stack auf 8bytes aligned sein (Quelle: Google). Floats in
> varargs werden automatisch zu double befördert. In dem Linkerscript von
> Atollic Truestudio, das den Beispielen von ST beiliegt, wird der Stack
> an die Adresse 0x2001FFFF gelegt, was natürlich kein ganzzahliges
> Vielfaches von 8 ist. Mit 0x2001FFF8 als Stack-anfang/ende tut nun
> printf für floats.

Zwischenfrage, weil es mich interessiert.

Was ist, wenn du printf nicht mit einem lausigen double alleine 
aufrufst, sondern da auch noch andere Dinge über den Stack wandern. Dann 
muss doch das Alignment immer noch garantiert sein. Ich sehe nicht, wie 
die Stackstartadresse in diesem Fall das Problem beheben könnte. Ein 
Missalignment ist doch dann unausweichlich.

: Bearbeitet durch User
von Lukas K. (carrotindustries)


Lesenswert?

Karl Heinz schrieb:
> Ich sehe nicht, wie
> die Stackstartadresse in diesem Fall das Problem beheben könnte. Ein
> Missalignment ist doch dann unausweichlich.

Ohne das Problem jetzt nähers angesehen zu haben, meine Vermutung: Der 
GCC geht von einem 8byte-aligned Stack aus und fügt dann bei Bedarf 
4bytes padding ein. Wenn der Stack nicht aligned ist, führt das eben 
nicht zum gewünschten Ergebnis.

Jim Meba schrieb:
> Schick das mal als Bugreport an den Hersteller
Atollic gibt nur Support für zahlende Kunden, ein solcher bin ich 
nicht...

von Roland H. (batchman)


Lesenswert?

Lukas K. schrieb:
> Mit 0x2001FFF8 als Stack-anfang/ende tut nun printf für floats.
> Vielleicht findet's wer und spart sich langwieriges debuggen..

Danke! Habs vor ein paar Tagen beiseite geschoben, aber so klappts!

Karl Heinz schrieb:
> Dann muss doch das Alignment immer noch garantiert sein. Ich sehe nicht, wie
> die Stackstartadresse in diesem Fall das Problem beheben könnte. Ein
> Missalignment ist doch dann unausweichlich.

Aus dem "reference manual": "Because the SP ignores writes to bits 
[1:0], it is autoaligned to a word, four-byte boundary."

Schaulus Tiger schrieb:
> Damit er 64-Bit aligned bleibt, muss er ja bei jedem push usw. bei
> Bedarf justiert werden.

Noch ein Zitat: "The Application Binary Interface (ABI) for the ARM 
architecture requires that the stack must be eight-byte aligned on all 
external interfaces, such as calls between functions in different
source files. However, code does not need to maintain eight-byte stack 
alignment internally, for example in leaf functions."

Schaulus Tiger schrieb:
> Hängt das nicht auch von so einem Bit ab?

Meinst Du das STKALIGN bit? Das gilt nur beim Auftreten einer Exception, 
und dann wird aus "four-byte" wieder "eight-byte alignment", so dass es 
im "fault handler" wieder passt.

von Gahlen F. (gahlenfeld)


Lesenswert?

Danke, danke, danke !!!
Ich bin eigentlich baff, dass dies funktioniert!

Ich habe den ganzen lieben langen Tag vor diesem Problem gesessen und 
alles mögliche untersucht, aber erst Dein Beitrag hat die Lösung 
gebracht!
Ich habe nur den Stack auf 8 aligned, mehr nicht.

Viele Grüße, Gahlen

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.