2012-02-01 12 views
6

Ho riscontrato qualcosa che non capisco completamente. C'è un prototipo di funzione:Puntatore funzione con GCC, assegnazione di un indirizzo

typedef void (* TMain) (void); 

e una variabile funzione di:

TMain myFunc = MyFunc; 
... 
myFunc(); 

Questo funziona bene, naturalmente. Perché non dovrebbe?

Dal file MAP so che "MyFunc" è in posizione 0x20100. E ora la cosa divertente. Dopo l'assegnazione "myFunc = MyFunc;" la variabile "myFunc" non contiene il valore 0x20100 ma piuttosto 0x20101!

Il mio problema è che devo chiamare una funzione di cui conosco l'indirizzo da una tabella. Così ho pensato che avrei potuto farlo in quel modo

myFunc = (TMain) myTable [ 5 ]; // that would be 0x20100 
myFunc();       // which produces a proper crash 

se faccio

myFunc = (TMain) ((Int8 *) myTable [ 5 ] + 1); 
myFunc(); 

allora funziona.

Cosa succede qui? Devo sempre aggiungere un offset di 1 o è più o meno accidentale? Oppure c'è un modo migliore (e funzionante) per eseguire l'operazione?

Grazie mille per ogni suggerimento. Walter

+2

Non sicuro, ma potrebbe dipendere dall'architettura. Quindi potrebbe voler dire quale sia l'architettura di destinazione. – phimuemue

+1

L'array 'myTable' di tipo' TMain [] '? Presumo che non lo sia da quando lo stai lanciando. –

+1

Alcune domande per voi: quale piattaforma state usando (ARM, x86 ...)? Hai mai controllato l'indirizzo effettivo della funzione con un debugger? Riesci a vedere come il compilatore genera la chiamata indiretta "myFunc()"? –

risposta

3

Diverse architetture CPU riservano i primi byte di una funzione per scopi specifici. VAXen ha una maschera di registro di salvataggio lì. CDC Cyber ​​inserisce qui l'indirizzo di ritorno. Alcuni usano alcuni bit dell '"indirizzo" per indicare l'indirizzo indiretto (a mano a mano non ricordo quali sono, ma sono degli anni '70).

A meno che tu non sappia veramente cosa stai facendo, non dovresti scrivere codice che faccia questo tipo di aritmetica puntatore. Assegna alla variabile il nome della funzione e fallo con essa: è garantito che funzioni su ogni implementazione C.

3

La mia ipotesi è che tu sia su un target ARM e hai creato il tuo programma in modalità Thumb? (Thumb è predefinito su ARM Ubuntu o Linaro.)

Il bit inferiore dell'indirizzo di una funzione indica alla CPU in quale set di istruzioni deve interpretare la funzione. 0 è la modalità ARM. 1 è la modalità Thumb. Quindi tutti i puntatori a funzione Thumb-mode saranno dispari.

Altre architetture usano questo idioma anche, in un modo o nell'altro. Solitamente è sicuro azzerare solo i due bit inferiori di un indirizzo (rendendolo allineato a 4 byte) e assumere che quella sia la vera posizione della funzione.

Problemi correlati