Partilhar via


Arquitetura x86

O processador Intel x86 usa a arquitetura CISC (complex instruction set computer), o que significa que há um número modesto de registros para fins especiais em vez de grandes quantidades de registros de uso geral. Significa também que predominarão instruções complexas para fins especiais.

O processador x86 traça sua herança pelo menos tão longe quanto o processador Intel 8080 de 8 bits. Muitas peculiaridades no conjunto de instruções x86 são devido à retrocompatibilidade com esse processador (e com sua variante Zilog Z-80).

Microsoft Win32 usa o processador x86 em modo plano de 32 bits. Esta documentação se concentrará apenas no modo plano.

Registos

A arquitetura x86 consiste nos seguintes registros inteiros sem privilégios.

eax

Acumulador

ebx

Registo de base

ecx

Registo de contador

edx

Registro de dados - pode ser usado para acesso à porta de E/S e funções aritméticas

esi

Registo do índice de origem

edi

Registo do índice de destino

ebp

Registo de ponteiro base

esp

Ponteiro de pilha

Todos os registros inteiros são de 32 bits. No entanto, muitos deles têm sub-registros de 16 bits ou 8 bits.

machado

Os 16 bits inferiores de eax

bx

Baixo 16 bits de ebx

cx

Os 16 bits inferiores de ecx

dx

Baixo 16 bits de edx

si

16 bits inferiores de esi

di

Baixo 16 bits de edi

bp

Baixo 16 bits de ebp

sp

Baixos 16 bits de esp

al

Os 8 bits inferiores de eax

ah

Parte alta dos 8 bits de ax

bl

Baixo 8 bits de ebx

BH

Alta de 8 bits de bx

cl

Baixo 8 bits de ecx

ch

8 bits superiores de cx

dl

Baixo 8 bits de edx

dh

8 bits superiores de dx

A exploração num subregisto afeta apenas o subregisto e nenhuma das partes fora do subregisto. Por exemplo, armazenar no ax registro deixa os 16 bits altos do registro eax inalteradas.

Ao usar o ? (Avaliar expressão) comando, os registos devem ser precedidos de um sinal "at" ( @ ). Por exemplo, você deve usar ? @ax em vez de ? ax. Isso garante que o depurador reconheça ax como um registro em vez de um símbolo.

No entanto, o (@) não é necessário no comando r (Registers). Por exemplo, r ax=5 será sempre interpretado corretamente.

Dois outros registros são importantes para o estado atual do processador.

eip

ponteiro de instrução

bandeiras

bandeiras

O ponteiro de instrução é o endereço da instrução que está sendo executada.

O registo de sinalizadores é um conjunto de sinalizadores de um único bit. Muitas instruções alteram as bandeiras para descrever o resultado da instrução. Esses sinalizadores podem então ser testados por instruções de salto condicional. Consulte Flags x86 para obter detalhes.

Convenções de chamada

A arquitetura x86 tem várias convenções de chamada diferentes. Felizmente, todos eles seguem as mesmas regras de preservação de registro e retorno de função:

  • As funções devem preservar todos os registros, exceto eax, ecxe edx, que podem ser alterados através de uma chamada de função, e esp, que devem ser atualizados de acordo com a convenção de chamada.

  • O registro eax recebe valores de retorno de função se o resultado for de 32 bits ou menor. Se o resultado for de 64 bits, o resultado será armazenado no par edx:eax .

A seguir está uma lista de convenções de chamada usadas na arquitetura x86:

  • Win32 (__stdcall)

    Os parâmetros de função são passados na pilha, empurrados da direita para a esquerda, e o destinatário limpa a pilha.

  • Chamada de método C++ nativo (também conhecida como thiscall)

    Os parâmetros de função são passados na pilha, empurrados da direita para a esquerda, o ponteiro "este" é passado no registro de ecx e o destinatário limpa a pilha.

  • COM (__stdcall para chamadas de método C++)

    Os parâmetros da função são passados na pilha, empurrados da direita para a esquerda, em seguida, o ponteiro "este" é empurrado na pilha e, em seguida, a função é chamada. O destinatário limpa a pilha.

  • __fastcall

    Os dois primeiros argumentos DWORD ou menores são passados nos registos ecx e edx. Os parâmetros restantes são passados sobre a pilha, empurrados da direita para a esquerda. O destinatário limpa a pilha.

  • __cdecl

    Os parâmetros de função são passados na pilha, empurrados da direita para a esquerda, e o chamador limpa a pilha. A convenção de chamada __cdecl é usada para todas as funções com parâmetros de comprimento variável.

Exibição do depurador de registros e sinalizadores

