I am writing a toy malloc(3) implementation, loaded with LD_PRELOAD
, as an exercise. I have a function annotated with __attribute__((destructor))
to dump a list of allocations and their status on exit for debugging purposes but I found it doesn't run in some cases. Specifically, it does run on locally-compiled code but not against system binaries like /bin/ls
(on Arch Linux). A constructor
-tagged function does work for both cases, though.
A simple repro of the problem is:
main.c
:
#include <stdio.h>
// compile with: clang -o main main.c
int main() {
printf("main\n");
}
wrap.c
:
#include <stdio.h>
// compile with: clang -o wrap -shared -fPIC wrap.c
void __attribute__((constructor)) say_hi() {
printf("hi y'all\n");
}
void __attribute__((destructor)) say_bye() {
printf("bye y'all\n");
}
Destructor runs with main.c
:
$ LD_PRELOAD=./wrap ./main
hi y'all
main
bye y'all
Destructor doesn't run with /bin/ls
:
$ LD_PRELOAD=./wrap /bin/ls
hi y'all
main main.c wrap wrap.c
I can't work out how to debug this. LD_DEBUG=all
doesn't show anything useful. ldd main
and ldd /bin/ls
look comparable. Both binaries are dynamically linked. The GCC docs don't list any caveats I should be aware of, as far as I can see.