ULONGLONG乘法分析
From: http://blog.csdn.net/syf442/article/details/6077715
64位乘法分析:
VC6 Console Code:
?
| int main(int argc, char* argv[]) { ????? ULONGLONG??? a = 0x87654321; ????? ULONGLONG??? b = 0x100000001; ????? a*=b; ????? //::MessageBox(NULL,"Content","Title",MB_OK); ????? return 0; } |
?
Debug模式下匯編Code:
| 9:??????? ULONGLONG?? a = 0x87654321; 00401028?? mov???????? dword ptr [ebp-8],87654321h 0040102F?? mov???????? dword ptr [ebp-4],0 10:?????? ULONGLONG?? b = 0x100000001; 00401036?? mov???????? dword ptr [ebp-10h],1 0040103D?? mov???????? dword ptr [ebp-0Ch],1 11:?????? a*=b; 00401044?? mov???????? eax,dword ptr [ebp-0Ch] 00401047?? push??????? eax??? ?;壓入b高4 bytes 00401048?? mov???????? ecx,dword ptr [ebp-10h] 0040104B?? push??????? ecx???? ;壓入b低4 bytes 0040104C?? mov???????? edx,dword ptr [ebp-4] 0040104F?? push??????? edx???? ;壓入a高4 bytes 00401050?? mov???????? eax,dword ptr [ebp-8] 00401053?? push??? ????eax???? ;壓入a低4 bytes 00401054?? call??????? _allmul (004010d0)?? ; _allmul計算64位乘法 00401059?? mov???????? dword ptr [ebp-8],eax 0040105C?? mov???????? dword ptr [ebp-4],edx 12: 13:?? //? ::MessageBox(NULL,"Content","Title",MB_OK); 14:?????? return 0; 0040105F?? xor???????? eax,eax |
?
_allmul:
?
| --- intel/llmul.asm? ------------------------------------------------- _allmul: 004010D0?? mov???? eax,dword ptr [esp+8]?? ;取a高4字節 004010D4?? mov???? ecx,dword ptr [esp+10h] ;取b高4字節 004010D8?? or?????? ecx,eax ?; 當ecx==0 && eax == 0時, go on 004010DA?? mov???? ecx,dword ptr [esp+0Ch] ;取 b低4字節 004010DE?? jne????? hard (004010e9) 004010E0?? mov???? eax,dword ptr [esp+4] 004010E4?? mul????? eax,ecx 004010E6?? ret?????? 10h hard: 004010E9?? push???? ebx????? ;保存ebx,使原棧內多偏移了4個字節 004010EA?? mul????? eax,ecx? ; a高4字節*b低4字節 004010EC?? mov???? ebx,eax? ;只保存乘法結果的低4字節到ebx 004010EE?? mov???? eax,dword ptr [esp+8] ;取a低4字節,因為push ebx,所以a在棧中多偏移4字節。 004010F2?? mul????? eax,dword ptr [esp+14h] ;a低4字節*b高4字節 004010F6?? add????? ebx,eax? ?;將兩次乘法低4位結果保存到ebx 004010F8?? mov???? eax,dword ptr [esp+8]? ;a低4字節 004010FC?? mul????? eax,ecx?? ;a低4字節*b低4字節 004010FE?? add????? edx,ebx?? ;加上之前的運算結果低4字節ebx。 00401100?? pop????? ebx 00401101?? ret?????? 10h |
?
代碼詳解:
??????
| 004010D8?? or?????? ecx,eax ?; 當ecx==0 && eax == 0時, go on 004010DA?? mov???? ecx,dword ptr [esp+0Ch] ;取 b低4字節 004010DE?? jne????? hard (004010e9) |
?
● or?? ecx,eax 該條指令判斷了ecx與eax是否同時為0。即僅當
eax==0 && ecx==0時,or ecx,eax的運算結果ecx才==0,此時才會置標志位ZF=1。否則ZF=0。所以,與后面的jne實現邏輯:
if(!(eax==0&&ecx==0))
jmp hard (004010e9);
????? 所以當?? ecx==0 && eax==0,即a和b的高4字節都為0 時,此時a*b即為進行普通的32位寄存器運算,運算結果高4字節放在edx,低4字節放在eax。
or后緊跟mov 是為了保存 b低4字節到ecx,且因為mov等傳送指令不會影響標志寄存器。
跳到hard標號處則是真正的“64位”乘法運算了:
?
????? 算法很簡單,即是小學乘法展開公式:(a+b)*(c+d) = a*c+a*d+b*c+b*d。
?
我們令aHigh4B為a高4字節,aLow4B為a低4字節,則得:
a*b = (aHigh4B<<32+aLow4B)*( bHigh4B<<32+bLow4B)
????? 左移32位,即左移4字節。由于(aHigh4B<<32)* (bHigh4B<<32)即該式結果等于(aHigh4B* bHigh4B)<<64,所以肯定會溢出,所以該結果忽略。為什么忽略?因為a*b運算的最終結果要保存為64位,所以忽略超出64位的值。于是該式拆分得:
?
????? (aHigh4B<<32 )* bHigh4B + aLow4B*( bHigh4B<<32) + aLow4B* bLow4
?
(aHigh4B<<32 )* bHigh4B對應指令為:
| 004010EA?? mul????? eax,ecx? ; a高4字節*b低4字節 004010EC?? mov???? ebx,eax? ;只保存乘法結果的低4字節到ebx |
?????
mul運算后,edx為結果高4字節,eax為結果低4字節。但為什么只保存eax低4字節的結果?而不保存edx高4字節的結果?
????? 因為(eax*ecx)<<32 = (edx:eax)<<32。所以真實結果的高4字節edx左移32位再次溢出了64位,所以只需保存eax即可。之后將兩次左移32位的乘法操作結果低4字節用ebx累積下來,再加上兩個低4字節的乘法高位結果,即為最終運算結果的高4字節edx。
?
總結
以上是生活随笔為你收集整理的ULONGLONG乘法分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 取拼音字头
- 下一篇: mysql 汉字拼音怎么获得_mysql