2

我开发了一个 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,NULL>

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))via 开始并进一步遍历树,TREE_CHAIN(...)但这似乎给出了参数的类型而不是相应的变量。

所以,问题是,如何正确添加函数参数的复制。

注意 也许,这可以在 MELT 或 GCC Python 插件的帮助下完成,但在这个项目中,我需要仅使用 GCC 本身提供的代码来执行所有代码转换。

4

1 回答 1

2

我发现参数的复制适用于 GCC 4.8 和 4.9,但不适用于 4.7。这是现在对我有用的代码(instrument_fentry()执行复制)。

为了避免在后面的编译过程中删除副本,我将相应的变量设置为 volatile。

此外,如果没有为给定参数指定默认定义语句的 SSA_NAME(请参阅SSA_NAME_IS_DEFAULT_DEF()参考资料),我添加了带有 GIMPLE_NOP 的此类 SSA_NAME 作为定义语句。

到目前为止,这在 GCC 4.8 和 4.9 上运行良好,所以它看起来像是 GCC 4.7 中的一个错误或 GCC 4.7 和 4.8 之间的一些规则更改。我无法确定确切的提交。

于 2014-09-22T19:54:35.657 回答