- UID
- 2
- 精华
- 积分
- 7738
- 威望
- 点
- 宅币
- 个
- 贡献
- 次
- 宅之契约
- 份
- 最后登录
- 1970-1-1
- 在线时间
- 小时
|
在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怎样实现乘除法和移位,请听下回分解~_~ |
|