Let's say, I have an executable a.out. It has shared libraries libcrypto.so, libmylib.so. I'd like to make some action at every of these libs load. Is there some function I can add my code to? So I will define some function inside my executable and it will be called twice for this example.
I'm aware of __attribute__ ((constructor)), but it should be defined for every library specifically, which is not possible.
Thanks.
I'd like to make some action at every of these libs load. Is there some function I can add my code to?
Your code, no. But you could LD_PRELOAD a dlopen interposer.
Example:
// foo.c
#include <stdio.h>
__attribute__((constructor))
void ctor()
{
printf("In %s:%d\n", __FILE__, __LINE__);
}
// main.c
#include <dlfcn.h>
#include <stdio.h>
int main()
{
printf(">>> main\n");
dlopen("./foo.so", RTLD_LAZY);
dlopen("./bar.so", RTLD_LAZY);
printf("<<< main\n");
return 0;
}
gcc -shared -fPIC -o foo.so foo.c
gcc -shared -fPIC -o bar.so foo.c
gcc main.c -ldl
./a.out
>>> main
In foo.c:6
In foo.c:6
<<< main
Now let's add a dlopen interposer:
// dlopen_preload.c
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
typedef void* (*FN)(const char *, int);
void *dlopen(const char *fname, int flags)
{
FN real_dlopen = (FN)dlsym(RTLD_NEXT, "dlopen");
void *ret = real_dlopen(fname, flags);
printf("my dlopen(%s, 0x%x) -> %p\n", fname, flags, ret);
return ret;
}
gcc -shared -o dlopen_preload.so dlopen_preload.c
LD_PRELOAD=./dlopen_preload.so ./a.out
>>> main
In foo.c:6
my dlopen(./foo.so, 0x1) -> 0x565039670690
In foo.c:6
my dlopen(./bar.so, 0x1) -> 0x565039670c90
<<< main
VoilĂ .
Related
Is it possible to load an extra helper .so during current gdb session?
// point.h
class Point
{
public:
int x;
int y;
Point(int x1, int y1) {x = x1; y = y1;}
};
// main.cpp
#include "point.h"
#include <stdio.h>
int main()
{
Point p(3, 4);
printf("%d\n", p.x);
return 0;
}
g++ -g -c main.cpp -o main.o
g++ -g main.o -o main
When debugging, I need to add a helper function to dump the Point object. But I don't want to recompile and rerun. (It might take a long time.) So I am trying to build another helper.so.
// helper.cpp
#include "point.h"
#include <stdio.h>
void dump_point(Point *p)
{
printf("Point(%d, %d)\n", p->x, p->y);
}
g++ -g -fPIC -shared helper.cpp -o helper.so
Is it possible to load this helper.so in gdb so I can call dump_point() without rerunning?
When debugging, I need to add a helper function to dump the Point object.
The "normal" way to do this to write a custom pretty printer in Python.
One advantage of doing that is that the pretty printer will also work for a core dump, whereas dump_point() solution will not (regardless of whether it's linked in or loaded from a separate .so).
So I am trying to build another helper.so.
If your main was linked against libdl, you could do this:
(gdb) call dlopen("./helper.so", 0)
(gdb) call dlsym($_, "dump_point")
Note: you will want to make dump_point extern "C" to avoid name mangling.
I am new to SWIG and I am trying some tutorials but running into compilation issues.
The functions I am trying to wrap (ex.cxx) :
#include <time.h>
double My_variable = 3.0;
int fact(int n) {
if (n <= 1) return 1;
else return n*fact(n-1);
}
int my_mod(int x, int y) {
return (x%y);
}
char *get_time()
{
time_t ltime;
time(<ime);
return ctime(<ime);
}
the SWIG wrapper definition (ex.i) :
%module ex
%{
/* Put header files here or function declarations like below */
extern double My_variable;
extern int fact(int n);
extern int my_mod(int x, int y);
extern char *get_time();
%}
extern double My_variable;
extern int fact(int n);
extern int my_mod(int x, int y);
extern char *get_time();
the minimal setup to call the wrappers (min.cxx) :
#include <stdio.h>
extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
#include <string.h>
//#include "ex_wrap.cxx"
extern "C" {
extern int luaopen_ex(lua_State* L); // declare the wrapped module
}
int main(int argc,char* argv[]) {
char buff[256];
int error;
lua_State *L;
if (argc<2) {
printf("%s: <filename.lua>\n",argv[0]);
return 0;
}
L=luaL_newstate(); // https://stackoverflow.com/questions/8552560/embedding-lua-in-c
luaL_openlibs(L); // load basic libs (eg. print)
luaopen_ex(L); // load the wrappered module
if (luaL_loadfile(L,argv[1])==0) // load and run the file
lua_pcall(L,0,0,0);
else
printf("unable to load %s\n",argv[1]);
/*while (fgets(buff, sizeof(buff), stdin) != NULL) {
error = luaL_loadbuffer(L, buff, strlen(buff), "line") ||
lua_pcall(L, 0, 0, 0);
if (error) {
fprintf(stderr, "%s", lua_tostring(L, -1));
lua_pop(L, 1); // pop error message from the stack
}
}*/
lua_close(L);
return 0;
}
and the compile commands :
swig -debug-symtabs -debug-symbols -debug-csymbols -o ex_wrap.cxx -c++ -lua ex.i
clang -std=c++11 -I/usr/local/include/lua -c min.cxx -o min.o
clang -std=c++11 -fvisibility=default -I/usr/local/include/lua -c ex_wrap.cxx -o ex_wrap.o
clang -std=c++11 -c ex.cxx -o ex.o
clang -std=c++11 -I/usr/local/include/lua -L/usr/local/lib/lua -llua ex_wrap.o min.o ex.o -o mylua
clang -shared -std=c++11 -I/usr/local/include/lua -L/usr/local/lib/lua -llua min.o ex.o -o ex.so
The last command fails with
Undefined symbols for architecture x86_64:
"_luaopen_ex", referenced from:
_main in min.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
luaopen_ex() is defined in the ex_wrap.cxx generated by the swig command, but the linker cannot seem to find it. BTW, if I include ex_wrap.cxx directly into min.cxx, it compiles and I can run Lua code with this mini interpreter afterwards. Any ideas, thank you.
luaopen_example is defined in an extern "C" {} block in ex_wrap.cxx, but compiling ex.c with g++ declares luaopen_example as a C++ function, so the linker looks for a C++ mangled name to resolve luaopen_example(lua_State*) and not simply luaopen_example
Change your declaration in ex.c to
extern "C" {
extern int luaopen_example(lua_State* L); // declare the wrapped module
}
and the code will compile.
( You might be also be interested in the answer to this question, which explains name mangling: What is the effect of extern "C" in C++? )
it's a linking failure error, and it happens because it can't link luaopen_example, but why it happens? luaopen_example is to load the wrapped module as you mentioned and it's named "example" only if the module name is the same.
in swig and lua wrapper, the wrapper name depends on the file to be wrapped name, but if you don't want to go this way, you can use the option -o, then the wrappered module will export one function "int luaopen_example(lua_State* L)" which must be called to register the module with the Lua interpreter. The name "luaopen_example" depends upon the name of the module.
so i suggest you just keep the name of the wrapper derived from the module, or you can adjust the loading function luaopen_xxxx to your wrapper name.
for full resource you can take a look at SWIG and Lua
I've been following Apple's Dynamic Library Programming Topics
docs to create and use a runtime-loaded library using dlopen() / dlsym().
It seems I'm getting a failure to find the desired symbol on my Mid 2012 MacBook Air, running macOS Mojave.
Library Source Code
// adder.h
int add(int x);
and
// adder.cpp
#include "adder.h"
int add(int x) {
return (x + 1);
}
Compiled with clang -dynamiclib adder.cpp -o libAdd.A.dylib
Main Source
// main.cpp
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include "adder.h"
int main() {
void* adder_handle = dlopen("libAdd.A.dylib", RTLD_LOCAL|RTLD_LAZY);
if (!adder_handle) {
printf("[%s] Unable to load library: %s\n\n", __FILE__, dlerror());
exit(EXIT_FAILURE);
}
while(true) {
void* voidptr = dlsym(adder_handle, "add");
int (*add)(int) = (int (*)(int))voidptr;
if (!add) {
printf("[%s] Unable to get symbol: %s\n\n", __FILE__, dlerror());
exit(EXIT_FAILURE);
}
printf("%d\n", add(0));
}
dlclose(adder_handle);
return 0;
}
Compiled with clang main.cpp -o main
I've also set the DYLD_LIBRARY_PATH environment variable to ensure the library can be found. Everything compiles ok.
Nevertheless, when I run the main executable, I get the error:
[main.cpp] Unable to get symbol: dlsym(0x7fb180500000, add): symbol not found
Running nm -gC libAdd.A.dylib outputs:
0000000000000fa0 T add(int)
U dyld_stub_binder
Any ideas on what could be wrong, or what I need to do to debug this issue?
Thanks!
C++ actually mangles the functionname which results in a different symbolname.
Your are able to spot these mangled symbol names using nm -g <yourlib.dylib>
You can change this behavior by wrapping your method into
extern "C" {
int add(int x);
}
I've a linux application that links against a static library (.a) and that library uses the dlopen function to load dynamic libraries (.so)
If I compile the static library as dynamic and link it to the application, the dlopen it will work as expected, but if I use it as described above it won't.
Can't a static library uses the dlopen function to load shared libraries?
Thanks.
There should be no problem with what you're trying to do:
app.c:
#include "staticlib.h"
#include "stdio.h"
int main()
{
printf("and the magic number is: %d\n",doSomethingDynamicish());
return 0;
}
staticlib.h:
#ifndef __STATICLIB_H__
#define __STATICLIB_H__
int doSomethingDynamicish();
#endif
staticlib.c:
#include "staticlib.h"
#include "dlfcn.h"
#include "stdio.h"
int doSomethingDynamicish()
{
void* handle = dlopen("./libdynlib.so",RTLD_NOW);
if(!handle)
{
printf("could not dlopen: %s\n",dlerror());
return 0;
}
typedef int(*dynamicfnc)();
dynamicfnc func = (dynamicfnc)dlsym(handle,"GetMeANumber");
const char* err = dlerror();
if(err)
{
printf("could not dlsym: %s\n",err);
return 0;
}
return func();
}
dynlib.c:
int GetMeANumber()
{
return 1337;
}
and build:
gcc -c -o staticlib.o staticlib.c
ar rcs libstaticlib.a staticlib.o
gcc -o app app.c libstaticlib.a -ldl
gcc -shared -o libdynlib.so dynlib.c
First line builds the lib
second line packs it into a static lib
third builds the test app, linking in the newly created static, plus the linux dynamic linking library(libdl)
fourth line builds the soon-to-be-dynamically-loaded shared lib.
output:
./app
and the magic number is: 1337
I've got a variable called global_count that I would like to share between the shared library and the main part of the program (and ultimately other libs, but for now I've simplified the testcase).
Given the declaration of global_count in globals.cpp:
extern "C" {
int* global_count;
}
We compile to create a global.o file:
gcc -c global.cpp
shared.cpp below will be used to create shared.so:
#include <stdio.h>
#include "global.h"
extern "C" {
void init_global_count(int* xp) {
printf("Initialize global count to: %d\n", *xp);
global_count = xp;
};
void print_global_count(){
if(global_count) {
printf("global_count is: %d\n",*global_count);
} else {
printf("global_count* is not initialized!\n");
}
};
}
global.h:
extern "C" {
extern int* global_count;
}
main.cpp:
#include <stdlib.h>
#include <dlfcn.h>
#include <stdio.h>
#include "global.h"
int answer = 42;
int* gc_copy;
typedef void (*func)();
void (*init_global_count)(int*);
void (*print_global_count)();
void load(char* shared_lib){
void* handle;
handle = dlopen(shared_lib,RTLD_NOW | RTLD_GLOBAL) ;
printf("load:after dlopen\n");
if(!handle)
{
printf("DID NOT LOAD!\n");
fflush(stdout);
fputs (dlerror(), stderr);
exit(1);
} else {
printf("Loaded OK!\n");
fflush(stdout);
void (*init_global_count)(int*) = (void (*)(int*))dlsym(handle, "init_global_count");
(*init_global_count)(&answer);
void (*print_global_count)() = (void (*)())dlsym(handle, "print_global_count");
(*print_global_count)();
}
}
int main(){
printf("main...\n");
load((char*)"./shared.so");
if(global_count)
printf("main:global_count is: %d\n", *global_count);
return 0;
}
To compile the shared lib and main:
gcc -g -Wall -fno-omit-frame-pointer -fPIC -shared -o shared.so shared.cpp global.o
gcc -g -o main main.cpp global.o -ldl
Note that we're linking in global.o in both of those compilations.
Now we run it and the output is:
main...
load:after dlopen
Loaded OK!
Initialize global count to: 42
global_count is: 42
So the *global_count* reported from inside *print_global_count()* (defined in shared.cpp) is 42 as expected. However, global_count is not reported from main because the global_count pointer has not been initialized - so the global_count in main.cpp is not the same as the global_count in shared.cpp.
I'm wondering if it's possible to do what I'm trying to do here (to share some global data between a .so and the module that loads the .so)? If so, do I need to link differently?
All objects in a shared library need to be compiled as position independent (-fpic or -fPIC). So linking in globals.o into your shared library is in error.
You are actually creating two instances of the global_count pointer. You are trying to print out a pointer value as a decimal integer from main. The global pointer variable global_count in the main version is not yet initialized, so it has the starting value of all bytes set to 0.
You can remove globals.o from your shared library, and only have one instance of the global_count variable in main. However, for the shared library to see the main global variables, they have to be made visible to them. You can do this by adding -rdynamic to the flags to gcc in your link line for main.