Template:GNU C Compiler Internals/GEM Framework

Hooks
GEM framework is designed to facilitate development of compiler extensions. The idea of GEM is similar to the idea of Linux Security Modules (LSM), a project that defines hooks throughout Linux kernel that allow one to enforce a security policy.

GEM defines a number of hooks throughout GCC's source code. It is implemented as a patch to GCC. With GEM, a compiler extension is developed as a stand-alone program. It is compiled into a dynamically-linked module which is specified as the command line argument when GCC is invoked. GCC loads the module and calls its initialization function. The module then registers its hooks that are call-back functions in GCC.

In addition to the compiler hooks, GEM provides macros and functions that simplify extension development. In this chapter we will first introduce the hooks that GEM framework adds to GCC. Then we describe the typical issues in extension programming.

The project home page is at http://research.alexeysmirnov.name/gem

GEM adds several hooks throughout GCC source code. New hooks are added to GEM as necessary.


 * Hook gem_handle_option to function handle_option which processes each command line option. The hook takes the current option as its argument. If the hook returns value GEM_RETURN then GCC ignores the option.


 * Hook gem_c_common_nodes_and_builtins which is called after all standard types are created. The GCC extension can create additional types.


 * Hook gem_macro_name allows one to save the name of the macro being defined. Another GEM hook gem_macro_def is called when the macro definition is parsed. Using the macro name of the new macro definition it is possible to re-define the macro. This hook is added to function create_iso_definition.


 * Hooks gem_start_decl and gem_start_function are called when a function or variable declaration/definition starts.


 * Hook gem_build_function_call allows one to modify the name and the arguments of a function call.


 * Hook gem_finish_function is inserted to finish_function which is called from from grammar file. The compiler extension receives the function body of the function before it is translated into RTL.


 * Hooks gem_output_asm_insn and gem_final_start_function are added to function output_asm_insn which is called for each instruction of the assembly code and function final_start_function called when the assembly code is written to the file, respectively. The former hook receives the text that is written to the file which allows it to modify the output. The latter hook can modify function's prolog.

Traversing an AST
When the function's AST is constructed one can instrument it. GEM's gem_finish_function hook receives the AST of a function. The idea is to traverse the AST and instrument the AST nodes as necessary. Function walk_tree takes the AST, the callback function, the optional data, NULL by default, and the walk_subtrees parameter, NULL by default. The callback function is called for each node of the AST before the operands are traversed. If the callback function modifies the walk_subtree variable then the operands are not processed.

The following code demonstrates the idea:

static tree walk_tree_callback(tree *tp, int *walk_subtrees, void *data) { tree t=*tp; enum tree_code code = TREE_CODE(t); switch (code) { case CALL_EXPR: instrument_call_expr(t); break; case MODIFY_EXPR: instrument_modify_expr(t); break; }  }   walk_tree(&t_body, walk_tree_callback, NULL, NULL);

Instrumenting an AST
In this section we describe functions that create new tree nodes and how to add the new nodes to an AST.

When to Instrument
In this section we will describe when each of GEM hooks is used.

Function Prolog/Epilog
The assembly instructions are written to the assembly file:

#define OUTPUT_ASM_INST(inst) \ p=inst;                    \ putc('\t', asm_out_file);  \ while (*p++) putc(p, asm_out_file); \ putc('\n', asm_out_file); OUTPUT_ASM_INST("pushl %%eax"); OUTPUT_ASM_INST("popl %%eax");