Ich arbeite an einem benutzerdefinierten Betriebssystem für einen ARM Cortex-M3-Prozessor. Um mit meinem Kernel zu interagieren, müssen Benutzer-Threads einen SuperVisor Call (SVC) -Befehl erzeugen (früher bekannt als SWI, für SoftWare Interrupt). Die Definition dieser Anweisung im ARM ARM lautet:
Dies bedeutet, dass die Anweisung ein sofortiges Argument und keinen Registerwert erfordert.
Dies erschwert es mir, meine Oberfläche lesbar zu gestalten. Es erfordert Code wie:
%Vor%wenn ich etwas lieber bevorzuge
%Vor%Ich bin jedoch nicht in der Lage, diese Funktion zu konstruieren, weil die SVC-Anweisung ein unmittelbares Argument benötigt und ich kann das nicht liefern, wenn der Wert über ein Register übergeben wird.
Für Hintergrund wird der SVC-Befehl wie folgt im Kernel decodiert:
%Vor%Diese Fallaussage gerät schnell außer Kontrolle, aber ich sehe kein Problem. Irgendwelche Vorschläge sind willkommen.
Ich habe zuerst überlegt
%Vor%aber das funktioniert natürlich nicht, da SVC ein Registerargument benötigt.
Der Brute-Force-Versuch, das Problem zu lösen, sieht so aus:
%Vor%aber das hat einen üblen Code-Geruch. Sicherlich kann das besser gemacht werden.
Ein letzter Versuch bestand darin, die Anweisung im RAM zu generieren (der Rest des Codes läuft von einem schreibgeschützten Flash) und dann auszuführen:
%Vor%aber das fühlt sich einfach nicht richtig an. Außerdem funktioniert es nicht - da ist etwas, was ich hier falsch mache; vielleicht ist meine Instruktion nicht richtig ausgerichtet oder ich habe den Prozessor nicht eingerichtet, um Code aus dem RAM an dieser Stelle laufen zu lassen.
Ich muss an der letzten Option arbeiten. Trotzdem fühlt es sich so an, als müsste ich etwas tun können wie:
%Vor%aber ich finde keine solche Option in der Dokumentation und ich kann nicht erklären, wie ein solches Feature implementiert werden würde, also existiert es wahrscheinlich nicht. Wie soll ich das machen?
Sie möchten eine Integritätsbedingung verwenden, um zu erzwingen, dass der Operand als 8-Bit-Sofortwert zugewiesen wird. Für ARM ist das die Einschränkung I
. Du willst also
In der GCC-Dokumentation finden Sie eine Zusammenfassung dessen, was alle Constaints sind - Sie müssen sich die prozessorspezifischen Notizen ansehen, um die Einschränkungen für bestimmte Plattformen zu sehen. In einigen Fällen müssen Sie möglicherweise die Datei " .md
" (Maschinenbeschreibung) für die Architektur in der gcc-Quelle nachsehen, um weitere Informationen zu erhalten.
Es gibt auch einige gute ARM-spezifische GCC-Dokumente hier . Ein paar Seiten weiter unten unter der Überschrift "Eingabe- und Ausgabeoperanden" gibt es eine Tabelle aller ARM-Einschränkungen
Wie von Chris Dodd in den Kommentaren zu dem Makro bemerkt, funktioniert es nicht ganz, aber das tut:
%Vor%Beachten Sie jedoch, dass es nicht funktioniert, wenn Sie ihm einen Aufzählungswert übergeben, nur einen #definierten Wert.
Daher ist die obige Antwort von Chris die beste, da sie einen unmittelbaren Wert verwendet, der für Daumenanweisungen mindestens erforderlich ist.
Meine Lösung ("Befehlscodierung während des Betriebs generieren"):
%Vor%Es funktioniert und es ist viel besser als Switch-Case-Variante, die ~ 2kb ROM für 256 svc dauert. Diese Funktion muss nicht in den RAM-Bereich gestellt werden, FLASH ist in Ordnung. Sie können es verwenden, wenn svc_num eine Laufzeitvariable sein soll.
Wie in besprochen Diese Frage, der Operand von SVC
ist fest, das heißt, er sollte dem Präprozessor bekannt sein und unterscheidet sich von unmittelbaren Datenverarbeitungsoperanden.
Das gcc-Handbuch liest
'I'- Integer, das als unmittelbarer Operand in einer Datenverarbeitungsinstruktion gilt. Das heißt, eine Ganzzahl im Bereich von 0 bis 255, die um ein Vielfaches von 2 gedreht ist.
Daher werden hier die Antworten bevorzugt, die ein Makro verwenden, und die Antwort von Chris Dodd funktioniert nicht garantiert, abhängig von der GCC-Version und der Optimierungsstufe. Siehe die Diskussion der anderen Frage.
Tags und Links c gcc assembly inline-assembly arm