如何使用x86汇编语言将两个64位数字相乘?

如何使用x86汇编语言将两个64位数字相乘?

How can I multiply two 64-bit numbers using x86 assembly language?

我该怎么办...

  • 两个64位数字相乘

  • 将两个16位十六进制数相乘

...使用汇编语言。

我只允许使用寄存器%eax,%ebx,%ecx,%edx和堆栈。

编辑:哦,我在x86上使用ATT语法
EDIT2:不允许反编译为程序集...


使用您的课程教科书,即兰德尔·海德(Randall Hyde)的"汇编语言的艺术"。

参见4.2.4-扩展精度乘法

Although an 8x8, 16x16, or 32x32 multiply is usually sufficient, there are times when you may want to multiply larger values together. You will use the x86 single operand MUL and IMUL instructions for extended precision multiplication ..

Probably the most important thing to remember when performing an extended precision multiplication is that you must also perform a multiple precision addition at the same time. Adding up all the partial products requires several additions that will produce the result. The following listing demonstrates the proper way to multiply two 64 bit values on a 32 bit processor ..

(有关完整的装配清单和插图,请参见链接。)


如果是64x86,

1
2
3
4
5
6
function(x, y, *lower, *higher)
movq %rx,%rax     #Store x into %rax
mulq %y           #multiplies %y to %rax
#mulq stores high and low values into rax and rdx.
movq %rax,(%r8)   #Move low into &lower
movq %rdx,(%r9)   #Move high answer into &higher


此代码假定您需要x86(而不是x64代码),您可能只想要64位产品并且您不在乎溢出或带符号的数字。 (签名版本与此类似)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
MUL64_MEMORY:
     mov edi, val1high
     mov esi, val1low
     mov ecx, val2high
     mov ebx, val2low
MUL64_EDIESI_ECXEBX:
     mov eax, edi
     mul ebx
     xch eax, ebx  ; partial product top 32 bits
     mul esi
     xch esi, eax ; partial product lower 32 bits
     add ebx, edx
     mul ecx
     add ebx, eax  ; final upper 32 bits
; answer here in EBX:ESI

这不符合OP的确切寄存器限制,但是结果完全适合x86提供的寄存器。 (此代码未经测试,但我认为是正确的)。

[注意:我从另一个已关闭的问题转移了这个答案,因为这里的其他"答案"中没有一个直接回答了该问题]。


由于您使用的是x86,因此需要4个考虑指令。将64位数量分成两个32位字,并将低位字乘以结果的最低和第二低字,然后分别使用不同编号的低和高字对(它们分别进入结果的第二和第三低字)和最终将两个高位词转换为结果的2个最高位词。将它们加在一起不要忘记处理进位。您没有指定输入和输出的内存布局,因此无法编写示例代码。


找到一个支持64位的C编译器(GCC执行IIRC),编译仅执行此操作的程序,然后进行反汇编。 GCC可以自己将其吐出,并且可以使用正确的工具将其从目标文件中删除。

OTOH他们是x86上的32bX32b = 64b op

1
2
3
4
5
a:b * c:d = e:f
// goes to
e:f = b*d;
x:y = a*d;  e += x;
x:y = b*c;  e += x;

一切都溢出

(未试)

仅编辑未签名


只需执行普通的长乘法,就好像您要对一对2位数字相乘,只是每个"数字"实际上是32位整数。如果您要在地址X和Y上将两个数字相乘并将结果存储在Z中,那么您想要做的(用伪代码)是:

1
2
Z[0..3] = X[0..3] * Y[0..3]
Z[4..7] = X[0..3] * Y[4..7] + X[4..7] * Y[0..3]

请注意,我们将舍弃结果的高64位(因为64位数字乘以64位数字就是128位数字)。另请注意,这是假设为小端。另外,请注意有符号乘法和无符号乘法。


啊,大会,因为我已经使用了一段时间。因此,我假设这里的真正问题是您正在使用的微控制器(无论如何我还是用汇编语言编写代码的)没有64位寄存器?如果是这样,您将需要分开处理正在使用的数字,并对该部分进行多次乘法。

听起来这是您的措辞方式中的一项家庭作业,所以我不会再详细说明了:P


这取决于您使用的语言。从我从学习MIPS汇编中学到的东西来看,有一个从高位移动命令和从低位移动命令,或者mflo和mfhi。 mfhi存储总数的高64位,而mflo存储总数的低64位。


我打赌你是一个学生,所以看看你能不能做这个工作:逐字逐句地做,并使用移位。想想最有效的解决方案。当心标志位。


