これが私が発見した解決策の興味深いヒントです。
gcc(およびllvm> = 3.0)には、-pg
コンパイル時にオプションがあります。これは、従来、gprofをサポートするためのものです。このフラグを使用してコードをコンパイルすると、コンパイラはmcount
すべての関数定義の先頭に関数の呼び出しを追加します。この関数をオーバーライドすることはできますが、アセンブリで行う必要があります。そうしないと、mcount
定義した関数がへの呼び出しでインストルメント化され、呼び出されるmcount
前にスタックスペースがすぐに不足しますmain
。
これが概念実証です。
foo.c:
int total_calls = 0;
void foo(int c) {
if (c > 0)
foo(c-1);
}
int main() {
foo(4);
printf("%d\n", total_calls);
}
foo.s:
.globl mcount
mcount:
movl _total_calls(%rip), %eax
addl $1, %eax
movl %eax, _total_calls(%rip)
ret
でコンパイルしclang -pg foo.s foo.c -o foo
ます。結果:
$ ./foo
6
これは、の場合は1、のmain
場合は4、の場合はfoo
1ですprintf
。
これがclangが出力するasmですfoo
:
_foo:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl %edi, -8(%rbp) ## 4-byte Spill
callq mcount
movl -8(%rbp), %edi ## 4-byte Reload
...