Nur das auf d15 noch Daten vom Compiler abgelegt sind, welche noch
gebraucht werden. Wie schreibe ich das richtig?
Ich dachte, wenn es zu so einer zusätzlichen Register Nutzung im
Extended Assembler kommt, wird das entsprechende Register automatisch
gesichert?
Stecke nicht so ganz in dem Intermixing drin … wenn ich mal Assembler
mache, dann in der Regel direkt in einer Assembler Datei.
Danke schon mal für jedwede Aufklärung!
__asm("mov %%d4, %0" : : "d" (parameter)); /* C variable
2
> parameter */
>> Produziert:>
1
mov %d15, -1
2
> mov %d4, %d15
Nö, das asm produziert nur eine Instruktion, nämlich "mov %d4, ...".
Die -1 in D15 wird aus irgend einem anderen Grund geladen; der Grund ist
aus dem unvollständigen Beispiel jedoch nicht ersichtlich. Welche
Instruktionen vom asm erzeugt werden und welche nicht ist im .s-File
ersichtlich, erzeigt z.B. oer -save-temps.
> Nur das auf d15 noch Daten vom Compiler abgelegt sind, welche noch> gebraucht werden. Wie schreibe ich das richtig?
Auf D15 wird nur lesend zugegriffen, es muss also nicht gesichert
werden: Nach dem asm enthält es immer noch -1 bzw 255. Dass D4
verändert wird muss dem Compiler hingegen mitgeteilt werden, entweder
durch Verwenden eines benanntes Register oder indem D4 zu den Clobbers
hinzugenommen wird.
> Ich dachte, wenn es zu so einer zusätzlichen Register Nutzung im> Extended Assembler kommt, wird das entsprechende Register automatisch> gesichert?
Ich verstehe nicht was mit "zusätzlicher" Registernutzung gemeint ist.
Alle Register müssen entweder durch Constraints oder Clobbers
beschrieben sein oder sie müssen fixed sein, d.h. nicht vom
Register-Allokator verwaltet.
squierrel schrieb:> Oder ist das ein gcc Fehler?
Mit 99.999% Wahrscheinlichkeit: Nein. Aufgrund des unvollständigen
Testfalls ist keine Aussage möglich.
> Gab es nicht auch mal beim AVR gcc das Problem, dass r0 nicht> wieder genullt wurde obwohl in der Clobber Liste definiert?
R0 und R1 sind bei avr-gcc Fixed Register, d.h. sie werden implizit
verwendet und nicht vom Register-Allokator verwaltet. Es ist also
kein Problem des Compilers sondern ergibt sich aus dem ABI:
http://gcc.gnu.org/wiki/avr-gcc#Register_Layout
Der Schnipsel ist nicht von mir muss ich noch dazusagen, … und war nur
ein schnell gehackter Code von einem Zulieferer, der mit weiteren
Fehlern für die Verwendung hier behaftet ist. Alle anderen Probleme die
Auftreten sind mir klar, aber das mit dem mov %d15, -1 verwunder mich
doch. Die C-Variablen Namen habe ich abgeändert, damit der Zulieferer
nicht erkennbar ist.
Jetzt noch der Assembler Code aus dem objectfile:
squierrel schrieb:> Das korrekte *.s welches jetzt auch oben zu den Ausgaben passt.
Passt immer noch nicht zum gezeigten asm, das z.B. kein LDLCX enthält.
Aber egal, das nicht gezeigte asm enthält wahrscheinlich nicht weniger
Fehler als das obige. Als da wären:
Problem #1: Das asm muss als ein asm Statement formuliert werden, denn
ansonsten kann der Compiler beliebig viele Instruktionen zwischen die
einzelnen asm bauen wie er eben braucht. Ein Beispiel für eine solche
eingestreute Instruktion ist "mov %d15,-1": Der Compiler beendet die
vorherigen asms mit #NO_APP, fügt dann Instruktion(en) ein und fährt
dann mit #APP fort.
Problem #2: Effekt der asm auf Register oder Speicher wird nicht
beschrieben. Zum Beispiel zerstört "mov.a %%a6,%0" den Inhalt von A6.
Falls der Compiler einen Wert in dem Register hält wird dieser zerstört.
I.d.R. sollte dem Compiler die Wahl der Register überlassen werden, also
z.B:
1
inttmp;
2
__asmvolatile("stlcx [%1]0""\n\t"
3
"...""\n\t"
4
"mov.d %0,%a11""\n\t"
5
"add %0,%0,12""\n\t"
6
"st.w [%1]4,%0"
7
:"=&d"(tmp)
8
:"a"(&s_p->pContext->contextFrame.LowerCtx)
9
:"memory");
Falls wie hier eine ABI mit bestimmten Registern involviert ist, kann
man benannte lokale Register verwenden oder man muss die Register zu den
Clobbers hinzunehmen:
1
inttmpregisterasm("d2");
2
__asmvolatile("stlcx [%%a6]0""\n\t"
3
"...""\n\t"
4
"mov.d %0,%a11""\n\t"
5
"add %0,%0,12""\n\t"
6
"st.w [%%a6]4,%0"
7
:"=d"(tmp)::"a6","memory");
Problem #3: Speicher wird verändert, daher muss "memory" zu den
Clobbers.
Problem #4: Das asm ist volatile, siehe mein Beispiel.
Problem #5: Es wird der Kontext der Funktion geändert, evtl. muss die
Funktion, in dem der Code verwendet wird, also Attribut "noinline"
bekommen (und evtl. das Modul -fno-inline-functions-unsed-once). Bei
Inlining wird ansonsten auf den Kontext des Callers bezogen.
Problem #6: Um Wartbarkeit und Lesbarkeit zu verbessern, SFR-Bezeichner
wie $PSW verwenden statt 0xFE04.
Hallo Johann,
hätte ich doch nochmal reingeschaut, dass mit den SFR Bezeichnern war
jetzt noch meine letzte Nachträgliche Änderung.
Den alten Code habe ich komplett entsorgt.
Aber noch Danke fürs reinschauen.
So, etwas wirr zusammengeschrieben:
Das d15 Problem kam daher, das von Funktion x mal eben in Funktion y
gesprungen wurde. Was aus meinen Schnipseln so nicht wirklich zu
erkennen war. In Funktion sagen wir y wurde d15 natürlich nicht
verwendet und mit -1 für Funktion x verfälscht. Das ist alles im Test
passiert. Im Standardablauf existiert das Verhalten so nur im Fehlerfall
(mit dem Funktionswechsel) … macht die Sache jetzt nicht unbedingt
besser. Zudem wird im Original d15 nicht verwendet -> normalerweise hat
alles richtig funktioniert und es hat sich niemand mehr darum gekümmert.
Aber schön das dieser Zulieferer Hack (finale korrekte Implementierung
war klar unsere Aufgabe), so lange unentdeckt im Code geschlummert hat.