Dea*_*ger -1 assembly multiplication bigint x86-16
我如何将汇编中的两个 32 位数字或一个 32 位与另一个 16 位相乘,有人知道算法吗?
data1 dw 32bit
data2 dw 32bit
mov ax,data2
Mul data1
Run Code Online (Sandbox Code Playgroud)
首先,dw用于创建一个 16 位(“字”)值。它不会保存 32 位值。您需要使用dd来存储 32 位“dword”,或使用一对 16 位值。
将一对 32 位值相乘,结果可以是 64 位(例如 0xFFFFFFFF * 0xFFFFFFFF = 0xFFFFFFFE00000001)。对于 8086(不仅仅是 80386 或更高版本的实模式代码),有一个 MUL 指令,但它仅限于乘以 2 个 16 位值(并获得 32 位结果)。这意味着您希望将每个 32 位值视为一对 16 位值。
如果A被拆分为A_low(第一个32位数字的最低16位)和A_high(第一个32位数字的最高16位),B按照同样的方式拆分为B_low和B_high;然后:
A * B = A_low * B_low
+ ( A_high * B_low ) << 16
+ ( A_low * B_high ) << 16
+ ( A_high * B_high ) << 32
Run Code Online (Sandbox Code Playgroud)
代码可能如下所示(NASM 语法):
section .data
first: dw 0x5678, 0x1234 ;0x12345678
second: dw 0xDEF0, 0x9ABC ;0x9ABCDEF0
result: dw 0, 0, 0, 0 ;0x0000000000000000
section .text
mov ax,[first] ;ax = A_low
mul word [second] ;dx:ax = A_low * B_low
mov [result],ax
mov [result+2],dx ;Result = A_low * B_low
mov ax,[first+2] ;ax = A_high
mul word [second] ;dx:ax = A_high * B_low
add [result+2],ax
adc [result+4],dx ;Result = A_low * B_low
; + (A_high * B_low) << 16
mov ax,[first] ;ax = A_low
mul word [second+2] ;dx:ax = A_low * B_high
add [result+2],ax
adc [result+4],dx ;Result = A_low * B_low
; + (A_high * B_low) << 16
; + (A_low * B_high) << 16
adc word [result+6], 0 ; carry could propagate into the top chunk
mov ax,[first+2] ;ax = A_high
mul word [second+2] ;dx:ax = A_high * B_high
add [result+4],ax
adc [result+6],dx ;Result = A_low * B_low
; + (A_high * B_low) << 16
; + (A_low * B_high) << 16
; + (A_high * B_high) << 32
Run Code Online (Sandbox Code Playgroud)
我们并不需要adc word [result+6], 0第二个步骤(后[first+2] * [second]),因为它的高半最多0xfffe。 [result+4]那时已经为零(因为此代码只能工作一次),因此adc [result+4],dx无法包装并产生进位。它最多可以生产0xffff。
(它可以作为adc dx, 0/mov [result+4], dx来避免依赖于result已经归零的那部分。同样,adc进入归零寄存器可用于第一次写入[result+6],以使此代码无需先归零即可使用result。)
如果您实际上使用的是 80386 或更高版本,那么它会简单得多:
section .data
first: dd 0x12345678
second: dd 0x9ABCDEF0
result: dd 0, 0 ;0x0000000000000000
section .text
mov eax,[first] ;eax = A
mul dword [second] ;edx:eax = A * B
mov [result],eax
mov [result+4],edx ;Result = A_low * B_low
Run Code Online (Sandbox Code Playgroud)