public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* How to insert external global variable declarations and pointer assignment statements through GCC plugin GIMPLE pass
@ 2011-05-25  0:41 Abhijit Nandy
  2011-05-25  8:20 ` Ian Lance Taylor
  0 siblings, 1 reply; 10+ messages in thread
From: Abhijit Nandy @ 2011-05-25  0:41 UTC (permalink / raw)
  To: gcc

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 

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2011-06-14 20:03 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-25  0:41 How to insert external global variable declarations and pointer assignment statements through GCC plugin GIMPLE pass Abhijit Nandy
2011-05-25  8:20 ` Ian Lance Taylor
2011-05-31 12:47   ` Abhijit Nandy
2011-05-31 19:40     ` Ian Lance Taylor
2011-06-14 17:29       ` Abhijit Nandy
2011-06-14 17:39         ` Ian Lance Taylor
2011-06-14 18:36           ` Abhijit Nandy
2011-06-14 20:03             ` Ian Lance Taylor
2011-06-15  7:25               ` Abhijit Nandy
2011-06-15  9:14                 ` Ian Lance Taylor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).