汇编语言的自动代码重复数据删除? [英] Automatic code deduplication of assembly language?

查看:161
本文介绍了汇编语言的自动代码重复数据删除?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在浏览一些汇编编程视频,以更好地了解如何手动优化* .s使用gcc/g++ -S ...编译后剩下的文件重构冗余代码演示如何将冗余代码移至其自己的带标签块,并以通话.

视频中给出的示例是2个块,其中包含:

mov eax,power
mul ebx
mov power,eax
inc count

call CalculateNextPower替换的

和CalculateNextPower看起来像:

CalculateNextPower:
mov eax,power
mul ebx
mov power,eax
inc count
ret

出于好奇,尝试减小编译大小,我使用-S和各种优化程序(包括-Os,-O2,-O3,-pipe,-combine和-fwhole-program)编译了一些C和C ++项目,并分析了结果* .s文件使用 duplo 的补丁(适用于.s文件)来实现冗余.只有-fwhole-program (现在已不推荐使用的IIRC)对消除文件中的重复代码具有显著作用(我假设其替换-flto在链接时间内的行为类似-大致等同于使用-ffunction-sections -fdata-sections进行编译,并使用--gc-sections进行链接),但仍然会丢失相当大的代码块.

使用duplo输出进行手动优化时,仅对具有至少5个连续重复指令的连续汇编块进行重复数据删除,在随机C项目中,大小减小了10%,在随机C ++项目中,减小了近30%.

我是否缺少编译器选项(甚至是独立工具),该选项可以在编译大小为(包括其他编译器:clang,icc等)时自动消除冗余程序集.该功能不存在(有原因吗?)?

如果不存在,则可以修改 duplo 以忽略以'开头的行.或者 ';' (以及其他?),并使用对具有重复代码的函数的调用来替换重复的代码块,但是我对其他直接与编译器的内部表示(最好是clang或gcc)配合使用的建议持开放态度./p>

我修补了duplo以识别重复程序集的块此处,但是目前仍然需要手动重构.只要使用相同的编译器来生成代码,就有可能(但可能很慢)来识别最大的重复代码块,将它们放在自己的功能"块中,并用CALL将该代码替换为该块

解决方案

您想要的是一个克隆检测器工具.

这些存在于多种实现中,具体取决于要处理的文档元素的粒度以及可用的结构数量.

与原始行匹配的代码(对您不起作用,您想通过不同的常量(数据和索引偏移)和/或命名位置或其他命名子例程来对子例程进行参数化).基于令牌的检测器可能会起作用,因为它们将识别变化的单点位置(例如,常数或标识符).但是,您真正想要的是一个结构匹配器,它可以在块中间选择变体寻址模式甚至代码中的变体(请参阅我偶然构建的基于AST的克隆检测器).

要检测结构,必须具有结构.幸运的是,甚至汇编语言代码也具有语法形式的结构,并且代码块由子例程入口和出口定界(后者在汇编中更难检测,因为每个例程可能不止一个).

检测到使用结构时,至少有潜力使用该结构来修改代码.但是,如果您将程序源表示为一棵树,则您具有检测克隆的结构(子树和子树序列),并且可以通过在匹配点处修改树来抽象克隆匹配. (我的COBOL克隆检测器的早期版本将克隆抽象为COPY库.我们停止这样做的主要原因是,您不想以这种方式抽象每个克隆.)

I've been going through some Assembly Programming Videos to get a better understanding of how to manually optimize the *.s files left after compiling with gcc/g++ -S ... One of the topics covered was Refactoring Redundant Code that demonstrates how to move redundant code to its own labeled block ending with a ret and replacing it with a call.

The example given in the video is 2 blocks containing:

mov eax,power
mul ebx
mov power,eax
inc count

which it replaces with call CalculateNextPower and CalculateNextPower looks like:

CalculateNextPower:
mov eax,power
mul ebx
mov power,eax
inc count
ret

Out of curiosity, trying to reduce compiled size, I compiled some C and C++ projects with -S and various optimizations including -Os,-O2,-O3,-pipe,-combine and -fwhole-program and analyzed the resulting *.s files for redundancy using a lightly patched (for .s files) version of duplo. Only -fwhole-program (now deprecated IIRC) had a significant effect toward eliminating duplicate code across files (I assume its replacement(s) -flto would behave similarly during link time - roughly equivalent to compiling with -ffunction-sections -fdata-sections and linking with --gc-sections) but still misses significantly large blocks of code.

Manual optimization using the duplo output resulted in ~10% size reduction in a random C project and and almost 30% in a random C++ project when only contiguous blocks of assembly with at least 5 contiguous duplicate instructions were deduplicated.

Am I missing a compiler option (or even a standalone tool) that eliminates redundant assembly automatically when compiling for size (including other compilers: clang, icc, etc..) or is this functionality absent (for a reason?)?

If it doesn't exist, it could be possible to modify duplo to ignore lines starting with a '.' or ';' (and others?) and replace duplicate code blocks with calls to functions with the duplicate code, but I am open to other suggestions that would work directly with the compiler's internal representations (preferably clang or gcc).

Edit: I patched duplo to identify blocks of duplicate assembly here, but it still requires manual refactoring at the moment. As long as the same compiler is used to generate the code, it may be possible (but probably slow) to identify the largest blocks of duplicate code, put them in their own "function" block and replace the code with a CALL to that block.

解决方案

What you want is a clone detector tool.

These exist in a variety of implementations that vary depending on the granularity of elements of the document being processed, and how much structure is available.

Those that match raw line (won't work for you, you want to parameterize your subroutines by differing constants [both data and index offset] and or named locations or other named suboutines). The token based detectors might work, in that they will identify single-point places (e.g., constants or identifiers) that vary. But what you really want is a structural matcher, that can pick out variant addressing modes or even variants in code in the middle of the block (See AST based clone detectors, which I happen to build).

To detect with structure, you have to have structure. Fortunately, even assembly language code has structure in the form of a grammar, and blocks of code delimited by subroutine entries and exits (these latter are bit more problematic to detect in assembly, because there may be more than one of each).

When you detect using structures, you have at least the potential to use the structure to modify the code. But if you have the program source represented as a tree, you have structure (subtrees and sequences of subtrees) over which to detect clones, and one can abstract clone matches by modifying the trees at the match points. (Early versions of my clone detector for COBOL abstracted clones into COPY libs. We stopped doing that mostly because you don't want to abstract every clone that way).

这篇关于汇编语言的自动代码重复数据删除?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