È necessario asmlinkage per chiamare una funzione c dall'assembly?

È necessario asmlinkage per chiamare una funzione c dall'assembly?


Sto scrivendo una funzione C che verrà invocata dal codice assembly.


(In particolare, voglio eseguire un lavoro di controllo nel percorso di gestione delle chiamate di sistema nel kernel Linux, quindi chiamerò la funzione c prima che venga inviata una chiamata di sistema in entry_32.S)


Sono confuso con il modificatore "asmlinkage" quando definisco la mia funzione c.


So che asmlinkage serve a dire al compilatore che i parametri verranno passati attraverso lo stack.


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


Domande:


(1) È necessario asmlinkage quando si definisce una tale funzione che verrà richiamata dal codice assembly?


(2) qual è la convenzione di chiamata predefinita in gcc. Se ometto "asmlinkage" quando definisco una funzione c, implica _cdecl o fastcall?


(3) se la convenzione di chiamata predefinita è cdecl, perché è necessario asmlinkage, considerando che cdecl è uguale a asmlinkage modificatore? (ho ragione qui?)


(4) perché quelle funzioni di chiamata di sistema sono tutte dichiarate con asmlinkage. Possiamo prima copiare i parametri nei registri, quindi chiamare quelle funzioni di chiamata di sistema? Dal mio punto di vista, in x86, quando si esegue una chiamata di sistema, i parametri vengono prontamente salvati nei registri; allora perché preoccuparsi di salvare poi nello stack per imporre tali parametri di passaggio tramite la convenzione dello stack?


Infine, qualcuno può consigliare alcune risorse/libri a cui posso fare riferimento per tale programmazione mix assembly/c?


Risposte:


Dopo diverse ore di ricerca, ho ottenuto i seguenti punti empirici:


(1) È necessario asmlinkage quando si definisce una tale funzione che verrà richiamata dal codice assembly?


No. In realtà si usa frequentemente la chiamata veloce.


Ad esempio, in entry_32.S, se cerchi "call", puoi ottenere tutte le funzioni c invocate da questo file assembly. Quindi puoi vedere che molti usano la chiamata rapida invece di asmlinkage come convenzione di chiamata. Ad esempio,


    /*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) qual è la convenzione di chiamata predefinita in gcc. Se ometto "asmlinkage" quando definisco una funzione c, implica _cdecl o fastcall?


(3) se la convenzione di chiamata predefinita è cdecl, perché è necessario asmlinkage, considerando che cdecl è uguale a asmlinkage modificatore? (ho ragione qui?)


Per le funzioni C non invocate dal codice assembly, possiamo tranquillamente presumere che la convenzione di chiamata predefinita sia cdecl (o chiamata rapida; non importa, perché gcc si prenderà cura del chiamante e del chiamato per il passaggio dei parametri. La convenzione di chiamata predefinita può essere specificato in fase di compilazione). Tuttavia, per le funzioni C invocate dal codice assembly, dovremmo dichiarare esplicitamente la convenzione di chiamata della funzione, poiché il parametro che passa il codice in assembly side è stato corretto. Ad esempio, se patch_espfix_desc è dichiarato come asmlinkage, gcc compilerà la funzione per recuperare i parametri dallo stack. Ciò non è coerente con il lato dell'assieme, che inserisce i parametri nei registri.


Ma non sono ancora chiaro quando usare asmlinkage e quando usare fastcall. Ho davvero bisogno di alcune linee guida e risorse a cui fare riferimento.