Ordem de Bytes em Assembly NASM: Big-endian e Little-endian
Ao trabalhar com dados binários em baixo nível, é importante entender o conceito de ordem de bytes. Atualmente, existem dois formatos principais de armazenamento de bytes na memória: big-endian e little-endian.
Conceito de Ordem de Bytes
Em big-endian, os bytes são armazenados do mais significativo para o menos significativo. Em little-endian, a ordem é invertida — os bytes são armazenados do menos significativo para o mais significativo.
Considere o número hexadecimal 0x01234567, composto por 4 bytes.
Veja como ele é armazenado em cada formato:
| Endereço | 0x0000 | 0x0001 | 0x0002 | 0x0003 |
|---|---|---|---|---|
| Big-endian | 01 | 23 | 45 | 67 |
| Little-endian | 67 | 45 | 23 | 01 |
No formato big-endian, o primeiro byte é o mais significativo (0x01).
No formato little-endian, o primeiro byte é o menos significativo (0x67).
A arquitetura Intel x86-64 — usada na maioria dos computadores modernos — segue o formato little-endian.
Exemplo 1: Acesso ao Primeiro Byte
global _start
section .data
number dd 0x01234567 ; 4 bytes
section .text
_start:
movzx rdi, byte [number] ; obtém o primeiro byte
mov rax, 60
syscallAqui, foi declarado um número de 4 bytes com o valor 0x01234567.
O byte mais significativo é 0x01, e o menos significativo é 0x67 (103 em decimal).
Ao executar o programa, o registrador RDI recebe o primeiro byte, ou seja, 0x67.
programicio@machine:~/asm$ nasm -f elf64 hello.asm -o hello.o programicio@machine:~/asm$ ld -o hello hello.o programicio@machine:~/asm$ ./hello programicio@machine:~/asm$ echo $? 103
O primeiro byte lido é 103 (0x67), confirmando que o menos significativo vem primeiro na arquitetura x86-64.
Para acessar o byte mais significativo (o quarto byte), basta somar um deslocamento de 3 bytes:
movzx rdi, byte [number + 3]Exemplo 2: Array de Bytes
global _start
section .data
numbers db 0x01, 0x23, 0x45, 0x67 ; 4 bytes
section .text
_start:
movzx rdi, byte [numbers] ; obtém o primeiro byte
mov rax, 60
syscallNeste caso, a seção de dados contém um array explícito de bytes, e os valores são armazenados na ordem em que foram definidos.
Portanto, o primeiro byte do array é 0x01.
programicio@machine:~/asm$ nasm -f elf64 hello.asm -o hello.o programicio@machine:~/asm$ ld -o hello hello.o programicio@machine:~/asm$ ./hello programicio@machine:~/asm$ echo $? 1
O resultado confirma que o primeiro byte lido é 1 (0x01).
Exemplo 3: Array de Words (2 bytes)
global _start
section .data
numbers dw 0x0123, 0x4567 ; 4 bytes — cada número ocupa 2 bytes
section .text
_start:
movzx rdi, byte [numbers] ; obtém o primeiro byte
mov rax, 60
syscallAqui temos um array de números de 2 bytes (words).
O primeiro número é 0x0123, mas, por causa do formato little-endian, os bytes são armazenados em ordem inversa:
| Endereço | 0x0000 | 0x0001 |
|---|---|---|
| Valor | 23 | 01 |
Assim, o primeiro byte lido é 0x23 (decimal 35):
programicio@machine:~/asm$ nasm -f elf64 hello.asm -o hello.o programicio@machine:~/asm$ ld -o hello hello.o programicio@machine:~/asm$ ./hello programicio@machine:~/asm$ echo $? 35
Exemplo 4: String como Conjunto de Bytes
global _start
section .data
number db "01234567" ; 8 bytes
section .text
_start:
movzx rdi, byte [number] ; obtém o primeiro byte
mov rax, 60
syscallNeste exemplo, a variável contém uma string ASCII, onde cada caractere ocupa 1 byte.
Logo, "01234567" representa um conjunto de 8 bytes.
Os caracteres são armazenados na mesma ordem em que aparecem na string, ou seja:
| Caractere | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' |
|---|---|---|---|---|---|---|---|---|
| Código | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 |
O primeiro byte da string corresponde ao código 48, que representa o caractere '0'.
programicio@machine:~/asm$ nasm -f elf64 hello.asm -o hello.o programicio@machine:~/asm$ ld -o hello hello.o programicio@machine:~/asm$ ./hello programicio@machine:~/asm$ echo $? 48
Conclusão
- A ordem de bytes determina como os valores são armazenados na memória.
- Big-endian: o byte mais significativo vem primeiro.
- Little-endian: o byte menos significativo vem primeiro (padrão nas arquiteturas Intel).
- Em arrays e strings, os dados são armazenados na ordem em que foram definidos.
- Compreender o formato de armazenamento é essencial para manipular corretamente dados binários em Assembly.