找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 3083|回复: 0

浅析MSVC的64位整数运算

[复制链接]
发表于 2014-11-7 15:26:17 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
在MSVC中存在一种64整数类型__int64,可以进行64位整数运算,现在分32位编译条件下分析MSVC的具体处理方式。

测试代码:
__int64 i,j;
i++        ++j        i--        --j i+100 i-100
i*j i/j i%j;
!i i&&j i||j
~i i&j i|j i<<10 i>>10 i^j
i<j i==j;

32位编译debug反汇编代码(以debug版本为例,release版本只是在debug指令框架上进行了优化):
①        __int64类型作为参数传递时,会将高32位和低32位先后分别压栈
②        __int64类型在进行加减法操作和自增自减操作时,先操作低32位,再利用进位或借位操作高32位,自增相当于加1,自减相当于减1
mov     eax, dword ptr [ebp+j]
sub     eax, 1
mov     ecx, dword ptr [ebp+j+4]
sbb     ecx, 0
mov     dword ptr [ebp+j], eax
mov     dword ptr [ebp+j+4], ecx
mov     edx, dword ptr [ebp+i]
mov     [ebp+var_E8], edx//前缀++先赋值后自增,var_E8为赋值所产生的中间变量
mov     eax, dword ptr [ebp+i+4]
mov     [ebp+var_E4], eax
mov     ecx, dword ptr [ebp+i]
sub     ecx, 1
mov     edx, dword ptr [ebp+i+4]
sbb     edx, 0
mov     dword ptr [ebp+i], ecx
mov     dword ptr [ebp+i+4], edx
③__int64 k=i*j; 同样地,2个变量为按值传递参数,分高32位和低32位依次传递,返回类型也为按值返回。
mov     eax, dword ptr [ebp+j+4]
push    eax
mov     ecx, dword ptr [ebp+j]
push    ecx
mov     edx, dword ptr [ebp+i+4]
push    edx
mov     eax, dword ptr [ebp+i]
push    eax
call    j___allmul
mov     dword ptr [ebp+k], eax//返回为__int64类型
mov     dword ptr [ebp+k+4], edx
其中_allmul子例程用于含__int64类型的乘法,如果2个相乘数中非__int64l类型自动转换为__int64类型,下面来看该子例程代码,单步进入_allmul后进入源代码,得到llmul.asm文件,该文件处于Microsoft Visual Studio\VC\crt\src\intel下,开头ll隐含longlong的意思,该目录下同时还有几个ll开头的文件,想必也是longlong类型操作所用子例程,先对这些文件进行总体分析,其中代码稍后分析:
lldiv.asm                长整型有符号除法
lldvrm.asm        长整型有符号除法和求余
llmul.asm                长整型乘法
llrem.asm        长整形有符号求余
llshl.asm                长整形左移
llshr.asm                长整形有符号右移
ulldiv.asm        长整形无符号除法
ulldvrm.asm        长整型无符号除法和求余
ullrem.asm        长整形无符号求余
ullshr.asm        长整形无符号右移

__int64 k=i/j;
mov     eax, dword ptr [ebp+j+4]
push    eax
mov     ecx, dword ptr [ebp+j]
push    ecx
mov     edx, dword ptr [ebp+i+4]
push    edx
mov     eax, dword ptr [ebp+i]
push    eax
call    j___alldiv
mov     dword ptr [ebp+k], eax//返回为__int64类型
mov     dword ptr [ebp+k+4], edx

__int64 k=i%j;
mov     eax, dword ptr [ebp+j+4]
push    eax
mov     ecx, dword ptr [ebp+j]
push    ecx
mov     edx, dword ptr [ebp+i+4]
push    edx
mov     eax, dword ptr [ebp+i]
push    eax
call    j___allrem
mov     dword ptr [ebp+k], eax
mov     dword ptr [ebp+k+4], edx

④__int64 k=(!i);从下面指令序列可见,逻辑非操作是高32位和低32位的位或并取反所得结果,在位或结果非零时使用xmm寄存器将栈上目标__int64变量清零即可
040131D 8B 44 24 10                             mov     eax, dword ptr [esp+28h+i]
.text:00401321 0B 44 24 14                             or      eax, dword ptr [esp+28h+i+4]
.text:00401325 75 09                                   jnz     short loc_401330
.text:00401327 B8 01 00 00 00                          mov     eax, 1
.text:0040132C 33 C9                                   xor     ecx, ecx
.text:0040132E EB 11                                   jmp     short loc_401341
.text:00401330                         ; ---------------------------------------------------------------------------
.text:00401330
.text:00401330                         loc_401330:                             ; CODE XREF: _main+B5 j
.text:00401330 0F 57 C0                                xorps   xmm0, xmm0
.text:00401333 66 0F 13 44 24 18                       movlpd  [esp+28h+k], xmm0
.text:00401339 8B 4C 24 1C                             mov     ecx, dword ptr [esp+28h+k+4]
.text:0040133D 8B 44 24 18                             mov     eax, dword ptr [esp+28h+k]

