我开发了一个GCC插件,用于检测正在编译的应用程序。这些应用程序是用C语言编写的,在x86 Linux系统上使用GCC 4.7(也可以选择4.8和4.9)构建。
我的插件实现了一个编译传递,它被放置在"ssa"标准传递之后,并对GIMPLE表示进行操作。除其他事项外,我需要实现以下内容,但目前不知道如何正确执行
当处理一个C函数时,我需要在它的开头插入代码,将它的参数复制到我创建的局部变量中,以便将来处理。
我的第一个朴素实现是这样的:
tree p;
gimple_seq seq = NULL;
gimple_stmt_iterator gsi = gsi_start_bb(single_succ(ENTRY_BLOCK_PTR));
for (p = DECL_ARGUMENTS(current_function_decl); p; p = DECL_CHAIN(param)) {
tree copy_par;
copy_par = create_tmp_var(TREE_TYPE(p), NULL);
add_referenced_var(copy_par);
copy_par = make_ssa_name(copy_par, NULL);
g = gimple_build_assign(copy_par, p);
SSA_NAME_DEF_STMT(copy_par) = g;
gimple_seq_add_stmt_without_update (&seq, g);
... // more processing here
}
...
gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT);
但是,通过这种方式,将根据转储创建参数声明对变量的无效赋值:
<>之前gimple_assign <parm_decl,>之前 D.2206_11
对应于我创建的局部变量par
——我要复制的函数的参数。
GCC在尝试处理这条添加的语句时,会在稍后的某个阶段崩溃。我想这是因为p
不是保存各自参数值的变量,而是该变量的声明。是这边吗?怎么得到这个变量呢?
我尝试使用gimple_build_assign_with_ops(NOP_EXPR, copy_par, p, NULL_TREE)
而不是gimple_build_assign()
,但它也没有做到。GCC仍然会在同一个地方崩溃。我可以提供回溯,但我觉得我只是错过了一些基本的东西。
我还研究了从TYPE_ARG_TYPES (TREE_TYPE (current_function_decl))
开始的树遍历,并进一步通过TREE_CHAIN(...)
,但这似乎给出了参数的类型,而不是各自的变量。
那么,问题是,如何正确地添加函数参数的复制。
注意也许,这可以在MELT或GCC Python插件的帮助下完成,但在这个项目中,我需要只使用GCC本身提供的代码来执行代码的所有转换。
我发现复制参数在GCC 4.8和4.9中可以工作,但在4.7中不行。下面是我现在使用的代码(instrument_fentry()
执行复制)。
为了避免副本在以后的编译过程中被删除,我将相应的变量设置为volatile。
此外,如果没有为给定参数指定带有默认定义语句的SSA_NAME(参见SSA_NAME_IS_DEFAULT_DEF()
),则添加带有GIMPLE_NOPs的SSA_NAME作为定义语句。
到目前为止,这在GCC 4.8和4.9上工作得很好,所以它看起来像是GCC 4.7中的一个bug,或者是GCC 4.7和4.8之间的一些规则更改。但是,我无法确定具体的提交。