LD_PRELOAD interpolation and variadic functions
As part of my work on OpenMP debugging, I had to implement interpolation functions to capture the beginning and end of some library functions. In general, that's easy:
// library function we want to intercept: // int test(int a, int b); int test(int a, int b) { static fct_t real_test = dlsym(RTLD_NEXT, "test"); //before test real_test(a, b); //after test
}
I didn't test this code, but that should work. Now, what it the function you want to intercept looks like that:
void myprintf_real(const char *fmt, ...);
Portable Answer
you can't intercept it!
ASM Hardcore Answer
//tested and certainly only working on x86-64 void myprintf_asm_interpo(const char *fmt, ...) { //before myprintf // unroll the frame asm volatile("mov -0xb8(%rbp),%rdi\n\t" "mov -0xa8(%rbp),%rsi\n\t" "mov -0xa0(%rbp),%rdx\n\t" "mov -0x98(%rbp),%rcx\n\t" "mov -0x90(%rbp),%r8\n\t" "mov -0x88(%rbp),%r9\n\t" "add $0xc0,%rsp\n\t"); //jump to myprintf_real; volatile register void ** rsp asm ("rsp"); //movq $[addrs], -8(%%rsp) // I can't compile that ... *(rsp-1) = myprintf_real; asm volatile( "mov %rbp,%rsp\n\t" "pop %rbp\n\t" "mov (%rax), %rax\n\t" "jmpq *%rax"); }
I disassembled the function prolog with GDB, then reversed it and put it before jumping to myprintf_real. With that technique I can't insert code after the function execution (because it returns directly to the caller frame), but that was already a good start.
GCC-Specific Clean Answer
With __builtin_apply_args() and __builtin_apply()! Easy peasy! I prefer my code to be gcc-specific than architecture specific, especially with such a hardcoded blob of assembly!
int myprintf_gcc_interpo(char *fmt, ...) { // before void *arg = __builtin_apply_args(); void *ret = __builtin_apply((void*)printf, arg, 100); //after __builtin_return(ret); }
From stackoverflow with love ;-) Test it with this file.