Aqui está um exemplo de exibição de registro do depurador:

eax=00000000 ebx=008b6f00 ecx=01010101 edx=ffffffff esi=00000000 edi=00465000
eip=77f9d022 esp=05cffc48 ebp=05cffc54 iopl=0         nv up ei ng nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000286

Na depuração em modo de utilizador, pode-se ignorar o iopl e toda a última linha do ecrã do depurador.

Bandeiras x86

No exemplo anterior, os códigos de duas letras no final da segunda linha são indicadores. Estes são registradores de bit único e têm uma variedade de usos.

A tabela a seguir lista os sinalizadores x86:

Código da bandeira Nome da bandeira Valor Estado da Bandeira Descrição
de Sinalizador de estouro 0 1 nvov Sem transbordo - Transbordo
df Bandeira de direção 0 1 updn Direção para cima - Direção para baixo
se Sinalizador de interrupção 0 1 diei Interrupções desativadas - Interrupções ativadas
sf Sinalizar Bandeira 0 1 plng Positivo (ou zero) - Negativo
zf Bandeira Zero 0 1 nzzr Não zero - Zero
af Bandeira de transporte auxiliar 0 1 naac Sem transporte auxiliar - Transporte auxiliar
pf Bandeira de paridade 0 1 pepo Paridade ímpar - Paridade par
cf Bandeira de transporte 0 1 nccy Sem transporte - Transportar
TF Bandeira de armadilha Se tf for igual a 1, o processador gerará uma exceção STATUS_SINGLE_STEP após a execução de uma instrução. Esse sinalizador é usado por um depurador para implementar o rastreamento de etapa única. Não deve ser utilizado por outras aplicações.
iopl Nível de privilégio de E/S Nível de privilégio de E/S Este é um inteiro de dois bits, com valores entre zero e 3. Ele é usado pelo sistema operacional para controlar o acesso ao hardware. Não deve ser utilizado por aplicações.

Quando os registros são exibidos como resultado de algum comando na janela Comando do Depurador, é a de status do sinalizador que é exibida. No entanto, se quiser alterar um flag usando o comando r (Registers), deve referir-se a ele pelo código de flag .

Na janela Registradores do WinDbg, o código do sinalizador é usado para exibir ou alterar sinalizadores. O status do sinalizador não é suportado.

Aqui está um exemplo. Na exibição de registro anterior, o status da bandeira ng aparece. Isso significa que o sinalizador de sinal está atualmente definido como 1. Para alterar isso, use o seguinte comando:

r sf=0

Isso define o sinalizador de sinal como zero. Se fizeres outra apresentação de registo, o código de estado ng não aparecerá. Em vez disso, o código de estado pl será exibido.

A Bandeira de Sinal, a Bandeira Zero e a Bandeira de Transporte são as bandeiras mais usadas.

Condições

Uma condição descreve o estado de um ou mais sinalizadores. Todas as operações condicionais no x86 são expressas em termos de condições.

O montador usa uma abreviatura de uma ou duas letras para representar uma condição. Uma condição pode ser representada por várias abreviaturas. Por exemplo, AE ("acima ou igual") é a mesma condição que NB ("não abaixo"). A tabela a seguir lista algumas condições comuns e seu significado.

Nome da condição Bandeiras Significado

Z

ZF=1

O resultado da última operação foi zero.

Nova Zelândia

ZF=0

O resultado da última operação não foi zero.

C

CF=1

A última operação teve necessidade de uma retenção ou empréstimo. (Para inteiros não assinados, isso indica overflow.)

NC

CF=0

A última operação não exigiu um carry ou empréstimo. (Para inteiros não assinados, isso indica transbordo.)

S

SF=1

Resultado da última operação tem seu bit alto definido.

NS

SF=0

Resultado da última operação tem o seu bit superior desativado.

O

OF=1

Quando tratada como uma operação inteira assinada, a última operação causou um estouro ou subfluxo.

NÃO

OF=0

Quando tratada como operação inteira assinada, a última operação não causou um estouro ou subfluxo.

As condições também podem ser usadas para comparar dois valores. A instrução cmp compara seus dois operandos e, em seguida, define sinalizadores como se subtraísse um operando do outro. As seguintes condições podem ser usadas para verificar o resultado de cmpvalue1, value2.

Nome da condição Bandeiras Ou seja, depois de uma operação CMP.

E

ZF=1

valor1 == valor2.

NE

ZF=0

valor1 != valor2.

GE Países Baixos

SF=OF

valor1>= valor2. Os valores são tratados como inteiros assinados.

LE NG

ZF=1 ou SF!=OF

