Compartilhar via


Instruções x86

Nas listas desta seção, as instruções marcadas com um asterisco (*) são particularmente importantes. Instruções não tão marcadas não são críticas.

No processador x86, as instruções são de tamanho variável, portanto, desmontar para trás é um exercício de correspondência de padrões. Para desmontar para trás de um endereço, você deve começar a desmontar em um ponto mais atrás do que realmente deseja ir e, em seguida, olhar para a frente até que as instruções comecem a fazer sentido. As primeiras instruções podem não fazer sentido porque você pode ter começado a desmontar no meio de uma instrução. Infelizmente, há a possibilidade de que a desmontagem nunca seja sincronizada com o fluxo de instruções e você terá que tentar desmontar em um ponto de partida diferente até encontrar um ponto de partida que funcione.

Para instruções de comutador bem empacotadas, o compilador emite dados diretamente no fluxo de código, portanto, desmontar por meio de uma instrução switch geralmente tropeçará em instruções que não fazem sentido (porque elas são realmente dados). Localize o final dos dados e continue desmontando lá.

Notação de instrução

A notação geral para instruções é colocar o registro de destino à esquerda e a origem à direita. No entanto, pode haver algumas exceções a essa regra.

Normalmente, as instruções aritméticas são de dois registros com os registros de origem e destino combinados. O resultado é armazenado no destino.

Algumas das instruções têm versões de 16 e 32 bits, mas apenas as versões de 32 bits estão listadas aqui. Não listados aqui estão instruções de ponto flutuante, instruções privilegiadas e instruções que são usadas apenas em modelos segmentados (que o Microsoft Win32 não usa).

Para economizar espaço, muitas das instruções são expressas em formato combinado, conforme mostrado no exemplo a seguir.

*

MOV

r1, r/m/#n

r1 = r/m/#n

significa que o primeiro parâmetro deve ser um registro, mas o segundo pode ser um registro, uma referência de memória ou um valor imediato.

Para economizar ainda mais espaço, as instruções também podem ser expressas conforme mostrado no seguinte.

*

MOV

r1/m, r/m/#n

r1/m = r/m/#n

o que significa que o primeiro parâmetro pode ser um registro ou uma referência de memória, e o segundo pode ser um registro, uma referência de memória ou um valor imediato.

A menos que indicado de outra forma, quando essa abreviação é usada, você não pode escolher memória para origem e destino.

Além disso, um sufixo de tamanho de bit (8, 16, 32) pode ser acrescentado à origem ou ao destino para indicar que o parâmetro deve ser desse tamanho. Por exemplo, r8 significa um registro de 8 bits.

Memória, Transferência de Dados e Conversão de Dados

As instruções de transferência de dados e memória não afetam os sinalizadores.

Endereço efetivo

*

LEA

r, m

Carregar endereço efetivo.

(r = endereço de m)

Por exemplo, LEA eax, [esi+4] significa eax = esi + 4. Essa instrução geralmente é usada para executar aritmética.

Transferência de dados

MOV

r1/m, r2/m/#n

r1/m = r/m/#n

MOVSX

r1, r/m

Mova-se com a extensão de sinal.

*

MOVZX

r1, r/m

Mover-se com extensão zero.

