Zugriff auf eine statische C ++ - Variable über gcc inline asm

7

Aus irgendeinem Grund möchte ich ein bisschen Assembly mit C ++ (nicht C) mischen.
Damit der Code mit der Standard-Arduino-IDE kompiliert werden kann, möchte ich keine direkte Assembly-Quelle verwenden.
Ich möchte auch keine Wrapper-C-Datei verwenden.

Mein Problem ist wie folgt:

Ich habe eine Klasse mit einer einzelnen Instanz (die eine Art Treiber implementiert), die folgendermaßen aussieht:

class cDriver {
public:
    char ISR_param;
    // ...
};

cDriver Driver;

Wenn ich ISR_paraminnerhalb eines ISR auf diese einzelne Instanz zugreifen möchte , kann ich Folgendes tun:

ISR (TIMER2_COMPA_Vect) {
    do_something_with (Driver.ISR_param);
}

Dies funktioniert wie ein Zauber: Die Adresse Driver.ISR_parambeign eine Konstante, der Compiler generiert einfach eine lds r24, &Driver.ISR_paramAnweisung, um das richtige Byte als Parameter für zu laden do_something_with.

Wenn ich jetzt versuche, denselben Mechanismus mit dem Inline-Assembler zu replizieren, werden die Dinge viel komplizierter.

Die Adresse von Driver.ISR_paramist dem C ++ - Compiler nur als entstelltes Label bekannt, und ich kann keine Möglichkeit finden, sie an den Inline-Assembler zu übergeben, um das Äquivalent zu generieren lds r24, <&Driver.ISR_param>.

versuchen, die Variable erneut zu bestimmen

Das Umbenennen von Variablen für Assembly wie folgt:

char global_var asm("my_var");

und ein Versuch, es so zu benutzen:

asm ("lds r24, my_var\n");

wird kompiliert, erzeugt aber einen Linkerfehler ( my_varist undefiniert).

In der Objektsymboltabelle ist die einzige Bezeichnung für global_vareinen C ++ - ähnlichen verstümmelten Namen.
So sehr ich mich auch um diesen Umbenennungstrick bemühte, ich konnte den Compiler nicht dazu bringen, ein my_varLabel zu generieren .

versuchen, asm-Einschränkungen zu verwenden

Eine Einschränkung wie

asm (lds r24, %0\n" : : "I"(&global_var));

wird einfach nicht kompiliert. Ich habe die möglichen Parametertypen durchsucht und konnte keinen Weg finden, den Assembler über diese blutige Adresse zu informieren.

eine schrecklich umständliche Problemumgehung

Die einzige Möglichkeit, den Compiler dazu zu bringen, diese gefürchtete lds r24,...Anweisung zu generieren , besteht darin, einen tatsächlichen Funktionsaufruf auszuführen.

Sie können also Folgendes tun:

__attribute__((always_inline)) give_me_my_friggin_variable(char data)
{
    asm volatile ("cmp  %0,%0\n"::"r"(data));
}   

ISR (TIMER2_COMPA_Vect, ISR_NAKED) {

    <some prologue to save SREG and all needed registers>

    //...

    give_me_my_friggin_variable(Driver.ISR_param);

    // continue assembly code with r24 properly initialized
}

Das wird erzeugen:

    lds r24, <the proper address> // added by the compiler...
    cmp r24,r24                   // ...because of the register constraint here

Nun, diese Art von Arbeiten, aber auf Kosten einer völlig nutzlosen Anweisung.

meine frage ist also ...

Gibt es eine einfachere Möglichkeit, den Assembler über Adressen von statischen C ++ - Variablen zu informieren?

kuroi neko
quelle

Antworten:

5

Versuche dies:

asm volatile("lds r24, %0" : : "i" (&Driver.ISR_param));

Die "i"Einschränkung bedeutet, dass Sie eine Ganzzahlkonstante angeben. Dies kann eine beliebige Ganzzahl sein, im Gegensatz zu der "I"Einschränkung in Großbuchstaben , die auf positive 6-Bit-Ganzzahlen beschränkt ist.

Nachtrag : Die von gcc unterstützten Einschränkungen sind in der gcc-Dokumentation im Abschnitt Einschränkungen für asmOperanden aufgeführt :

  • Die "i"Einschränkung ist im Unterabschnitt „Einfache Einschränkungen“ aufgeführt und wird wie folgt beschrieben:

Ein sofortiger ganzzahliger Operand (einer mit konstantem Wert) ist zulässig. Dies schließt symbolische Konstanten ein, deren Werte erst zum Zeitpunkt der Montage oder später bekannt werden.

  • Die "I"Einschränkung befindet sich im Unterabschnitt „Maschinenbeschränkungen“ und ist für die AVR-Architektur definiert als

Konstante größer als -1, kleiner als 64.

Edgar Bonet
quelle
1
Dang ... und danke :). Dieser "i" -Typ wurde in den von mir gefundenen Online-Handbüchern nicht aufgeführt. Können Sie der Vollständigkeit halber einen Link zu einer aktuellen Dokumentation hinzufügen? Übrigens. Ich frage mich, warum ein Beispiel für eine so offensichtliche Verwendung des Inline-Assemblers so schwer zu finden ist.
Kuroi Neko
@kuroineko: Die "i"Einschränkung fehlt tatsächlich im Inline Assembler-Kochbuch von avr-libc . Ich habe einen Link zur gcc-Dokumentation hinzugefügt, in der er aufgeführt ist.
Edgar Bonet
Vielen Dank. Diese Art des Kochens ist ziemlich vertraulich, denke ich :).
Kuroi Neko