valor1<= valor2. Os valores são tratados como inteiros assinados.

G NLE

ZF=0 e SF=OF

valor1>valor2. Os valores são tratados como inteiros assinados.

L NGE

SF!=OF

valor1<valor2. Os valores são tratados como inteiros assinados.

AE NB

CF=0

valor1>= valor2. Os valores são tratados como inteiros não assinados.

SEJA NA

CF=1 ou ZF=1

valor1<= valor2. Os valores são tratados como inteiros não assinados.

Um NBE

CF=0 e ZF=0

valor1>valor2. Os valores são tratados como inteiros não assinados.

B NAE

CF=1

valor1<valor2. Os valores são tratados como inteiros não assinados.

As condições são geralmente usadas para agir sobre o resultado de uma instrução cmp ou teste . Por exemplo

cmp eax, 5
jz equal

Compara o registo EAX com o número 5 calculando a expressão (EAX - 5) e definindo sinalizadores de acordo com o resultado. Se o resultado da subtração for zero, então o indicador zr será ativado, e a condição jz será verdadeira, então o salto será realizado.

Tipos de dados

  • Byte: 8 bits

  • Palavra: 16 bits

  • dword: 32 bits

  • qword: 64 bits (inclui duplos de ponto flutuante)

  • Tword: 80 bits (inclui duplos estendidos de ponto flutuante)

  • oword: 128 bits

Notação

A tabela a seguir indica a notação usada para descrever as instruções da linguagem assembly.

Notação Significado

r, r1, r2...

Registos

m

Endereço de memória (consulte a seção Modos de endereçamento subsequentes para obter mais informações.)

#n

Constante imediata

r/m

Registo ou memória

r/#n

Registo ou constante imediata

r/m/#n

Registro, memória ou constante imediata

cc

Um código de condição listado na seção Condições anterior.

T

"B", "W" ou "D" (byte, palavra ou dword)

accT

Tamanho T acumulador: al se T = "B", ax se T = "W", ou eax se T = "D"

Modos de endereçamento

Existem vários modos de endereçamento diferentes, mas todos eles assumem a forma T ptr [expr], onde T é algum tipo de dados (consulte a seção Tipos de dados anterior) e expr é alguma expressão envolvendo constantes e registros.

A notação para a maioria dos modos pode ser deduzida sem muita dificuldade. Por exemplo, BYTE PTR [esi+edx*8+3] significa "pegue o valor do registro esi, adicione a ele oito vezes o valor do registro edx, adicione três e acesse o byte no endereço resultante."

Tubulação

O Pentium é dual-issue, o que significa que pode executar até duas ações em um ciclo de relógio. No entanto, as regras sobre quando é capaz de realizar duas ações ao mesmo tempo (conhecidas como emparelhamento ) são muito complicadas.

Como x86 é um processador CISC, você não precisa se preocupar com slots de atraso de salto.

Acesso sincronizado à memória

As instruções de carregamento, modificação e armazenamento podem receber o prefixo de bloqueio , que modifica a instrução da seguinte maneira:

  1. Antes de emitir a instrução, a CPU liberará todas as operações de memória pendentes para garantir a coerência. Todos os pré-carregamentos de dados são cancelados.

  2. Ao emitir a instrução, a CPU terá acesso exclusivo ao barramento. Isso garante a atomicidade da operação de carga/modificação/armazenamento.

A instrução xchg obedece automaticamente às regras anteriores sempre que troca um valor com a memória.

Todas as outras instruções, por padrão, são de não bloqueio.

Previsão de salto

Prevê-se que os saltos incondicionais sejam realizados.

Prevê-se que os saltos condicionais sejam tomados ou não, dependendo se foram tomados na última vez que foram executados. O cache para gravar o histórico de saltos é limitado em tamanho.

Se a CPU não tiver um registro de se o salto condicional foi feito ou não na última vez que foi executado, ele prevê saltos condicionais para trás como tomados e saltos condicionais para frente como não realizados.

Alinhamento

O processador x86 corrigirá automaticamente o acesso à memória não alinhada, o que resulta numa penalização de desempenho. Nenhuma exceção é levantada.

Um acesso à memória é considerado alinhado se o endereço for um múltiplo inteiro do tamanho do objeto. Por exemplo, todos os acessos BYTE estão alinhados (tudo é um múltiplo inteiro de 1), os acessos WORD a endereços pares estão alinhados e os endereços DWORD devem ser um múltiplo de 4 para serem alinhados.

O bloqueio prefixo não deve ser usado para acessos à memória desalinhados.

Ver também

Arquitetura x64

X86-64 Wikipédia