Marioh Posted April 23, 2020 at 10:02 PM Share Posted April 23, 2020 at 10:02 PM 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 to comment Share on other sites More sharing options...
Felipe.Silva Posted April 24, 2020 at 10:02 PM Share Posted April 24, 2020 at 10:02 PM 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 to comment Share on other sites More sharing options...
Marioh Posted April 25, 2020 at 01:04 AM Author Share Posted April 25, 2020 at 01:04 AM Valeu felipe, nem fazia ideia dessa CQO. Link to comment Share on other sites More sharing options...
fredericopissarra Posted April 25, 2020 at 12:55 PM Share Posted April 25, 2020 at 12:55 PM 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 to comment Share on other sites More sharing options...
fredericopissarra Posted April 25, 2020 at 01:35 PM Share Posted April 25, 2020 at 01:35 PM 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 to comment Share on other sites More sharing options...
fredericopissarra Posted April 25, 2020 at 01:42 PM Share Posted April 25, 2020 at 01:42 PM 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 to comment Share on other sites More sharing options...
Marioh Posted April 25, 2020 at 07:29 PM Author Share Posted April 25, 2020 at 07:29 PM 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 to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.