2009-09-08 12 views

Odpowiedz

12

Aby to zrobić, musisz stworzyć "nagą" metodę z _declspec (naga) i napisać sobie prolog i epilog, które są zwykle tworzone przez kompilator.

Celem w prologu jest:

  • skonfigurować EBP i ESP
  • przestrzeń
  • rezerwa na stosie dla zmiennych lokalnych
  • Zapisz rejestrów, które powinny być modyfikowane w ciele funkcji

epilog musi:

  • przywrócić wartości zapisane rejestr
  • oczyścić zarezerwowaną przestrzeń dla zmiennych lokalnych

Oto standardowy prolog

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

i standard epilog:

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

zmienne lokalne rozpocznie się od (ebp - 4) i przejdzie w dół do (ebp - 4 - localbytes). Parametry funkcji rozpoczynają się od (ebp + 8) i idą w górę.

3

To niemożliwe, aby utworzyć zmienną C w asemblerze: kompilator C musi wiedzieć o zmiennej (czyli jego typ i adres), co oznacza, że ​​musi być zadeklarowane w kodzie C.

Co można zrobić, to uzyskać dostęp do symboli zdefiniowanych w asemblerze poprzez deklaracje extern w C. To nie zadziała dla zmiennych z automatycznym czasem przechowywania, ponieważ nie mają one stałego adresu, ale są odnoszone do bazy wskaźnik.

Jeśli nie chcesz uzyskać dostępu do zmiennych poza blokiem asm, możesz użyć stosu do przechowywania danych lokalnych dla asemblera. Wystarczy pamiętać, że trzeba przywrócić wskaźnik stosu do jej poprzedniej wartości po opuszczeniu bloku asm, np

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 

Jeśli nie chcesz względne adresy zmiennych lokalnych zmienić w dowolnym momencie manipulować stosu (tzn. użyj push lub pop), musisz ustalić ramkę stosu (tj. zapisać podstawę stosu w ebp i adresować locale względem tej wartości), jak opisano w cedrou's answer.

+0

jesteś pewna sub esp, 3 da przestrzeń do 3 32bit vars? Miałem pomysł, że dla każdego 32-bitowego var będę musiał wziąć 4 z esp. –

+0

Przynajmniej C++ wewnętrznie definiuje to tak: var_4 = dword ptr -4 –

+0

masz rację - nie odpowiadaj na pytania tak późno w nocy;) – Christoph

3

Zmienne lokalne są przydzielane i uwolniony przez manipulowanie dostępnego miejsca na stosie wywołań poprzez rejestr ESP, czyli:

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

Generalnie, to lepiej obsługiwane przez ustanowienie „ramkę stosu” do funkcji wywołującej zamiast, a następnie uzyskać dostęp do zmiennych lokalnych (oraz parametry funkcji) za pomocą przesunięcia wewnątrz ramy, zamiast korzystania z eSP zarejestrować bezpośrednio, tj:

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