Hi,
I an writing a plugin to insert some function calls and extern variable
declarations into a C program.
If the original program is the following :
#include <stdio.h>
#include "molen_htx.h"
int main(void)
{
printf("hello from program\n");
return 0;
}
It has to be transformed to :
#include <stdio.h>
#include "molen_htx.h"
extern char _binary_ccu_start;
int main(void)
{
char *p = &_binary_ccu_start;
molen_elfset(p);
molen_reset();
printf("hello from program\n");
return 0;
}
------------------------------------------------------------------------------------------------------
I have got about half way through this using the following gcc plugin code :
------------------------------------------plugin.c-------------------------------------------------------------
//Global tree nodes
tree elfset_decl = NULL;
tree reset_decl = NULL;
//Check the attribute for a function and capture the AST tree node into a
global tree node
static tree handle_user_attribute(tree *node, tree name, tree args, int
flags, bool *no_add_attrs)
{
if(node == NULL || TREE_CODE(*node) != FUNCTION_DECL)
{
*no_add_attrs = true;
return NULL_TREE;
}
if(args != NULL)
{
if(!(TREE_CODE(TREE_VALUE(args)) == STRING_CST))
{
warning(0, "argument to user attribute should be a string");
*no_add_attrs = true;
return NULL_TREE;
}
const char *arg = TREE_STRING_POINTER(TREE_VALUE(args));
if(strcmp(arg, "elfset") == 0)
{
elfset_decl = *node;
}
else if(strcmp(arg, "reset") == 0)
{
reset_decl = *node;
}
}
return NULL_TREE;
}
//Insert the molen_elfset() call
void insert_elfset_call()
{
basic_block bb = ENTRY_BLOCK_PTR->next_bb;
gimple_stmt_iterator gsi = gsi_start_bb(bb);
//Simple assignment statement
tree lhs = create_tmp_var(TREE_TYPE(TREE_TYPE(elfset_decl)), "p");
tree rhs = create_tmp_var(TREE_TYPE(TREE_TYPE(elfset_decl)), "q");
gimple assign = gimple_build_assign_stat (lhs, rhs);
gsi_insert_before(&gsi, assign, GSI_SAME_STMT);
//Build a function call from the compiled molen_elfset() code first :
function has unique attribute which helps pick it using elfset_decl
gimple elfcall = gimple_build_call(elfset_decl, 1, temp);
gsi_insert_before(&gsi, elfcall, GSI_SAME_STMT);
cgraph_create_edge(cgraph_node(current_function_decl),
cgraph_node(elfset_decl), elfcall, bb->count,
compute_call_stmt_bb_frequency(current_function_decl, bb),
bb->loop_depth);
}
//Insert the molen_htx_init() call,
void insert_init_call()
{
basic_block bb = ENTRY_BLOCK_PTR->next_bb;
gimple_stmt_iterator gsi = gsi_start_bb(bb);
//Insert function call graph edge from current function to
molen_htx_init()
gimple call = gimple_build_call(init_decl, 0);
gsi_insert_before(&gsi, call, GSI_SAME_STMT);
/* Create edge from Function CALLER to CALLEE in the cgraph. See
http://opensource.apple.com/source/gcc/gcc-5572.10.2/gcc/cgraph.c*/
cgraph_create_edge(cgraph_node(current_function_decl),
cgraph_node(init_decl), call, bb->count,
compute_call_stmt_bb_frequency(current_function_decl, bb),
bb->loop_depth);
}
//Insert the molen_reset() call
void insert_reset_call()
{
basic_block bb = ENTRY_BLOCK_PTR->next_bb;
gimple_stmt_iterator gsi = gsi_start_bb(bb);
gimple resetcall = gimple_build_call(reset_decl, 0);
gsi_insert_before(&gsi, resetcall, GSI_SAME_STMT);
cgraph_create_edge(cgraph_node(current_function_decl),
cgraph_node(reset_decl), resetcall, bb->count,
compute_call_stmt_bb_frequency(current_function_decl, bb),
bb->loop_depth);
}
//The pass function called by GCC to add / remove compiled code using gimple
static unsigned int replace_func(void)
{
if(is_replace_function(current_function_decl))
{
if(!have_molen_functions())
return 1;
replace_function_body();
}
else if(MAIN_NAME_P(DECL_NAME(current_function_decl)))
{
if(!have_molen_functions())
return 1;
insert_reset_call(); //Call in reverse order of the actual
statment order : as inserts happen before 1st stmnt in the functions
insert_elfset_call();
insert_init_call();
}
return 0;
}
//Pass information structure
static struct gimple_opt_pass pass_replace =
{
{
GIMPLE_PASS,
"replace",
NULL,
replace_func,
NULL,
NULL,
0,
0,
PROP_gimple_any | PROP_cfg,
0,
0,
0,
TODO_remove_unused_locals|TODO_cleanup_cfg|TODO_dump_func
}
};
//Called automatically to initialize the pass
int plugin_init (struct plugin_name_args *plugin_info, struct
plugin_gcc_version *version)
{
const char *plugin_name = plugin_info->base_name;
struct register_pass_info replace_pass_info;
replace_pass_info.pass = &pass_replace.pass;
replace_pass_info.reference_pass_name = "inline_param";
replace_pass_info.ref_pass_instance_number = 1;
replace_pass_info.pos_op = PASS_POS_INSERT_AFTER;
register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
&replace_pass_info);
register_callback (plugin_name, PLUGIN_ATTRIBUTES, register_attributes,
NULL);
printf("plugin init %s\n", plugin_name);
return 0;
}
-------------------------------------------------------------------------------------------------------------------------
The functions are declared in a header file included in plugin.c using
attributes such as :
__attribute__((user("elfset")))
char* molen_elfset(char* start);
__attribute__((user("reset")))
void molen_reset(void);
So I basically use the attributes to find the proper function node and
insert them in the beginning of main()
My output is as follows :
;; Function main (main)
main ()
{
char * p.1;
char * p.0;
<bb 2>:
molen_htx_init ();
p.0 = p.1;
molen_elfset (p.0);
molen_reset ();
return 0;
}
This is ok but I am unable to figure out how to insert a statement like the
following in global scope:
extern char _binary_ccu_start;
or to make an assigment like the following inside main :
char *p = &_binary_ccu_start;
Is this possible to do using a plugin ?
Abhi