Atualizado: 30/08/2025

Este conteúdo é original e não foi gerado por inteligência artificial.

Divisão de Inteiros em Assembly NASM: As Instruções DIV e IDIV

As operações de divisão em Assembly (div e idiv) são mais rigorosas do que outras operações aritméticas, exigindo uma preparação cuidadosa dos operandos para funcionar corretamente. A arquitetura x86-64 oferece duas instruções primárias para essa finalidade:

  • div: Realiza a divisão de inteiros sem sinal (unsigned).
  • idiv: Realiza a divisão de inteiros com sinal (signed).

Ambas as instruções aceitam um único operando explícito: o divisor. O dividendo (o número a ser dividido) é sempre um operando implícito, que deve ser preparado em um par de registradores. O resultado da operação são dois valores: o quociente e o resto.

O Mecanismo de Operação: A Regra do Dobro do Tamanho

A regra fundamental da divisão em x86-64 é que o dividendo deve ter o dobro do tamanho do divisor. A instrução espera que o dividendo já esteja corretamente posicionado no par de registradores apropriado antes de ser executada.

Tamanho do Divisor (source)Dividendo (Implícito, 2n bits)Operação RealizadaQuociente (n bits)Resto (n bits)
8 bits (byte)AX (16 bits)AX / sourceALAH
16 bits (word)DX:AX (32 bits)DX:AX / sourceAXDX
32 bits (dword)EDX:EAX (64 bits)EDX:EAX / sourceEAXEDX
64 bits (qword)RDX:RAX (128 bits)RDX:RAX / sourceRAXRDX

Erro Comum: A falha mais comum é a exceção de divisão por zero (#DE), que ocorre se o divisor for zero, ou uma exceção de overflow, se o quociente for grande demais para caber no registrador de destino.

Exemplos e Preparação do Dividendo

Exemplo 1: Divisão de 16 bits por 8 bits (Linux) Neste caso, o dividendo em AX (16 bits) já tem o dobro do tamanho do divisor em BL (8 bits).

global _start
section .text
_start:
    xor     rax, rax        ; Zera RAX para garantir que AH (parte alta de AX) esteja limpa.
    mov     ax, 22          ; Dividendo de 16 bits em AX.
    mov     bl, 5           ; Divisor de 8 bits em BL.
    div     bl              ; Executa AX / BL.
                            ; Quociente (4) vai para AL, Resto (2) vai para AH.
    movzx   rdi, al         ; Move o quociente para rdi para o código de saída.
    mov     rax, 60
    syscall

Exemplo 1 Análogo para Windows:

global _start
section .text
_start:
    xor     rax, rax
    mov     ax, 22
    mov     bl, 5
    div     bl              ; AL = 4 (quociente), AH = 2 (resto).
    movzx   rax, al         ; Move o quociente para rax para o código de saída.
    ret

Exemplo 2: Divisão de 32 bits por 16 bits (Linux) Para dividir um dividendo de 32 bits (EAX) por um divisor de 16 bits (BX), precisamos preparar o dividendo completo de 64 bits em EDX:EAX.

global _start
section .text
_start:
    mov     eax, 0x12003    ; Dividendo original de 32 bits.
    ; Abordagem padrão: zerar a parte alta do dividendo
    xor     edx, edx        ; Prepara EDX:EAX como um número de 64 bits
                            ; onde EDX=0 e EAX=0x12003.

    mov     bx, 0x10        ; Divisor de 16 bits.
    div     bx              ; Executa EDX:EAX / BX.
                            ; AX = 0x1200 (quociente), DX = 3 (resto).

    movzx   rdi, ax         ; Move o quociente para rdi.
    mov     rax, 60
    syscall

Estendendo o Dividendo para Divisão

A forma correta de preparar o dividendo quando se quer dividir dois números do mesmo tamanho é crucial.

Para Divisão Sem Sinal (div): Extensão com Zeros Preencha o registrador da parte alta com zeros. A forma mais eficiente é xor reg, reg.

Exemplo 3: Divisão de 64 bits por 64 bits (Sem Sinal, Linux)

global _start
section .text
_start:
    mov     rax, 22         ; Dividendo sem sinal.
    mov     rcx, 5          ; Divisor.
    xor     rdx, rdx        ; Zera RDX para preparar o dividendo de 128 bits RDX:RAX.
    div     rcx             ; Executa RDX:RAX / RCX.
                            ; RAX = 4 (quociente), RDX = 2 (resto).
    mov     rdi, rax        ; Move o quociente para o código de saída.
    mov     rax, 60
    syscall

Para Divisão Com Sinal (idiv): Extensão de Sinal Propague o bit de sinal do dividendo para o registrador da parte alta. Para isso, use as instruções dedicadas: cbw, cwd, cdq, cqo.

Exemplo 4: Divisão de 64 bits por 64 bits (Com Sinal, Linux)

global _start
section .text
_start:
    mov     rax, -22        ; Dividendo com sinal.
    mov     rcx, 5          ; Divisor.
    cqo                     ; Estende o sinal de RAX para RDX. RDX fica com -1.
    idiv    rcx             ; Executa RDX:RAX / RCX.
                            ; RAX = -4 (quociente), RDX = -2 (resto).
    mov     rdi, rax        ; Move o quociente para o código de saída.
    mov     rax, 60
    syscall

Exemplo 4 Análogo para Windows (Com Sinal):

global _start
section .text
_start:
    mov     rax, -22
    mov     rcx, 5
    cqo                     ; Estende o sinal de RAX para RDX.
    idiv    rcx             ; RAX = -4 (quociente), RDX = -2 (resto).
    ; O quociente já está em RAX, pronto para ser o código de saída.
    ret

Resumo

  • div é para divisão sem sinal; idiv é para com sinal.
  • A regra fundamental é que o dividendo (implícito) deve ter o dobro do tamanho do divisor (explícito).
  • O resultado da divisão é sempre um quociente e um resto, armazenados em registradores específicos.
  • Antes de uma div de operandos do mesmo tamanho, o registrador da parte alta do dividendo (ex: RDX) deve ser zerado (xor rdx, rdx).
  • Antes de uma idiv de operandos do mesmo tamanho, o dividendo deve ser estendido com sinal usando instruções como cqo.
Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com