Domanda

Se si desidera chiamare la funzione di un C / C ++ da linea di assemblaggio, si può fare qualcosa di simile:

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

GCC sarà quindi emettere codice che assomiglia a questo:

movl $callee, %eax
call *%eax

Questo può essere problematico in quanto la chiamata indiretta distruggerà il gasdotto sul vecchie CPU.

Poiché l'indirizzo di callee è finalmente una costante, si può immaginare che sarebbe possibile utilizzare il vincolo i. Citando dal GCC linea docs :

  

`i '

     

Un operando intero immediata (uno con valore costante), è consentito. Questo   include costanti simboliche la cui   valori saranno noti solo a montaggio   tempo o successiva.

Se cerco di usare in questo modo:

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

ottengo il seguente errore dal assembler:

  

Errore: il suffisso o operandi non validi per `chiamata '

Questo perché GCC emette il codice

call $callee

Al posto di

call callee

Quindi la mia domanda è se sia possibile fare uscita GCC il corretto call.

È stato utile?

Soluzione

Ho avuto la risposta dalla mailing list di GCC :

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

Ora ho solo bisogno di scoprire che cosa significa in realtà %P0 perché sembra essere una caratteristica non documentata ...

Modifica : Dopo aver guardato il codice sorgente GCC, non è esattamente chiaro quale sia il codice di P di fronte a un mezzo di vincolo. Ma, tra le altre cose, impedisce GCC da mettere un $ davanti valori costanti. Il che è esattamente quello che mi serve in questo caso.

Altri suggerimenti

Forse mi manca qualcosa qui, ma

extern "C" void callee(void) 
{

}

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

dovrebbe funzionare bene. È necessario extern "C" in modo che il nome non sarà decorato basata su C ++ naming regole di mutilazione.

Il trucco è concatenazione di stringhe letterali. Prima di GCC inizia cercando di ottenere qualsiasi significato reale dal codice sarà concatenare stringhe letterali adiacenti, quindi, anche se il montaggio stringhe non sono le stesse di altre stringhe che si utilizzano nel programma dovrebbero essere concatenati se lo si fa:

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


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

Dal momento che si sta utilizzando GCC si potrebbe anche fare

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

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

Se non si conosce già si dovrebbe essere consapevoli del fatto che chiamare le cose da linea di assemblaggio è molto difficile. Quando il compilatore genera le proprie chiamate ad altre funzioni che include il codice per impostare il backup e ripristinare le cose prima e dopo la chiamata. Non sa che dovrebbe fare nulla di tutto questo per la vostra chiamata, però. Si dovrà anche includere che da soli (molto difficile da ottenere e può rompere con un aggiornamento del compilatore o di compilazione bandiere) oppure assicurarsi che la funzione è scritto in modo tale che non sembra aver cambiato eventuali registri o condizioni del pila (o variabile su di esso).

Modifica questo funziona solo per i nomi delle funzioni C -. Non C ++ come sono alterati

Se si sta generando codice a 32 bit (ad esempio -m32 gcc opzione), la seguente linea asm emette una chiamata diretta:

asm ("call %0" :: "m" (callee));
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top