10

我该怎么去...

  • 将两个 64 位数字相乘

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

...使用汇编语言。

我只能使用寄存器 %eax、%ebx、%ecx、%edx 和堆栈。

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

4

11 回答 11

14

使用可能应该是您的课程教科书,Randall Hyde 的“汇编语言的艺术”。

请参见4.2.4 - 扩展精度乘法

虽然 8x8、16x16 或 32x32 乘法通常就足够了,但有时您可能希望将更大的值相乘。您将使用 x86 单操作数 MUL 和 IMUL 指令进行扩展精度乘法..

执行扩展精度乘法时要记住的最重要的事情可能是您还必须同时执行多精度加法。将所有部分产品相加需要多次添加才能产生结果。下面的清单演示了在 32 位处理器上将两个 64 位值相乘的正确方法。

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

于 2008-09-17T21:26:53.447 回答
4

如果这是 64x86,

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
于 2013-03-21T08:45:34.417 回答
2

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

于 2008-09-17T21:29:28.120 回答
2

此代码假定您需要 x86(不是 x64 代码),您可能只需要 64 位产品,并且您不关心溢出或有符号数字。(签名版本类似)。

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 提供的寄存器。(此代码未经测试,但我认为它是正确的)。

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

于 2014-05-11T01:47:37.337 回答
0

这取决于您使用的语言。从我学习 MIPS 汇编的记忆中,有一个 Move From High 命令和一个 Move From Lo 命令,或者 mflo 和 mfhi。mfhi 存储前 64 位,而 mflo 存储总数的低 64 位。

于 2008-09-17T21:22:24.313 回答
0

啊组装,自从我使用它以来已经有一段时间了。所以我假设这里真正的问题是你正在使用的微控制器(我曾经在汇编中编写代码)没有 64 位寄存器?如果是这种情况,您将打破您正在使用的数字,并对这些数字进行多次乘法运算。

从你的措辞来看,这听起来像是一项家庭作业,所以我不会再详细说明了:P

于 2008-09-17T21:29:21.880 回答
0

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

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 位数字)。另请注意,这是假设小端。此外,请注意有符号乘法与无符号乘法。

于 2008-09-17T21:29:52.847 回答
0

找一个支持 64 位的 C 编译器(GCC 做 IIRC)编译一个程序,然后得到反汇编。GCC 可以自己将其吐出,您可以使用正确的工具将其从目标文件中取出。

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

a:b * c:d = e:f
// goes to
e:f = b*d;
x:y = a*d;  e += x;
x:y = b*c;  e += x;

其他一切都溢出

(未经测试)

仅编辑未签名

于 2008-09-17T21:31:05.387 回答
-1

我打赌你是个学生,所以看看你能不能完成这项工作:逐字逐句,并使用位移。想出最有效的解决方案。当心符号位。

于 2008-09-17T21:32:04.603 回答
-3

如果你想要 128 模式试试这个...

__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           \n\t"       
                 "movq          %1,             %%rdi           \n\t"
                 "movq          %2,             %%rbx           \n\t"
                 "movq          %3,             %%rcx           \n\t"
                 "movq          %%rdi,          %%rax           \n\t"
                 "mulq          %%rbx                           \n\t"
                 "xchgq         %%rbx,          %%rax           \n\t"
                 "mulq          %%rsi                           \n\t"
                 "xchgq         %%rax,          %%rsi           \n\t"
                 "addq          %%rdx,          %%rbx           \n\t"
                 "mulq          %%rcx                           \n\t"
                 "addq          %%rax,          %%rbx           \n\t"
                 "movq          %%rsi,          %0              \n\t"
                 "movq          %%rbx,          %1              \n\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;
}
于 2016-03-05T10:44:26.173 回答
-3

如果你想要 128 位乘法,那么这应该是 AT&T 格式的。

__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                   \n\t"
    "movq           %1,                             %%rdx                   \n\t"
    "movq           %2,                             %%rsi                   \n\t"
    "movq           %3,                             %%rdi                   \n\t"
    "movq           %%rsi,                          %%rbx                   \n\t"
    "movq           %%rdi,                          %%rcx                   \n\t"
    "movq           %%rax,                          %%rsi                   \n\t"
    "movq           %%rdx,                          %%rdi                   \n\t"
    "xorq           %%rax,                          %%rax                   \n\t"
    "xorq           %%rdx,                          %%rdx                   \n\t"
    "movq           %%rdi,                          %%rax                   \n\t"
    "mulq           %%rbx                                                   \n\t"
    "xchgq          %%rbx,                          %%rax                   \n\t"
    "mulq           %%rsi                                                   \n\t"
    "xchgq          %%rax,                          %%rsi                   \n\t"
    "addq           %%rdx,                          %%rbx                   \n\t"
    "mulq           %%rcx                                                   \n\t"
    "addq           %%rax,                          %%rbx                   \n\t"
    "movq           %%rsi,                          %%rax                   \n\t"
    "movq           %%rbx,                          %%rdx                   \n\t"
    "movq           %%rax,                          %0                      \n\t"
    "movq           %%rdx,                          %1                      \n\t"
    "movq           %%rsi,                          %2                      \n\t"
    "movq           %%rdi,                          %3                      \n\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;
}
于 2017-06-18T12:11:09.113 回答