x86 nasm 程序集,如何正确打印乘法结果?
x86 nasm assembly, how to print multiplication result correctly?
所以我在 Stack Overflow 上找到了很多答案,但我仍然无法让它工作。我的代码有什么问题?
mov al, 12
mov bl, 12
mul bl ; answer in ax
aam
mov bx, 10 ; Divisor constant
xor cx, cx ; Clear counter
.a: xor dx, dx ; Clear dx
div bx ; Divide ax with bx, quotient in al, remainder in ah
mov dh, ah ; Move ah to dh, so we can push the 16 bit register of dx
push dx ; Push dx which contains the remainder
inc cx ; Increment counter
test al, al ; If al (the quotient) is not zero, loop again.
jnz .a
.b: pop dx ; Pop the last remainder to dx from stack
add dx, '0' ; Add '0' to make it into character
push cx ; Push loop counter to stack so printing wont interfere with it
mov eax, 4 ;
mov ebx, 1 ;
mov ecx, edx ; Print last popped character
mov edx, 1 ;
int 0x80 ;
pop cx ; Pop the loop counter back to cx
loop .b ; loop for as long as cx is not 0
AAM
指令在结果最多有 2 位数的情况下可能很有用。在你的情况下 12 x 12 = 144,所以这是不行的。
您使用的转换循环几乎是正确的,但是您混合了与 DIV
指令相关的大小。如果您给 DIV
一个字节大小的操作数,那么该操作会将 AX
除以该字节,余数将在 AH
中。如果您给 DIV
一个字大小的操作数,那么该操作会将 DX:AX
除以该字,余数将在 DX
.
中
因为您正在编写 32 位代码,所以最好也使用 32 位寄存器编写转换。
不使用数字计数器,而是使用堆栈上的哨兵。显示时无需保留ECX
。
显示函数需要 ECX
中的指针。为此只需使用堆栈指针并弹出值 post-printing.
mov al, 12
mov bl, 12
mul bl ; answer in AX
movzx eax, ax
mov ebx, 10 ; Divisor constant
push ebx ; Sentinel
.a: xor edx, edx
div ebx ; Divide EDX:EAX with EBX, quotient EAX, remainder EDX
add edx, '0' ; Add '0' to make it into character
push edx
test eax, eax ; If EAX (the quotient) is not zero, loop again.
jnz .a
.b: mov eax, 4
mov ebx, 1
mov ecx, esp
mov edx, 1
int 0x80
pop eax
cmp dword [esp], 10 ; Is it the sentinel ?
jne .b ; No, it's a digit
pop eax ; Remove sentinel
虽然不是 32 位代码,Displaying numbers with DOS 有更多关于将数字转换为文本的信息。
所以我在 Stack Overflow 上找到了很多答案,但我仍然无法让它工作。我的代码有什么问题?
mov al, 12
mov bl, 12
mul bl ; answer in ax
aam
mov bx, 10 ; Divisor constant
xor cx, cx ; Clear counter
.a: xor dx, dx ; Clear dx
div bx ; Divide ax with bx, quotient in al, remainder in ah
mov dh, ah ; Move ah to dh, so we can push the 16 bit register of dx
push dx ; Push dx which contains the remainder
inc cx ; Increment counter
test al, al ; If al (the quotient) is not zero, loop again.
jnz .a
.b: pop dx ; Pop the last remainder to dx from stack
add dx, '0' ; Add '0' to make it into character
push cx ; Push loop counter to stack so printing wont interfere with it
mov eax, 4 ;
mov ebx, 1 ;
mov ecx, edx ; Print last popped character
mov edx, 1 ;
int 0x80 ;
pop cx ; Pop the loop counter back to cx
loop .b ; loop for as long as cx is not 0
AAM
指令在结果最多有 2 位数的情况下可能很有用。在你的情况下 12 x 12 = 144,所以这是不行的。
您使用的转换循环几乎是正确的,但是您混合了与 DIV
指令相关的大小。如果您给 DIV
一个字节大小的操作数,那么该操作会将 AX
除以该字节,余数将在 AH
中。如果您给 DIV
一个字大小的操作数,那么该操作会将 DX:AX
除以该字,余数将在 DX
.
因为您正在编写 32 位代码,所以最好也使用 32 位寄存器编写转换。
不使用数字计数器,而是使用堆栈上的哨兵。显示时无需保留ECX
。
显示函数需要 ECX
中的指针。为此只需使用堆栈指针并弹出值 post-printing.
mov al, 12
mov bl, 12
mul bl ; answer in AX
movzx eax, ax
mov ebx, 10 ; Divisor constant
push ebx ; Sentinel
.a: xor edx, edx
div ebx ; Divide EDX:EAX with EBX, quotient EAX, remainder EDX
add edx, '0' ; Add '0' to make it into character
push edx
test eax, eax ; If EAX (the quotient) is not zero, loop again.
jnz .a
.b: mov eax, 4
mov ebx, 1
mov ecx, esp
mov edx, 1
int 0x80
pop eax
cmp dword [esp], 10 ; Is it the sentinel ?
jne .b ; No, it's a digit
pop eax ; Remove sentinel
虽然不是 32 位代码,Displaying numbers with DOS 有更多关于将数字转换为文本的信息。