[英]GCC preprocessor PLUS static analysis?
我知道如何运行gcc预处理程序 。 Gcc显然会执行代码的静态分析/优化,因为如果您添加两个常量或移位常量,则无论您保持“ a = constant << 3”还是手动执行该操作,生成的汇编代码都是相同的并在代码中包含“ a = shifted_constant”。
给定SHA256代码中的切片,
A=0x6a09e667;
B=0xbb67ae85;
C=0x3c6ef372;
D=0xa54ff53a;
E=0x510e527f;
F=0x9b05688c;
G=0x1f83d9ab;
H=0x5be0cd19;
P(A, B, C, D, E, F, G, H, W[ 0], 0x428a2f98);
运行gcc -EI后
{ tmp = ((((E) >> (6)) | ((E) << (32-(6)))) ^ (((E) >> (11))
| ((E) << (32-(11)))) ^ (((E) >> (25)) | ((E) << (32-(25)))))
+ (G ^ (E & (F ^ G))) + 0x428a2f98 + W[ 0]; D += (tmp + H);
H += tmp + ((((A) >> (2)) | ((A) << (32-(2)))) ^ (((A) >> (13))
| ((A) << (32-(13)))) ^ (((A) >> (22)) | ((A) << (32-(22)))))
+ ((A & B) | (C & (A | B))); };
对于P线,它是宏的嵌套宏。
很好,但是我想得到一个更摘要的结果,其中替换了常量,执行了常量算术等。因此,如果我得到的不是上述内容,则为:
{ tmp = hex_constant1 + W[0]; D += (tmp + 0x5be0cd19); H += tmp + hex_constant2; };
我更喜欢。 我没有耐心手动计算表达式,但是基本上它们应该折叠为两个十六进制常量。
是否有任何工具/命令行选项可以执行此操作?
GCC不会优化预处理的C代码。 经过预处理后,此代码会转换为高级IR(GIMPLE),在大多数情况下都会应用该优化,然后再降低为像RTL这样的低级IR。
您想要的是经过优化的GIMPLE转储以将其查找为常数。 您应该像这样使用优化的树转储:
gcc -O2 -fdump-tree-optimized test.c -S
然后查找类似test.c.211t.optimized的文件(数字211可能有所不同,具体取决于gcc版本)。 Gimple代码与原始C非常相似,因此您可以从中读取常量没有问题。
大多数编译器运行预处理器以获取程序源的文本字符串,然后将其解析为编译器内部数据结构。 解析完程序后,您将看不到编译器对代码的处理方式(嗯,也许编译器具有某种调试转储,但您不能指望它)。
若要执行所需的操作,您需要在扩展的宏位置对代码进行部分评估 。 没有标准的编译器可以帮助您做到这一点。
您需要一个程序转换系统(PTS) ,该程序可以解析源代码,应用代码转换,然后重新生成修改后的源文本。 一个好的PTS将使您编写要应用的源到源转换规则集,每个规则的形式为:
when you see *this*, then replace it by *that* if *condition* is true
要进行简单的常量折叠,您需要以下规则:
rule simplify_times_zero(e: power): product -> product
" \e * 0 " -> " \e ";
处理特殊乘数乘以零的特殊(代数)情况。 您显然需要一堆这些规则,更多内容请参见下文。
您的PTS还必须能够读取您正在使用的C或C ++的特定方言,并且能够将任何标识符解析为其定义(否则,您将无法知道E在使用时是常数)。
据我所知,唯一可以解析许多C或C ++方言并进行宏扩展的PTS是我们的DMS软件再造工具包 。 它使用上面示例的语法接受规则。
您需要的其他规则是实际进行算术运算的规则:
rule fold_addition(c1: INT32CONSTANT, c2: INT32CONSTANT): product -> product =
" \c1 + \c2 " -> int32_multiply(c1,c2);
其中int32_multiply是执行数学运算的函数。 对于每个运算符和操作数类型,您都需要使用其中之一,以遵守C和C ++语言的规则。
您还需要执行替换已知值的规则:
rule substitute_defined_constant(i: IDENTIFIER): primitive -> primitive
" \i " -> macro_definition_value(i) if is_defined_constant(i);
is_defined_constant在DMS前端为宏定义而建立的符号表中查找和标识符,并在引用i的地方检查i是否为“ define i”形式的宏。 通过将其写为条件,除非宏定义值实际存在,否则不会调用macro_definition_value函数。 DMS的C和C ++前端提供了原始符号表支持。
有了这套规则,以及将这些规则应用于感兴趣的宏扩展点的规则策略,DMS应该能够将方程式“折叠”为您表示的形式。 现在,所有转换都在DMS的程序内部表示上完成,但是DMS可以漂亮地打印结果,以便您可以实际看到它。
作为开发UI中的常规功能,这可能非常有用。 实际设置所有这些并使其付诸实践可能需要几天的时间。 DMS是一个复杂的系统,而C和C ++则无济于事。
如果您只打算执行一次或两次,那么最好只是咬一下子弹,然后手工完成(或者如其他答案所示,如果可以,请使用调试检查编译器的输出)。 如果这是日常任务,则PTS解决方案可能会节省大量时间(和准确性)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.