apeluri de funcții, partea 2 (stivă și convențiile de apel)

În prima parte ați învățat elementele de bază ale asteptare funcții ale mecanismului, care a fost luată în considerare în ceea ce privește codul generat. În același timp, veți auzi despre cele două registre, care sunt utilizate în familia de procesoare x86 - registrul PEI (indicatorul de instrucțiuni) și registrul ESP (stiva indicator). În a doua parte vă va învăța un pic mai mult despre stivă și rolul său important în mecanismul de apeluri de funcții. În plus, veți învăța despre două dintre cele mai populare convențiile de apel [convențiile de apel] în programare pentru Windows / C.

Stivă - o locație de memorie (în alocate patru gigabytes), în care fluxul poate stoca datele necesare pentru exercitarea. În special, stiva pot fi stocate variabilele locale utilizate de codul, variabilele temporare utilizate de compilator, argumente funcționale etc. Comportamentul stivă seamănă cu comportamentul unui pachet de cărți [teanc de cărți], prin urmare, a primit numele său. Acest lucru înseamnă că, atunci când a pus obiectele pe stivă, ele sunt întotdeauna pe partea de sus a acesteia, și atunci când ștergeți un obiect din stivă, aveți posibilitatea să eliminați întotdeauna obiectul cel mai de sus. Din punct de vedere tehnic această metodă de acces la date este numit LIFO (Last In First Out - ultimul, primul ieșit).

Așa cum am explicat în prima parte, sistemul oferă un teanc de fiecare fir. Prin mărimea stack-ului implicit este de 1 MB, dar poate fi înlocuită cu valoarea conținută în procesul de antet a imaginii [procesul de valoarea antet de imagine]. Mărimea stack poate fi specificat în CreateThread apel () sau _beginthreadex ().

Procesorul trebuie să știe întotdeauna unde partea de sus a stivei. registrul de locație specifică ESP. PEI valoare registru în mod clar nu poate fi modificată. ESP valoare registru nu numai poate fi modificat de către procesorul implicit, dar, de asemenea, acesta poate fi modificat în mod explicit prin instrucțiuni.


Cum parametrii trecut la funcția?


Cum funcție primește parametrii?

Astfel, atunci când introduceți un cod de funcție are tot ce are nevoie pentru a efectua.


convențiile de apel [Calling convenții]

Acum, va fi necesar să se ia în considerare convențiile de asteptare. Chemarea - este un protocol pentru transmiterea de argumente funcționale. Cu alte cuvinte, acesta este un acord între chemarea și numitul cod. Considerat în subiectele „Cum parametrii trecut la funcția?“ și „Cum funcționează devine opțiunile?“ - este acest protocol, este descrierea generală. Cu toate acestea, în cazul în care aveți de-a face cu software-ul Microsoft, atunci există acorduri adiționale. Cele mai utile:

__cdecl
__stdcalll
thiscall

În acest articol, vom discuta acordurile și mecanismele __cdecl __stdcall și să învețe cum stiva arată ca și codul compilat în fiecare dintre aceste cazuri.

Detaliată de protocol __cdecl descriere pot fi găsite aici. Deosebit de importante sunt următoarele puncte:

* Ordinea argumentelor de trecere: de la dreapta la stânga
* Responsabilitatea pentru integritatea stiva: apelantul trebuie să înlăture argumentele din stivă


Procedura de trecere argumente în protocolul __cdecl

Procedura de trecere argumente pentru a descrie modul în care argumentele sunt puse pe stiva de către apelant. În cazul protocolului __cdecl vorbim despre ordinea de „dreapta“. Acesta este ultimul argument este pus pe stivă, în primul rând, urmat de argumentul pus penultima, și așa mai departe, până când toate argumentele nu vor apărea pe stivă. Odată ce acest lucru se face, instrucțiunea este executată de apel, funcția de apelare.

apeluri de funcții, partea 2 (stivă și convențiile de apel)

