diff --git a/curso/exemplos/09/exemplo.c b/curso/exemplos/09/exemplo.c new file mode 100644 index 0000000..0505a2c --- /dev/null +++ b/curso/exemplos/09/exemplo.c @@ -0,0 +1,14 @@ +#include + +int main(void) { + + int a = 123; + char *b = "123"; + int *c = (int *)b; // Casting do valor no endereço 'b' para inteiro + + printf("Inteiro a: %d\n", a); + printf("String b: %s\n", b); + printf("Inteiro c: %d\n", *c); // Imprime o valor no endereço 'c' + + return 0; +} diff --git a/curso/exemplos/09/uint.asm b/curso/exemplos/09/uint.asm new file mode 100644 index 0000000..00fe262 --- /dev/null +++ b/curso/exemplos/09/uint.asm @@ -0,0 +1,129 @@ +; ---------------------------------------------------------- +; 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 diff --git a/curso/exemplos/09/uint.c b/curso/exemplos/09/uint.c new file mode 100644 index 0000000..15f05dc --- /dev/null +++ b/curso/exemplos/09/uint.c @@ -0,0 +1,51 @@ +/* + * Arquivo : uint.c + * Compilação: gcc -Wall uint.c -o uintc + */ +#include +#include // Requerido para obter UINT_MAX da plataforma + +unsigned int str_to_uint(char *str, int *err /* nullable */); + +int main(int argc, char **argv) { + if (argc == 1) { + fprintf(stderr, "Uso: %s NÚMERO\n", argv[0]); + return 1; + } + + int status; + unsigned int num = str_to_uint(argv[1], &status); + + if (status) { + printf("String: %s\nNúmero: %u\n", argv[1], num); + } else { + fprintf(stderr, "Erro de conversão!\n"); + return 1; + } + + return 0; +} + +unsigned int str_to_uint(char *str, int *err /* nullable */) { + if (err) *err = 0; // Estado padrão é de erro (0 = falso)! + + // Termina com erro e valor 0 se str==NULL ou se '0'>str[0]>'9'... + if (str == NULL || str[0] < '0' || str[0] > '9') return 0; + + int dig; // Recebe o dígito convertido + unsigned int conv = 0; // Recebe a parcial da conversão + + for (int i = 0; str[i] != '\0'; i++) { + // Se o caractere não for um dígito, termina a conversão... + if (str[i] < '0' || str[i] > '9') break; + // Converte o dígito corrente... + dig = str[i] - '0'; + // Termina com erro e valor 0 se a próxima conversão exceder UINT_MAX... + if (conv > (UINT_MAX - dig) / 10) return 0; + // Processa a parcial da conversão... + conv = (conv * 10) + dig; + } + + if (err) *err = 1; // Altera estado para sucesso (1 = verdadeiro) + return conv; +}