# Opcode

Como já foi dito antes existem opcodes cujo os 3 últimos bits são usados para identificar o registrador usado na instrução. Opcodes nesse estilo de codificação são usados para instruções que só precisam usar um registrador. Por exemplo `mov eax, 123` cujo o opcode é `B8`.

Já em instruções que usam o [byte ModR/M](https://mentebinaria.gitbook.io/assembly/apendices/codigo-de-maquina/modr-m-e-sib) os dois bits menos significativos do opcode tem um significado especial, que são chamados de bit <mark style="color:green;">**D**</mark> (*direction bit*) e <mark style="color:red;">**S**</mark> (*size bit*). Conforme ilustração:

![Representação dos bits de um opcode.](https://2466397120-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lif0YmrEB3G3dh1VxSC%2Fuploads%2FAeuHV4OIwmKcMFUQaLTR%2Fopcode-ilustra%C3%A7%C3%A3o.png?alt=media\&token=8f2af5c0-e11d-4e90-b871-efd190f6d4ff)

### **BIT D**

A função do bit <mark style="color:green;">**D**</mark> é indicar a direção para onde a operação está sendo executada. Se do REG para o R/M ou vice-versa. Repare nas instruções abaixo e seus respectivos opcodes:

```nasm
mov eax, [ebx] ; 8B03
mov [ebx], eax ; 8903
```

Convertendo os opcodes `8B` e `89` para binário dá para notar um fato interessante:

```
8B -> 10001011
89 -> 10001001
```

A única diferença entre os opcodes é que em um o bit <mark style="color:green;">**D**</mark> está ligado e no outro não. Quando o bit <mark style="color:green;">**D**</mark> está ligado o campo REG é usado como operando destino e o campo R/M usado como fonte. E quando ele está desligado é o inverso: o campo R/M é o destino e o REG é o fonte. Obviamente o mesmo também se aplica se o R/M também for um registrador.

Por exemplo a instrução `xor eax, eax` pode ser escrita em código de máquina como `31 C0` ou `33 C0`. Como no campo REG e no campo R/M são os mesmos registradores não faz diferença qual é o fonte e qual é o destino, a operação executada será a mesma. Usando um *disassembler* como o **ndisasm** dá para notar isso:

```
felipe@silva-lenovo:~$ echo -ne "\x31\xC0\x33\xC0" > tst
felipe@silva-lenovo:~$ ndisasm -b32 tst
00000000  31C0              xor eax,eax
00000002  33C0              xor eax,eax
```

### **BIT S**

O bit <mark style="color:red;">**S**</mark> é usado para definir o tamanho do operando, onde:

* `0` -> Indica que o operando é de 8-bit
* `1` -> Indica que o operando é do tamanho do **operand-size**.

Repare por exemplo a instrução `30 C0`:

```
felipe@silva-lenovo:~$ echo -ne "\x30\xC0" > tst
felipe@silva-lenovo:~$ ndisasm -b32 tst
00000000  30C0              xor al,al
```

Onde `31 C0` (com o bit <mark style="color:red;">**S**</mark> ligado) usa o operando de 32-bit EAX. Mas `30 C0` usa o operando de 8-bit AL.

Repare também no seguinte caso:

```
felipe@silva-lenovo:~$ echo -ne "\x66\x30\xC0\x66\x31\xC0" > tst
felipe@silva-lenovo:~$ ndisasm -b32 tst
00000000  6630C0            o16 xor al,al
00000003  6631C0            xor ax,ax
```

Veja que ao usar o prefixo `66` ([*operand-size override*](https://mentebinaria.gitbook.io/assembly/apendices/atributos-e-prefixos#atributo-operand-size)) em `31 C0` o registrador AX é utilizado. Mas esse prefixo é ignorado em instruções cujo o bit <mark style="color:red;">**S**</mark> esteja desligado. Por isso o **ndisasm** faz o *disassembly* da instrução ainda como `xor al, al`. Embora ele adicione um `o16` ali para denotar o uso (inútil) do prefixo.
