pbn/curso/exemplos/07/getenv.asm
2025-05-26 08:04:03 -03:00

136 lines
6.5 KiB
NASM

; ----------------------------------------------------------
; Montagem: nasm -f elf64 -o getenv.o getenv_v2.asm
; Ligação : ld -o getenv getenv.o
; Uso : ./getenv NOME_VARIAVEL
; ----------------------------------------------------------
section .rodata
; ----------------------------------------------------------
newline db 10, 0 ; caractere de nova linha
msg_nf db "Not found", 10, 0 ; mensagem de erro
msg_usage db "Usage: ./getenv VAR", 10, 0 ; mensagem de uso incorreto
; ----------------------------------------------------------
section .bss
; ----------------------------------------------------------
argc resq 1 ; quantidade de argumentos (argc)
argv resq 1 ; endereço do vetor de argumentos (argv)
envp resq 1 ; endereço do vetor de ambiente (envp)
; ----------------------------------------------------------
section .text
; ----------------------------------------------------------
global _start
_start:
; ----------------------------------------------------------
; Carregar e salvar argc, argv e envp
; ----------------------------------------------------------
mov rax, [rsp] ; argc está no topo da pilha
mov [argc], rax ; salva argc em argc
lea rax, [rsp + 8] ; argv começa logo após argc
mov [argv], rax ; salva ponteiro de argv
mov rbx, [argc]
lea rax, [rsp + rbx*8 + 16] ; envp vem após argc + argv[] + ponteiro nulo
mov [envp], rax ; salva ponteiro de envp
; ----------------------------------------------------------
; Verificar se argc == 2
; ----------------------------------------------------------
cmp qword [argc], 2
jl show_usage ; se argc < 2, mostrar uso correto
; ----------------------------------------------------------
; Obter endereço do nome da variável: argv[1]
; ----------------------------------------------------------
mov rax, [argv]
mov rsi, [rax + 8] ; rsi = argv[1]
; ------------------------------------------
; Iterar sobre envp para buscar a variável
; ------------------------------------------
mov rcx, [envp] ; rcx recebe endereço de envp[0]
.next_env:
mov rdx, [rcx] ; rdx recebe endereço da string "VAR=valor"
test rdx, rdx ; verifica se rdx = 0
jz not_found ; se rdx = 0, termina com erro (não encontrada)
; ------------------------------------------
; Comparar caractere a caractere: se argv[1] é prefixo de rdx
; e é seguido por '=' → variável encontrada
; ------------------------------------------
mov r8, rsi ; r8 = nome buscado (argv[1])
mov r9, rdx ; r9 = string atual do envp
.cmp_loop:
mov al, [r8] ; próximo char do nome buscado
mov bl, [r9] ; próximo char da string do envp
cmp al, 0
je .check_equals ; se al = 0, chegou ao fim do nome buscado: checar '='
cmp al, bl
jne .next ; se al != bl, não bateu, próxima variável
inc r8
inc r9
jmp .cmp_loop
; ------------------------------------------
; Comparar se o caractere no endereço é '='
; ------------------------------------------
.check_equals:
cmp byte [r9], '=' ; verifica se o caractere em envp é '='
jne .next ; não era uma '=': próximo elemento em envp
inc r9 ; avança para o início do valor
mov rsi, r9 ; rsi = endereço do primeiro byte do valor
mov rdi, 1 ; stdout
call print_string ; imprime valor
mov rsi, newline ; carrega endereço de '\n' em rsi
call print_string ; imprime \n
mov rdi, 0 ; estado de término 0 (sucesso)
call exit_program ; termina o programa
.next:
add rcx, 8 ; avança para próximo emdereço em envp
jmp .next_env
; ----------------------------------------------------------
; Caso variável não seja encontrada
; ----------------------------------------------------------
not_found:
lea rsi, [rel msg_nf]
mov rdi, 2 ; stderr
call print_string
mov rdi, 1 ; código de erro
call exit_program
; ----------------------------------------------------------
; Caso uso incorreto (menos de 2 argumentos)
; ----------------------------------------------------------
show_usage:
lea rsi, [rel msg_usage] ; endereço da mensagem de uso
mov rdi, 2 ; fd 2 = stderr
call print_string ; imprime a mensagem
mov rdi, 1 ; estado de término 1 (erro)
call exit_program ; termina o programa
; ----------------------------------------------------------
; SUB-ROTINAS
; ----------------------------------------------------------
print_string:
; ----------------------------------------------------------
; Imprime string terminada em '\0' no descritor indicado
; Entrada:
; rdi = file descriptor (1 = stdout, 2 = stderr)
; rsi = ponteiro para string terminada em '\0'
; ----------------------------------------------------------
push rdi ; salva rdi (fd)
mov rax, rsi
xor rcx, rcx ; contador = 0
.count:
cmp byte [rax + rcx], 0 ; fim da string?
je .write
inc rcx
jmp .count
.write:
mov rdx, rcx ; número de bytes a escrever
pop rax ; restaura fd original
mov rdi, rax
mov rax, 1 ; syscall: write
syscall
ret
; ----------------------------------------------------------
exit_program:
; ----------------------------------------------------------
; Encerra o programa com código em rdi
; Entrada:
; rdi = código de saída (0 = sucesso, 1 = erro)
; ----------------------------------------------------------
mov rax, 60 ; syscall: exit
syscall