steffen
steffen

Reputation: 8958

__attribute__((weak)) and LD_PRELOAD

I want a code to be able to run an application with a certain self-written library and without it. So I use the __attribute__ ((weak)) and preload the library if needed. I need to be able to do that without recompiling. Everything works fine if I link the library statically, though.

Furthermore the library is written in C++ while the applications using it can be C++ or C.

I boils down to this:

library header test_lib.h:

#ifdef __cplusplus
extern "C"
#endif
void test_func() __attribute__ ((weak));    

library implementation test_lib.cpp:

#include "test_lib.h"
#include <iostream>
extern "C"
void test_func()
{
    std::cout << "in test_func\n";
}

the C test test_main.c:

#include <stdio.h>
#include "test_lib.h"

int main(void)
{
    if (test_func){ printf("+\n"); }
    else{ printf("-\n"); }
    return 0;
}

the C++ test test_main_cpp.cpp:

#include <iostream>
#include "test_lib.h"

int main(void)
{
    if (test_func){ std::cout << "+\n"; }
    else{ std::cout << "-\n"; }
    return 0;
}

the compile and run script for your convenience:

#!/bin/bash

g++ -shared -fPIC test_lib.cpp -o libtest.so

gcc test_main.c -o test_c
g++ test_main_cpp.cpp -o test_cpp

# output should be "-"
./test_c
./test_cpp

# output should be "+"
LD_PRELOAD=libtest.so ./test_c
LD_PRELOAD=libtest.so ./test_cpp

The expected output is:

-
-
+
+

What I get is:

-
-
-
-

and finally a little extra information:

$ uname -a
Linux bermuda-iii 3.8.6-1-ARCH #1 SMP PREEMPT Sat Apr 6 07:27:01 CEST 2013 x86_64 GNU/Linux
$ gcc --version
gcc (GCC) 4.8.0
$ nm libtest.so | grep -i func
0000000000000858 W test_func
$ nm test_c | grep -i func
             w test_func
$ nm test_cpp | grep -i func
             w test_func

So: (de)mangling seems to work fine, the symbol test_func is known to the executables. But the `LD_PRELOAD´ doesn't seem to work.

What am I missing?

Upvotes: 2

Views: 2080

Answers (1)

Anya Shenanigans
Anya Shenanigans

Reputation: 94654

The trick is to make sure that the application is compiled as position independent code as well, otherwise the symbol can't be replaced at run-time:

Where you link the executables, you need to do:

gcc -fPIC test_main.c -o test_c

or

g++ test_main_cpp.cpp -o test_cpp

e.g.

$ gcc test_main.c -o test_c -fPIC
$ ./test_c
-
$ LD_PRELOAD=`pwd`/libtest_lib.so ./test_c
+

By compiling the main executable as position independent code, it allows the weak symbol to be replaced at run-time by the overriding library.

Upvotes: 2

Related Questions