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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux