This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

How to insert external global variable declarations and pointer assignment statements through GCC plugin GIMPLE pass


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]