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。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/406975.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

T-SQL中REPLACE的用法_字符串替换

REPLACE 用第三个表达式替换第一个字符串表达式中出现的所有第二个给定字符串表达式。 语法 REPLACE ( string_expression1 , string_expression2 , string_expression3 ) 参数 string_expression1 待搜索的字符串表达式。string_expression1 可以是字符数据或二进制数据。 str…

Linux字符编码转换 UTF8转GB3212

在LINUX上进行编码转换时,既可以利用iconv函数族编程实现,也可以利用iconv命令来实现,只不过后者是针对文件的,即将指定文件从一种编码转换为另一种编码。 一、利用iconv函数族进行编码转换 iconv函数族的头文在LINUX上进行编码转换时,既可以利用iconv函数族编程实现,也可以利用…

ULARGE_INTEGER运算

在调用GetDiskFreeSpaceEx()获取磁盘空间时&#xff0c;由于参数是ULARGE_INTEGER(64位整数)&#xff0c;所以普通的“加减乘除”并不支持(是没有实现)&#xff0c;因此我们采用其他办法来实现&#xff0c;先来看下ULARGE_INTEGER的结构定义&#xff1a; typedef union _ULARG…

IMG图片和文字同一行显示,图片和文字居中显示

问题其实很好解决&#xff0c;只要设定img标签的vertical-align CSS属性就好了&#xff0c;代码如下&#xff1a;

Leetcode刷题(6)有效的括号

最好的种树是十年前,其次是现在。歌谣 每天一个前端小知识 提醒你改好好学习了 知乎博主 csdn博主 b站博主 放弃很容易但是坚持一定很酷 我是歌谣 喜欢就一键三连咯 你得点赞是对歌谣最大的鼓励 题目 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0…

eclipe安装中文语言包 CDT Pydev

一、中文语言包eclipse的国际化项目已经交由Eclipse宝贝项目来进行[url]https://babel.eclipse.org[/url]在线安装&#xff1a;&#xff08;1&#xff09;打开eclipse&#xff0c;菜单 Help -> Software Update …&#xff1b;&#xff08;2&#xff09;打开Software Update…

vue-环境变量和模式

vue项目使用.env文件配置全局环境变量 模式是 Vue CLI 项目中一个重要的概念。默认情况下&#xff0c;一个 Vue CLI 项目有三个模式&#xff1a; development 模式用于 vue-cli-service serve production 模式用于 vue-cli-service build 和 vue-cli-service test:e2e test 模…

printf的两个需要注意的问题:无符号整数和64位整数

From: http://www.cnblogs.com/lidp/articles/1696079.html 1) %d和%u的区别unsigned int dwValue;printf("%d", dwValue);在dwValue的值大于0x7FFFFFFF时&#xff0c;输出的结果会变成负数。正确的程序应该为&#xff1a;printf("%u", dwValue); 2) 使用…

CSS 相对|绝对(relative/absolute)定位系列(一)

1. 绝对定位和浮动元素是近亲&#xff1a;都具备包裹性和破坏性 包裹性&#xff1a;包裹性换种说法就是让元素inline-block化&#xff0c;例如一个div标签默认宽度是100%显示的&#xff0c;但是一旦被absolute属性缠上&#xff0c;则100%默认宽度就会变成自适应内部元素的宽度…

SharePoint 2013 List 备份使用

在测试环境新建List后经过不懈的调整&#xff0c;验证终于做出一个像模像样的表单。 这时候问题来。。。 要怎么迁移到生产环境或者正式环境呢&#xff1f; 在网上找了一些资料&#xff0c;不过都是10的。。 其实想想13跟10区别不大&#xff0c;于是顺利找到了解决方案 备份Lis…

javascript学习系列(24):数组中的substring方法

最好的种树是十年前,其次是现在。歌谣 每天一个前端小知识 提醒你改好好学习了 知乎博主 csdn博主 b站博主 放弃很容易但是坚持一定很酷 我是歌谣 喜欢就一键三连咯 你得点赞是对歌谣最大的鼓励 1前言 在我们的日常开发中 不免会有很多需要处理数据的方法 本节主要说一说s…

LINUX下SYN***战

(一)SYN***原理SYN***属于DOS***的一种,它利用TCP协议缺陷,通过发送大量的半连接请求,耗费服务器CPU和内存资源.SYN***聊了能影响主机外,还可以危 害路由器,防火墙等网络系统,事实上SYN***并不管目标是什么系统,只要这些系统打开TCP服务就可以实施.我们知道,在网络中两台电脑建…

将一个BYTE数组转换成16进制字符串和10进制字符串格式

背景&#xff1a; unsigned char port[5]; 以02x的格式打印出来是 00 00 02 00 00 1.如何转成16进制形式的字符串&#xff0c;使得char *strport16 "0000020000"; 2.如何转成10进制形式的字符串&#xff0c;使得char *strport10 "131072"; C code:…

CSS 相对|绝对(relative/absolute)定位系列(二)

1. 因为事先标准就已经在文字的后面显示&#xff0c;设置absolute之后因为跟随性仍然是在原来的文字&#xff0c;然后再设置margin实现定位即可 2. absolute正业之元素隐藏 元素隐藏与显示是我们在页面制作与交互效果实现中非常常见的&#xff0c;如果您只是使用display:none与…

7天后自动更新cookie

原生js操作cookie 6s后cookie自动删除 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><meta http-equiv&…

js中replace的用法

replace方法的语法是&#xff1a;stringObj.replace(rgExp, replaceText) 其中stringObj是字符串(string)&#xff0c;reExp可以是正则表达式对象(RegExp)也可以是字符串(string)&#xff0c;replaceText是替代查找到的字符串。。为了帮助大家更好的理解&#xff0c;下面举个简…

ospf 单区域配置

在骨干区域(eare0)中:配置方法:router ospf 进程号如:10network 加 你想宣告的网段 反向子网掩码 area 加id 号假如是在路由器的接口ip 是 192.168.1.1 和192.168.2.1 在area 0 中 router ospf 10network 192.168.1.0 0.0.0.255 area 0network 192.168.2.0 0.0.0.255 area 0就可…

javascript学习系列(25):数组中的substr

最好的种树是十年前,其次是现在。歌谣 每天一个前端小知识 提醒你改好好学习了 知乎博主 csdn博主 b站博主 放弃很容易但是坚持一定很酷 我是歌谣 喜欢就一键三连咯 你得点赞是对歌谣最大的鼓励 1前言 在我们的日常开发中 不免会有很多需要处理数据的方法 本节主要说一说s…

CSS 相对|绝对(relative/absolute)定位系列(三)

1. absolute与等高布局 拿简单的两栏布局举例&#xff0c;左栏与右栏有不同的背景色&#xff0c;且中间隔边框线分隔&#xff0c;如何实现&#xff1f;因为随着内容的不同&#xff0c;有可能左侧栏高度较高&#xff0c;也有可能是右侧栏高度较高。所以&#xff0c;要实现无缝的…

CPUID详解[增加TLB与Cache]

From: http://bbs.pediy.com/showthread.php?threadid21646 标 题:CPUID详解[增加TLB与Cache]作 者: Pr0Zel 时 间: 2006-02-21,22:00:23 链 接: http://bbs.pediy.com/showthread.php?t21646 这是文章最后一次更新,加入了TLB与Cache信息等资料前言:论坛上面有人不明白CPUID指…