O processador 80386 (e posteriores) possuem registradores de 32 bits. Os oito registradores de propósito geral possuem equivalentes com 32 bits. São eles eax, ebx, ecx, edx, esi, edi, ebp e esp. Estes registradores podem ser utilizados como operandos de muitas instruções 80386.
O processador 80386 generalizou os modos de endereçamento à memória. Enquanto o 8086 só permitia usar bx ou bp como registradores de base e si ou di como registradores de índice, o 80386 permite que praticamente todos os registradores de propósito geral de 32 bits seja usado como um registrador de base ou de índice. Além do mais, o 80386 novos modos de endereçamento indexado em escala que simplificam o acesso a elementos de arrays. Além do aumento para 32 bits, os novos modos de endereçamento são, provavelmente, o maior progresso do chip em relação a processadores anteriores.
No 80386 é possível especificar qualquer registrador de 32 bits de propósito geral quando se usa o modo de endereçamento indireto com registradores. Tanto [eax], [ebx], [ecx], [edx], [esi] como [edi] fornecem deslocamentos, como padrão, para o segmento de dados. Os modos de endereçamento [ebp] e [esp] usam o segmento da pilha como padrão.
Note que, rodando em modo real de 16 bits no 80386, os deslocamentos nestes registradores de 32 bits precisam continuar dentro do limite de 0 a 0FFFFh. Não é possível usar valores maiores que isto para acessar mais do que 64K num segmento. Note também que é preciso usar o nome de 32 bits dos registradores (eax ao invés de ax, por exemplo). As instruções seguintes mostram todas as formas válidas:
mov al, [eax] mov al, [ebx] mov al, [ecx] mov al, [edx] mov al, [esi] mov al, [edi] mov al, [ebp] ;Usa SS como padrão mov al, [esp] ;Usa SS como padrão
Os modos de endereçamento indexado (registrador indireto mais um deslocamento) permitem misturar um registrador de 32 bits com uma constante. Os modos de endereçamento base/indexado permitem associar dois registradores de 32 bits. Finalmente, os modos de endereçamento base/indexado/deslocamento permitem combinar uma constante e dois registradores para formar o endereço efetivo. Lembre-se de que o deslocamento produzido pelo cálculo do endereço efetivo precisa ser de 16 bits quando se opera no modo real.
No 80386 os termos registrador base e registrador índice ampliam o sentido. QUando se combina dois registradores de 32 bits num modo de endereçamento, o primeiro registrador é o registrador base e o segundo o registrador índice. Isto é verdadeiro, independentemente dos nomes dos registradores. Note que o 80386 permite usar o mesmo registrador como base e como índice, o que pode ser útil em várias ocasiões. As instruções seguintes fornecem exemplos representativos dos vários modos de endereçamento base e indexado, junto com suas variações sintáticas:
mov al, disp[eax] ; Modos de endereçamento mov al, [ebx+disp] ; indexado. mov al, [ecx][disp] mov al, disp[edx] mov al, disp[esi] mov al, disp[edi] mov al, disp[ebp] ; Usa SS como padrão. mov al, disp[esp] ; Usa SS como padrão.
As instruções seguintes usam o modo de endereçamento base+indexado. O primeiro registrador no segundo operando é o registrador base, o segundo é o registrador de índice. Se o registrador base for esp ou ebp, o endereço efetivo é relativo ao segmento de pilha. Nos outros casos, o endereço efetivo é relativo ao segmento de dados. Note que a escolha do registrador índice não afeta a escolha do segmento padrão.
mov al, [eax][ebx] ; Modos de endereçamento Base+indexed mov al, [ebx+ebx] ; base + indexado. mov al, [ecx][edx] mov al, [edx][ebp] ; Usa DS como padrão. mov al, [esi][edi] mov al, [edi][esi] mov al, [ebp+ebx] ; Usa SS como padrão. mov al, [esp][ecx] ; Usa SS como padrão.
É claro que podemos adicionar um deslocamento aos modos de endereçamento acima citados para produzir o modo de endereçamento base+indexado+deslocamento. As instruções seguintes são uma amostra representativa dos modos de endereçamento possíveis:
mov al, disp[eax][ebx] ; Modos de endereçamento mov al, disp[ebx+ebx] ; base+indexado. mov al, [ecx+edx+desloc] mov al, disp[edx+ebp] ; Usa DS como padrão. mov al, [esi][edi][disp] mov al, [edi][disp][esi] mov al, disp[ebp+ebx] ; Usa SS como padrão. mov al, [esp+ecx][disp] ; Usa SS como padrão.
Existe uma restrição em relação ao uso do registrador índice no 80386: não se pode usar o registrador esp como um registrador índice. Ele pode ser usado como registrador base, mas não como registrador índice.
Os modos de endereçamento indexado, bas/indexado e base/indexado/deslocamento descritos acima, na realidade são instâncias especiais dos modos de endereçamento indexado em escala do 80386. Estes modos de endereçamento são particularmente úteis para acessar elementos de arrays, apesar de não estarem limitados a este propósito. Estes modos permitem multiplicar o registrador índice por um, dois, quatro ou oito. A sintaxe geral é:
desloc[índice*n] [base][índice*n] ou desloc[base][índice*n]
onde "base" e "índice" representam qualquer registrador de propósito geral de 32 bits do 80386 e "n" é o valor de um, dois, quatro ou oito.
O 80386 calcula o endereço efetivo somando desloc, base e índice*n. Por exemplo, se ebx contiver 1000h e esi contiver 4, então
mov al,8[ebx][esi*4] ; Carrega AL com o valor da posição 1018h mov al,1000h[ebx][ebx*2] ; Carrega AL com o valor da posição 4000h mov al,1000h[esi*8] ; Carrega AL com o valor da posição 1020h
Note que os modos de endereçamento ampliados indexado, base/indexado e base/indexado/deslocamento do 80386 na realidade são casos especiais deste modo de endereçamento indexado em escala com "n" igual a um. Isto é, os pares de instruções seguintes são absolutamente idênticos:
mov al, 2[ebx][esi*1] mov al, 2[ebx][esi] mov al, [ebx][esi*1] mov al, [ebx][esi] mov al, 2[esi*1] mov al, 2[esi]
É claro que o MASM permite uma porção de variações destes modos de endereçamento. A seguir uma pequena amostra destas possibilidades:
desloc[bx][si*2] [bx+desloc][si*2] [bx+si*2+desloc] [si*2+bx][desloc] desloc[si*2][bx] [si*2+desloc][bx] [desloc+bx][si*2]
Como os modos de endereçamento do 80386 são mais ortogonais, eles são mais fáceis de memorizar do que os modos de endereçamento do 8086. Para programadores trabalhando com o processador 80386 sempre existe a tentação de deixar os modos de endereçamento do 8086 de lado e usar unicamento o conjunto do 80386. Entretanto, veremos no próximo módulo que os modos de endereçamento do 8086 são mais eficientes que os comparáveis do 80386. Portanto, é importante conhecer todos os modos de endereçamento e escolher o modo apropriado para cada situação.
Quando se usa os modos de endereçamento base/indexado e base/indexado/deslocamento no 80386, sem a opção de escala (isto é, deixando a escala padrão em "*1"), o primeiro registrador que aparece no modo de endereçamento é o registrdor base e, o segundo registrador, é o registrador índice. Este é um aspecto importante porque a escolha do segmento padrão é determinada pela escolha do registrador base. Se o registrador base for ebp ou esp, o 80386 usa como padrão o segmento de dados, mesmo se o registrador índice for ebp. Se usarmos o operador índice de escala ("*n") com um registrdor, este registrador sempre será o registrador índice, independentemente de onde aparecer no modo de endereçamento:
[ebx][ebp] ; Usa DS como padrão. [ebp][ebx] ; Usa SS como padrão. [ebp*1][ebx] ; Usa DS como padrão. [ebx][ebp*1] ; Usa DS como padrão. [ebp][ebx*1] ; Usa SS como padrão. [ebx*1][ebp] ; Usa SS como padrão. es:[ebx][ebp*1] ; Usa ES.
Os exemplos do texto usarão com muita frequência a instrução mov 80x86. Além disso, a instrução mov é a instrução de máquina mais comum do 80x86. Portanto, compensa gastar um pouco de tempo discutindo o funcionamento desta instrução. A instrução mov é muito simples e tem a seguinte forma:
mov faz uma cópia da fonte e armazena este valor no destino. Esta instrução não afeta o conteúdo original da fonte. Ela sobrepõe o valor anterior do destino. A operação desta instrução pode descrita pela seguinte declaração Pascal:
Esta instrução tem muitas limitações. Seremos confrontados com ela no nosso estudo da linguagem Assembly 80x86. Para entender porque estas limitações existem, é preciso dar uma olhada no código de máquina das várias formas desta instrução. Um alerta: eles nunca chamam o CISC (Complex Instruction Set Computer) do 80386. A codificação da instrução mov provavelmente é a mais complexa do conjunto de instruções. Isto significa que, se não estudarmos o código de máquina desta instrução, não seremos capazes de avaliá-la e não seremos capazes de escrever código otimizado usando esta instrução. Agora você vai entender porque trabalhamos com os processadores x86 (os "de mentira") nos módulos anteriores ao invés de usar as instruções 80x86.
![]() Fig.13 - A instrução MOV |
Existem diversas versões da instrução mov. O menumônico mov descreve mais de uma dúzia de instruções diferentes no 80386. A forma mais usada tem a seguinte codificação binária (veja a Fig.13).
Os oito primeiros bits da instrução são o opcode. Os bits zero e um definem a largura da instrução (8, 16 ou 32 bits) e a direção da transferência. Quando forem analisadas instruções específicas neste texto, os valores de d e w estarão sempre preenchidos. Outros textos, com frequência, costumam pedir que estes valores sejam preenchidos pelo leitor.
O opcode seguinte é o byte do modo de endereçamento, carinhosamente chamado de byte "mod-reg-r/m" pela maioria dos programadores. Este byte escolhe qual das 256 combinações possíveis de operandos a instrução genérica mov permite. A instrução mov genérica assume três formas diferentes na linguagem Assembly:
Observe que pelo menos um dos operandos é sempre um registrador de propósito geral. O campo reg no byte mod/reg/rm especifica este registrador (ou um dos registradores se usarmos a terceira forma). O bit d (de direção) do opcode decide se a instrução deve armazenar dados nos registradores (d=1) ou na memória (d=0).
| reg | w = 0 | w = 1 16 bits | w = 1 32 bits |
| 000 | AL | AX | EAX |
| 001 | CL | CX | ECX |
| 010 | DL | DX | EDX |
| 011 | BL | BX | EBX |
| 100 | AH | SP | ESP |
| 101 | CH | BP | EBP |
| 110 | DH | SI | ESI |
| 111 | BH | DI | EDI |
Os bits do campo reg permitem selecionar um de oito registradores diferentes. O 8086 permite oito registradores de 8 bits e oito registradores de propósito geral de 16 bits. O 80386 também permite oito registradores de propósito geral de 32 bits. A CPU decodifica o significado do campo reg da seguinte maneira:
Para diferenciar registradores de 16 e de 32 bits, o processador 80386 e posteriores usam um byte especial de prefixo no opcode das instruções com registradores de 32 bits. No restante, as codificações das instruções são as mesmas para os dois tipos de instrução.
O campo r/m, juntamente com o campo mod, escolhe o modo de endereçamento. A codificação do campo mod é a seguinte:
| MOD | Significado |
| 00 | O campo r/m indica um modo de endereçamento de memória indireta por registrador ou de base/indexado (veja a codificação para r/m) a não ser que o campo r/m contenha 110. Se MOD=00 e r/m=110, os campos mod e r/m indicam endereçamento apenas por deslocamento (direto). |
| 01 | O campo r/m indica um modo de endereçamento indexado ou base/indexado/deslocamento. Há um deslocamento de 8 bits com sinal seguindo o byte mod/reg/rm. |
| 10 | O campo r/m indica um modo de endereçamento indexado ou base/indexado/deslocamento. Há um deslocamento de 16 bits com sinal (no modo 16 bits) ou um deslocamento de 32 bits com sinal (no modo 32 bits) seguindo o byte mod/reg/rm. |
| 11 | O campo r/m indica um registrador e usa a mesma codificação do campo reg. |
O campo mod escolhe entre mover de registrador para registrador e mover da memória para registrador. Também escolhe o tamanho do deslocamento (zero, um, dois ou quatro bytes) que segue a instrução dos modos de endereçamento de memória. Se MOD=00, significa que se trata de um dos modos de endereçamento sem deslocamento (indireto via registrador ou base/indexado). Note o caso especial onde MOD=00 e r/m=110. Normalmente corresponderia ao modo de endereçamento [bp]. O 8086 usa esta codificação para o modo de endereçamento apenas por deslocamento. Isto mostra que não existe um modo de endereçamento por [bp] verdadeiro no 8086.
Para entender porque é possível usar o modo de endereçamento por [bp], analise os MOD=01 e MOD=02 da tabela acima. Estes padrões de bits ativam os modos de endereçamento desloc[reg] e desloc[reg][reg]. Aparentemente não correspondem a um modo de endereçamento [bp], mas considere as seguintes instruções:
mov al, 0[bx] mov ah, 0[bp] mov 0[si], al mov 0[di], ah
Estas declarações, que usam os modos de endereçamento indexado, realizam as mesmas operações que as correspondentes indiretas por registradores (obtidas removendo-se o deslocamento das instruções acima). A única diferença real entre as duas formas é que o modo de endereçamento indexado é um byte mais longo (se MOD=01 e dois bytes mais longo se MOD=10), o qual contém o deslocamento zero. Por serem maiores, estas instruções também são um pouco mais lentas.
Esta característica do 8086 - de permitir duas ou mais maneiras de realizar a mesma coisa - ocorre em todo o conjunto de isntruções. Na verdade, veremos vários outros exemplos antes de terminarmos a análise da instrução mov. O MASM geralmente escolhe a melhor forma automaticamente. Se escrevêssemos o código acima e o submetêssemos ao MASM, ele geraria o modo de endereçamento indireto por registradores para todas as instruções, exceto para mov ah,0[bp]. Mesmo neste caso, emitiria apenas um byte para um deslocamento zero. Note que o MASM não exige que se indique 0[bp]. Podemos usar apenas [bp] que o MASM automaticamente supre o byte zero.
Se MOD for diferente de 11b, o campo r/m codifica o modo de endereçamento à memória da seguinte forma:
| R/M | Modo de endereçamento (MOD=00, 01 ou 10) |
| 000 | [BX+SI] ou DESLOC[BX][SI] (depende de MOD) |
| 001 | [BX+DI] ou DESLOC[BX+DI] (depende de MOD) |
| 010 | [BP+SI] ou DESLOC[BP+SI] (depende de MOD) |
| 011 | [BP+DI] ou DESLOC[BP+DI] (depende de MOD) |
| 100 | [SI] ou DESLOC[SI] (depende de MOD) |
| 101 | [DI] ou DESLOC[DI] (depende de MOD) |
| 110 | Apenas deslocamento ou DESLOC[BP] (depende de MOD) |
| 111 | [BX] ou DESLOC[BX] (depende de MOD) |
Não se esqueça de que os modos de endereçamento envolvendo bp usam o segmento da pilha (ss) como padrão. Todos os outros usam o segmento de dados (ds) como padrão.
Se você já ficou perdido com esta explicação, ainda não sabe do pior. Lembre-se de que estes são apenas alguns dos modos de edereçamento 8086 e ainda é preciso conhecer todos os modos de endereçamento do 80386. Agora começa a ficar claro o que o pessoal quiz dizer com computador de instruções complexas. Entretanto, o conceito importante que deve ser notado é que é possível construir instruções 80x86 da mesma forma como foram construídas as instruções do x86 no capítulo 3 - criando as instruções bit a bit.
Existem vários fatos importantes, relacionados à instrução mov, que devem ser lembrados. Antes de mais nada, não existem movimentos da memória para a memória. Por alguma razão, os iniciantes da linguagem Assembly têm uma certa dificuldade de lembrar deste aspecto. Apesar de existirem algumas instruções que realizam movimentos da memória para a memória, carregar um registrador e depois armazenar este valor na memória é quase sempre mais eficiente. Outro fato importante é que existem muitas instruções mov diferentes que realizam a mesma coisa. Também existem vários modos de endereçamento diferentes que podem ser usados para a mesma posição na memória. Se você tiver interesse em escrever programas mais curtos e mais rápidos possíveis na linguagem Assembly, será preciso observar constantemente as vantagens e desvantagens de instruções equivalentes.
A análise deste capítulo refere-se principalmente às instruções mov genéricas para realçar a maneira como os processadores 80x86 codificam os modos de endereçamento de memória e de registradores numa instrução mov. Outras formas da instrução mov permitem transferir dados entre os registradores de 16 bits de propósito geral e os registradores de segmento. Outras ainda permitem carregar registradores ou posições de memória com uma constante. Estas variações da instrução mov usam opcodes diferentes. Para maiores detalhes veja a codificação de instruções no Apêndice D (em formato pdf).
Na tabela abaixo estão as principais instruções MOV e suas respectivas codificações em binário:
| Instrução | Binário | Observação |
| mov reg8, reg8 | 1000 1000 [11-reg-r/m] | r/m especifica o reg destino |
| mov reg8, reg8 | 1000 1010 [11-reg-r/m] | Modo alternativo. r/m especifica o reg destino |
| mov reg16, reg16 | 1000 1001 [11-reg-r/m] | r/m especifica o reg destino |
| mov reg16, reg16 | 1000 1011 [11-reg-r/m] | Modo alternativo. r/m especifica o reg destino |
| mov reg32, reg32 | 0110 0110 1000 1001 [11-reg-r/m] | r/m especifica o reg destino |
| mov reg32, reg32 | 0110 0110 1000 1011 [11-reg-r/m] | Modo alternativo. r/m especifica o reg destino |
| mov mem, reg8 | 1000 1000 [mod-reg-r/m] | |
| mov reg8, mem | 1000 1010 [mod-reg-r/m] | |
| mov mem, reg16 | 1000 1001 [mod-reg-r/m] | |
| mov reg16, mem | 1000 1011 [mod-reg-r/m] | |
| mov mem, reg32 | 0110 0110 1000 1001 [mod-reg-r/m] | |
| mov reg32, mem | 0110 0110 1000 1011 [mod-reg-r/m] | |
| mov reg8, imed | 1011 0rrr [imed8] | |
| mov reg8, imed | 1100 0110 [11-000-r/m] [imed8] | Modo alternativo. |
| mov reg16, imed | 1011 1rrr [imed16] | |
| mov reg16, imed | 1100 0111 [11-000-r/m] [imed16] | Modo alternativo. |
| mov reg32, imed | 0110 0110 1011 1rrr [imed32] | |
| mov reg32, imed | 0110 0110 1100 0111 [11-000-r/m] [imed32] | Modo alternativo. |
| mov mem8, imed | 1100 0110 [mod-000-r/m] [imed8] | |
| mov mem16, imed | 1100 0111 [mod-000-r/m] [imed16] | |
| mov mem32, imed | 1100 0111 [mod-000-r/m] [imed32] | |
| mov al, desloc | 1010 0000 [desloc] | |
| mov ax, desloc | 1010 0001 [desloc] | |
| mov eax, desloc | 0110 0110 1010 0001 [desloc] | |
| mov desloc, al | 1010 0010 [desloc] | |
| mov desloc, ax | 1010 0011 [desloc] | |
| mov desloc, eax | 0110 0110 1010 0011 [desloc] | |
| mov sreg, reg16 | 1000 1110 [11-sreg-r/m] | |
| mov sreg, mem | 1000 1110 [mod-reg-r/m] | |
| mov reg16, sreg | 1000 1100 [11-sreg-r/m] | |
| mov mem, sreg | 1000 1100 [mod-reg-r/m] |
Existem várias instruções mov adicionais no 80386 que permitem carregar os registradores de propósito especial do 80386. Eles não serão analisados neste texto. No 80x86 também existem algumas instruções para strings, as quais realizam operações da memória para a memória. Estas instruções aparecem no próximo capítulo, mas não são boas substituitas da instrução mov.
Gostou do conjunto complexo de instruções? Bota complexo nisso, compadre! Como tudo, a complexidade tem suas vantagens e suas dificuldades. Se, por um lado, entender tudo fica meio embolado, por outro, as possibilidades e formas de atuação são ampliadas. O importante é entender o mecanismo da coisa.
Volto a reforçar um argumento: conhecer os processadores mais antigos e seus conjuntos de instruções é o caminho certo e confiável para dominar os processadores atuais. De instrução mov, que faz o empurra-empurra de dados, já temos know-how. Agora chegou a hora de dar uma olhada em variáveis e estruturas de dados.