; ----------------------------------------------------------
; 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
