Ist Asmlinkage erforderlich, damit eine C-Funktion von Assembly aufgerufen wird?

Ist Asmlinkage erforderlich, damit eine C-Funktion von Assembly aufgerufen wird?


Ich schreibe eine C-Funktion, die vom Assembler-Code aufgerufen wird.


(Insbesondere möchte ich einige Prüfaufgaben im Pfad der Systemaufrufbehandlung im Linux-Kernel ausführen, also werde ich die c-Funktion aufrufen, bevor ein Systemaufruf in entry_32.S abgesetzt wird)


Ich bin verwirrt mit dem Modifizierer "asmlinkage", wenn ich meine c-Funktion definiere.


Ich weiß, dass asmlinkage dem Compiler mitteilen soll, dass die Parameter durch den Stapel geleitet werden.


#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))


Fragen:


(1) Ist asmlinkage erforderlich, wenn eine solche Funktion definiert wird, die vom Assemblercode aufgerufen wird?


(2) Was ist die Standard-Aufrufkonvention in gcc. Wenn ich "asmlinkage" weglasse, wenn ich eine c-Funktion definiere, impliziert das _cdecl oder fastcall?


(3) Wenn die Standardaufrufkonvention cdecl ist, warum wird asmlinkage benötigt, wenn man bedenkt, dass cdecl gleich dem asmlinkage-Modifikator ist? (Habe ich hier recht?)


(4) Warum sind diese Systemaufruffunktionen alle mit asmlinkage deklariert? Können wir die Parameter zuerst in Register kopieren und dann diese Systemaufruffunktionen aufrufen? Aus meiner Sicht werden in x86 beim Ausgeben eines Systemaufrufs die Parameter problemlos in Registern gespeichert. warum sich dann die Mühe machen, dann im Stack zu speichern, um solche Übergabeparameter über die Stack-Konvention zu erzwingen?


Kann schließlich jemand einige Ressourcen/Bücher empfehlen, auf die ich mich für eine solche Mix-Assembly/C-Programmierung beziehen kann?


Antworten:


Nach mehrstündiger Recherche habe ich folgende Erfahrungswerte erhalten:


(1) Ist asmlinkage erforderlich, wenn eine solche Funktion definiert wird, die vom Assemblercode aufgerufen wird?


Nein. Tatsächlich wird der Fastcall häufig verwendet.


Wenn Sie beispielsweise in entry_32.S nach „call“ suchen, können Sie alle C-Funktionen abrufen, die von dieser Assemblydatei aufgerufen werden. Dann können Sie sehen, dass viele fastcall anstelle von asmlinkage als Aufrufkonvention verwenden. Zum Beispiel


    /*in entry_32.S*/
movl PT_OLDESP(%esp), %eax
movl %esp, %edx
call patch_espfix_desc
/*in traps_32.c*/
fastcall unsigned long patch_espfix_desc(unsigned long uesp,
unsigned long kesp)

(2) was ist die standardmäßige Aufrufkonvention in gcc. Wenn ich "asmlinkage" weglasse, wenn ich eine C-Funktion definiere, impliziert das _cdecl oder fastcall?


(3) Wenn die Standard-Aufrufkonvention cdecl ist, warum wird asmlinkage benötigt, wenn man bedenkt, dass cdecl gleich dem asmlinkage-Modifizierer ist? (Liege ich hier richtig?)


Für C-Funktionen, die nicht aus Assembler-Code aufgerufen werden, können wir getrost davon ausgehen, dass die Standard-Aufrufkonvention cdecl ist (oder schneller Aufruf; es spielt keine Rolle, da sich gcc um den Aufrufer und den Aufgerufenen für die Parameterübergabe kümmert. Die Standard-Aufrufkonvention kann sein beim Kompilieren angegeben). Für C-Funktionen, die aus Assemblycode aufgerufen werden, sollten wir jedoch die Aufrufkonvention der Funktion explizit deklarieren, da der Parameterübergabecode auf der Assemblyseite behoben wurde. Wenn beispielsweise patch_espfix_desc als asmlinkage deklariert ist, kompiliert gcc die Funktion, um Parameter vom Stack abzurufen. Dies widerspricht der Assembly-Seite, die die Parameter in Registern ablegt.


Aber mir ist immer noch nicht klar, wann ich asmlinkage und wann fastcall verwenden soll. Ich brauche wirklich einige Richtlinien und Ressourcen, auf die ich mich beziehen kann.