I've got an issue I am not able to solve. Looked up everything I found so far.
My problem is, I create a dyn library in my program a want to dlopen it and dlsym a method out of that lib.
It seems that dlopen works but dlsym return me the error "undefined symbol: method"
where "method" is the name of the method I passed to dlsym.
Here is how I create the library:
execl("/usr/bin/gcc", "gcc", "-fPIC", "-Wall", "-g", "-c", "userinput.c", NULL);
and:
execl("/usr/bin/gcc", "gcc", "-ggdb3", "-shared",
"-Wl,-soname,libuserinput.so.1", "-o", "libuserinput.so.1.0",
"userinput.o", "-lc", NULL);
This should work as there is a library after running my code.
I open the library like this:
static void *my_load_dyn (const char *lib) {
static void *handle;
handle = dlopen ("./libuserinput.so.1.0", RTLD_NOW | RTLD_DEEPBIND);
if (handle == NULL) {
printf ("error at dlopen(): %s\n", dlerror ());
exit (EXIT_FAILURE);
}
return handle;
}
/* load func from dyn lib"*/
static void *my_load_func (void *handle, char *func) {
void *funcptr = dlsym (handle, func);
if (funcptr == NULL) {
printf ("error at dlsym(): %s\n", dlerror ());
exit (EXIT_FAILURE);
}
return funcptr;
}
and call those functions like this:
void *libhandle;
void (*userMethod) (unsigned char *d);
libhandle = my_load_dyn(LIBUSERINPUT);
userMethod = my_load_func(libhandle, "testMethod");
(*userMethod)(d);
EDIT:
here is the code from the userinput.c:
#include <stdio.h>
#include <unistd.h>
void testMethod(unsigned char *d)
{
d[0] = 'Z';
}
It is generated in my programm and also compiled and linked in the running programm
i can see two possible problems
there's a problem in the code
are you sure that you declare your method as a public function in userinput.c?
e.g. if your method is declared static, then it won't be accessible from "outside".
also there are other ways to hide functions from being seen outside of the library, but it's impossible to tell whether you are having that problem without seeing any code.
your compilation/linking of the library is broken
e.g. you seem to be linking in a header-file (userinput.h) into the resulting libray?
i'd suggest to use a proper build system until the problem is solved, and switch to on-the-fly compilation later (e.g. using make)
Related
I'm writing an application using libao for audio output. The portion
of my program that calls into libao lives in a shared object:
// playao.c
// compile with: gcc -shared -o libplayao.so playao.c -lao -lm
#include <ao/ao.h>
#include <stdio.h>
#include <math.h>
void playao(void) {
int i;
unsigned char samps[8000];
ao_initialize();
ao_sample_format sf;
sf.bits = 8;
sf.rate = 8000;
sf.channels = 1;
sf.byte_format = AO_FMT_NATIVE;
sf.matrix = "M";
ao_device *device = ao_open_live(ao_default_driver_id(), &sf, NULL);
if(!device) {
puts("ao_open_live error");
ao_shutdown();
return;
}
for(i = 0; i < 8000; ++i) {
float time = (float)i / 8000;
float freq = 440;
float angle = time * freq * M_PI * 2;
float value = sinf(angle);
samps[i] = (unsigned char)(value * 127 + 127);
}
if(!ao_play(device, (char *)samps, 8000)) {
puts("ao_play error");
}
ao_close(device);
ao_shutdown();
}
If I link against this shared object in a program, it works fine:
// directlink.c
// compile with: gcc -o directlink directlink.c libplayao.so -Wl,-rpath,'$ORIGIN'
void playao(void);
int main(int argc, char **argv) {
playao();
return 0;
}
However, if I use dlopen/dlsym to invoke it, there are no errors, but the
program does not cause any sound to be emitted:
// usedl.c
// compile with: gcc -o usedl usedl.c -ldl
#include <dlfcn.h>
#include <stdio.h>
int main(int argc, char **argv) {
void *handle = dlopen("./libplayao.so", RTLD_LAZY);
if(!handle) {
puts("dlopen failed");
return 1;
}
void *playao = dlsym(handle, "playao");
if(!playao) {
puts("dlsym failed");
dlclose(handle);
return 1;
}
((void (*)(void))playao)();
dlclose(handle);
return 0;
}
However, running usedl with LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libao.so.4
does work. So there's something about libao that wants to be loaded when the
program starts up, and doesn't like being loaded any later.
Why is this? Is there any way to work around this, so that libao works
correctly even if loaded later in the program's execution?
I'm running Debian 10 "buster" if it matters.
I asked about this on the #xiph channel on Freenode and xiphmont suggested turning turning on verbose mode. Once I did that, the failing case started getting the message:
ERROR: Failed to load plugin /usr/lib/x86_64-linux-gnu/ao/plugins-4/libalsa.so => dlopen() failed
So libao itself is trying to dlopen something, and it's failing. It's not showing me any more details, so I ran the program under GDB and set a breakpoint on dlopen. After hitting the dlopen breakpoint for libalsa and running finish, I tried finding what the error was by using print (const char *)dlerror(). And with this, I get a more detailed error:
/usr/lib/x86_64-linux-gnu/ao/plugins-4/libalsa.so: undefined symbol: ao_is_big_endian
So ao's libalsa plugin is trying to reference symbols back in libao, but it's not finding them. Why could this be? Referencing the dlopen documentation, I see:
Zero or more of the following values may also be ORed in flags:
RTLD_GLOBAL: The symbols defined by this shared object will be made available for symbol resolution of subsequently loaded shared objects.
RTLD_LOCAL: This is the converse of RTLD_GLOBAL, and the default if neither flag is specified. Symbols defined in this shared object are not made available to resolve references in subsequently loaded shared objects.
Because my dlopen call only used RTLD_LAZY and didn't include RTLD_GLOBAL or RTLD_LOCAL, it defaulted to RTLD_LOCAL, which does not expose the symbols in the shared object (like ao_is_big_endian) to subsequently loaded shared objects (like libalsa.so).
So, I tried changing the code from:
void *handle = dlopen("./libplayao.so", RTLD_LAZY);
To:
void *handle = dlopen("./libplayao.so", RTLD_LAZY | RTLD_GLOBAL);
And lo and behold, it works!
I have one base library written in C. And other external extensions/definitions files. With a simple search tool the base library (when is used) can search in a directory for extensions libraries. Without telling the compiler which files it are. Then the C program can call a function in that external file.
So i want to run a function in a external file. I can choose which file I want to run the function from at running time. (Ex, I enter that the file is located at ./external_file at running time) (NOT COMPILE TIME!). Is this possible?
I need to read a return from the function, I need to wait until the function is finished, I need to call the function with arguments and it must be possible that the program at run time can choose the file and function.
Is this possible? Yes, program files does contains function names (with names). Only I need to know HOW do I call that function in a external file at run time.
Use dynamic libraries - most OS's provide support for loading a library given a name and getting the address of the function to call.
In windows see LoadLibrary and ProcAddress. In linux see dlopen and dlsym.
You can use the dlopen function to load a shared library (i.e. a .so file) at runtime, then use dlsym to get the functions to call.
For example, suppose you had the following library file:
mylib.c:
#include <stdio.h>
void f1(int a)
{
printf("in f1, a=%d\n", a);
}
int f2(char *s)
{
printf("in f2, s=%s\n", s);
return *s;
}
Then you compile it to a shared library:
gcc -g -Wall -Wextra -fPIC -c mylib.c
gcc -g -Wall -Wextra -fPIC -o libmylib.so mylib.o
You can call these functions as follows:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main()
{
// get a handle to the shared library
void *handle = dlopen("./libmylib.so", RTLD_LAZY);
if (!handle) {
printf("dlopen failed: %s\n", dlerror());
exit(1);
}
// get a pointer to the function to call
void (*myf1)(int) = dlsym(handle, "f1");
if (!myf1) {
printf("dlsym 1 failed: %s\n", dlerror());
exit(1);
}
myf1(4);
// get a pointer to another function to call
int (*myf2)(char *) = dlsym(handle, "f2");
if (!myf2) {
printf("dlsym 2 failed: %s\n", dlerror());
exit(1);
}
printf("rval=%d\n", myf2("hello"));
dlclose(handle);
return 0;
}
Note that you need to know at compile time what the function signatures look like so you can call them correctly.
I am trying to compile the example code which is using APIs from libdl library:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int
main(int argc, char **argv)
{
void *handle;
double (*cosine)(double);
char *error;
handle = dlopen("libm.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
dlerror(); /* Clear any existing error */
/* Writing: cosine = (double (*)(double)) dlsym(handle, "cos");
would seem more natural, but the C99 standard leaves
casting from "void *" to a function pointer undefined.
The assignment used below is the POSIX.1-2003 (Technical
Corrigendum 1) workaround; see the Rationale for the
POSIX specification of dlsym(). */
*(void **) (&cosine) = dlsym(handle, "cos");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
printf("%f\n", (*cosine)(2.0));
dlclose(handle);
exit(EXIT_SUCCESS);
}
I used the following command to compile:
--> gcc -static -o foo foo.c -ldl
I got the following error:
foo.c:(.text+0x1a): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
After google, since I am trying to compile it statically, I can find the libdl.a in the lib directory. I am getting the same issue with gethostbyname API also..
What are the other libraries needs to add to compile dl_open statically.
One possible problem:
dlsym()
Should be declared or implemented before it is referenced in main().
dlopen() works only with shared libs. That means that you can't link it statically. Have you tried without -static ?
I want to store the called functions addresses or names from the start up of the system to crash of the system. Is there any way to retrieve these function addresses from any hardware register when they called during program execution?
From the gcc documentation:
Generate instrumentation calls for entry and exit to functions. Just after function entry and just before function exit, the following profiling functions are called with the address of the current function and its call site. (On some platforms, __builtin_return_address does not work beyond the current function, so the call site information may not be available to the profiling functions otherwise.)
void __cyg_profile_func_enter (void *this_fn,
void *call_site);
void __cyg_profile_func_exit (void *this_fn,
void *call_site);
Example:
#include <stdio.h>
void __cyg_profile_func_enter(void * this_fn, void * call_site)
{
fprintf(stderr, "enter: %p %p\n", this_fn, call_site);
}
void __cyg_profile_func_exit(void * this_fn, void * call_site)
{
fprintf(stderr, " exit: %p %p\n", this_fn, call_site);
}
void foo(void);
void bar(void);
void foo(void)
{
bar();
return;
}
void bar(void)
{
return;
}
int main(void)
{
bar();
foo();
return 0;
}
Compile and link this using:
gcc -finstrument-functions -finstrument-functions-exclude-function-list=__cyg_profile_func_enter,__cyg_profile_func_exit -Wall -g -o main main.c
The expected output would look similar to this:
enter: 0x400665 0x7fcfedaf6c8d
enter: 0x400643 0x400681
exit: 0x400643 0x400681
enter: 0x40061c 0x400686
enter: 0x400643 0x400633
exit: 0x400643 0x400633
exit: 0x40061c 0x400686
exit: 0x400665 0x7fcfedaf6c8d
If you are on linux:
You can trace your program using ptrace and check the register.
To get the informations about your functions you can use the libelf. (or use nm & objdump)
You can't save the function address from within the function itself and you can't access the function name during the execution but you can save it before invoking the function:
savefptr(myfunction);
savefname("myfunction");
myfunction(a,b,c);
With the appropriate definition of savefptr() and savefname().
If this is done for tracing/debugging (e.g. you want to produce a log to know what's going on in the code) it might be good enoug to trace the file name and line of code using the __FILE__ and __LINE__ macros:
fprintf (stderr, "I'm in:'%s' line %d.",
__FILE__, __LINE__);
I would advice against using compiler or OS specifics if can avoid them.
I ONLY did some similar work under *nix system, therefore I provide my solution for you base on *nix.
I assumed you use gcc as your default compiler, and then you'd better enable both -finstrument-functions and -fdump-rtl-expand in your makefile, for example:
CFLAGS += -Wall -O -ggdb -Wstrict-prototypes -Wno-pointer-sign -finstrument-functions -fdump-rtl-expand
After this, you can implement the trace function, for example, your_trace.c:
#include <stdio.h>
#include <stdlib.h>
/* Function prototypes with attributes */
void main_constructor( void )
__attribute__ ((no_instrument_function, constructor));
void main_destructor( void )
__attribute__ ((no_instrument_function, destructor));
void __cyg_profile_func_enter( void *, void * )
__attribute__ ((no_instrument_function));
void __cyg_profile_func_exit( void *, void * )
__attribute__ ((no_instrument_function));
static FILE *fp;
void main_constructor( void )
{
fp = fopen( "trace.txt", "w" );
if (fp == NULL) exit(-1);
}
void main_deconstructor( void )
{
fclose( fp );
}
void __cyg_profile_func_enter( void *this, void *callsite )
{
fprintf(fp, "E%p\n", (int *)this);
}
void __cyg_profile_func_exit( void *this, void *callsite )
{
fprintf(fp, "X%p\n", (int *)this);
}
After these, after compile your code, you will see a *.map file, which contain function information. Also compiled with trace.c, and if simply run you output file after compile, and it will generate function call information, namely, trace.txt file, it has function address, you can use add2line to see each of them or you can use pvtrace tool to get the function call with trace.txt, for example, my compiled program named DEMO, then:
-> pvtrace ./DEMO
You will get graph.dot and it recorded your run time function call.
OR
use just enable -ggdb and use debug tool to see each function address, like DDD or GDB.
When loaded a shared library is opened via the function dlopen(), is there a way for it to call functions in main program?
Code of dlo.c (the lib):
#include <stdio.h>
// function is defined in main program
void callb(void);
void test(void) {
printf("here, in lib\n");
callb();
}
Compile with
gcc -shared -olibdlo.so dlo.c
Here the code of the main program (copied from dlopen manpage, and adjusted):
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
void callb(void) {
printf("here, i'm back\n");
}
int
main(int argc, char **argv)
{
void *handle;
void (*test)(void);
char *error;
handle = dlopen("libdlo.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
dlerror(); /* Clear any existing error */
*(void **) (&test) = dlsym(handle, "test");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
(*test)();
dlclose(handle);
exit(EXIT_SUCCESS);
}
Build with
gcc -ldl -rdynamic main.c
Output:
[js#HOST2 dlopen]$ LD_LIBRARY_PATH=. ./a.out
here, in lib
here, i'm back
[js#HOST2 dlopen]$
The -rdynamic option puts all symbols in the dynamic symbol table (which is mapped into memory), not only the names of the used symbols. Read further about it here. Of course you can also provide function pointers (or a struct of function pointers) that define the interface between the library and your main program. It's actually the method what i would choose probably. I heard from other people that it's not so easy to do -rdynamic in windows, and it also would make for a cleaner communication between library and main program (you've got precise control on what can be called and not), but it also requires more house-keeping.
Yes, If you provide your library a pointer to that function, I'm sure the library will be able to run/execute the function in the main program.
Here is an example, haven't compiled it so beware ;)
/* in main app */
/* define your function */
int do_it( char arg1, char arg2);
int do_it( char arg1, char arg2){
/* do it! */
return 1;
}
/* some where else in main app (init maybe?) provide the pointer */
LIB_set_do_it(&do_it);
/** END MAIN CODE ***/
/* in LIBRARY */
int (*LIB_do_it_ptr)(char, char) = NULL;
void LIB_set_do_it( int (*do_it_ptr)(char, char) ){
LIB_do_it_ptr = do_it_ptr;
}
int LIB_do_it(){
char arg1, arg2;
/* do something to the args
...
... */
return LIB_do_it_ptr( arg1, arg2);
}
The dlopen() function, as discussed by #litb, is primarily provided on systems using ELF format object files. It is rather powerful and will let you control whether symbols referenced by the loaded library can be satisfied from the main program, and generally does let them be satisfied. Not all shared library loading systems are as flexible - be aware if it comes to porting your code.
The callback mechanism outlined by #hhafez works now that the kinks in that code are straightened out.