元始天尊 发表于 2014-11-7 15:26:17

浅析MSVC的64位整数运算

在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
sub   eax, 1
mov   ecx, dword ptr
sbb   ecx, 0
mov   dword ptr , eax
mov   dword ptr , ecx
mov   edx, dword ptr
mov   , edx//前缀++先赋值后自增,var_E8为赋值所产生的中间变量
mov   eax, dword ptr
mov   , eax
mov   ecx, dword ptr
sub   ecx, 1
mov   edx, dword ptr
sbb   edx, 0
mov   dword ptr , ecx
mov   dword ptr , edx
③__int64 k=i*j; 同样地,2个变量为按值传递参数,分高32位和低32位依次传递,返回类型也为按值返回。
mov   eax, dword ptr
push    eax
mov   ecx, dword ptr
push    ecx
mov   edx, dword ptr
push    edx
mov   eax, dword ptr
push    eax
call    j___allmul
mov   dword ptr , eax//返回为__int64类型
mov   dword ptr , 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
push    eax
mov   ecx, dword ptr
push    ecx
mov   edx, dword ptr
push    edx
mov   eax, dword ptr
push    eax
call    j___alldiv
mov   dword ptr , eax//返回为__int64类型
mov   dword ptr , edx

__int64 k=i%j;
mov   eax, dword ptr
push    eax
mov   ecx, dword ptr
push    ecx
mov   edx, dword ptr
push    edx
mov   eax, dword ptr
push    eax
call    j___allrem
mov   dword ptr , eax
mov   dword ptr , edx

④__int64 k=(!i);从下面指令序列可见,逻辑非操作是高32位和低32位的位或并取反所得结果,在位或结果非零时使用xmm寄存器将栈上目标__int64变量清零即可
040131D 8B 44 24 10                           mov   eax, dword ptr
.text:00401321 0B 44 24 14                           or      eax, dword ptr
.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, xmm0
.text:00401339 8B 4C 24 1C                           mov   ecx, dword ptr
.text:0040133D 8B 44 24 18                           mov   eax, dword ptr

__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
.text:00401383 0B 44 24 14                           or      eax, dword ptr
.text:00401387 74 13                                 jz      short loc_40139C
.text:00401389 8B 44 24 20                           mov   eax, dword ptr
.text:0040138D 0B 44 24 24                           or      eax, dword ptr
.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, xmm0

__int64 k=i||j; 从以下汇编指令序列可知,逻辑或和逻辑与操作类似,都使用了表达式短路技法
.text:004013EB 8B 44 24 10                           mov   eax, dword ptr
.text:004013EF 0B 44 24 14                           or      eax, dword ptr
.text:004013F3 75 1D                                 jnz   short loc_401412
.text:004013F5 8B 44 24 20                           mov   eax, dword ptr
.text:004013F9 0B 44 24 24                           or      eax, dword ptr
.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, xmm0
.text:00401408 8B 44 24 1C                           mov   eax, dword ptr
.text:0040140C 8B 4C 24 18                           mov   ecx, dword ptr
.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
.text:00414FAA F7 D0                                 not   eax
.text:00414FAC 8B 4D F8                              mov   ecx, dword ptr
.text:00414FAF F7 D1                                 not   ecx
.text:00414FB1 89 45 D4                              mov   dword ptr , eax
.text:00414FB4 89 4D D8                              mov   dword ptr , ecx.text:00414FB4 89 4D D8                              

__int64 k=(i&j); 和取反类似,分高位和低位分别进行与操作
.text:00415016 8B 45 F4                              mov   eax, dword ptr
.text:00415019 23 45 E4                              and   eax, dword ptr
.text:0041501C 8B 4D F8                              mov   ecx, dword ptr
.text:0041501F 23 4D E8                              and   ecx, dword ptr
.text:00415022 89 45 D4                              mov   dword ptr , eax
.text:00415025 89 4D D8                              mov   dword ptr , 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
.text:0041508A 0B 45 E4                              or      eax, dword ptr
.text:0041508D 8B 4D F8                              mov   ecx, dword ptr
.text:00415090 0B 4D E8                              or      ecx, dword ptr
.text:00415093 89 45 D4                              mov   dword ptr , eax
.text:00415096 89 4D D8                              mov   dword ptr , ecx

__int64 k=(i<<1); 调用__allshl子例程,同理右移也用到子例程
.text:004150F8 8B 45 F4                              mov   eax, dword ptr
.text:004150FB 8B 55 F8                              mov   edx, dword ptr
.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 , eax
.text:00415108 89 55 D8                              mov   dword ptr , edx

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

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

欲知__int64怎样实现乘除法和移位,请听下回分解~_~
页: [1]
查看完整版本: 浅析MSVC的64位整数运算