Utilizați și salvați registrele în ansamblul încorporat

În general, la începutul blocului __asm, nu trebuie să presupunem că registrul va avea o valoare specifică. Salvarea registrelor între diferite blocuri __asm ​​nu este garantată. Când un bloc de cod încorporat se termină și începe următorul bloc, nu presupuneți că registrele din al doilea bloc își păstrează valorile din primul bloc. Blocul __asm ​​moștenește valorile registrelor care rezultă din fluxul normal de control.

Dacă se folosește convenția de apel __ rapidcall. Compilatorul trece argumentele în funcții în registre, nu pe stivă. Acest lucru poate crea probleme în funcțiile cu blocuri __asm. deoarece pentru funcția respectivă nu există nici o modalitate de a determina modul în care parametrii sunt distribuiți în registre. Dacă funcția a primit un parametru în registrul EAX și a scris imediat o altă valoare pentru registrul EAX, parametrul original va fi pierdut. În plus, este necesar să se stocheze valoarea registrului ECX în orice funcție declarată cu atributul __fastcall.

Pentru a evita astfel de conflicte de registru, nu utilizați convenția __ fastcall pentru funcțiile care conțin blocul __asm. Dacă convenția __ rapidcall este specificată global folosind opțiunea / Gr compilator, declarați fiecare funcție care conține blocul __asm. cu atributul __cdecl sau __stdcall. (Atributul __cdecl indică compilatorului să utilizeze convenția de apel în limba C pentru această funcție.) Dacă compilarea cu / Gr nu este făcută, nu declanșați o astfel de funcție cu atributul __fastcall.

Dacă utilizați blocul __asm ​​pentru a scrie codul de asamblare în funcțiile C / C ++, nu este necesar să stocați valorile registrelor EAX, EBX, ECX, EDX, ESI și EDI. De exemplu, în exemplul POWER2.C, din secțiunea Funcții de scriere a codului asamblător încorporat, funcția power2 nu stochează valoarea în registrul EAX. Cu toate acestea, utilizarea acestor registre afectează calitatea codului, deoarece distribuitorul de registru nu le poate folosi pentru a stoca valori între blocurile __asm. În plus, dacă codul de asamblare încorporat utilizează registrul EBX, ESI sau EDI, compilatorul trebuie să stocheze și să restaureze valorile acestor registre în epilogul prolog și al funcției.

Este necesar să se stocheze valorile celorlalte registre utilizate (de exemplu, DS, SS, SP, BP și registrele de pavilion) în zona blocului __asm. Este necesar să salvați valorile registrelor ESP și EBP, cu excepția cazului în care există un motiv specific pentru a le schimba (de exemplu, comutarea stack-ului). Consultați de asemenea secțiunea Optimizarea codului încorporat în limbajul de asamblare.

Pentru anumite tipuri de SSE, este necesară o aliniere de stivă de 8 octeți, rezultând un compilator care trebuie să creeze un cod dinamic de aliniere a stivei. Pentru a putea accesa variabilele locale și parametrii funcționali după aliniere, compilatorul acceptă doi indicatori de cadru. Dacă compilatorul scade pointerul de cadru (FPO), va folosi registrele EBP și ESP. Dacă compilatorul nu execută FPO, va folosi registrele EBX și EBP. Pentru a asigura execuția corectă a codului, nu schimbați valoarea registrului EBX în codul de asamblare dacă funcția necesită alinierea dinamică a stivei, deoarece pointerul de cadru se poate schimba. Mutați tipurile cu o aliniere de 8 octeți în afara funcției sau nu utilizați registrul EBX.

Dacă codul de asamblare încorporat modifică steagul de direcție folosind instrucțiunile STD sau CLD, trebuie să restabiliți valoarea inițială a acestui steag.

Articole similare