Frage

Wenn Sie eine C / C ++ Funktion von Inline-Assembler anrufen möchten, können Sie etwas tun:

void callee() {}
void caller()
{
    asm("call *%0" : : "r"(callee));
}

GCC wird dann emittieren Code, der wie folgt aussieht:

movl $callee, %eax
call *%eax

Dies kann problematisch sein, da der indirekte Aufruf wird die Pipeline auf älteren CPUs zerstören.

Da die Adresse von callee schließlich eine Konstante ist, kann man sich vorstellen, dass es möglich wäre, die i Einschränkung zu verwenden. Zitiert aus der GCC Online docs :

  

`i '

     

Ein unmittelbarer ganzzahlige Operand (eines mit konstantem Wert) ist zulässig. Dies   enthält symbolische Konstanten, deren   Werte werden nur bei der Montage bekannt sein   Zeit oder später.

Wenn ich versuche, es so zu verwenden:

asm("call %0" : : "i"(callee));

ich folgende Fehlermeldung aus dem Assembler erhalten:

  

Fehler: Suffix oder Operanden ungültig für `Aufruf"

Das ist, weil GCC der Code

aussendet
call $callee

Anstelle von

call callee

Also meine Frage ist, ob es möglich ist, GCC Ausgang der korrekten call zu machen.

War es hilfreich?

Lösung

habe ich die Antwort von GCC-Mailingliste :

asm("call %P0" : : "i"(callee));

Jetzt gerade muss ich herausfinden, was tatsächlich Mittel %P0, weil es scheint eine nicht dokumentierte Funktion ...

zu sein

Bearbeiten : Nachdem an der GCC Quellcode suchte, ist es nicht ganz klar, was der Code P vor einem Zwangsmittel. Aber, unter anderem verhindert, dass GCC einem $ vor konstanten Werten von Putten. Und das ist genau das, was ich in diesem Fall benötigen.

Andere Tipps

Vielleicht etwas, was ich bin fehlt hier, aber

extern "C" void callee(void) 
{

}

void caller(void)
{
  asm("call callee\n");
}

sollte funktionieren. Sie müssen „C“ extern, so dass der Name wird auf C nicht eingerichtet werden, basierend ++ Mangeln Regeln zu nennen.

Der Trick ist Stringliteral Verkettung. Bevor beginnt GCC eine wirkliche Bedeutung aus dem Code zu bekommen versucht, wird es neben Stringliterale verketten, so obwohl Montageketten als andere Saiten nicht gleich sind Sie in Ihrem Programm verwenden, sollten sie verkettet werden, wenn Sie das tun:

#define ASM_CALL(X) asm("\t call  " X "\n")


int main(void) {
    ASM_CALL( "my_function" );
    return 0;
}

Da Sie GCC verwenden Sie könnten auch tun

#define ASM_CALL(X) asm("\t call  " #X "\n")

int main(void) {
   ASM_CALL(my_function);
   return 0;
}

Wenn Sie nicht bereits wissen, Sie sollten sich bewusst sein, dass die Dinge von Inline-Assembler-Aufruf sehr schwierig ist. Wenn der Compiler seine eigenen Anrufe an andere Funktionen generiert enthält es Code einzurichten und Dinge wiederherstellen vor und nach dem Aufruf. Er weiß nicht, dass es für Ihren Anruf irgendetwas davon zu tun, obwohl werden soll. Sie müssen entweder diese selbst (sehr schwierig richtig zu machen und mit einem Compiler-Upgrade oder Kompilation Flags brechen kann) oder stellen Sie sicher, dass Ihre Funktion so geschrieben, dass es keine Register oder den Zustand des sich geändert zu haben scheint Stapel (oder Variable auf sie).

Bearbeiten nur für C-Funktionsnamen funktionieren -. Nicht C ++, wie sie verstümmelt werden

Wenn Sie sich Erzeugungs 32-Bit-Code (z -m32 gcc-Option), gibt das folgende asm inline einen direkten Aufruf:

asm ("call %0" :: "m" (callee));
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top