汇编中32位数相乘时,结果放在EDX:EAX组合中。结果的上半部分进入 EDX,下半部分进入 EAX。如果 EDX 和 EAX 都有两部分结果,我如何使用 Irvine32 位库将这些值打印到屏幕上?查看示例代码和注释:
.386
.model flat, stdcall
.stack 4096
ExitProcess proto, dwExitCode:dword
include Irvine32.inc
.data
num1 dword 1000000
num2 dword 1000000
temp dword ?
full_result qword ?
.code
main proc
mov eax, num1
mul num2 ;Result will be put in EDX:EAX (Upper half of number and Lower half of number)
;EDX has the value 232 in decimal. 000000E8 in hex
;EAX has the value 3567587328 in decimal. D4A51000 in hex
;When you put these numbers togather, you get 000000E8D4A51000 in hex.
;When you convert these numbers back to its decimal representation, we get the correct value of 1000000000000
;How to display the result into the screen using Irvine32 library (not 64)
mov temp, eax
mov eax, edx ;Put the upper half of result in eax
call WriteDec ;Write the value in eax
mov eax, temp ;Put the lower half of result in eax
call WriteDec
;This will prints out 2323567587328 instead of 1000000000000
invoke ExitProcess, 0
main endp
end main
有没有办法将这个数字 2323567587328 转换成不同的形式,以便我可以正确显示上半部分和下半部分? (打包 BCD 等。)
如果无法以某种方式格式化此数字,以便我可以在两个不同的寄存器中拥有 1000000000000,请告诉我如何将此值分配给
full_result
qword 类型变量。
mov eax, num1 mul num2
这个
mul
指令在 EDX:EAX 中产生一个 unsigned 64 位产品。WriteString
函数输出一个字符串。
在 x86 上,需要级联 2 个除法来将 EDX:EAX 中的 64 位值除以 10.
第一除法除以高股息(用 0 扩展)产生高商。第二个除法除以低股息(用第一个除法的余数扩展)产生低商。这是我们保存在堆栈中的第二部分的剩余部分。
为了检查 EDX:EAX 中的 qword 是否为零,我在临时寄存器中对两半进行了或运算。
我没有计算数字,需要寄存器,而是选择在堆栈上放置一个哨兵。因为这个哨兵得到一个值 (10),任何数字都不可能有 ([0,9]),所以它很好地允许确定存储循环何时必须停止。
.data
num1 dword 1000000
num2 dword 1000000
Buffer byte 32 dup(0)
.code
main proc
mov eax, num1
mul num2
mov edi, OFFSET Buffer ; Begin of the buffer
mov ebx, 10 ; CONST
push ebx ; Sentinel
.a: mov ecx, eax ; Temporarily store LowDividend in ECX
mov eax, edx ; First divide the HighDividend
xor edx, edx ; Setup for division EDX:EAX / EBX
div ebx ; -> EAX is HighQuotient, Remainder is re-used
xchg eax, ecx ; Temporarily move it to ECX restoring LowDividend
div ebx ; -> EAX is LowQuotient, Remainder EDX=[0,9]
push edx ; (1) Save remainder for now
mov edx, ecx ; Build true 64-bit quotient in EDX:EAX
or ecx, eax ; Is the true 64-bit quotient zero?
jnz .a ; No, use as next dividend
pop eax ; (1a) First pop (Is digit for sure)
.b: add eax, "0" ; Turn into character [0,9] -> ["0","9"]
stosb ; Store in buffer
pop eax ; (1b) All remaining pops
cmp eax, ebx ; Was it the sentinel?
jb .b ; Not yet
mov BYTE PTR [edi], 0 ; Irvine32 requires zero-termination
mov edx, OFFSET Buffer
call WriteString
程序如下:
首先通过测试符号位来判断有符号数是否为负数
如果是,则将数字取反并输出一个“-”字符。
该片段的其余部分与无符号数相同。
mov edi, OFFSET Buffer ; Begin of the buffer
test edx, edx ; Sign bit is bit 31 of high dword
jns .u ; It's a positive number
neg edx ; |
neg eax ; | Negate EDX:EAX
sbb edx, 0 ; |
mov BYTE PTR [edi], "-"
inc edi
.u: mov ebx, 10 ; CONST
push ebx ; Sentinel
.a:
...
以上代码片段基于我的16位问答DOS显示数字。你也可以阅读它以获得一些额外的解释......