valgrind コマンドを叩くと普通に main が動きます。 main は coregrind/launcher-linux.c にあります。ごちゃごちゃと環境を調べたり tool を調べたりした後、情報を残すために環境変数をいじったりした後、即 tool を execve して終了します。
で、 tool なんですが… tool の実体は memcheck-
> ldd rmemcheck-amd64-linux not a dynamic executable
static link されてます。
> nm rmemcheck-amd64-linux | grep -r ' printf$' >
僕らの printf がありません。ていうか実のところ、 glibc をリンクしてません。さらに、
> nm rmemcheck-amd64-linux | grep -r ' main$' >
main もどこにもありません。 gcc にヘンなオプションを渡すことによって crt1.o をリンクしないようにしてあります。事情があって、全ては guest のためです…
ただ、 memcpy と memset は定義されてたりします。
> nm rmemcheck-amd64-linux | grep -r ' memcpy$' 0000000038023180 T memcpy > nm rmemcheck-amd64-linux | grep -r ' memset$' 000000003801f7b0 T memset
これは gcc が構造体をほげほげする時にこの二つの関数を呼ぶコードを埋めちゃうことがあるからだそうです。てか GCC そんなことするのかよ。ちなみに、これらの関数は自力で実装してます。
まぁとにかく、こんなバイナリですので、 _start から定義されてます。ソースコードで言うと coregrind/m_main.c です。 _start はアセンブリですけど、特にヘンなことはせずに _start_in_C_linux を呼びます。その先でも argc とか argv を作ったら、割とすぐに valgrind_main を呼びます。これで普通の世界です。 libc は無いですが!
でまぁ libc がどうなってるかってういと、まぁ実のところ、必要なものは自前で実装してます。 coregrind/pub_core_libc*.h や coregrind/m_libc*.c を参照。ミニマル実装な libc の一つとしてこれ使えるんじゃないかなぁとかいう程度にはそろってます。ただ呼ぶ時に VG_(printf)("Hello, world!") などと、 VG_() でシンボル名をかこう必要があることに注意です。
valgrind_main に続く(気がする)