Cópia e Gravação em Strings em Assembly NASM
Em sentido amplo, uma string é uma sequência de bytes armazenada em uma área contínua de memória. O processador x86-64 oferece suporte a quatro tipos principais de strings:
- Bytes (byte) — sequência de valores de 8 bits.
- Palavras (word) — sequência de valores de 16 bits.
- Palavras duplas (doubleword ou dword) — sequência de valores de 32 bits.
- Palavras quádruplas (quadword ou qword) — sequência de valores de 64 bits.
Para manipular strings, o processador fornece instruções específicas voltadas à cópia, comparação, busca e armazenamento de valores.
Essas instruções utilizam registradores fixos como operandos:
| Registrador | Função |
|---|---|
| RSI | Endereço (índice) da string de origem |
| RDI | Endereço (índice) da string de destino |
| RCX | Contador de elementos |
| AL/AX/EAX/RAX | Valor de trabalho (dependendo do tamanho dos dados) |
| FLAGS | Contém os flags que controlam a direção e o estado das operações |
Cópia de Strings
As principais instruções para cópia são:
| Instrução | Operação | Incremento / Decremento |
|---|---|---|
| MOVSB | Copia 1 byte | ±1 |
| MOVSW | Copia 1 word (2 bytes) | ±2 |
| MOVSD | Copia 1 doubleword (4 bytes) | ±4 |
| MOVSQ | Copia 1 quadword (8 bytes) | ±8 |
Cada uma copia um valor do endereço apontado por RSI (origem) para o endereço apontado por RDI (destino), ajustando ambos os registradores conforme o tamanho do dado copiado.
Exemplo (Linux)
global _start
section .data
nums dw 10, 11, 12, 13, 14, 15, 16, 17
section .bss
copy resw 8 ; espaço para 8 palavras (16 bytes)
section .text
_start:
mov rsi, nums ; origem
mov rdi, copy ; destino
mov rcx, 8 ; número de elementos
movsw ; copia um elemento (2 bytes)
movzx rdi, word [copy] ; verifica: RDI = 10
mov rax, 60
syscallEssa instrução copia apenas um único elemento. Para repetir a operação automaticamente várias vezes, usa-se o prefixo REP.
Prefixo REP
O prefixo rep (repeat) faz com que a instrução seja repetida automaticamente até que RCX chegue a zero.
A cada iteração, o processador copia um elemento e decrementa RCX.
global _start
section .data
nums dw 10, 11, 12, 13, 14, 15, 16, 17
section .bss
copy resw 8
section .text
_start:
mov rsi, nums
mov rdi, copy
mov rcx, 8
rep movsw ; repete a cópia 8 vezes
movzx rdi, word [copy+2] ; RDI = 11
mov rax, 60
syscallAqui o processador copia os 8 elementos de nums para copy, repetindo movsw até que RCX = 0.
Cópia Otimizada com MOVSQ
Quando o tamanho dos dados for múltiplo de 8 bytes, é mais eficiente usar movsq (64 bits). No exemplo anterior, temos 8 palavras de 2 bytes = 16 bytes, o que equivale a 2 quadwords.
global _start
section .data
nums dw 10, 11, 12, 13, 14, 15, 16, 17
section .bss
copy resw 8
section .text
_start:
mov rsi, nums
mov rdi, copy
mov rcx, 2 ; 2 blocos de 8 bytes
rep movsq
movzx rdi, word [copy+4] ; RDI = 12
mov rax, 60
syscallSe o total não for múltiplo de 8, pode-se combinar instruções:
global _start
section .data
nums dw 10, 11, 12, 13, 14, 15, 16, 17, 18
section .bss
copy resw 9
section .text
_start:
mov rsi, nums
mov rdi, copy
mov rcx, 2 ; 2 qwords + 1 word
rep movsq
movsw ; copia o último elemento
movzx rdi, word [copy+16] ; RDI = 18
mov rax, 60
syscallDireção da Cópia
O flag de direção (DF) em RFLAGS controla se os registradores RSI e RDI serão incrementados ou decrementados após cada cópia.
- CLD (Clear Direction Flag) — cópia no sentido normal (endereços crescentes).
- STD (Set Direction Flag) — cópia no sentido inverso (endereços decrescentes).
Exemplo: cópia reversa
global _start
section .data
nums dw 10, 11, 12, 13, 14, 15, 16, 17
len equ $-nums
elemSize equ 2
count equ len / elemSize
lastPosition equ len - elemSize
section .bss
copy resw 8
section .text
_start:
mov rsi, nums
add rsi, lastPosition
mov rdi, copy
add rdi, lastPosition
mov rcx, count
std
rep movsw
mov rdi, [copy+14] ; RDI = 17
mov rax, 60
syscallCom std, os registradores são decrementados após cada cópia, fazendo a operação ocorrer do final para o início da string.
Instruções STOS
As instruções stos (store string) gravam um valor do registrador AL/AX/EAX/RAX em uma sequência de memória.
Elas também possuem variações conforme o tamanho do operando:
| Instrução | Tamanho | Fonte | Descrição |
|---|---|---|---|
| STOSB | 1 byte | AL | Armazena 1 byte |
| STOSW | 2 bytes | AX | Armazena 1 palavra |
| STOSD | 4 bytes | EAX | Armazena 1 palavra dupla |
| STOSQ | 8 bytes | RAX | Armazena 1 palavra quádrupla |
Essas instruções requerem:
- RDI — endereço da string de destino.
- AL/AX/EAX/RAX — valor a ser gravado.
- RCX — número de repetições (quando usado com
rep).
Exemplo (Linux)
global _start
section .data
message db "Hello"
len equ $-message
char db "A"
section .text
_start:
mov rdi, message
mov al, [char]
stosb ; substitui o primeiro caractere
mov rdi, 1
mov rsi, message
mov rdx, len
mov rax, 1
syscall
mov rax, 60
syscallApós a execução, o primeiro caractere é substituído e a string se torna "Aello".
Repetição com REP STOS
Quando é necessário preencher uma área de memória inteira, rep stosb é ideal.
O processador grava o valor de AL em RCX posições consecutivas.
global _start
section .data
char db "A"
section .bss
buffer resb 8
len equ $-buffer
section .text
_start:
mov rdi, buffer
mov al, [char]
mov rcx, len
rep stosb
mov rdi, 1
mov rsi, buffer
mov rdx, len
mov rax, 1
syscall
mov rax, 60
syscallO resultado é a string "AAAAAAAA".
Assim como em movs, o flag de direção também controla o sentido da gravação — se estiver definido, a escrita ocorrerá de trás para frente.
Resumo
- O processador x86-64 oferece instruções para cópia (
movs*) e gravação (stos*) de strings. - O prefixo
reprepete a operação até que RCX = 0. - O flag de direção define se o endereço é incrementado (
cld) ou decrementado (std). - O uso de movsq é mais eficiente para blocos múltiplos de 8 bytes.
- As instruções
stospermitem inicializar buffers ou sobrescrever strings rapidamente. - Strings podem ser tratadas como sequências de bytes contínuos na memória, permitindo manipulações diretas e de baixo nível.