ModR/M e SIB

Entendendo os byte ModR/M e SIB.

Como j√° foi mencionado anteriormente o byte ModR/M √© usado em algumas instru√ß√Ķes para especificar o operando na mem√≥ria ou registrador.

Em Assembly existem dois "tipos" de instru√ß√Ķes que recebem dois operandos:

  1. As que tem um operando registrador e imediato. Exemplo: mov eax, 123

  2. As que tem um operando na memória ou dois operandos registradores. Exemplos: mov [ebx], 123 e mov eax, ebx.

O primeiro tipo n√£o precisa do byte ModR/M, pois o registrador destino √© especificado nos 3 √ļltimos bits do byte do opcode. Por exemplo o opcode B8 da instru√ß√£o mov eax, 123 √© o seguinte em bin√°rio: 10111000 Onde o n√ļmero zero (000) √© o c√≥digo para identificar o registrador EAX.

pageCodificação dos registradores

Um jeito mais simples de especificar esse campo no opcode sem precisar lidar com binário é simplesmente somar o opcode "base" (correspondente ao uso de AL/AX/EAX) mais o código do registrador. Por exemplo se a instrução B8 (B8 + 0) corresponde a mov eax, 123, então o opcode BB (B8 + 3) é mov ebx, 123. E se eu quiser fazer mov bx, 123 basta adicionar o prefixo 66 à instrução.

J√° as instru√ß√Ķes do segundo tipo usam o byte ModR/M para definir o operando destino na mem√≥ria (no caso de instru√ß√Ķes sem o operando registrador) ou os dois operandos. Onde o byte ModR/M consiste nos tr√™s campos:

  • MOD - Os primeiros 2 bits que definem o "modo" do operando R/M.

  • REG - Os 3 pr√≥ximos bits que definem o c√≥digo do operando registrador.

  • R/M - Os 3 √ļltimos bits que definem o c√≥digo do operando R/M.

O byte define 2 operandos:

  1. Um operando que é sempre um registrador, definido no campo REG.

  2. Um operando que pode ser um registrador ou operando na memória.

Para que o campo R/M defina também o código de um registrador, assim como o REG, o valor 3 (11 em binário) deve ser usado no campo MOD.

Um adendo sobre o byte ModR/M √© que em algumas instru√ß√Ķes o campo REG √© usado como uma extens√£o do opcode. √Č o caso por exemplo das instru√ß√Ķes inc dword [ebx] (FF 03) e dec dword [ebx] (FF 0B) que cont√©m o mesmo byte de opcode mas fazem opera√ß√Ķes diferentes. Repare como o campo R/M √© necess√°rio para especificar o operando na mem√≥ria mas o REG fica "sobrando", por isso os engenheiros da Intel tomaram essa decis√£o minimamente confusa (vulgo gambiarra), afim de aproveitar dessa peculiaridade em instru√ß√Ķes que precisam de um operando na mem√≥ria mas n√£o precisam de um operando registrador.

Para os demais valores do campo MOD os seguintes endereçamentos são feitos de acordo com o valor de R/M:

Endereçamento em 16-bit

MOD 00

R/MEndereçamento

000

[BX+SI]

001

[BX+DI]

010

[BP+SI]

011

[BP+DI]

100

[SI]

101

[DI]

110

displacement 16-bit

111

[BX]

MOD 01

R/MEndereçamento

000

[BX+SI] + displacement 8-bit

001

[BX+DI] + displacement 8-bit

010

[BP+SI] + displacement 8-bit

011

[BP+DI] + displacement 8-bit

100

[SI] + displacement 8-bit

101

[DI] + displacement 8-bit

110

[BP] + displacement 8-bit

111

[BX] + displacement 8-bit

MOD 10

R/MEndereçamento

000

[BX+SI] + displacement 16-bit

001

[BX+DI] + displacement 16-bit

010

[BP+SI] + displacement 16-bit

011

[BP+DI] + displacement 16-bit

100

[SI] + displacement 16-bit

101

[DI] + displacement 16-bit

110

[BP] + displacement 16-bit

111

[BX] + displacement 16-bit

Endereçamento em 32-bit