__int64 k=i&&j;从下面指令序列可知,逻辑与操作是将2个__int64变量的高低位逐个进行高32位和低32位位或操作,可以看做一种表达式短路做法:(((DWORD)i|(DWORD)(i>>32)) && ((DWORD)j|(DWORD)(j>>32))),再利用结果设置新变量。至于这里为何使用xmm指令,笔者认为这一定是出于效率上xmm指令效率高于普通内存操作指令mov
.text:0040137F 8B 44 24 10                             mov     eax, dword ptr [esp+28h+i]
.text:00401383 0B 44 24 14                             or      eax, dword ptr [esp+28h+i+4]
.text:00401387 74 13                                   jz      short loc_40139C
.text:00401389 8B 44 24 20                             mov     eax, dword ptr [esp+28h+j]
.text:0040138D 0B 44 24 24                             or      eax, dword ptr [esp+28h+j+4]
.text:00401391 74 09                                   jz      short loc_40139C
.text:00401393 B8 01 00 00 00                          mov     eax, 1
.text:00401398 33 C9                                   xor     ecx, ecx
.text:0040139A EB 11                                   jmp     short loc_4013AD
.text:0040139C                         ; ---------------------------------------------------------------------------
.text:0040139C
.text:0040139C                         loc_40139C:                             ; CODE XREF: _main+117 j
.text:0040139C                                                                 ; _main+121 j
.text:0040139C 0F 57 C0                                xorps   xmm0, xmm0
.text:0040139F 66 0F 13 44 24 18                       movlpd  [esp+28h+k], xmm0

__int64 k=i||j; 从以下汇编指令序列可知,逻辑或和逻辑与操作类似,都使用了表达式短路技法
.text:004013EB 8B 44 24 10                             mov     eax, dword ptr [esp+28h+i]
.text:004013EF 0B 44 24 14                             or      eax, dword ptr [esp+28h+i+4]
.text:004013F3 75 1D                                   jnz     short loc_401412
.text:004013F5 8B 44 24 20                             mov     eax, dword ptr [esp+28h+j]
.text:004013F9 0B 44 24 24                             or      eax, dword ptr [esp+28h+j+4]
.text:004013FD 75 13                                   jnz     short loc_401412
.text:004013FF 0F 57 C0                                xorps   xmm0, xmm0
.text:00401402 66 0F 13 44 24 18                       movlpd  [esp+28h+k], xmm0
.text:00401408 8B 44 24 1C                             mov     eax, dword ptr [esp+28h+k+4]
.text:0040140C 8B 4C 24 18                             mov     ecx, dword ptr [esp+28h+k]
.text:00401410 EB 07                                   jmp     short loc_401419
.text:00401412                         ; ---------------------------------------------------------------------------
.text:00401412
.text:00401412                         loc_401412:                             ; CODE XREF: _main+183 j
.text:00401412                                                                 ; _main+18D j
.text:00401412 B9 01 00 00 00                          mov     ecx, 1
.text:00401417 33 C0                                   xor     eax, eax

__int64 k=(~i); 从以下汇编指令序列可知,按位取反操作是将高32位和低32位分别取反
.text:00414FA7 8B 45 F4                                mov     eax, dword ptr [ebp+i]
.text:00414FAA F7 D0                                   not     eax
.text:00414FAC 8B 4D F8                                mov     ecx, dword ptr [ebp+i+4]
.text:00414FAF F7 D1                                   not     ecx
.text:00414FB1 89 45 D4                                mov     dword ptr [ebp+k], eax
.text:00414FB4 89 4D D8                                mov     dword ptr [ebp+k+4], ecx.text:00414FB4 89 4D D8                                

__int64 k=(i&j); 和取反类似,分高位和低位分别进行与操作
.text:00415016 8B 45 F4                                mov     eax, dword ptr [ebp+i]
.text:00415019 23 45 E4                                and     eax, dword ptr [ebp+j]
.text:0041501C 8B 4D F8                                mov     ecx, dword ptr [ebp+i+4]
.text:0041501F 23 4D E8                                and     ecx, dword ptr [ebp+j+4]
.text:00415022 89 45 D4                                mov     dword ptr [ebp+k], eax
.text:00415025 89 4D D8                                mov     dword ptr [ebp+k+4], ecx

__int64 k=(i|j); 和与操作类似
.text:00415082 E8 B7 C2 FF FF                          call    j___RTC_CheckEsp
.text:00415087 8B 45 F4                                mov     eax, dword ptr [ebp+i]
.text:0041508A 0B 45 E4                                or      eax, dword ptr [ebp+j]
.text:0041508D 8B 4D F8                                mov     ecx, dword ptr [ebp+i+4]
.text:00415090 0B 4D E8                                or      ecx, dword ptr [ebp+j+4]
.text:00415093 89 45 D4                                mov     dword ptr [ebp+k], eax
.text:00415096 89 4D D8                                mov     dword ptr [ebp+k+4], ecx

__int64 k=(i<<1); 调用__allshl子例程,同理右移也用到子例程
.text:004150F8 8B 45 F4                                mov     eax, dword ptr [ebp+i]
.text:004150FB 8B 55 F8                                mov     edx, dword ptr [ebp+i+4]
.text:004150FE B1 01                                   mov     cl, 1
.text:00415100 E8 C3 BF FF FF                          call    j___allshl
.text:00415105 89 45 D4                                mov     dword ptr [ebp+k], eax
.text:00415108 89 55 D8                                mov     dword ptr [ebp+k+4], edx

__int64 k=(i^j); 和与操作类似
.text:0041524C 8B 45 F4                                mov     eax, dword ptr [ebp+i]
.text:0041524F 33 45 E4                                xor     eax, dword ptr [ebp+j]
.text:00415252 8B 4D F8                                mov     ecx, dword ptr [ebp+i+4]
.text:00415255 33 4D E8                                xor     ecx, dword ptr [ebp+j+4]
.text:00415258 89 45 D4                                mov     dword ptr [ebp+k], eax
.text:0041525B 89 4D D8                                mov     dword ptr [ebp+k+4], ecx

__int64 k=(i==j);
__int64 k=(i!=j);  操作原理相同,比较高32位和低32位,利用前述表达式短路判断

欲知__int64怎样实现乘除法和移位,请听下回分解~_~
回复

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-11-26 00:10 , Processed in 0.029579 second(s), 21 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表