Loops 循环针工具的通用模式
我试图找到一个通用模式,以便能够运行pintool程序,因此它总是会告诉我Loops 循环针工具的通用模式,loops,assembly,loop-unrolling,Loops,Assembly,Loop Unrolling,我试图找到一个通用模式,以便能够运行pintool程序,因此它总是会告诉我索引在哪里,或者是什么,以及循环指向哪个值 例如,下面是某个循环的组装: 40c374: 48 8b 55 e8 mov -0x18(%rbp),%rdx 40c378: 8b 45 fc mov -0x4(%rbp),%eax 40c37b: 48 98 cltq 40c37d: 0
索引在哪里,或者是什么,以及循环指向哪个值
例如,下面是某个循环的组装:
40c374: 48 8b 55 e8 mov -0x18(%rbp),%rdx
40c378: 8b 45 fc mov -0x4(%rbp),%eax
40c37b: 48 98 cltq
40c37d: 0f b6 84 02 80 00 00 movzbl 0x80(%rdx,%rax,1),%eax
40c384: 00
40c385: 84 c0 test %al,%al
40c387: 74 2a je 40c3b3 <makeMaps_e+0x5b>
40c389: 48 8b 45 e8 mov -0x18(%rbp),%rax
40c38d: 8b 40 7c mov 0x7c(%rax),%eax
40c390: 89 c1 mov %eax,%ecx
40c392: 48 8b 55 e8 mov -0x18(%rbp),%rdx
40c396: 8b 45 fc mov -0x4(%rbp),%eax
40c399: 48 98 cltq
40c39b: 88 8c 02 80 01 00 00 mov %cl,0x180(%rdx,%rax,1)
40c3a2: 48 8b 45 e8 mov -0x18(%rbp),%rax
40c3a6: 8b 40 7c mov 0x7c(%rax),%eax
40c3a9: 8d 50 01 lea 0x1(%rax),%edx
40c3ac: 48 8b 45 e8 mov -0x18(%rbp),%rax
40c3b0: 89 50 7c mov %edx,0x7c(%rax)
40c3b3: 83 45 fc 01 addl $0x1,-0x4(%rbp)
40c3b7: 81 7d fc ff 00 00 00 cmpl $0xff,-0x4(%rbp)
40c3be: 7e b4 jle 40c374 <makeMaps_e+0x1c>
40c374:48 8b 55 e8 mov-0x18(%rbp),%rdx
40c378:8b 45 fc mov-0x4(%rbp),%eax
40c37b:48 98 cltq
40c37d:0f b6 84 02 80 00 movzbl 0x80(%rdx,%rax,1),%eax
40c384:00
40c385:84 c0测试%al,%al
40c387:74 2a je 40c3b3
40c389:48 8b 45 e8 mov-0x18(%rbp),%rax
40c38d:8b 40 7c mov 0x7c(%rax),%eax
40c390:89 c1 mov%eax,%ecx
40c392:48 8b 55 e8 mov-0x18(%rbp),%rdx
40c396:8b 45 fc mov-0x4(%rbp),%eax
40c399:48 98 cltq
40c39b:88 8c 02 80 01 00 mov%cl,0x180(%rdx,%rax,1)
40c3a2:48 8b 45 e8 mov-0x18(%rbp),%rax
40c3a6:8b 40 7c mov 0x7c(%rax),%eax
40c3a9:8d 50 01 lea 0x1(%rax),%edx
40c3ac:48 8b 45 e8 mov-0x18(%rbp),%rax
40c3b0:89 50 7c移动%edx,0x7c(%rax)
40c3b3:83 45 fc 01地址$0x1,-0x4(%rbp)
40c3b7:81 7d fc ff 00 cmpl$0xff,-0x4(%rbp)
40c3be:7e b4 jle 40c374
现在我注意到,检查CMD
并不总是CMP
有没有办法找出索引
值和总迭代次数
有没有办法找出索引值和总迭代次数
没有
一些循环可能具有非索引逻辑,例如以非平凡的方式推进两个+组件键,例如链表遍历(您必须实际遍历树才能知道总计数),其中主要终止条件是(leaf_ptr==nullptr)
,另外,一些循环可能有几个不同的终止条件(break;
),所以您会选择哪一个作为迭代次数?最大值,还是在实际运行中触发循环退出的较早值
对于经典的For(i=…)
循环,您可以在代码中手动找到它,但是“索引”几乎可以隐藏在任何东西中,没有通用模式。有些循环从例如<代码> -> 10代码>代码> > 1代码>代码(C++源为<代码> >(i=0;i as @ pED7G),并非所有循环都有在第一次迭代运行之前已知的行程计数。
但是对于循环,它们通常只在循环中使用一个条件分支(通常在底部)进行编译。类似的启发式方法可能会检测到它们
- 找到循环分支
如果循环中有多个条件分支,其中一个离开循环而不返回,或者跳过计数器增量,那么这不是一个简单的循环
如果可以验证循环体中的嵌套循环或条件没有修改正在查看的(外部)循环的循环计数器,则它们不是问题
- 查找它所依赖的寄存器。例如,
cmp,end\u指针/jne
或dec eax/jnz
e、 g.从循环分支向后工作到第一个标志设置指令。(如果编译器正在为宏融合进行优化,那么它们将是背靠背的,但不幸的是,这并不总是在通用调整中启用。)编译器通常避免部分标志欺骗(如sub-ecx,1
/dec-eax
/jnc
),但如果您想更加安全,请确保标志设置指令实际设置了分支读取的标志
- 检查只有一个寄存器在循环中被实际修改
- 检查修改后的寄存器(循环计数器)在每次迭代中仅修改常量
给定循环计数器的起始值和与之比较的结束值,您可以计算行程计数。如果这些检查中的任何一个失败,根据这个启发式,它不是一个“简单循环”
如果你想让它在未优化的代码上工作,你就必须通过存储/重新加载到内存来跟踪循环计数器。即使是优化编译器有时也会发出多条与循环计数器相关的指令,比如lea ecx,[rdi+1]
然后使用ecx一段时间,然后使用mov edi,ecx
。通常这看起来像是错过了优化(循环中有更多指令,以使编译器想要的东西在循环之外)但是它确实发生了。这就是我目前正在尝试做的。然而,查找它所依赖的寄存器有点困难,因为有时编译器会执行一定数量的MOV
命令。所以我试图通过从下到上扫描来捕获它。@sijaanhallak:循环分支将取决于标志。查找指令n设置这些标志,是的,从循环分支向后操作到第一个标志设置指令。然后查看该指令使用的寄存器。