Hallo,
beim Versuch, ein funktionierendes printf für den VLE-Port zu schreiben,
bin ich auf folgendes Problem gestoßen:
Die Parameter werden alle in Registern übergeben aber va_arg greift auf
den Stack zu, was irgendwelche Werte zur Ausgabe bringt, nur nicht die
übergebenen. Das passiert auch bei -O0. Meine gegenwärtige Lösung ist
ein kleines "Scratch RAM" oberhalb des Stacks, in das ich blind eine
Anzahl von Registern per Inline-ASM schreibe und dann dort meinen
Parameter-Pointer hinsetze. Das funktioniert auch und mit einer
maximalen Anzahl von Parametern kann ich auch leben. Aber eine elegante
Lösung ist es nicht gerade.
Gibt es eine Möglichkeit, den GCC zur Parameterübergabe per Stack in
solchen Situationen zu zwingen? Oder lässt sich das irgendwie in den GCC
reinpatchen?
Jörg
Ist die Funktion beim Aufruf korrekt deklariert (mit ...)?
Dann hätte ich erwartet, daß alles in diesem Bereich eben nicht per
Register übergeben wird.
Es ergibt eigentlich kein Sinn, dass der Compiler versucht Parameter via
Register an eine Funktion mit Ellipse zu übergeben. Zeig doch einfach
mal ein kleines Beispiel.
Das aufrufende Programm packt den Pointer auf den String in R3 und die
Parameter 0x5555, 0x6666, 0x7777 in die Register R4,R5 und R6.
1
voidprintf(constchar*format,...)
2
{
3
va_listpointer;
4
unsignedcharsigned_argument;
5
value_tvalue;
6
unsignedcharmode;
7
charc;
8
inttemp;
9
10
va_start(pointer,format);
Hier wird auch format in R3 übernommen, nach va_start zeigt aber der
Pointer auf den Stack und will mit va_arg auch die Parameter vom Stack
holen, was natürlich schief geht. Ich helfe mir jetzt mit:
1
voidprintf(constchar*format,...)
2
{
3
va_listpointer;
4
unsignedcharsigned_argument;
5
value_tvalue;
6
unsignedcharmode;
7
charc;
8
inttemp;
9
10
pointer=0x40007fc0;
11
12
asmvolatile("e_lis 28,0x4000");
13
asmvolatile("e_or2i 28,0x7FC0");
14
asmvolatile("se_stw 4,0(28)");
15
asmvolatile("se_stw 5,4(28)");
16
asmvolatile("se_stw 6,8(28)");
17
asmvolatile("se_stw 7,12(28)");
18
asmvolatile("e_stw 8,16(28)");
19
asmvolatile("e_stw 9,20(28)");
20
asmvolatile("e_stw 10,24(28)");
21
asmvolatile("e_stw 11,28(28)");
wobei ich im Startup den Stack unterhalb von 0x40007FC0 initialisiere.
Ab dieser Stelle kann ich mir dann auch die Parameter mittels
va_arg(pointer,xxx) holen, halt maximal 8 Stück (sofern man keine
Doubles nutzt).
Jörg
Ja, den kennt es, wenn ich den Prototypen im Header auskommentiere,
bekomme ich die übliche "implicit declaration..." Warnung.
Der Compiler ist ein 4.8.0 mit diversen Patches aus dem Internet, ein
offizielles Release für PowerPC it VLE habe ich nirgendwo gefunden.
Ähnliche Probleme hatte ich auch beim Renesas 78K0R und beim Freescale
S12X. Um den konstanten Format-String NUR im Flash zu haben, scheinen
auf den meisten Plattformen irgendwelche "Verrenkungen" notwendig zu
sein.
Ziel ist eine Bibliothek, die auf allen möglichen Plattformen das selbe
oder zmindest nachvollziehbar ähnliches Verhalten zeigt, der folgende
Codeausschnitt ist nur ein Beispiel:
Viele Compiler versuchen, zu optimieren und nicht alles stur über
Pointer zu übergeben. Speziell bei RISC kann ja nicht direkt im RAM
gerechnet werden, sondern muß erstmal in Register zurück geladen werden.
Oft landen daher die ersten 3 Argumente direkt in Registern und nur
darüber wird ein Pointer bemüht.
Das printf der Standard-Lib des Compilers weiß das und verhält sich
entsprechend.
_cdecl kennt der Compiler nicht und __attribute__((stdcall)) behebt das
Problem auch nicht. Es funktioniert ja so, anders wäre es mir aber
lieber gewesen.
Eine Standard-Lib gibt es nicht, da es bis dato noch nicht einmal ein
funktionierendes Compiler-Binary zum Download gab. Mein printf ist eine
Variante, die für die Ausgabe einen Funktionspointer nutzt. Damit kann
ich dieselben Routinen für UART, SPI, Speicher (Strings), LCD, Video
etc. verwenden.
Jörg
Die stdarg.h ist vom SDCC, vielleicht ist das das Problem. Aber damit
war es mir immerhin möglich, Funktionen plattformübergreifend zu
implementieren.
>Und die Autoren wissen was sie tun?
Welche Autoren? Wie ich schon weiter oben geschrieben habe, habe ich
keinen fertigen GCC für diese Architektur (Powerpc-VLE) gefunden. Anhand
von Patches von u.a. James Lemke sowie zig SVN checkouts habe ich mir
dann einen funktionierenden Compiler selbst "zusammengebaut". Damit habe
ich allerdings kein lauffähiges Programm zusammenbekommen. Also: zuerst
eigenes Startupfile mit den notwendigen Initialisierungen in ASM
erstellt und mit -nostartfiles dazugelinkt. Und so habe ich mich Schritt
für Schritt "vorgetastet".
Jörg
Joerg Wolfram schrieb:> Die stdarg.h ist vom SDCC, vielleicht ist das das Problem.
aber ganz bestimmt. Nimm das, das zu deinem Compiler paßt und alles ist
gut.
Joerg Wolfram schrieb:> Johann L. schrieb:>>Und die Autoren wissen was sie tun?>> Welche Autoren?
Die Autoren der entsprechenden Patches bzw. der entsprechenden
Erweiterungen des Compilers und der Bibliotheken und was sonst noch
alles dazu gehört und benötigt wird.
> einen funktionierenden Compiler selbst "zusammengebaut"
Was sagen denn die Ergebnisse der Testsuite? Da werden ja auch
variadische Funktionen getestet. Wenn du das halbwegs ernsthaft
betreibst und dich entschieden hast einen entsprechenden GCC-Port zu
maintainen (auch wenn nur für dich selbst) gehört Testing ja definitiv
dazu.
Oder ist es lediglich ein Hobbyprojekt?
> Die stdarg.h ist vom SDCC
stdarg.h ist hoch gradig System- und ABI-abhängig. Du kannst nicht
erwarten dass die generisch für alle Compiler / ABIs funktioniert.
Also vielen Dank für die Hinweise, mit der stdarg.h vom GCC hat es dann
funktioniert. Das werde ich demnächst auch bei den anderen
Nicht-SDCC-Plattformen ausprobieren.
Das Ganze ist nur ein Hobbyprojekt und ein bisschen "Denkübung". Ziel
ist eine Art "Universalbibliothek", mit der man auch I/O lastige
Anwendungen problemlos und ohne größeren Aufwand zwischen verschiedenen
Mikrocontrollerplattformen (momentan:10) portieren kann. Dazu gehören
Clock-Einstellungen, IO-Ports, UART, SPI, ADC, PWM, effizientes
Fliesskomma... Einen Teil davon schreibe ich in ASM, dafür mache ich
dann auch Tests.
Vor einiger Zeit habe ich im Forum nachgefragt, ob Interesse an so einer
Lösung besteht, aber nur eine einzige Antwort bekommen. Von daher habe
ich erstmal von einer Veröffentlichung abgesehen.
Jörg