2009-09-08 13 views

risposta

12

Per fare ciò, devi creare un metodo "nudo" con _declspec (nudo) e scrivere te stesso il prologo e l'epilogo che vengono normalmente creati dal compilatore.

L'obiettivo di un prologo è quello di:

  • istituito EBP e ESP
  • spazio
  • riserva sulla pila per le variabili locali
  • Salva registri che deve essere modificato nel corpo della funzione

un epilogo deve:

  • ripristinare il registro salvato Valori
  • ripulire lo spazio riservato per le variabili locali

Ecco un prologo di serie

push  ebp    ; Save ebp 
mov   ebp, esp   ; Set stack frame pointer 
sub   esp, localbytes ; Allocate space for locals 
push  <registers>  ; Save registers 

e un epilogo di serie:

pop   <registers> ; Restore registers 
mov   esp, ebp  ; Restore stack pointer 
pop   ebp   ; Restore ebp 
ret      ; Return from function 

vostri variabili locali inizierà quindi a (ebp - 4) e andrà in basso a (ebp - 4 - localbytes). I parametri della funzione inizieranno da (ebp + 8) e saliranno.

3

E' impossibile creare una variabile C in assembler: compilatore C deve conoscere la variabile (cioè la sua tipologia e indirizzo), che significa che deve essere dichiarato nel codice C.

Ciò che è possibile fare è accedere ai simboli definiti nell'assembler tramite le dichiarazioni extern in C. Ciò non funzionerà per le variabili con durata di archiviazione automatica, tuttavia, poiché questi non hanno un indirizzo fisso ma sono riferiti rispetto alla base puntatore.

Se non si desidera accedere alle variabili esterne al blocco asm, è possibile utilizzare lo stack per la memorizzazione dei dati locali dell'assemblatore. Basta tenere a mente che è necessario ripristinare lo stack pointer al valore precedente al momento di lasciare il blocco asm, ad esempio

sub esp, 12  ; space for 3 asm-local 32bit vars 
mov [esp-8], 42 ; set value of local var 
[...] 
push 0xdeadbeaf ; use stack 
[...]    ; !!! 42 resides now in [esp-12] !!! 
add esp, 16  ; restore esp 

Se non si desidera che i relativi indirizzi delle variabili locali di cambiare ogni volta che si manipolare lo stack (ad esempio, utilizzare push o pop), è necessario stabilire un frame di stack (ovvero salvare la base della pila in ebp e indirizzare i locali in relazione a questo valore) come descritto in cedrou's answer.

+0

Sei sicuro sub esp, 3 darà spazio per 3 32bit vars? Ho avuto l'idea che per ogni 32 bit var dovrei prendere 4 da esp. –

+0

Almeno C++ definisce internamente in questo modo: var_4 = dword ptr -4 –

+0

hai ragione - non dovresti rispondere alle domande a tarda notte;) – Christoph

3

variabili locali sono allocati e liberati manipolando lo spazio disponibile nello stack di chiamate tramite registro ESP, ossia:

__asm 
{ 
    add esp, 4 
    mov [esp], 2; 
    ... 
    sub esp, 4 
} 

Generalmente, questo è meglio gestita da stabilire un "stack frame" per la funzione chiamante invece, e quindi accedere alle variabili locali (e parametri di funzionalità) utilizzando gli offset all'interno della cornice, invece di utilizzare registro ESP direttamente, vale a dire:

__asm 
{ 
    push ebp 
    mov ebp, esp 
    add esp, 4 
    ... 
    mov [ebp-4], 2; 
    ... 
    mov esp, ebp 
    pop ebp 
} 
Problemi correlati