[英]How can I multiply two 64-bit numbers using x86 assembly language?
我該怎么辦……
兩個 64 位數字相乘
兩個 16 位十六進制數相乘
...使用匯編語言。
我只允許使用寄存器 %eax、%ebx、%ecx、%edx 和堆棧。
編輯:哦,我在 x86 上使用 ATT 語法
EDIT2:不允許反編譯成程序集...
使用應該是您的課程教科書的 Randall Hyde 的“匯編語言藝術”。
盡管 8x8、16x16 或 32x32 乘法通常就足夠了,但有時您可能希望將更大的值相乘。 您將使用 x86 單操作數 MUL 和 IMUL 指令進行擴展精度乘法..
執行擴展精度乘法時要記住的最重要的事情可能是您還必須同時執行多精度加法。 將所有部分乘積相加需要多次相加才能產生結果。 以下清單演示了在 32 位處理器上將兩個 64 位值相乘的正確方法..
(請參閱完整組件列表和插圖的鏈接。)
如果這是 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
此代碼假定您需要 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 提供的寄存器。 (此代碼未經測試,但我認為它是正確的)。
[注意:我從另一個已關閉的問題轉移了(我的)這個答案,因為這里的其他“答案”都沒有直接回答這個問題]。
由於您使用的是 x86,因此您需要 4 條 mull 指令。 將 64 位數量拆分為兩個 32 位字並將低字乘以結果的最低和第二低的字,然后將來自不同數字的兩對低和高的字(它們轉到結果的第二和第三低的字)和最后兩個高的詞變成了結果的2個最高的詞。 將它們全部加在一起不要忘記處理carry。 您沒有指定輸入和輸出的內存布局,因此無法編寫示例代碼。
這取決於您使用的語言。 根據我在學習 MIPS 匯編時的記憶,有一個 Move From High 命令和一個 Move From Lo 命令,或 mflo 和 mfhi。 mfhi 存儲最高 64 位,而 mflo 存儲總數的低 64 位。
啊組裝,自從我使用它以來已經有一段時間了。 所以我假設這里真正的問題是你正在使用的微控制器(無論如何我用來在匯編中編寫代碼)沒有 64 位寄存器? 如果是這種情況,您將打破您正在處理的數字,並對這些數字進行多次乘法運算。
從你的措辭來看,這聽起來像是一項家庭作業,所以我不會再詳細說明了:P
只需進行普通的長乘法,就好像您在乘以一對 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 位數字)。 還要注意,這是假設小端。 另外,請注意有符號乘法與無符號乘法。
找到一個支持 64 位的 C 編譯器(GCC 執行 IIRC)編譯一個程序,然后進行反匯編。 GCC 可以自己吐出它,您可以使用正確的工具將其從目標文件中取出。
OTOH 他們是 x86 上的 32bX32b = 64b op
a:b * c:d = e:f
// goes to
e:f = b*d;
x:y = a*d; e += x;
x:y = b*c; e += x;
其他一切都溢出了
(未經測試)
僅編輯未簽名
我打賭你是個學生,所以看看你能不能完成這項工作:一個字一個字地做,並使用位移。 想出最有效的解決方案。 小心符號位。
如果你想要 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;
}
如果你想要 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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.