Exercício da Aula 14 #29

Open
opened 2025-08-01 21:16:58 -03:00 by leandrossantos · 0 comments
%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
; ----------------------------------------------------------
```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 ; ---------------------------------------------------------- ```
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: blau_araujo/pbn#29
No description provided.