-1

アセンブリで 2 つの 32 ビット桁を乗算する方法、または 1 つの 32 ビットと別の 16 ビットを乗算するにはどうすればよいですか?アルゴリズムは誰でも知っていますか?

data1 dw 32bit
data2 dw 32bit    
mov ax,data2
Mul data1
4

1 に答える 1

5

まず、dw16 ビット (「ワード」) 値を作成するために使用されます。32 ビット値は保持されません。dd32 ビットの「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

コードは次のようになります (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

2 番目のステップ ( )の後は必要ありませ。 はその時点ですでにゼロであるため (このコードは 1 回しか機能しないため)、ラップしてキャリーアウトを生成することはできません。せいぜい.adc word [result+6], 0[first+2] * [second]0xfffe[result+4]adc [result+4],dx0xffff

(すでにゼロ化されている部分に依存することを避けるためにadc dx, 0/として実行できます。同様に、ゼロ化されたレジスタへの最初の書き込みに使用して、最初のゼロ化なしでこのコードを使用できるようにすることができます。)mov [result+4], dxresultadc[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
于 2012-11-19T12:08:42.573 に答える