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

Confira também

Assembler embutido