Korzystanie z rejestrów i zachowywanie ich w asemblerze wbudowanym
Specyficzne dla firmy Microsoft
Ogólnie rzecz biorąc, nie należy zakładać, że rejestr będzie miał daną wartość po rozpoczęciu __asm
bloku. Nie ma gwarancji, że wartości rejestru zostaną zachowane w oddzielnych __asm
blokach. Jeśli zakończysz blok kodu wbudowanego i rozpoczniesz inny, nie możesz polegać na rejestrach w drugim bloku, aby zachować ich wartości z pierwszego bloku. Blok __asm
dziedziczy wszystkie wartości rejestru wynikające z normalnego przepływu sterowania.
Jeśli używasz __fastcall
konwencji wywoływania, kompilator przekazuje argumenty funkcji w rejestrach zamiast na stosie. Może to powodować problemy w funkcjach z blokami, __asm
ponieważ funkcja nie ma sposobu na określenie parametru, w którym rejestrze. Jeśli funkcja otrzyma parametr w programie EAX i natychmiast zapisze coś innego w programie EAX, oryginalny parametr zostanie utracony. Ponadto należy zachować rejestr ECX w dowolnej funkcji zadeklarowanej za pomocą __fastcall
polecenia .
Aby uniknąć takich konfliktów rejestrów, nie należy używać __fastcall
konwencji dla funkcji, które zawierają __asm
blok. Jeśli określisz konwencję __fastcall
globalnie z opcją /Gr kompilatora, zadeklaruj każdą funkcję zawierającą blok z opcją __asm
__cdecl
lub __stdcall
. (Atrybut __cdecl
nakazuje kompilatorowi użycie konwencji wywoływania języka C dla tej funkcji). Jeśli nie kompilujesz z /Gr, unikaj deklarowania funkcji za pomocą atrybutu __fastcall
.
Podczas __asm
pisania języka zestawu w funkcjach C/C++ nie trzeba zachowywać rejestrów EAX, EBX, ECX, EDX, ESI lub EDI. Na przykład w usłudze POWER2. Przykład języka C w artykule Writing Functions with Inline Assembly (power2
Pisanie funkcji za pomocą zestawu wbudowanego) funkcja nie zachowuje wartości w rejestrze EAX. Jednak użycie tych rejestrów będzie miało wpływ na jakość kodu, ponieważ alokator rejestru nie może ich używać do przechowywania wartości w __asm
blokach. Ponadto przy użyciu EBX, ESI lub EDI w wbudowanym kodzie zestawu wymusisz, aby kompilator zapisywał i przywracał te rejestry w prologu funkcji i epilogu.
Należy zachować inne rejestry używane (takie jak DS, SS, SP, BP i rejestry flag) dla zakresu __asm
bloku. Należy zachować rejestry ESP i EBP, chyba że masz jakiś powód, aby je zmienić (na przykład do przełączania stosów). Zobacz również Optymalizowanie wbudowanego zestawu.
Niektóre typy SSE wymagają wyrównania stosu ośmiu bajtów, co zmusza kompilator do emitowania dynamicznego kodu wyrównania stosu. Aby uzyskać dostęp zarówno do zmiennych lokalnych, jak i parametrów funkcji po wyrównaniu, kompilator zachowuje dwa wskaźniki ramki. Jeśli kompilator wykonuje pominięcie wskaźnika ramki (FPO), będzie używać EBP i ESP. Jeśli kompilator nie wykonuje obiektu FPO, będzie używać EBX i EBP. Aby upewnić się, że kod działa poprawnie, nie należy modyfikować ebX w kodzie asm, jeśli funkcja wymaga dynamicznego wyrównania stosu, ponieważ może modyfikować wskaźnik ramki. Przenieś typy wyrównane z ośmiu bajtów z funkcji lub unikaj korzystania z EBX.
Uwaga
Jeśli wbudowany kod zestawu zmienia flagę kierunku przy użyciu instrukcji STD lub CLD, musisz przywrócić flagę do oryginalnej wartości.
END Microsoft Specific