Exercício da Aula 14 #29
```asm
%define BUF_SIZE 21
%define E_NUMB 42
%define E_OVER 23
%define SYS_WRITE 1
%define STDOUT_FD 1
%define EOL_CHAR 0x0a
%define MUL10_MAX 922337203685477580
%define INT64_MIN 0x8000000000000000
%define INT64_MAX 0x7fffffffffffffff
%define TCFLSH 0x540B
%define TCIFLUSH 0
section .bss
buf resb BUF_SIZE ; i64: 19 dígitos + 1 sinal + '\0' (21 bytes)
section .text
global _start
_start:
; receber valor pela digitação
xor rax, rax
xor rdi, rdi
mov rsi, buf
mov rdx, BUF_SIZE - 1 ; como 'fgets()', lê até size-1
syscall ; retorna qtd de bytes lidos em rax
push rax ; salva rax na pilha
_term_flush:
; ioctl(FD0, TCFLSH, TCIFLUSH)
mov rax, 16 ; syscall ioctl
xor rdi, rdi ; fd = 0 (stdin)
mov rsi, TCFLSH ; TCFLSH -> /usr/include/asm-generic/ioctls.h
mov rdx, TCIFLUSH ; TCIFLUSH -> /usr/include/asm-generic/termbits-common.h
syscall
pop rax ; restaura rax
_check_read:
cmp rax, 0 ; se rax == 0, é erro
je _exit_err
mov byte [buf+rax], 0 ; garante terminador nulo
; converter caracteres em números
_convert:
xor rax, rax ; resultados
mov rbx, 10 ; multiplicador por 10
xor rcx, rcx ; índice = 0
xor rdx, rdx ; dígitos convertidos
xor r9, r9 ; flag de sinal
.test_sig:
mov r8b, byte [buf+rcx] ; carrega primeiro caractere
.check_minus:
cmp r8b, '-' ; tem sinal de negativo?
jne .check_plus
inc r9 ; flag de sinal = 1 (negativo)
inc rcx ; avança para próximo caractere
jmp .digit_loop
.check_plus:
cmp r8b, '+' ; tem sinal de positivo?
jne .check_digit
inc rcx ; só avança para próximo caractere
.digit_loop:
mov r8b, byte [buf+rcx] ; carrega caractere seguinte
.check_digit:
cmp r8b, '0' ; se menor, termina
jl .check_count
cmp r8b, '9' ; se maior, termina
jg .check_count
sub r8b, 0x30 ; converter para int
.check_i64max: ; isso sacrifica INT64_MIN
mov r10, MUL10_MAX ; INT64_MAX / 10
cmp rax, r10 ; se maior, overflow
ja _exit_overflow
jb .safe
cmp r8b, 7 ; rax == MUL10_MAX, só pode somar até 7
ja _exit_overflow
.safe:
mul rbx ; rax = rax × 10
add rax, r8 ; rax = rax + r8b
inc rcx ; índice do próximo caractere
inc rdx ; incrementa contagem de dígitos
jmp .digit_loop
.check_count:
cmp rdx, 0 ; se rcx == 0, nada foi convertido
je _exit_err
.negative:
cmp r9, 0 ; negativo?
je .done
neg rax ; torna negativo
.done:
; verificar se pode somar (NUM <= INT64_MAX-valor)
mov rbx, 42
mov rcx, INT64_MAX
sub rcx, rbx
cmp rax, rcx
ja _exit_overflow
; somar rax valor com 42
add rax, rbx
; converter soma para string
mov rdi, rax
mov rsi, buf
call i64_to_str
; imprimir resultado
call echo_str
_exit_ok:
xor rdi, rdi
jmp _exit
_exit_err:
mov rdi, E_NUMB
jmp _exit
_exit_overflow:
mov rdi, E_OVER
_exit:
mov rax, 60
syscall
; ----------------------------------------------------------
i64_to_str:
; ----------------------------------------------------------
; Descrição: Converte inteiro (int64) para string.
; Entradas:
; rdi -> valor uint64 (com ou sem sinal)
; rsi -> endereço do buffer de saída
; Saída:
; rsi -> endereço do buffer
; Altera: rax, rcx, rdx, r8, r9
; Depende de i64_count_digits!
; ----------------------------------------------------------
call i64_count_digits ; retorna dígitos em rax
test rdi, rdi ; número tem sinal? (precisa testar de novo?)
jns .write_term ; se não tem, escreve o terminador
.int64_min:
mov r9, INT64_MIN ; 'cmp' só aceita imm até 32 bits
cmp rdi, r9 ; INT64_MIN não pode ser negado!
je .write_int64min ; esrceve os caracteres de INT64_MIN
.sig_handler:
neg rdi ; torna número positivo (absoluto)
inc rax ; inclui o sinal na contagem de caracteres
mov byte [rsi], '-' ; escreve o sinal no início do buffer
.write_term:
mov rcx, rax ; rcx => índice do fim da string + 1
mov byte [rsi+rcx], 0 ; terminador nulo
dec rcx ; rcx => byte anterior no buffer
.convert_start:
mov rax, rdi ; copia valor para rax (dividendo)
mov r8, 10 ; r8 = 10 (divisor)
.convert_loop:
xor rdx, rdx ; zera rdx para o resto (dígito)
div r8 ; rax = valor/10, rdx = valor%10
add dl, 0x30 ; converte resto para ASCII
mov byte [rsi+rcx], dl ; salva caractere no buffer
dec rcx ; endereço do byte anterior
cmp rax, 0 ; quociente == 0?
je .done
jmp .convert_loop
.done:
ret
.write_int64min:
; Escreve diretamente em rsi os caracteres de INT64_MIN...
mov dword [rsi], '-922'
mov dword [rsi+4], '3372'
mov dword [rsi+8], '0368'
mov dword [rsi+12], '5477'
mov dword [rsi+16], '5808'
mov byte [rsi+20], 0
ret
; ----------------------------------------------------------
i64_count_digits:
; ----------------------------------------------------------
; Descrição: Conta dígitos de uma constante inteira (int64).
; Entrada : rdi -> Valor int64 (inteiro com ou sem sinal)
; Saída : rax -> Quantidade de dígitos
; Altera : rax (retorno), rcx, r8, r9
; ----------------------------------------------------------
mov r8, rdi ; salva rdi em r8
mov rax, 1 ; inicia rax = 1 dígito
test r8, r8 ; inteiro é negativo ou zero?
jz .done ; se ZF=1, retorna rax = 1 (10^0)
jns .count_start ; se SF=0, salta para contagem
.sig_handler:
mov r9, INT64_MIN ; 'cmp' só aceita imm ate 32 bits
cmp r8, r9 ; INT64_MIN não pode ser negado!
je .int64_min ; rax = 19 dígitos
neg r8 ; r8 => valor agora é positivo
.count_start:
mov rcx, 10 ; potência de 10 inicial (10^1)
.count_loop:
cmp r8, rcx ; num < 10^rax?
jb .done ; sem menor, termina
inc rax ; incrementa o contador
imul rcx, rcx, 10 ; rcx = rcx * 10 => 10^rax
jmp .count_loop
.int64_min:
mov rax, 19 ; INT64_MIN tem 19 bytes
.done:
ret
; ----------------------------------------------------------
echo_str:
; ----------------------------------------------------------
; Descrição: Imprime string em rsi com uma quebra de linha.
; Entrada : rsi -> char *src (endereço da string)
; Saída : Nenhuma
; Altera : rax, rcx, rdx, rdi, rsi, r11
; Depende de str_len, print_str e print_eol!
; ----------------------------------------------------------
call print_str
call print_eol
ret
; ----------------------------------------------------------
; ----------------------------------------------------------
print_str:
; ----------------------------------------------------------
; Descrição: Imprime string em rsi.
; Entrada : rsi -> char *src (endereço da string)
; Altera : rax, rcx, rdx, rdi, r11
; Depende de str_len!
; ----------------------------------------------------------
call str_len ; retorna str_len em rax
mov rdx, rax
mov rax, SYS_WRITE
mov rdi, STDOUT_FD
syscall
ret
; ----------------------------------------------------------
print_eol:
; ----------------------------------------------------------
; Descrição: Imprime uma quebra de linha.
; Entrada : não tem entradas
; Altera : rax, rcx, rdx, rdi, rsi, r11
; ----------------------------------------------------------
push EOL_CHAR ; salva '\n' na pilha
mov rax, SYS_WRITE
mov rdi, STDOUT_FD
mov rsi, rsp
mov rdx, 1
syscall
add rsp, 8 ; restaura o topo da pilha
ret
; -----------------------------------------------------------
str_len:
; ----------------------------------------------------------
; Descrição: obtém o tamanho da string em rsi.
; Entrada : rsi -> char *str (endereço da string)
; Saída : rax -> quantidade de caracteres excluindo '\0'
; Altera : rax (retorno), rcx
; ----------------------------------------------------------
xor rcx, rcx ; contador = 0
.count_loop:
mov al, byte [rsi+rcx] ; copia byte em rsi[rcx] para rax
cmp al, 0 ; o byte em rax é 0x00?
je .done
inc rcx ; contador += 1
jmp .count_loop
.done:
mov rax, rcx
ret
; ----------------------------------------------------------
```
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?