Usando e preservando registros no assembly embutido
Seção específica da Microsoft
Em geral, não se deve assumir que um registro terá um determinado valor quando um bloco __asm
for iniciado. Não há garantia de que os valores de registro serão preservados em blocos separados __asm
. Se você encerrar um bloco de código embutido e começar outro, não poderá contar com os registros no segundo bloco reterão os valores do primeiro bloco. Um bloco __asm
herda os valores de registro resultantes do fluxo normal de controle.
Se você usar a convenção de chamada __fastcall
, o compilador passará argumentos de função em registros em vez de na pilha. Isso pode criar problemas em funções com blocos __asm
porque uma função não tem como informar qual parâmetro está no registro. Se a função receber um parâmetro no EAX e armazenar imediatamente outra coisa no EAX, o parâmetro original será perdido. Além disso, é necessário preservar o registro ECX em qualquer função declarada com __fastcall
.
Para evitar esses conflitos de registro, não use a convenção __fastcall
em funções que contêm um bloco __asm
. Se especificar a convenção __fastcall
globalmente com a opção do compilador /Gr, declare as funções que contém um bloco __asm
com __cdecl
ou __stdcall
. (O atributo __cdecl
informa que o compilador deve usar a convenção de chamada C nessa função.) Se você não está compilando com /Gr, evite declarar a função com o atributo __fastcall
.
Ao usar __asm
para escrever linguagem de assembly em funções C/C++, não é necessário preservar os registros EAX, EBX, ECX, EDX, ESI ou EDI. Por exemplo, no exemplo POWER2.C em Funções de Gravação com Assembly Embutido, a função power2
não preserva o valor no registro EAX. No entanto, o uso desses registros afetará a qualidade do código porque o alocador de registro não poderá usá-los para armazenar valores entre blocos __asm
. Além disso, ao usar EBX, ESI ou EDI no código de assembly embutido, você forçará o compilador a salvar e restaurar esses registros no prólogo e epílogo da função.
É necessário preservar outros registros usados (como registros DS, SS, SP, BP e sinalizadores) no escopo do bloco __asm
. É necessário preservar os registros ESP e EBP, a menos que exista algum motivo para alterá-los (para alternar pilhas, por exemplo). Veja também Otimizando o assembly embutido.
Alguns tipos de SSE exigem alinhamento de pilha de oito bytes, forçando o compilador a emitir código de alinhamento dinâmico de pilha. Para poder acessar as variáveis locais e os parâmetros de função após o alinhamento, o compilador mantém dois ponteiros de quadro. Se o compilador executar a omissão do ponteiro de quadro (FPO), ele usará EBP e ESP. Se o compilador não executar o FPO, ele usará EBX e EBP. Para garantir que o código será executado corretamente, não modifique o EBX no código asm se a função exigir alinhamento de pilha dinâmica, pois ele poderá modificar o ponteiro do quadro. Remova os tipos alinhados de oito bytes da função ou evite usar o EBX.
Observação
Se o código do assembly embutido alterar o sinalizador de direção usando as instruções STD ou CLD, será necessário restaurar o sinalizador para o valor original.
Fim da seção específica da Microsoft