反汇编代码还原之除数为2的幂
本文为看雪论坛精华文章
看雪论坛作者ID:TkBinary
目录
系列文章
一. 除法优化以及反汇编代码还原
1.1 为什么学习除法优化以及除法为什么优化
1.2 学习除法优化的必备数学能力
1.3 除法的向零取整
1.4 汇编中除法要了解的知识
二. 除法除数为正数2的幂有符号表现形式与代码还原
2.1 向下取整转化为向上取整 数学定理
2.2的幂有符号高级代码与汇编代码
2.3 除数为变量,未知除数不做优化
2.4除数为2以及无分支优化
2.5除数为4的优化
2.6 除数为8的优化
三. 除法除数为正数2的幂无符号表现形式与代码还原
3.1 高级代码与核心汇编代码
四. 除数为负2的幂表现形式
4.1 高级代码与核心汇编代码
五. Visual Studio 2019 x86x64 下除数为2的幂的优化方式
5.1 x86下 除数为正数2的幂
5.2 x86下除数为负数2的幂
5.3 x64下除数为负数2的幂
系列文章
一. 除法优化以及反汇编代码还原
1.1 为什么学习除法优化以及除法为什么优化
1.2 学习除法优化的必备数学能力
1.3 除法的向零取整
比如现实中:
7/3 = 2..1 而计算机中就如下 7 / 3 = 2
向下取整
向上取整
向零取整
1.4 汇编中除法要了解的知识
二. 除法除数为正数2的幂
有符号表现形式与代码还原
2.1 向下取整转化为向上取整数学定理
2.2 幂有符号高级代码与汇编代码
int main(int argc, char* argv[])
{
/*
除法
*/
int NumberOne = 0;
int NumberTwo = 0;
scanf("%d",&NumberOne);
scanf("%d",&NumberTwo);
int Count1 = NumberOne / NumberTwo;
int Count2 = NumberOne / 2;
int Count3 = NumberTwo / 4 ;
int Count5 = NumberTwo / 8;
printf("%d%d%d%d%d",Count5,Count3,Count2,Count1);
system("pause");
return 0;
}
mov ecx, [esp+1Ch+var_8]
mov esi, [esp+1Ch+var_4]
mov eax, ecx
cdq
idiv esi
mov eax, ecx
cdq
sub eax, edx
sar eax, 1
mov eax, esi
cdq
and edx, 3
add eax, edx
sar eax, 2
cdq
and edx, 7
add eax, edx
sar eax, 3
push eax
2.3 除数为变量,未知除数不做优化
int Count1 = NumberOne / NumberTwo;
mov ecx, [esp+1Ch+var_8]
mov esi, [esp+1Ch+var_4]
mov eax, ecx
cdq
idiv esi
ecx = var_8
esi = var_4
ecx / esi == var_8 / var_4
2.4 除数为2以及无分支优化
int Count2 = NumberOne / 2;
mov eax, ecx 获得被除数
cdq 被除数进行符号扩展
sub eax, edx 被除数减去符号扩展位
sar eax, 1 算术右移
mov eax, ecx 获得被除数
sar eax, 1
mov eax, ecx 获得被除数
cdq 被除数进行符号扩展
sub eax, edx 被除数减去符号扩展位
sar eax, 1 算术右移
负数的情况下,sub eax,edx === (-被除数) - (-1) 。根据数学定理,负负得正,等价于 (-被除数) + 1。
正数的请开情况下 sub eax,edx == 被除数- 0 == 被除数。所以如果是正数的情况下,cdq + sub eax,edx。
这两个指令是没有用的。
mov eax, ecx 获得被除数
cdq 被除数进行符号扩展
sub eax, edx 被除数减去符号扩展位
sar eax, 1 算术右移
mov eax, ecx
cdq 被除数为负数 edx = -1
sub eax, edx -被除数 - 1 == (被除数 + 1)
sar eax, 1 /n
2.5 除数为4的优化
4 = 2的2次方
mov eax, esi 获得被除数
cdq 符号扩展.edx 要么为1 要么为0
and edx, 3 被除数 & 2^n - 1
add eax, edx 被除数 + 符号扩展
sar eax, 2 向下取整完成除法
mov eax, esi 获得被除数
sar eax, 2 向下取整完成除法
mov eax, esi 获得被除数
cdq 符号扩展.edx 要么为1 要么为0
and edx, 3 被除数 & 2^n - 1
add eax, edx 被除数 + 符号扩展
sar eax, 2 向下取整完成除法
sar 2 等价于 /4
mov eax, esi
cdq
and edx, 3
add eax, edx
sar eax, 2
eax = var_xxx
eax = eax / 4 == var_xxx / 4
2.6 除数为8的优化
mov eax, esi
cdq
and edx, 7
add eax, edx
sar eax, 3
三. 除法除数为正数2的
幂无符号表现形式与代码还原
3.1 高级代码与核心汇编代码
int main(int argc, char* argv[])
{
/*
除法
*/
unsigned int NumberOne = 0;
unsigned int NumberTwo = 0;
scanf("%u",&NumberOne);
scanf("%u",&NumberTwo);
unsigned Count1 = NumberOne / NumberTwo;
unsigned Count2 = NumberOne / 2;
unsigned Count3 = NumberTwo / 4 ;
unsigned Count5 = NumberTwo / 8;
printf("%d%d%d%d%d",Count5,Count3,Count2,Count1);
system("pause");
return 0;
}
.text:0040102C mov esi, [esp+1Ch+var_8]
.text:00401030 mov ecx, [esp+1Ch+var_4]
.text:00401034 mov eax, esi
.text:00401036 xor edx, edx
.text:00401038 div ecx 变量/变量 符号位不适用cdq因为无符号所以直接清空edx
.text:0040103A mov edx, ecx
.text:0040103C shr esi, 1 直接使用逻辑右移来进行计算结果.符号位补0
.text:0040103E shr edx, 2
.text:00401041 shr ecx, 3
.text:0040103C shr esi, 1 除数还原为 esi / 2^1
.text:0040103E shr edx, 2 除数还原为 edx /2^2
.text:00401041 shr ecx, 3 除数还原为 ecx /2^3
四. 除数为负2的幂表现形式
4.1 高级代码与核心汇编代码
int main(int argc, char* argv[])
{
/*
除法
*/
int NumberOne = 0;
int NumberTwo = 0;
scanf("%d",&NumberOne);
scanf("%d",&NumberTwo);
int Count1 = NumberOne / NumberTwo;
int Count2 = NumberOne / -2;
int Count3 = NumberTwo / -4 ;
int Count5 = NumberTwo / -8;
printf("%d%d%d%d%d",Count5,Count3,Count2,Count1);
system("pause");
return 0;
}
mov esi, [esp+1Ch+var_8]
mov ecx, [esp+1Ch+var_4]
mov eax, esi
cdq
idiv ecx
mov eax, esi
cdq
sub eax, edx
sar eax, 1
neg eax
mov eax, ecx
cdq
and edx, 3
add eax, edx
sar eax, 2
neg eax
mov eax, ecx
cdq
and edx, 7
add eax, edx
sar eax, 3
neg eax
sar eax,1 还原为 eax / (-2^1) 下面同上
neg eax
sar eax,2
neg eax
sar eax,3
neg eax
五. Visual Studio 2019 x86x64
下除数为2的幂的优化方式
5.1 x86下 除数为正数2的幂
int main(int argc, char* argv[])
{
/*
除法
*/
int NumberOne = 0;
int NumberTwo = 0;
scanf("%d", &NumberOne);
scanf("%d", &NumberTwo);
int Count1 = NumberOne / NumberTwo;
int Count2 = NumberOne / 2;
int Count3 = NumberTwo / 4;
int Count5 = NumberTwo / 8;
printf("%d%d%d%d%d", Count5, Count3, Count2, Count1);
system("pause");
return 0;
}
.text:00401080 push ebp
.text:00401081 mov ebp, esp
.text:00401083 sub esp, 8
.text:00401086 push esi
.text:00401087 lea eax, [ebp+var_4]
.text:0040108A mov [ebp+var_4], 0
.text:00401091 push eax
.text:00401092 push offset unk_41ECDC
.text:00401097 mov [ebp+var_8], 0
.text:0040109E call sub_401050
.text:004010A3 lea eax, [ebp+var_8]
.text:004010A6 push eax
.text:004010A7 push offset unk_41ECDC
.text:004010AC call sub_401050
核心汇编
.text:004010B1 mov eax, [ebp+var_4]
.text:004010B4 mov esi, [ebp+var_8]
.text:004010B7 cdq
.text:004010B8 idiv esi
.text:004010BA push eax
.text:004010BB mov eax, [ebp+var_4]
.text:004010BE cdq
.text:004010BF sub eax, edx
.text:004010C1 sar eax, 1
.text:004010C3 push eax
.text:004010C4 mov eax, esi
.text:004010C6 cdq
.text:004010C7 and edx, 3
.text:004010CA add eax, edx
.text:004010CC sar eax, 2
.text:004010CF push eax
.text:004010D0 mov eax, esi
.text:004010D2 cdq
.text:004010D3 and edx, 7
.text:004010D6 add eax, edx
.text:004010D8 sar eax, 3
.text:004010DB push eax
.text:004010DC push offset aDDDDD ; "%d%d%d%d%d"
.text:004010E1 call sub_401020
.text:004010E6 push offset aPause ; "pause"
.text:004010EB call sub_4048C7
.text:004010F0 add esp, 28h
.text:004010F3 xor eax, eax
.text:004010F5 pop esi
.text:004010F6 mov esp, ebp
.text:004010F8 pop ebp
.text:004010F9 retn
.text:004010F9 sub_401080 endp
5.2 x86下除数为负数2的幂
int main(int argc, char* argv[])
{
/*
除法
*/
int NumberOne = 0;
int NumberTwo = 0;
scanf("%d", &NumberOne);
scanf("%d", &NumberTwo);
int Count1 = NumberOne / NumberTwo;
int Count2 = NumberOne / -2;
int Count3 = NumberTwo / -4;
int Count5 = NumberTwo / -8;
printf("%d%d%d%d%d", Count5, Count3, Count2, Count1);
system("pause");
return 0;
}
.text:004010B1 mov eax, [ebp+var_4]
.text:004010B4 mov esi, [ebp+var_8]
.text:004010B7 cdq
.text:004010B8 idiv esi
.text:004010BA push eax
.text:004010BB mov eax, [ebp+var_4]
.text:004010BE cdq
.text:004010BF sub eax, edx
.text:004010C1 sar eax, 1
.text:004010C3 neg eax
.text:004010C5 push eax
.text:004010C6 mov eax, esi
.text:004010C8 cdq
.text:004010C9 and edx, 3
.text:004010CC add eax, edx
.text:004010CE sar eax, 2
.text:004010D1 neg eax
.text:004010D3 push eax
.text:004010D4 mov eax, esi
.text:004010D6 cdq
.text:004010D7 and edx, 7
.text:004010DA add eax, edx
.text:004010DC sar eax, 3
.text:004010DF neg eax
.text:004010E1 push eax
5.3 x64下除数为负数2的幂
int main(int argc, char* argv[])
{
/*
除法
*/
__int64 NumberOne = 0;
__int64 NumberTwo = 0;
scanf("%Id", &NumberOne);
scanf("%Id", &NumberTwo);
__int64 Count1 = NumberOne / NumberTwo;
__int64 Count2 = NumberOne / -2;
__int64 Count3 = NumberTwo / -4;
__int64 Count5 = NumberTwo / -8;
printf("%lld%I64d%lld%I64d", Count5, Count3, Count2, Count1);
system("pause");
return 0;
}
.text:000000014000110E mov rax, [rsp+38h+arg_10]
.text:0000000140001113 cqo
.text:0000000140001115 idiv r10
.text:000000014000111B mov rax, [rsp+38h+arg_10]
.text:0000000140001120 cqo
.text:0000000140001122 mov [rsp+38h+var_18], r11
.text:0000000140001127 sub rax, rdx
.text:000000014000112A sar rax, 1
.text:000000014000112D neg rax
.text:0000000140001130 mov r9, rax
.text:0000000140001133 mov rax, r10
.text:0000000140001136 cqo
.text:0000000140001138 and edx, 3
.text:0000000140001144 sar r8, 2
.text:000000014000114B neg r8
.text:000000014000113F mov rax, r10
.text:0000000140001142 cqo
.text:0000000140001148 and edx, 7
.text:000000014000114E add rdx, rax
.text:0000000140001151 sar rdx, 3
.text:0000000140001155 neg rdx
.text:0000000140001158 call sub_140001020
.text:000000014000115D lea rcx, aPause ; "pause"
.text:0000000140001164 call sub_1400045A4
.text:0000000140001169 xor eax, eax
.text:000000014000116B add rsp, 38h
看雪ID:TkBinary
https://bbs.pediy.com/user-home-723188.htm
*本文由看雪论坛 TkBinary 原创,转载请注明来自看雪社区。
本文参与了#看雪30天发帖打卡挑战#活动。
发帖见证成长,坚持见证不凡。
不仅可以收获进步,还可赢取物质奖励哦!
想要了解更多活动详情,戳 ↓
另外,贴心提示本次再印刷还没购买0day安全正版书籍的小伙伴抓紧时间啦!
目前已热销486本,满500本就可安排发货啦!
点击以下小程序即可预购!
推荐文章++++
求分享
求点赞
求在看