I'm trying to use LD_PRELOAD.
original.cpp
void myPuts() {
puts ("Hello myPuts");
}
int main() {
myPuts();
return 0;
}
hacked.cpp
void myPuts() {
std::cout >> "Hello hacked myPuts";
}
I compile original.cpp:
g++ original.cpp
And hacked.cpp:
g++ -shared -fPIC hacked.cpp
I try:
LD_PRELOAD=./hacked.so ./original.out
The string "Hello hacked myPuts" should be seen, by "Hello myPuts" appears.
(If I try to "overwrite" the puts function, it works correctly)
What am I missing?
From man ld.so
LD_PRELOAD
A whitespace-separated list of additional, user-specified, ELF shared libraries to be loaded before all others. This can be used to selectively override functions in other shared libraries.
If myPuts was in shared library linked to main application it would work, but not when
myPuts exists in the application and does not resolved in an external library.
You should have:
main.cpp
int main() {
myPuts();
return 0;
}
original.cpp
void myPuts() {
puts ("Hello myPuts");
}
hacked.cpp
void myPuts() {
std::cout << "Hello hacked myPuts";
}
Compiling all:
g++ -shared -fPIC original.cpp -o liboriginal.so
g++ -shared -fPIC hacked.cpp -o libhacked.so
g++ main.cpp -loriginal -o main.out
And using:
LD_PRELOAD=./libhacked.so ./main.out
Related
I want to have the functions which are defined in another .cpp file become available in another simulation tool.
I found the following code in this question: -finstrument-functions doesn't work with dynamically loaded g++ shared objects (.so)
Trace.cpp
#include <stdio.h>
#ifdef __cplusplus
extern "C"
{
void __cyg_profile_func_enter(void *this_fn, void *call_site)
__attribute__((no_instrument_function));
void __cyg_profile_func_exit(void *this_fn, void *call_site)
__attribute__((no_instrument_function));
}
#endif
void __cyg_profile_func_enter(void* this_fn, void* call_site)
{
printf("entering %p\n", (int*)this_fn);
}
void __cyg_profile_func_exit(void* this_fn, void* call_site)
{
printf("exiting %p\n", (int*)this_fn);
}
Trace.cpp is compiled by doing:
g++ -g -finstrument-functions -Wall -Wl,-soname,libMyLib.so.0 -shared -fPIC -rdynamic MyLib.cpp MyLibStub.cpp Trace.cpp -o libMyLib.so.0.0
ln -s libMyLib.so.0.0 libMyLib.so.0
ln -s libMyLib.so.0.0 libMyLib.so
g++ MainStatic.cpp -g -Wall -lMyLib -L./ -o MainStatic
g++ MainDynamic.cpp -g -Wall -ldl -o MainDynamic
Note that I don't need: MyLib.cpp and MyLibStub.cpp.
Instead compiled Trace.cpp doing:
g++ -g -finstrument-functions -Wall -Wl,-soname,libMyLib.so.0 -shared -fPIC -rdynamic Trace.cpp -o libMyLib.so.0.0
What I've tried:
The shared object where I want to have Trace.cpp is obtained by:
opp_makemake -f --deep --no-deep-includes --make-so -I . -o veins -O out -I../../inet/src/util/headerserializers/sctp/headers -L../../inet/src -linet
I added -L and -l:
opp_makemake -f --deep --no-deep-includes --make-so -I . -o veins -L /home/user/Desktop/test/ -lMyLib -O out -I../../inet/src/util/headerserializers/sctp/headers -L../../inet/src -linet
and got:
/usr/bin/ld: cannot find -lMyLib
I also tried:
opp_makemake -f --deep --no-deep-includes --make-so -I . -o veins /home/user/Desktop/test/libMyLib.so.0.0 -O out -I../../inet/src/util/headerserializers/sctp/headers -L../../inet/src -linet
which compiled successfully but the application crashed:
Error during startup: Cannot load library
'../../src//libveins.so': libMyLib.so.0: cannot open shared object
file: No such file or directory.
Question:
How to compile Trace.cpp correctly?
How to link it with the rest of the shared library?
As you might notice I am not very experienced with compiling, linking and similar. So, any extra explanation is very welcome!
As #Flexo restates what #EmployedRussian said in the linked question, the main point is to get your implementation of __cyg_profile_func_*** before the one provided by libc.so.6.
One method to do this, is to use the LD_PRELOAD environment variable. Here you can read what LD_PRELOAD does and how it works.
To use the LD_PRELOAD trick you will need to compile your implementation of the above-mentioned functions as a shared library.
You can do this by doing:
g++ -shared -fPIC myImp.cc -o myImp.so -ldl
Once you get the .so file, navigate to the directory where your executable is located and do:
LD_PRELOAD=<path/to/myImp.so>- ./<myExecutable>
For shared libraries, dynamic linking is used. Meaning:
resolving of some undefined symbols (is postponed) until a program is run.
By using LD_PRELOAD you resolve the symbols of your interest before letting the linked do that.
Here you have an implementation of myImp.cc, which I took from: https://groups.google.com/forum/#!topic/gnu.gcc.help/a-hvguqe10I
The current version lacks proper implementation for __cyg_profile_func_exit, and I have not been able to demangle the function names.
#ifdef __cplusplus
extern "C"
{
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
void __cyg_profile_func_enter(void *this_fn, void *call_site)__attribute__((no_instrument_function));
void __cyg_profile_func_exit(void *this_fn, void *call_site)__attribute__((no_instrument_function));
}
#endif
static FILE *fp;
int call_level=0;
void * last_fn;
void __cyg_profile_func_enter(void *this_fn, void *call_site)
{
Dl_info di;
if (fp == NULL) fp = fopen( "trace.txt", "w" );
if (fp == NULL) exit(-1);
if ( this_fn!=last_fn) ++call_level;
for (int i=0;i<=call_level;i++)
{
fprintf(fp,"\t");
}
//fprintf(fp, "entering %p\n", (int *)this_fn);
fprintf(fp, "entering %p", (int *)this_fn);
if (dladdr(this_fn, &di)) {
fprintf(fp, " %s (%s)", di.dli_sname ? di.dli_sname : "<unknown>", di.dli_fname);
}
fputs("\n", fp);
(void)call_site;
last_fn = this_fn;
}
void __cyg_profile_func_exit(void *this_fn, void *call_site)
{
--call_level;
for (int i=0;i<=call_level;i++) fprintf(fp,"\t");
fprintf(fp, "exiting %p\n", (int *)this_fn);
(void)call_site;
}
Another option for function tracing which uses LD_PRELOAD is used by LTTng, in the section Function Tracing, but I have never used it...
Consider the following setup consisting of two shared libraries which both use a static library:
static.cpp
#include "static.h"
static int a = 0;
int getA()
{
return a++;
}
static.h
#pragma once
int getA();
shareda.cpp
#include <iostream>
#include "shareda.h"
#include "static.h"
void printA()
{
std::cout << getA() << std::endl;
}
shareda.h
#pragma once
void printA();
sharedb.cpp
#include <iostream>
#include "sharedb.h"
#include "static.h"
void printB()
{
std::cout << getA() << std::endl;
}
sharedb.h
#pragma once
void printB();
main.cpp
#include "shareda.h"
#include "sharedb.h"
int main()
{
printA();
printA();
printB();
printA();
printB();
return 0;
}
I compiled and ran these files with the following commands (using Clang 3.8.0, compiled from source, and 64-bit Debian with GNU ld 2.25):
clang++ -c static.cpp -o static.o -fPIC
ar rcs libstatic.a static.o
clang++ -c shareda.cpp -o shareda.o -fPIC
clang++ -shared -o libshareda.so shareda.o libstatic.a
clang++ -c sharedb.cpp -o sharedb.o -fPIC
clang++ -shared -o libsharedb.so sharedb.o libstatic.a
clang++ -L. -lshareda -lsharedb -o main main.cpp
LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./main
To my surprise, the output was the following:
0
1
2
3
4
My expectation was this:
0
1
0
2
1
Apparently, despite the static keyword in front of a in static.cpp, only one instance of a exists. Is there a way to have two instances of a, one for each of the shared libraries?
Apparently, despite the static keyword in front of a in static.cpp, only one instance of a exists.
That is incorrect: two instances of a exist, but only one is actually used.
And that is happening because (contrary to your expectations) printB calls the first getA available to it (the one from libshareda.so, not the one from libsharedb.so). That is one major difference between UNIX shared libraries and Windows DLLs. UNIX shared libraries emulate what would have happened if your link was:
clang++ -L. -o main main.cpp shareda.o sharedb.o libstatic.a
So what can you do to "fix" this?
You could link libsharedb.so to prefer its own getA, by using -Bsymbolic.
You could hide getA inside libsharedb.so completely (as if it's a private implementation detail):
clang++ -c -fvisibility=hidden -fPIC static.cpp
ar rcs libstatic.a static.o
clang++ -shared -o libsharedb.so sharedb.o libstatic.a
You could achieve similar result using linker version script.
P.S. Your link command:
clang++ -L. -lshareda -lsharedb -o main main.cpp
is completely backwards. It should be:
clang++ -L. -o main main.cpp -lshareda -lsharedb
The order of sources/object files and libraries on command line matters, and libraries should follow object files that reference them.
I've read multiple posts here relating to dynamic libraries on os x and debugging with gdb. But I still can't figure out why I can't debug a simple test case.
The main issue is that when I start up GDB it never loads any shared libraries.
Update: I've tried this with GDB from macports, from homebrew, and built from source and the behavior is the same.
I have a class that I compile into a library.
Test.hpp
class Test {
public:
void set(int i);
void out() const;
private:
int i;
};
Test.cpp
#include "Test.hpp"
#include <iostream>
void Test::set(int ii) { i = ii; }
void Test::out() const {
auto j = i * 100;
std::cout << i << ", " << j << "\n";
++j;
std::cout << i << ", " << j << "\n";
}
I compile it and create a library with g++. Note: the behavior is the same with macports gcc and the gcc from xcode.
/opt/local/bin/g++-mp-4.8 -O0 -g -ggdb -Wall -c -std=c++11 -o Test.o Test.cpp
/opt/local/bin/g++-mp-4.8 -dynamiclib -o libTest.dylib Test.o
Then I test it with this simple main
#include "Test.hpp"
int main() {
Test t;
auto x = 4;
t.set(x);
t.out();
return 0;
}
This is compiled and linked with
/opt/local/bin/g++-mp-4.8 -O0 -g -ggdb -Wall -c -std=c++11 -o main.o main.cpp
/opt/local/bin/g++-mp-4.8 -L . -o testing main.o -lTest
Everything compiles and runs as expected. But when I try to debug this with gdb (installed from macports, or installed from source, the behavior is the same), I have problems.
As I step through main, if I call info sharedlibrary it always says "No shared libraries loaded at this time.", so it apparently never loads libTest.dylib. Therefore, I can't step into any of the Test member functions or create breakpoints anywhere in libTest.dylib.
Indeed ggdb installed from macports for some reason does not respect the DYLD_LIBRARY_PATH. However, if you "patch" your executable with the correct paths for the .dylibs you should be able to debug with ggdb. Take a look at this question and especially the answer by Akos Cz.
I'm trying to write a program to use a static library of a C++ code into another C++ code. The first C++ code is hello.cpp:
#include <iostream>
#include <string.h>
using namespace std;
extern "C" void say_hello(const char* name) {
cout << "Hello " << name << "!\n";
}
int main(){
return 0;
}
The I made a static library from this code, hello.a, using this command:
g++ -o hello.a -static -fPIC hello.cpp -ldl
Here's the second C++ code to use the library, say_hello.cpp:
#include <iostream>
#include <string>
#include <dlfcn.h>
using namespace std;
int main(){
void* handle = dlopen("./hello.a", RTLD_LAZY);
cout<<handle<<"\n";
if (!handle) {
cerr<<"Cannot open library: "<<dlerror()<<'\n';
return 1;
}
typedef void (*hello_t)();
dlerror(); // reset errors
hello_t say_hello = (hello_t) dlsym(handle, "say_hello");
const char *dlsym_error = dlerror();
if (dlsym_error) {
cerr<<"Cannot load symbol 'say_hello': "<<dlsym_error<<'\n';
dlclose(handle);
return 1;
}
say_hello("World");
dlclose(handle);
return 0;
}
Then I compiled say_hello.cpp using:
g++ -W -ldl say_hello.cpp -o say_hello
and ran ./say_hello in the command line. I expected to get Hello World! as output, but I got this instead:
0x8ea4020
Hello ▒▒▒▒!
What is the problem? Is there any trick to make compatibility for method's argument like what we use in ctypes or what?
If it helps I use a lenny.
EDIT 1:
I have changed the code and used a dynamic library, 'hello.so', which I've created using this command:
g++ -o hello.so -shared -fPIC hello.cpp -ldl
The 6th line of the code changed to:
void* handle = dlopen("./hello.so", RTLD_LAZY);
When I tried to compile say_hello.cpp, I got this error:
say_hello.cpp: In function ‘int main()’:
say_hello.cpp:21: error: too many arguments to function
I also tried to compile it using this line:
g++ -Wall -rdynamic say_hello.cpp -ldl -o say_hello
But same error raised. So I removed the argument "World" and the it has been compiled with no error; but when I run the executable, I get the same output like I have mentioned before.
EDIT 2:
Based on #Basile Starynkevitch 's suggestions, I changed my say_hello.cpp code to this:
#include <iostream>
#include <string>
#include <dlfcn.h>
using namespace std;
int main(){
void* handle = dlopen("./hello.so", RTLD_LAZY);
cout<<handle<<"\n";
if (!handle) {
cerr<<"Cannot open library: "<<dlerror()<<'\n';
return 1;
}
typedef void hello_sig(const char *);
void* hello_ad = dlsym(handle, "say_hello");
if (!hello_ad){
cerr<<"dlsym failed:"<<dlerror()<<endl;
return 1;
}
hello_sig* fun = reinterpret_cast<hello_sig*>(hello_ad);
fun("from main");
fun = NULL;
hello_ad = NULL;
dlclose(handle);
return 0;
}
Before that, I used below line to make a .so file:
g++ -Wall -fPIC -g -shared hello.cpp -o hello.so
Then I compiled say_hello.cpp wth this command:
g++ -Wall -rdynamic -g say_hello.cc -ldl -o say_hello
And then ran it using ./say_hello. Now everything is going right. Thanks to #Basile Starynkevitch for being patient about my problem.
Functions never have null addresses, so dlsym on a function name (or actually on any name defined in C++ or C) cannot be NULL without failing:
hello_t say_hello = (hello_t) dlsym(handle, "say_hello");
if (!say_hello) {
cerr<<"Cannot load symbol 'say_hello': "<<dlerror()<<endl;
exit(EXIT_FAILURE);
};
And dlopen(3) is documented to dynamically load only dynamic libraries (not static ones!). This implies shared objects (*.so) in ELF format. Read Drepper's paper How To Use Shared Libraries
I believe you might have found a bug in dlopen (see also its POSIX dlopen specification); it should fail for a static library hello.a; it is always used on position independent shared libraries (like hello.so).
You should dlopen only position independent code shared objects compiled with
g++ -Wall -O -shared -fPIC hello.cpp -o hello.so
or if you have several C++ source files:
g++ -Wall -O -fPIC src1.cc -c -o src1.pic.o
g++ -Wall -O -fPIC src2.cc -c -o src2.pic.o
g++ -shared src1.pic.o src2.pic.o -o yourdynlib.so
you could remove the -O optimization flag or add -g for debugging or replace it with -O2 if you want.
and this works extremely well: my MELT project (a domain specific language to extend GCC) is using this a lot (generating C++ code, forking a compilation like above on the fly, then dlopen-ing the resulting shared object). And my manydl.c example demonstrates that you can dlopen a big lot of (different) shared objects on Linux (typically millions, and hundred of thousands at least). Actually the limitation is the address space.
BTW, you should not dlopen something having a main function, since main is by definition defined in the main program calling (perhaps indirectly) dlopen.
Also, order of arguments to g++ matters a lot; you should compile the main program with
g++ -Wall -rdynamic say_hello.cpp -ldl -o say_hello
The -rdynamic flag is required to let the loaded plugin (hello.so) call functions from inside your say_hello program.
For debugging purposes always pass -Wall -g to g++ above.
BTW, you could in principle dlopen a shared object which don't have PIC (i.e. was not compiled with -fPIC); but it is much better to dlopen some PIC shared object.
Read also the Program Library HowTo and the C++ dlopen mini-howto (because of name mangling).
example
File helloshared.cc (my tiny plugin source code in C++) is
#include <iostream>
#include <string.h>
using namespace std;
extern "C" void say_hello(const char* name) {
cout << __FILE__ << ":" << __LINE__ << " hello "
<< name << "!" << endl;
}
and I am compiling it with:
g++ -Wall -fPIC -g -shared helloshared.cc -o hello.so
The main program is in file mainhello.cc :
#include <iostream>
#include <string>
#include <dlfcn.h>
#include <stdlib.h>
using namespace std;
int main() {
cout << __FILE__ << ":" << __LINE__ << " starting." << endl;
void* handle = dlopen("./hello.so", RTLD_LAZY);
if (!handle) {
cerr << "dlopen failed:" << dlerror() << endl;
exit(EXIT_FAILURE);
};
// signature of loaded function
typedef void hello_sig_t(const char*);
void* hello_ad = dlsym(handle,"say_hello");
if (!hello_ad) {
cerr << "dlsym failed:" << dlerror() << endl;
exit(EXIT_FAILURE);
}
hello_sig_t* fun = reinterpret_cast<hello_sig_t*>(hello_ad);
fun("from main");
fun = NULL; hello_ad = NULL;
dlclose(handle);
cout << __FILE__ << ":" << __LINE__ << " ended." << endl;
return 0;
}
which I compile with
g++ -Wall -rdynamic -g mainhello.cc -ldl -o mainhello
Then I am running ./mainhello with the expected output:
mainhello.cc:7 starting.
helloshared.cc:5 hello from main!
mainhello.cc:24 ended.
Please notice that the signature hello_sig_t in mainhello.cc should be compatible (homomorphic, i.e. the same as) with the function say_hello of the helloshared.cc plugin, otherwise it is undefined behavior (and you probably would have a SIGSEGV crash).
I am looking for basic examples/tutorials on:
How to write/compile libraries in C++ (.so files for Linux, .dll files for Windows).
How to import and use those libraries in other code.
The code
r.cc :
#include "t.h"
int main()
{
f();
return 0;
}
t.h :
void f();
t.cc :
#include<iostream>
#include "t.h"
void f()
{
std::cout << "OH HAI. I'M F." << std::endl;
}
But how, how, how?!
~$ g++ -fpic -c t.cc # get t.o
~$ g++ -shared -o t.so t.o # get t.so
~$ export LD_LIBRARY_PATH="." # make sure t.so is found when dynamically linked
~$ g++ r.cc t.so # get an executable
The export step is not needed if you install the shared library somewhere along the global library path.