MOD 00

R/MEndereçamento

000

[eax]

001

[ecx]

010

[edx]

011

[ebx]

100

SIB

101

displacement 32-bit

110

[esi]

111

[edi]

MOD 01

R/MEndereçamento

000

[eax] + displacement 8-bit

001

[ecx] + displacement 8-bit

010

[edx] + displacement 8-bit

011

[ebx] + displacement 8-bit

100

SIB + displacement 8-bit

101

[ebp] + displacement 8-bit

110

[esi] + displacement 8-bit

111

[edi] + displacement 8-bit

MOD 10

R/MEndereçamento

000

[eax] + displacement 32-bit

001

[ecx] + displacement 32-bit

010

[edx] + displacement 32-bit

011

[ebx] + displacement 32-bit

100

SIB + displacement 32-bit

101

[ebp] + displacement 32-bit

110

[esi] + displacement 32-bit

111

[edi] + displacement 32-bit

Endereçamento em 64-bit

Devido ao prefixo REX o campo R/M é estendido em 1 bit no modo de 64-bit.

MOD 00

R/MEndereçamento

0000

[rax/eax]

0001

[rcx/ecx]

0010

[rdx/edx]

0011

[rbx/ebx]

0100

SIB

0101

[rip/eip] + displacement 32-bit

0110

[rsi/esi]

0111

[rdi/edi]

1000

[r8/r8d]

1001

[r9/r9d]

1010

[r10/r10d]

1011

[r11/r11d]

1100

SIB

1101

[rip/eip] + displacement 32-bit

1110

[r14/r14d]

1111

[r15/r15d]

MOD 01

R/MEndereçamento

0000

[rax/eax] + displacement 8-bit

0001

[rcx/ecx] + displacement 8-bit

0010

[rdx/edx] + displacement 8-bit

0011

[rbx/ebx] + displacement 8-bit

0100

SIB + displacement 8-bit

0101

[rbp/ebp] + displacement 8-bit

0110

[rsi/esi] + displacement 8-bit

0111

[rdi/edi] + displacement 8-bit

1000

[r8/r8d] + displacement 8-bit

1001

[r9/r9d] + displacement 8-bit

1010

[r10/r10d] + displacement 8-bit

1011

[r11/r11d] + displacement 8-bit

1100

SIB + displacement 8-bit

1101

[r13/r13d] + displacement 8-bit

1110

[r14/r14d] + displacement 8-bit

1111

[r15/r15d] + displacement 8-bit

MOD 10

R/MEndereçamento

0000

[rax/eax] + displacement 32-bit

0001

[rcx/ecx] + displacement 32-bit

0010

[rdx/edx] + displacement 32-bit

0011

[rbx/ebx] + displacement 32-bit

0100

SIB + displacement 32-bit

0101

[rbp/ebp] + displacement 32-bit

0110

[rsi/esi] + displacement 32-bit

0111

[rdi/edi] + displacement 32-bit

1000

[r8/r8d] + displacement 32-bit

1001

[r9/r9d] + displacement 32-bit

1010

[r10/r10d] + displacement 32-bit

1011

[r11/r11d] + displacement 32-bit

1100

SIB + displacement 32-bit

1101

[r13/r13d] + displacement 32-bit

1110

[r14/r14d] + displacement 32-bit

1111

[r15/r15d] + displacement 32-bit

Byte SIB

Os endereçamentos com R/M 100 (em 32-bit e 64-bit) são os que usam o byte SIB (exceto MOD 11), que como já foi explicado anteriormente contém os campos Scale, Index e Base que são calculados de maneira equivalente a expressão:

base + index * scale

Onde o campo scale são os 2 primeiros bits, onde seu valor numérico é equivalente aos seguintes fatores de escala:

  • 00 - N√£o multiplica o index

  • 01 - Multiplica o index por 2

  • 10 - Multiplica o index por 4

  • 11 - Multiplica o index por 8

Já os campos index e base contém 3 bits cada e os mesmos armazenam o código dos registradores que serão usados. Os bits dos campos no byte seguem a ordem que o próprio nome sugere. Como em: SSIIIBBB.

Last updated