http://www.atdot.net/~ko1/diary/200807.html#d17
こういうのはえーと GEM とかあったような(無論名前とか覚えてなかったけど)…ということで遊んでみました。 GEM って何かっていうと、まぁ GCC のそこらこちらに適当にフックがかけられるようになってるとかいう感じかと思います。
http://www.ecsl.cs.sunysb.edu/gem/
ビルド
% tar -xvzf ~/arch/gem-1.7.tar.gz % cd src/gem-1.7 % tar -xvjf ~/arch/gcc-core-4.1.0.tar.bz2 # % mkdir gcc-4.1.0/bin # % cd gcc-4.1.0 # % patch -p2 < ../patch/gem-4.1.0.patch # % cd .. # % vi Makefile # GCC_RELEASE=4.1.0 % make
途中 # が並んでる 5行は省略可。省略すると勝手にダウンロードとかしてくれる。
適当に代入文を hook するコードを書く。
assign_hook.c:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include "config.h" #include "system.h" #include "coretypes.h" #include "tree.h" #include "c-tree.h" #include "gem.h" static tree get_fndecl(char* name) { tree fndecl; fndecl=get_identifier(name); if (fndecl!=NULL_TREE) { fndecl=lookup_name(fndecl); } if (fndecl==NULL_TREE) { printf("unable to find %s\n", name); abort(); } return fndecl; } void assign_hook(tree* t) { if (TREE_CODE(*t) != MODIFY_EXPR) { return; } puts("assign_hook"); //dump_node(*t, 0, stdout); tree type = TREE_TYPE(*t); tree lhs = TREE_OPERAND(*t, 0); tree rhs = TREE_OPERAND(*t, 1); // We only hook integral type assignments. if (!INTEGRAL_TYPE_P(TREE_TYPE(lhs)) || !INTEGRAL_TYPE_P(TREE_TYPE(lhs))) { return; } // Ignore artificial assignments. if (!DECL_NAME(lhs)) { return; } tree arglist = build_tree_list(NULL_TREE, rhs); *t = build2(MODIFY_EXPR, type, lhs, build_function_call_expr(get_fndecl("assign_hook"), arglist)); } void gem_init() { puts("gem_init"); gem_expand_expr_pre = assign_hook; } void gem_destroy() { puts("gem_destroy"); }
MODIFY_EXPR とかいうのが代入文とからしいので、それを見かけたら
- 両辺が int 型で
- 左辺に名前があれば (この条件ないと return 文とかも MODIFY_EXPR になるみたいだったので)
- lhs = assign_hook(rhs); の形に
ってようなことをやってます。ちなみにこれで完全にフックできてるかとか、余計なものフックしないかとかは全く調べてないので、よく知らない。
で assign_hook 関数を定義しておく。
assign_hook_lib.c:
#include <stdio.h> int assign_hook(int i) { printf("assignment hooked!: %d\n", i); return i; }
あとテスト用のコード。
assign_hook_test.c:
#include <stdio.h> int assign_hook(int i); int main() { int i = 0; int s = 0; for (i = 0; i < 5; i++) { s += i; } printf("%d\n", s); return s; }
このファイル群を gem-1.7/examples とかに放り込んでやって、 Makefile に
assign_hook_obj = assign_hook.o assign_hook: $(assign_hook_obj) gcc -shared -Wl,-soname,test.so -o $(bindir)/assign_hook.gem $(assign_hook_obj) $(LDFLAGS) assign_hook_test: assign_hook_test.c assign_hook_lib.c assign_hook $(GCC_BASE)/bin/bin/gcc assign_hook_lib.c -c -o assign_hook_lib.o $(GCC_BASE)/bin/bin/gcc -fextension-module=$(bindir)/assign_hook.gem assign_hook_test.c -c -o assign_hook_test.o $(GCC_BASE)/bin/bin/gcc assign_hook_test.o assign_hook_lib.o -o $@
とか書いてやれば、
> make assign_hook_test gcc -shared -Wl,-soname,test.so -o ../gcc-4.1.0/bin/bin/assign_hook.gem assign_hook.o -ldl -lc ../gcc-4.1.0/bin/bin/gcc assign_hook_lib.c -c -o assign_hook_lib.o ../gcc-4.1.0/bin/bin/gcc -fextension-module=../gcc-4.1.0/bin/bin/assign_hook.gem assign_hook_test.c -c -o assign_hook_test.o gem_init assign_hook assign_hook assign_hook assign_hook assign_hook assign_hook gem_destroy ../gcc-4.1.0/bin/bin/gcc assign_hook_test.o assign_hook_lib.o -o assign_hook_test > ./assign_hook_test assignment hooked!: 0 assignment hooked!: 0 assignment hooked!: 0 assignment hooked!: 0 assignment hooked!: 1 assignment hooked!: 1 assignment hooked!: 2 assignment hooked!: 3 assignment hooked!: 3 assignment hooked!: 6 assignment hooked!: 4 assignment hooked!: 10 assignment hooked!: 5 10
なんかフックできてますね。おしまい。