; ---------------------------------------------------------- ; Arquivo : uint.asm ; Montagem: nasm -g -f elf64 uint.asm ; Ligação : ls uint.o -o uint ; ---------------------------------------------------------- section .data ; ---------------------------------------------------------- num_str db "123", 0 ; string numérica ; ---------------------------------------------------------- section .bss ; ---------------------------------------------------------- num resd 1 ; 4 bytes para o valor UINT32 status resd 1 ; 4 bytes para o estado de término ; ---------------------------------------------------------- section .text global _start ; ---------------------------------------------------------- _start: ; ---------------------------------------------------------- ; Teste de chamada (verificar com o GDB)... ; ---------------------------------------------------------- mov rsi, num_str ; copia endereço da string em rsi mov rdx, status ; copia o endereço do estado de erro em rdx call _str_to_uint ; chama a sub-rotina de conversão mov dword [num], eax ; copia o resultado como int para [num] ; ---------------------------------------------------------- _exit: ; ---------------------------------------------------------- mov rax, 60 mov rdi, 0 syscall ; ---------------------------------------------------------- ; Sub-rotinas... ; ---------------------------------------------------------- _str_to_uint: ; ---------------------------------------------------------- ; Converte string numérica em inteiro sem sinal (uint32_t). ; Entradas: ; RSI = Endereço da string (char *str) ; RDX = Endereço para estado de erro (int *err /* nullable */) ; Saída: ; RAX = valor convertido (uint32_t) ou 0, no caso de erro ; Sucesso: *rdx = 1 ; Erro: *rdx = 0 ; ---------------------------------------------------------- ; Definição condicional do estado inicial de erro... ; ------------------------------------------------------ test rdx, rdx ; Se *err = NULL, rdx = 0 jz .skip_error ; Se for 0, pula a definição do erro mov dword [rdx], 0 ; *err = 0 => estado inicial é de erro (falso) ; ------------------------------------------------------ .skip_error: ; ------------------------------------------------------ ; Teste de ponteiro nulo... ; ------------------------------------------------------ test rsi, rsi ; verifica se enderçeo é nulo (0) jz .error ; se for, termina retornando -1 (erro) ; ------------------------------------------------------ ; Preparação... ; ------------------------------------------------------ push rbx ; salva rbx na pilha xor rax, rax ; rax = 0 (acumula o resultado) xor rbx, rbx ; rbx = 0 (recebe os caracteres no loop) mov bl, [rsi] ; lê o primeiro byte ; ------------------------------------------------------ ; Validação do primeiro byte... ; ------------------------------------------------------ cmp bl, 0x30 ; compara com menor byte válido jl .error ; se menor, termina retornando -1 cmp bl, 0x39 ; compara com maior byte válido jg .error ; se maior, termina retornando -1 .conv_loop: ; ------------------------------------------------------ ; Condições de término da conversão ... ; ------------------------------------------------------ test bl, bl ; verifica se o byte é o terminador 0x00 je .success ; se for, termina com sucesso cmp bl, 0x30 ; compara o byte em rbx com o menor dígito jl .success ; se for menor, termina com sucesso cmp bl, 0x39 ; compara o byte em rbx com o maior dígito jg .success ; se for maior, termina com sucesso ; ------------------------------------------------------ ; Conversão do dígito corrente... ; ------------------------------------------------------ sub rbx, 0x30 ; converte o dígito para seu valor numérico ; ------------------------------------------------------ ; Limite válido: conv < (UINT_MAX - dígito) / 10 ; ------------------------------------------------------ mov r8, rax ; Salva parcial da conversão em r8 mov r10, rdx ; Salva ponteiro de erro em r10 mov eax, -1 ; eax = 0xffffffff (UINT_MAX - 32 bits) sub eax, ebx ; rax = UINT_MAX - dígito (dividendo) xor rdx, rdx ; prepara rdx para receber o resto da divisão mov r9, 10 ; divisor div r9 ; limite(rax) = (UINT_MAX - dígito) / 10 cmp r8, rax ; se parcial > limite, teremos um estouro jg .error ; se maior, termina com erro mov rdx, r10 ; restaura rdx (pontiero para erros) mov rax, r8 ; restaura rax (parcial da conversão) ; ------------------------------------------------------ ; Processa a parcial da conversão... ; ------------------------------------------------------ imul rax, rax, 10 ; rax *= 10 (deslocamento do peso posicional) add rax, rbx ; rax += novo algarismo inc rsi ; avança para o próximo byte mov bl, [rsi] ; carrega o dígito corrente em rbx jmp .conv_loop ; ------------------------------------------------------ .error: ; ------------------------------------------------------ xor rax, rax ; Retorna 0 em caso de erro jmp .done ; ------------------------------------------------------ .success: ; ------------------------------------------------------ ; Redefinição condicional do estado final de sucesso... ; ------------------------------------------------------ test rdx, rdx ; Se *err = NULL, rdx = 0 jz .done ; Se for 0, pula a definição de sucesso mov dword [rdx], 1 ; *err = 1 => estado final é de sucesso (verdadeiro) ; ------------------------------------------------------ .done: ; ------------------------------------------------------ pop rbx ; Restaura rbx ret