Marioh Postado Abril 23, 2020 em 22:02 Compartilhar Postado Abril 23, 2020 em 22:02 Tava mexendo no nasm fazendo umas funções e resolvi fazer uma função que imprime numeros em decimal. Até onde eu sei a instrução div divide o rax pelo valor em outro registrador, colocando o resultado da divisão no rax e o resto no rdx, porém se na hora da divisão o rdx não estiver zerado alguma coisa maluca acontece e é essa minha duvida. Oque que rola se o rdx não estiver zerado e fizermos uma div ? Aqui o código da função: _printnum: push rbp mov rbp, rsp sub rsp, 8 mov r10, 10 push r10 ; quebra de linha mov qword [rbp - 8], 1 ; length _prntn_lp_bgn: mov rdx, 0 idiv r10 add rdx, 0x30 push rdx inc qword[rbp - 8] cmp rax, 0 jne _prntn_lp_bgn mov rax, qword[rbp - 8] mov r10, 8 mul r10 mov rdx, rax ;gambiarra da stack mov rax, 1 mov rdi, 1 mov rsi, rsp syscall mov rax, qword [rbp - 8] ; length mov rsp, rbp pop rbp ret Sem a linha mov rdx, 0 logo depois do loop o bagulho buga todo. (Nem reparem na gambiarra que eu fiz na stack, dicas são muito bem vindas) Link para o comentário Compartilhar em outros sites More sharing options...
Felipe.Silva Postado Abril 24, 2020 em 22:02 Compartilhar Postado Abril 24, 2020 em 22:02 A questão é que usando um registrador de 64 bits, a instrução divide o valor contido em RDX:RAX pelo valor passado como operando. Considere que RDX são os 8 bytes mais significativos do valor, e RAX seriam os 8 bytes menos significativos. Simplesmente zerar RDX traria um resultado incorreto se o número em RAX fosse negativo, o certo seria fazer um sign-extend e a instrução CQO faz isso para você: mov rax, 2345 cqo ; RDX:RAX = sign_extend(RAX) idiv rbx Link para o comentário Compartilhar em outros sites More sharing options...
Marioh Postado Abril 25, 2020 em 01:04 Autor Compartilhar Postado Abril 25, 2020 em 01:04 Valeu felipe, nem fazia ideia dessa CQO. Link para o comentário Compartilhar em outros sites More sharing options...
fredericopissarra Postado Abril 25, 2020 em 12:55 Compartilhar Postado Abril 25, 2020 em 12:55 A ideia de empilhar os restos foi interessante, mas tem um problema: Vocẽ está empilhando QWORDs, não BYTES. Pra quê alocar o "tamanho" na pilha... Existem 16 registradores de uso geral disponíveis. Existem alguns "acertos" a serem feitos no código... Por exemplo: XOR EDX,EDX (sim EDX, não RDX) é mais performático e menor que MOV RDX,0, mas, como o @Felipe.Silva disse, estender o sinal é melhor. E você acabará com um problema com valores negativos (acho que não testou esses, né?)... -12, por exemplo, resultará num resto de -2 na primeira divisão, o que empilhará '0'-2 ou o caracter '.'. Ainda... multiplicações são sempre mais rápidas que divisões. Veja isso: https://is.gd/rB9Vlb Como calcular o resto... Ora... se tem o quociente Q, o resto de A/10 é A - (Q*10) "Q*10" pode ser fácilmente calculado com 'LEA RDX,[RAX+RAX*4] / ADD EDX,EDX' (unsigned). Link para o comentário Compartilhar em outros sites More sharing options...
fredericopissarra Postado Abril 25, 2020 em 13:35 Compartilhar Postado Abril 25, 2020 em 13:35 Recomendo algo assim: #include <unistd.h> void print_decimal( long n ) { char buffer[24]; // buffer local que conterá a string. char *p; // ponteiro para o buffer. unsigned long m; // O valor "sem sinal" de n. unsigned long r; // resto. _Bool signaled; size_t size; p = buffer + sizeof buffer - 1; // aponta para o fim do buffer. // Verifica sinal. signaled = 0; m = n; // O caso de n==0 falha, então precisamos disso. if ( ! n ) { size = 1; *p-- = '0'; goto print; } if ( n < 0 ) { signaled = !signaled; m = -n; } size = 0; while ( m ) { r = m % 10; m /= 10; *p-- = '0' + r; size++; } if ( signaled ) { *p-- = '-'; size++; } print: write( STDOUT_FILENO, p+1, size ); } int main( void ) { print_decimal(-12); putchar('\n'); } Convertido para asm: ; NASM code. bits 64 default rel section .text global print_decimal print_decimal: sub rsp, 40 ; Aloca espaço na pilha para o buffer. test rdi, rdi ; testa se n é 0 ou negativo. je .zero_case js .negative xor r9d, r9d ; Usa R9 como booleano (signaled). .prepare: xor ecx, ecx ; RCX é size lea rsi, [rsp+23] ; Aponta para o final do buffer. mov r8, -3689348814741910323 ; Constante usada no "macete" da multiplicação por 1/10, abaixo. jmp .divide .loop: mov rcx, rdx .divide: mov rax, rdi sub rsi, 1 mul r8 shr rdx, 3 ; Obtém o quociente da divisão por 10 em RAX mov rax, rdx lea rdx, [rdx+rdx*4] ; Calcula o resto em RDX. add rdx, rdx sub rdi, rdx mov rdx, rdi mov rdi, rax ; O quociente é o novo dividendo. add edx, '0' mov [rsi+1], dl lea rdx, [rcx+1] test rax, rax ; Dividendo é 0? jne .loop ; Não? permanece no loop. test r9d, r9d ; Tem sinal? je .print ; Não? salta para impressão. mov rax, rsi lea rdx, [rcx+2] sub rsi, 1 mov BYTE [rax], '-' .print: add rsi, 1 ; de volta para o primeiro caracter do buffer. mov edi, 1 ; STDOUT_FILENO. mov eax, edi ; SysV ABI write syscall syscall add rsp, 40 ; Dealloca espaço para o buffer. ret .zero_case: mov BYTE [rsp+23], '0' mov edx, 1 lea rsi, [rsp+22] jmp .print .negative: neg rdi mov r9d, 1 jmp .prepare Dá pra melhorar? Yep... meu ponto é que criar uma rotina em ASM não necessariamente a faz mais rápida (essa ai é mais rápida que a sua - medida!), nem menor. Link para o comentário Compartilhar em outros sites More sharing options...
fredericopissarra Postado Abril 25, 2020 em 13:42 Compartilhar Postado Abril 25, 2020 em 13:42 PS: Usei um buffer de 24 bytes para mantê-lo alinhado na pilha, um buffer de 20 bytes seria suficiente, já que ceil(log10(2⁶³-1)) = 19. Link para o comentário Compartilhar em outros sites More sharing options...
Marioh Postado Abril 25, 2020 em 19:29 Autor Compartilhar Postado Abril 25, 2020 em 19:29 Quote Vocẽ está empilhando QWORDs, não BYTES. Na verdade eu tentei fazer tudo pela stack mesmo, e até onde eu sei não se empilha byte por causa do alinhamento (até onde eu sei...), então eu ia fazer com DWORD e depois só multiplicar por 4, mas deixei QWORD mesmo já que é uma "gambiarra" anyway. Muito f**a seu artigo, precisei ler com mais calma da segunda vez! Suspeitamente parecido com LaTex... (segundo paragrafo, acho que tem um erro ortográfico) Valeu mesmo @fredericopissarra ! Link para o comentário Compartilhar em outros sites More sharing options...
Posts Recomendados
Arquivado
Este tópico foi arquivado e está fechado para novas respostas.