MOVSX e MOVZX são versões especiais da instrução mov que executam a extensão de sinal ou a extensão zero da origem para o destino. Essa é a única instrução que permite que a origem e o destino sejam tamanhos diferentes. (E, na verdade, eles devem ter tamanhos diferentes.

Manipulação de pilha

A pilha é apontada pelo registro esp . O valor em esp é a parte superior da pilha (mais recentemente enviada por push, primeiro a ser exibida); Os elementos de pilha mais antigos residem em endereços mais altos.

PUSH

r/m/#n

Efetuar push do valor para a pilha.

POP

r/m

Valor pop da pilha.

PUSHFD

Efetuar push de sinalizadores na pilha.

POPFD

Sinalizadores pop da pilha.

PUSHAD

Envie por push todos os registros inteiros.

POPAD

Pop de todos os registros inteiros.

Enter

#n, #n

Criar quadro de pilha.

*

DEIXAR

Derrubar o quadro de pilha

O compilador C/C++ não usa a instrução enter . (A instrução enter é usada para implementar procedimentos aninhados em linguagens como Algol ou Pascal.)

A instrução de licença é equivalente a:

mov esp, ebp
pop ebp

Conversão de dados

CBW

Converter byte (al) em word (ax).

CWD

Converter palavra (ax) em dword (dx:ax).

CWDE

Converter palavra (ax) em dword (eax).

CDQ

converter dword (eax) em qword (edx:eax).

Todas as conversões executam a extensão de sinal.

Manipulação aritmética e de bits

Todas as instruções aritméticas e de manipulação de bits modificam sinalizadores.

Aritmética

ADD

r1/m, r2/m/#n

r1/m += r2/m/#n

ADC

r1/m, r2/m/#n

r1/m += r2/m/#n + carry

SUB

r1/m, r2/m/#n

r1/m -= r2/m/#n

SBB

r1/m, r2/m/#n

r1/m -= r2/m/#n + carry

NEG

r1/m

r1/m = -r1/m

INC

r/m

r/m += 1

DEC

r/m

r/m -= 1

CMP

r1/m, r2/m/#n

Computação r1/m - r2/m/#n

A instrução cmp calcula a subtração e define sinalizadores de acordo com o resultado, mas joga o resultado fora. Normalmente, ele é seguido por uma instrução de salto condicional que testa o resultado da subtração.

MUL

r/m8

Machado = Al * r/m8

MUL

r/m16

dx:ax = ax * r/m16

MUL

r/m32

edx:eax = eax * r/m32

IMUL

r/m8

Machado = Al * r/m8

IMUL

r/m16

dx:ax = ax * r/m16

IMUL

r/m32

edx:eax = eax * r/m32

IMUL

r1, r2/m

r1 *= r2/m

IMUL

r1, r2/m, #n

r1 = r2/m * #n

Multiplicação sem sinal e assinada. O estado dos sinalizadores após a multiplicação é indefinido.

DIV

r/m8

(ah, al) = (ax % r/m8, ax / r/m8)

DIV

r/m16

(dx, ax) = dx:ax / r/m16

DIV

r/m32

(edx, eax) = edx:eax / r/m32

IDIV

r/m8

(ah, al) = ax / r/m8

IDIV

r/m16

(dx, ax) = dx:ax / r/m16

IDIV

r/m32

(edx, eax) = edx:eax / r/m32

Divisão sem sinal e assinada. O primeiro registro na explicação do pseudocódigo recebe o restante e o segundo recebe o quociente. Se o resultado estourar o destino, uma exceção de estouro de divisão será gerada.

O estado dos sinalizadores após a divisão é indefinido.

*

SETcc

r/m8

Definir r/m8 como 0 ou 1

Se a condição cc for verdadeira, o valor de 8 bits será definido como 1. Caso contrário, o valor de 8 bits será definido como zero.

Decimal codificado em binário

Você não verá essas instruções, a menos que esteja depurando o código escrito em COBOL.

DAA

Ajuste decimal após a adição.

DAS

Ajuste decimal após a subtração.

Essas instruções ajustam o registro al depois de executar uma operação decimal com código binário empacotado.

AAA

Ajuste ASCII após a adição.

AAS

Ajuste ASCII após a subtração.

Essas instruções ajustam o registro al depois de executar uma operação decimal codificada em binário descompactada.

AAM

Ajuste asCII após a multiplicação.

AAD

Ajuste asCII após a divisão.

Essas instruções ajustam os registros al e ah depois de executar uma operação decimal codificada em binário descompactada.

Bits

AND

r1/m, r2/m/#n

r1/m = r1/m e r2/m/#n

OU

r1/m, r2/m/#n

r1/m = r1/m ou r2/m/#n

XOR

r1/m, r2/m/#n

r1/m = r1/m xor r2/m/#n

NOT

r1/m

r1/m = bit a bit não r1/m

*

TEST

r1/m, r2/m/#n

Computar r1/m e r2/m/#n

A instrução de teste calcula o operador AND lógico e define sinalizadores de acordo com o resultado, mas joga o resultado fora. Normalmente, ele é seguido por uma instrução de salto condicional que testa o resultado do AND lógico.

SHL

r1/m, cl/#n

r1/m <<= cl/#n

SHR

r1/m, cl/#n

r1/m >>= cl/#n preenchimento zero

*

SAR

r1/m, cl/#n

r1/m >>= cl/#n sign-fill

O último bit deslocado é colocado no transporte.

SHLD

r1, r2/m, cl/#n

Shift double para a esquerda.

Shift r1 à esquerda por cl/#n, preenchendo com os bits superiores de r2/m. O último bit deslocado é colocado no transporte.

SHRD

r1, r2/m, cl/#n

Shift double para a direita.

Shift r1 para a direita por cl/#n, preenchendo com os bits inferiores de r2/m. O último bit deslocado é colocado no transporte.

ROL

r1, cl/#n

Gire r1 para a esquerda por cl/#n.

ROR

r1, cl/#n

Gire r1 para a direita por cl/#n.

RCL

r1, cl/#n

Gire r1/C à esquerda por cl/#n.

RCR

r1, cl/#n

Gire r1/C para a direita por cl/#n.

A rotação é como mudar, exceto que os bits deslocados para fora reaparecem como os bits de preenchimento de entrada. A versão da linguagem C das instruções de rotação incorpora o bit de transporte na rotação.

BT

r1, r2/#n

Copie o bit r2/#n de r1 para transporte.

BTS

r1, r2/#n

Defina bit r2/#n de r1, copie o valor anterior para carry.

BTC

r1, r2/#n

Limpe o bit r2/#n de r1, copie o valor anterior para carry.

Fluxo de Controle

Jcc

Dest

Condicional de ramificação.

JMP

Dest

Pule direto.

JMP

r/m

Ir indireto.

CALL

Dest

Chame direto.

*

CALL

r/m

Chamar indireto.

A instrução de chamada envia o endereço de retorno para a pilha e, em seguida, salta para o destino.

*

RET

#n

Retorno

A instrução ret é exibida e salta para o endereço de retorno na pilha. Um #n diferente de zero na instrução RET indica que, depois de estourar o endereço de retorno, o valor #n deve ser adicionado ao ponteiro de pilha.

LOOP

Decremente ecx e pule se o resultado for diferente de zero.

LOOPZ

Decremente ecx e jump se result for diferente de zero e zr foi definido.

LOOPNZ

Decremente ecx e jump se result for diferente de zero e zr estiver claro.

JECXZ

Pule se ecx for zero.

Essas instruções são remanescentes do patrimônio cisc do x86 e, em processadores recentes, são, na verdade, mais lentas do que as instruções equivalentes escritas no longo caminho.

Manipulação de cadeia de caracteres

MOVST

Mova T de esi para edi.

CMPST

Compare T de esi com edi.

SCAST

Examine T de edi para accT.

LODST

Carregue T de esi em accT.

STOST

Armazene T para edi do accT.

Depois de executar a operação, o registro de origem e destino é incrementado ou decrementado por sizeof(T), de acordo com a configuração do sinalizador de direção (para cima ou para baixo).

A instrução pode ser prefixada pelo REP para repetir a operação o número de vezes especificado pelo registro ecx .

A instrução rep mov é usada para copiar blocos de memória.

A instrução rep stos é usada para preencher um bloco de memória com accT.

Sinalizadores

LAHF

Carregue ah de sinalizadores.

SAHF

Armazene ah para sinalizadores.

STC

Defina carry.

CLC

Limpar transporte.

CMC

Complementar transporte.

STD

Defina a direção para baixo.

CLD

Defina a direção para cima.

STI

Habilitar interrupções.

CLI

Desabilitar interrupções.

Instruções interligadas

XCHG

r1, r/m

Troque r1 e r/m.

XADD

r1, r/m

Adicione r1 a r/m, coloque o valor original em r1.

CMPXCHG

r1, r/m

Comparar e trocar condicionalmente.

A instrução cmpxchg é a versão atômica do seguinte:

   cmp     accT, r/m
   jz      match
   mov     accT, r/m
   jmp     done
match:
   mov     r/m, r1
done:

Diversos

INT

#n

Interceptar para kernel.

LIMITE

r, m

Interceptar se r não estiver no intervalo.

*

NOP

Sem operação.

XLATB

al = [ebx + al]

BSWAP

r

Trocar ordem de bytes no registro.

Aqui está um caso especial da instrução int .

INT

3

Interceptação de ponto de interrupção do depurador.

O opcode para INT 3 é 0xCC. O opcode para NOP é 0x90.

Ao depurar o código, talvez seja necessário aplicar patch em algum código. Você pode fazer isso substituindo os bytes ofensivos por 0x90.

Idiomas

XOR

r, r

r = 0

TEST

r, r

Verifique se r = 0.

*

ADD

r, r

Shift r para a esquerda por 1.