tec*_*rus 7 size assembly code-duplication compiler-optimization
我一直在阅读一些汇编编程视频,以便更好地理解如何手动优化编译后留下的*.s文件.gcc/g++ -S ... 其中一个主题是重构冗余代码,演示如何将冗余代码移动到自己的标记块以ret结束并用呼叫替换它.
视频中给出的示例是2个块,包含:
mov eax,power
mul ebx
mov power,eax
inc count
Run Code Online (Sandbox Code Playgroud)
它取而代之的是call CalculateNextPower和CalculateNextPower看起来像:
CalculateNextPower:
mov eax,power
mul ebx
mov power,eax
inc count
ret
Run Code Online (Sandbox Code Playgroud)
出于好奇,试图减少编译大小,我用-S和各种优化编译了一些C和C++项目,包括-Os,-O2,-O3,-pipe,-combine和-fwhole-program,并分析了结果*.s使用轻微修补(for .s文件)版本的duplo进行冗余的文件.只有-fwhole-program (现已弃用的IIRC)对消除文件中的重复代码有显着影响(我认为它的替换(-s)-flto在链接时会表现相似 - 大致相当于用-ffunction-sections -fdata-sections编译和--gc-sections链接)但仍然错过了大量的代码块.
使用duplo输出的手动优化导致随机C项目的大小减少约10%,并且当仅具有至少5个连续重复指令的连续块组件被重复数据删除时,随机C++项目中几乎减少30%.
我是否遗漏了一个编译器选项(甚至是一个独立的工具),在编译大小时会自动消除冗余程序集(包括其他编译器:clang,icc等等) 或者是否缺少此功能(原因?)?
如果它不存在,则可以修改duplo以忽略以'.'开头的行.要么 ';' (以及其他人?)并使用重复代码调用函数替换重复的代码块,但我对其他可直接使用编译器内部表示(最好是clang或gcc)的建议持开放态度.
编辑:我修补杜普洛识别重复组装块在这里,但它仍然需要在此刻手动重构.只要使用相同的编译器生成代码,就可以(但可能很慢)识别最大的重复代码块,将它们放在自己的"函数"块中,并用CALL替换代码到该块.
您想要的是一个克隆检测工具。
这些存在于各种实现中,这些实现根据正在处理的文档元素的粒度以及可用的结构而变化。
那些匹配原始行的(对你不起作用,你想通过不同的常量[数据和索引偏移]和/或命名位置或其他命名子例程来参数化你的子例程)。基于令牌的检测器可能会起作用,因为它们将识别变化的单点位置(例如,常量或标识符)。但你真正想要的是一个结构匹配器,它可以挑选出变体寻址模式,甚至是块中间代码中的变体(请参阅我碰巧构建的基于 AST 的克隆检测器)。
为了用结构来检测,你必须有结构。幸运的是,即使是汇编语言代码也具有语法形式的结构,以及由子例程入口和出口分隔的代码块(后者在汇编中检测起来有点问题,因为每种代码可能不止一个)。
当您检测到使用结构时,您至少有可能使用该结构来修改代码。但是,如果您将程序源表示为一棵树,那么您就有了用于检测克隆的结构(子树和子树序列),并且可以通过修改匹配点处的树来抽象克隆匹配。(我的 COBOL 克隆检测器的早期版本将克隆抽象为 COPY 库。我们停止这样做主要是因为您不想以这种方式抽象每个克隆)。
| 归档时间: |
|
| 查看次数: |
560 次 |
| 最近记录: |