如果要使用128位乘法,则应采用AT&T格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
__uint128_t FASTMUL128(const __uint128_t TA,const __uint128_t TB)
{
    union
    {
        __uint128_t WHOLE;
        struct
        {
            unsigned long long int LWORDS[2];
        } SPLIT;
    } KEY;
    register unsigned long long int __RAX,__RDX,__RSI,__RDI;
    __uint128_t RESULT;

KEY.WHOLE=TA;
__RAX=KEY.SPLIT.LWORDS[0];
__RDX=KEY.SPLIT.LWORDS[1];
KEY.WHOLE=TB;
__RSI=KEY.SPLIT.LWORDS[0];
__RDI=KEY.SPLIT.LWORDS[1];
__asm__ __volatile__(
   "movq           %0,                             %%rax                  
\t"
   "movq           %1,                             %%rdx                  
\t"
   "movq           %2,                             %%rsi                  
\t"
   "movq           %3,                             %%rdi                  
\t"
   "movq           %%rsi,                          %%rbx                  
\t"
   "movq           %%rdi,                          %%rcx                  
\t"
   "movq           %%rax,                          %%rsi                  
\t"
   "movq           %%rdx,                          %%rdi                  
\t"
   "xorq           %%rax,                          %%rax                  
\t"
   "xorq           %%rdx,                          %%rdx                  
\t"
   "movq           %%rdi,                          %%rax                  
\t"
   "mulq           %%rbx                                                  
\t"
   "xchgq          %%rbx,                          %%rax                  
\t"
   "mulq           %%rsi                                                  
\t"
   "xchgq          %%rax,                          %%rsi                  
\t"
   "addq           %%rdx,                          %%rbx                  
\t"
   "mulq           %%rcx                                                  
\t"
   "addq           %%rax,                          %%rbx                  
\t"
   "movq           %%rsi,                          %%rax                  
\t"
   "movq           %%rbx,                          %%rdx                  
\t"
   "movq           %%rax,                          %0                      
\t"
   "movq           %%rdx,                          %1                      
\t"
   "movq           %%rsi,                          %2                      
\t"
   "movq           %%rdi,                          %3                      
\t"
    :"=m"(__RAX),"=m"(__RDX),"=m"(__RSI),"=m"(__RDI)
    : "m"(__RAX),"m"(__RDX),"m"(__RSI),"m"(__RDI)
    :"rax","rbx","ecx","rdx","rsi","rdi"
);
KEY.SPLIT.LWORDS[0]=__RAX;
KEY.SPLIT.LWORDS[1]=__RDX;
RESULT=KEY.WHOLE;
return RESULT;
}

如果要使用128模式,请尝试此...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
__uint128_t AES::XMULTX(__uint128_t TA,__uint128_t TB)
{
    union
    {
        __uint128_t WHOLE;
        struct
        {
            unsigned long long int LWORDS[2];
        } SPLIT;
    } KEY;
    register unsigned long long int __XRBX,__XRCX,__XRSI,__XRDI;
    __uint128_t RESULT;

    KEY.WHOLE=TA;
    __XRSI=KEY.SPLIT.LWORDS[0];
    __XRDI=KEY.SPLIT.LWORDS[1];
    KEY.WHOLE=TB;
    __XRBX=KEY.SPLIT.LWORDS[0];
    __XRCX=KEY.SPLIT.LWORDS[1];
    __asm__ __volatile__(
                "movq          %0,             %%rsi          
\t"      
                "movq          %1,             %%rdi          
\t"
                "movq          %2,             %%rbx          
\t"
                "movq          %3,             %%rcx          
\t"
                "movq          %%rdi,          %%rax          
\t"
                "mulq          %%rbx                          
\t"
                "xchgq         %%rbx,          %%rax          
\t"
                "mulq          %%rsi                          
\t"
                "xchgq         %%rax,          %%rsi          
\t"
                "addq          %%rdx,          %%rbx          
\t"
                "mulq          %%rcx                          
\t"
                "addq          %%rax,          %%rbx          
\t"
                "movq          %%rsi,          %0              
\t"
                "movq          %%rbx,          %1              
\t"
                 :"=m" (__XRSI),"=m" (__XRBX)
                 :"m" (__XRSI), "m" (__XRDI),"m" (__XRBX),"m" (__XRCX)
                 :"rax","rbx","rcx","rdx","rsi","rdi"
                 );
    KEY.SPLIT.LWORDS[0]=__XRSI;
    KEY.SPLIT.LWORDS[1]=__XRBX;
    RESULT=KEY.WHOLE;
    return RESULT;
}


推荐阅读