* Construi proiectul (Build soluție element de meniu).
Apăsați F5 pentru a rula programul sub un depanator. Executarea programului se va opri la linia de al 13-lea.
* Apăsați Alt + 5. O fereastră care va afișa conținutul registrelor [Registre Window].
* Apăsați Alt + 6. Va apărea o fereastră care afișează conținutul memoriei [Memory Watch Window].
* Du-te la linia 13, pentru a deschide meniul contextual și selectați Salt asamblarii.
* Disassembler deschide din nou meniul contextual și asigurați-vă că marcat următoarele elemente:
- Arată Adresa
- Afișare Cod sursă
- Afișare Cod Bytes

fereastra dezasamblor ar trebui să arate astfel:

apeluri de funcții, partea 2 (stivă și convențiile de apel)

apeluri de funcții, partea 2 (stivă și convențiile de apel)


Responsabilitatea pentru integritatea __cdecl stiva protocolului

* Apăsați F5, pentru a porni programul sub un depanator. Executarea programului se va opri la linia de al 13-lea.
* Apăsați Alt + 5. O fereastră care va afișa conținutul registrelor [Registre Window].
* Apăsați Alt + 6. Va apărea o fereastră care afișează conținutul memoriei [Memory Watch Window].
* Du-te la linia 13, pentru a deschide meniul contextual și selectați Salt asamblarii.
* Disassembler deschide din nou meniul contextual și asigurați-vă că marcat următoarele elemente:
- Arată Adresa
- Afișare Cod sursă
- Afișare Cod Bytes

fereastra dezasamblor ar trebui să arate astfel:

apeluri de funcții, partea 2 (stivă și convențiile de apel)

* Amintiți-vă, ce valoare este în registrul ESP acum (nu au pus argumentele în stivă). În ilustrația noastră, această valoare este 0x12FF64. Primul lucru pe care trebuie să se întâmple imediat după instrucțiunea de apel, - o restaurare a ESP în importanța pe care vă amintiți. Apăsați F10, pentru a sări peste blocul care conține două instrucțiuni împinge și pentru instrucțiuni. Apoi uita-te la valoarea ESP.

apeluri de funcții, partea 2 (stivă și convențiile de apel)

* În exemplul nostru ESP registru va fi numărul 0x12FF5C. După cum puteți vedea, nu este egală cu valoarea inițială. Prin urmare, este necesar pentru a restabili integritatea stivei. Acum, uita-te la linia de cod, care se opresc în prezent execuția. Această linie
La efectuarea acestei acțiuni vom obține 12FF5Ch + 8h = 12FF64h - avem nevoie de numărul. Astfel, acest șir restabilește integritatea stivei, deoarece ESP revine la valoarea sa inițială. Rețineți că această linie este deținută de către apelant, nu numit. Este în numit înregistrarea __cdecl „funcția de asteptare elimină argumentele din stivă [funcția Calling apare argumentele din stivă]“. Deși acest lucru nu este instrucțiuni utilizate direct pop, încă rezultatul este același - ESP indicatorul primește valoarea precedentă.


Concluzii privind Protocolul __cdecl

* Responsabilitatea codului de asteptare pentru integritatea stiva înseamnă că, în cazul în care codul de apel în diferite locuri numite 100 de funcții, folosind protocolul __cdecl, acesta pentru fiecare dintre aceste apeluri pentru a executa cod suplimentar pentru integritatea stiva, chiar dacă chemarea tot timpul aceeași funcție . Astfel, cantitatea de cod generat poate fi crescută.
* Deoarece responsabilitatea pentru integritatea stiva se bazează pe codul de apel, __cdecl protocol vă permite să creați o listă de argumente de lungime variabilă. Atunci când apelați o funcție cu un număr variabil de argumente, doar apelantul știe cât de mulți parametri au fost trecut la ea. Prin urmare, protocolul __cdecl este foarte potrivit pentru o astfel de situație.