取模运算的汇编奥秘揭秘

除法已经说完了,来说一下取模。

代码

汇编

wingw

main(int, char**):

push %rbp

mov %rsp,%rbp

sub $0x20,%rsp

mov %ecx,0x10(%rbp)

mov %rdx,0x18(%rbp)

call 0x7ff7410d1837 ; <__main> mov 0x10(%rbp),%eax ;eax = argc

cltd

shr $0x1d,%edx ;edx >> 29(这里相当于判断)

add %edx,%eax ;eax = argc + (argc <0 ? 7 : 0)

and $0x7,%eax ;eax = eax & 7

sub %edx,%eax ;减回修正量

mov %eax,%edx

lea 0x88f5(%rip),%rax ; 0x7ff7410da000 mov %rax,%rcx

call 0x7ff7410d8e40 ; <printf(char const*, ...)> mov 0x10(%rbp),%edx ;edx = argc

movslq %edx,%rax

imul $0x38e38e39,%rax,%rax ;rax = argc * 0x38e38e39

shr $0x20,%rax ;rax = rax >> 32(逻辑)

sar %eax ;eax = eax >> 1(算数)

mov %edx,%ecx ;ecx = argc >> 31

sar $0x1f,%ecx ;ecx >> 1

sub %ecx,%eax ;ecx = ecx -- eax(%eax = argc / 9)

mov %eax,%ecx ;ecx = eax

shl $0x3,%ecx ;ecx >> 3

add %eax,%ecx ;ecx = eax + ecx(%ecx = (%eax << 3) + %eax = 8*q + q = 9*q)

mov %edx,%eax

sub %ecx,%eax ;eax = argc - 9 * (argc / 9)

mov %eax,%edx

lea 0x88bf(%rip),%rax ; 0x7ff7410da000 mov %rax,%rcx

call 0x7ff7410d8e40 ; <printf(char const*, ...)> mov $0x0,%eax

add $0x20,%rsp

pop %rbp

ret

msvc

64->64

main(int,char **):

movq %rdx, 0x10(%rsp)

movl %ecx, 0x8(%rsp)

pushq %rdi

subq $0x20, %rsp

movl 0x30(%rsp), %eax ; eax = argc

cltd ;扩展eax

andl $0x7, %edx ;edx = edx & 7

addl %edx, %eax ;edx = edx & eax

andl $0x7, %eax ;eax = eax = & 7

subl %edx, %eax ;(argc + (argc<0?7:0)) & 7 - (argc<0?7:0)

movl %eax, %edx

leaq 0x86ca(%rip), %rcx

callq 0x140001195 ; printf movl 0x30(%rsp), %eax ;eax = aegc

cltd ;扩展

movl $0x9, %ecx ;eax = argc / 9

idivl %ecx ;eax = argc /9,edx = argc % 9

movl %edx, %eax

movl %eax, %edx

leaq 0x86b6(%rip), %rcx

callq 0x140001195 ; printf xorl %eax, %eax

addq $0x20, %rsp

popq %rdi

retq

64->32

main(int,char **):

pushl %ebp

movl %esp, %ebp

movl 0x8(%ebp), %eax

andl $0x80000007, %eax ; imm = 0x80000007 jns 0x4014d2 ; <+18> at main.cpp:4(%eax 的符号位为 0(argc >= 0)时跳转) decl %eax

orl $-0x8, %eax

incl %eax ;负数取模修正

pushl %eax

pushl 0x606b30 *; imm = 0x606B30* calll 0x40119a *; _printf* addl 0x8, %esp

movl 0x8(%ebp), %eax ;eax = argc

cltd ;扩展(后面是正常的除法操作)

movl $0x9, %ecx

idivl %ecx

pushl %edx

pushl 0x606b38 *; imm = 0x606B38* calll 0x40119a *; _printf* addl 0x8, %esp

xorl %eax, %eax

cmpl %esp, %ebp

calll 0x4010ff ; __RTC_CheckEsp popl %ebp

retl

对于2的幂的取模有一下四种方案:

方案1

对2的k次方取余,余数只需要被除数低k位的值就可以,如果是负数需要在k位之前补1。

代码模板:

mov reg, 被除数

and reg , 80000007h

jns lab1

or reg,0ffffff8h

lab1:

余数的值非0没有问题;如果为0他就是错误的。需要进行调整。方法是在or运算之前-1,or算完了再+1。如果余数不为0不影响计算结果。

代码模板:

mov reg,被除数

and reg,80000007h(这个数由2^k决定)

jns lab1

dec reg

or reg,fffffff8

inc reg

lab1:

碰到这个就能判定是取模代码,模型是变量对2k 执行取模运算。还原就直接去掉高位保留低位代码,统计地位有多少个1就能得到k值。

方案2

对2的k次方取余对于正数使用方案1,负数可以使用下面的调整公式。

x% 2 k = x+ 2 k - 1 & 2 k -1 - 2 k-1

遇到这个公式页可以判定是取模代码,原型是变量对2k 执行取模运算。还原就是直接看and reg,0fffffff8统计低位一共保留有多少0即可得到k的值。

方案3

对2的k次方取余,对正数使用以下调整公式

x% 2 k =x- x&~ 2 k-1

对负数使用以下调整公式

x% 2 k =x- x+ 2 k -1 &~ 2 k-1

遇到这个公式页可以判定是取模代码,原型是变量对2k 执行取模运算。还原就是直接看and reg,0fffffff8统计低位一共保留有多少0即可得到k的值。

方案4

对非2的k次方取余,

r=a%b

根据性质可以得到

r=a-q*b=a- a b*b

碰到这个很简单直接看b就可以了。

相关推荐
奈落246 小时前
AI辅助的另一面:从2026年国际AI安全报告的“故障”清单到国内专家的可靠性短板,自主行动的Agent为什么更难及时干预
人工智能·安全·agent·本地部署·ai 办公
赛博守夜人11 小时前
AI安全攻防与治理之十六:对抗样本、恶意文件与多模态攻击,AI 内容安全检测的真实盲区
人工智能·安全
蹊黎11 小时前
Linux 下用 C 语言实现进度条
linux·c语言·单片机
ZEB110613 小时前
首届安全应急救援机器人大赛在广州举办 深圳璇玑动力斩获多项冠军
安全·机器人·消防
爱聊灵光的维C13 小时前
从看见世界到重构认知:在视觉与硬件的交汇处,寻找我们这代人的北极星
c语言·物联网·计算机视觉·重构·硬件工程·射频工程
AI+程序员在路上14 小时前
RV1126B 上支持的模型及全流程应用--从CNN及语音到 LLMVLM 与跨平台选型
linux·c语言·人工智能
揽星河..15 小时前
【C语言】扫雷游戏
c语言·算法·游戏
未来之窗软件服务15 小时前
WAF负载均衡+蜜罐混淆安全体系-东方仙盟
运维·安全·负载均衡·仙盟创梦ide·东方仙盟·阿雪技术观·网关开发
高德开放平台16 小时前
构建“车-云-端”安全闭环:新大洲本田通过高德开放平台接入“鹰眼守护预警系统”
安全
冻柠檬飞冰走茶16 小时前
PTA刷题集之Airline Routes(C语言实现)
c语言·开发语言·数据结构·算法