The question is how I can get function address from shared library (UNIX/LINUX)?
I had written some testcases in C (see below), compiled and run on Ubuntu 10.04 (amd64) and FreeBSD-8.2 (amd64). I hadn't feel any difference but I want to know more about possible troubles.
Here they are:
Test 1
lib.c
char* f0(void) {
return "Hello, World!";
}
main.c
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
void *hlib, *addr;
char* (*foo)(void);
char* s;
int main(int argc, char** argv) {
if ( !(hlib = dlopen("./lib.so", RTLD_LAZY)) )
return 1;
if ( !(addr = foo = dlsym(hlib, "f0")) )
return 2;
s = foo();
printf("%p => %s\n", addr, s);
return 0;
}
Now build it:
gcc -o lib.o -c lib.c -Wall -Werror -O3 -fPIC
gcc -o lib.so -shared -nostartfiles lib.o
gcc -o main.o -c main.c -Wall -Werror -O3
gcc -o prog main.o -ldl
This prints the address of library function f0() and the result of execution.
Test 2
lib.h (define here the standard interface of dynamically linking libraries)
#ifndef __LIB_H__
#define __LIB_H__
typedef struct __syminfo {
char* name; // function name
void* addr; // function address
} syminfo_t;
typedef struct __libinfo {
int num; // number of exported functions
syminfo_t sym[1]; // vector of exported function information
} libinfo_t;
extern int (*__getinfo)(libinfo_t**);
#endif
/* __LIB_H__
*/
lib.c (the library itself)
#include <stdlib.h>
#include <lib.h>
static libinfo_t* li;
char* foo(void);
__attribute__((constructor)) void __init() {
if ( (li = calloc(1, sizeof(libinfo_t))) ) {
li->num = 1;
li->sym[0].name = "foo";
li->sym[0].addr = &foo;
}
}
__attribute__((destructor)) void __free() {
if (li)
free(li);
}
int getinfo(libinfo_t** inf) {
if (!inf)
return -1;
*inf = li;
return 0;
}
char* foo(void) {
return "Hello, World!";
}
main.c
#include <stdio.h>
#include <dlfcn.h>
#include <lib.h>
libinfo_t* inf;
void* hlib;
int (*__getinfo)(libinfo_t**);
char* (*foo)(void);
char* s;
int main(int argc, char** argv) {
if ( !(hlib = dlopen("./lib.so", RTLD_LAZY)) )
return 1;
if ( !(__getinfo = dlsym(hlib, "getinfo")) )
return 2;
if (__getinfo(&inf))
return 3;
if ( !(foo = inf->sym[0].addr) )
return 4;
s = foo();
printf("%p => %s\n", inf->sym[0].addr, s);
return 0;
}
Now compile it (without -nostartfiles):
gcc -I. -o lib.o -c lib.c -Wall -Werror -O3 -fPIC
gcc -o lib.so lib.o -shared
gcc -I. -o main.o -c main.c -Wall -Werror -O3
gcc -o prog main.o -ldl
This printf the same as Test 1: the address of library function foo() and the result of its execution.
I tried to show how can I get shared library function address, but am I right in the second test? Shall I have got some troubles with it?
NOTE: in FreeBSD-8.2 there is no need to use -ldl argument, all dlfcn.h routines are in libc library.
Respectively waithing for any explanations.
That looks fairly standard to me. The only thing that you're using that could pose some problems is that you're using gcc attributes to create a constructor and destructor for your shared library. That may not be entirely portable; it depends on what platforms you care about.
Note that in this specific case there's no need to do something this complicated. The information that you're returning from the shared library in your second example is all known at compile time, so you can just create a static struct with that information and either retrieve the address of the struct with dlsym and poke around in it from the main program or call a known function to return the struct. (The latter is slightly more flexible in some corner cases, but both are fairly flexible.)
Related
I'm using Cmocka to write a unit testing suite for a shared object written in C, but I'm having some issue. Since I cannot share the source code, I have written a minimum "not-working" example to show what is the issue:
my program is composed 5 files: foo.c, foo.h bar.c bar.h main.c.
bar.* files define a bar() function, which simply returns the argument multiplied by 2
foo.* files declare a foo() function that uses the bar() function defined by bar.h
main.c contains a simple cmocka test and a __wrap_bar()
function, returning the argument multiplied by 3.
I compile the program by producing a libfootest.so object (foo+bar) and then I link this object with main.o passing the -Wl,--wrap=bar flag to the compiler. In this configuration libfootest is the module under test and main is the tester program. I expect the __wrap__bar to be called (failing the test), but the standard bar() is called(test is passed). How can I solve this problem? Below you find all the code I'm using.
bar.c:
#include "bar.h"
int bar(int val) {
return val*2;
}
bar.h:
int bar(int val);
foo.h:
#include <stdio.h>
int foo(int val);
foo.c:
#include "foo.h"
#include "bar.h"
int foo(int val) {
int ret;
ret = bar(val);
printf("RET: %d", ret);
return ret;
}
main.c:
#include <stdio.h>
//required include for CMOCKA
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <setjmp.h>
#include <cmocka.h>
//library under test
#include "foo.h"
int __wrap_bar(int val) {
return 3*val;
}
static void test_foo(void **state) {
int ret = foo(5);
assert_int_equal(ret, 10);
}
int main (int argc, char** argv) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_foo),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}
Makefile:
CMOCKA_LIB_DIR=../../cmocka-1.1.5/build/src
CXXFLAGS+=-g -Og -fPIC
CFLAGS+=-g -Og -std=c99 -fPIC
CC=gcc
CXX=g++
all: main.o ./libfootest.so
gcc -o linux-test -g -L. -L$(CMOCKA_LIB_DIR) $(filter %.o, $^) -lcmocka -lfootest -Wl,-rpath=. -Wall -Wl,--wrap=bar -Wl,-rpath=$(CMOCKA_LIB_DIR)
./libfootest.so: foo.o bar.o
$(CC) -shared -o $# -g $^ -pedantic -Wall
clean:
rm -f *.o
rm -f *.so
The problem is your build of the library. You don't create a link library as commonly done, with separated modules. Instead you link all given modules and place the resulting single module in the target library.
That's why the linker resolved the call to bar() already, and it is no longer unresolved when linking the test program.
The option --wrap works only for unresolved references between modules.
The solution is to build the library from separated modules. Use the tool ar for this:
ar r libfootest.a foo.o bar.o
It is possible to implement a static function registry in C for gcc/clang by using the section variable attribute and relying on the ELF linker to define the __start_<section> and __stop_<section> symbols pointing to the address of the custom section.
(See below for an example using this approach, which should illustrate the point.)
This approach, however, is very specific to GCC, ELF and Unix/Linux.
Is there an alternative approach to solve this same problem of static function registry, only in a more portable way?
In particular, I would like to be able to target MSVC compiler for Windows.
As an example, consider this program using this set of source files:
1) registry.h
struct reg_func {
const char *name;
int (*func)(void);
};
#define REGISTER_FUNC(name) \
static int func_ ## name(void); \
static struct reg_func descr_ ## name \
__attribute__((section("registry"))) \
= { # name, func_ ## name }; \
static int func_ ## name(void)
extern struct reg_func __start_registry;
extern struct reg_func __stop_registry;
2) a.c
#include "registry.h"
REGISTER_FUNC(a) {
return 1;
}
3) b.c
#include "registry.h"
REGISTER_FUNC(b) {
return 4;
}
4) c.c
#include "registry.h"
REGISTER_FUNC(cde) {
return 999;
}
5) main.c
#include <stdio.h>
#include "registry.h"
int main(int argc, char *argv[]) {
struct reg_func *p;
for (p = &__start_registry; p < &__stop_registry; p++) {
printf("Function %s returned %d.\n", p->name, p->func());
}
return 0;
}
6) Makefile
registry: main.o a.o b.o c.o
$(CC) -o $# $^
Build with:
$ make
cc -c -o main.o main.c
cc -c -o a.o a.c
cc -c -o b.o b.c
cc -c -o c.o c.c
cc -o registry main.o a.o b.o c.o
Execute with:
$ ./registry
Function a returned 1.
Function b returned 4.
Function cde returned 999.
I want to call backtrace function to get the callchain, the following is my code, this code works good on x86, but can't work on mips
gcc -o hello-x86 hello.c -g -rdynamic -O0 -Wall
./hello-x86
size = 6
0x40095c : ./hello-x86(foo+0x1f) [0x40095c]
0x400a2d : ./hello-x86(b+0x9) [0x400a2d]
0x400a38 : ./hello-x86(a+0x9) [0x400a38]
0x400a4e : ./hello-x86(main+0x14) [0x400a4e]
0x7fee0d003f45 : /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5) [0x7fee0d003f45]
0x400879 : ./hello-x86() [0x400879]
but on mips, just only got the last frame, how to fix it ?
mips-linux-gnu-gcc -o hello hello.c -g -rdynamic -O0 -Wall -msoft-float -EL
./hello
size = 1
0x400a04 : ./hello(foo+0x24) [0x400a04]
can't get b and a and main. but i can got full callchain in gdb, why can't got it via backtrace function ?
my toolchain is codesourcery mips-2016.05, the libc version is 2.23
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <execinfo.h>
#define BACKTRACE_SIZ 100
int i = 0;
void foo(void)
{
void *array[BACKTRACE_SIZ];
size_t size, i;
char **strings;
size = backtrace(array, BACKTRACE_SIZ);
strings = backtrace_symbols(array, size);
printf("size = %ld\n", (long)size);
for (i = 0; i < size; ++i) {
printf("%p : %s\n", array[i], strings[i]);
}
free(strings);
while (1) {
i++;
}
}
void b(void)
{
foo();
}
void a(void)
{
b();
}
int main(int argc, char **argv)
{
a();
return 0;
}
i tried -fno-omit-frame-pointer and -fomit-frame-pointer, these two option all can't work.
mips-linux-gnu-gcc -o hello hello.c -g -rdynamic -O0 -Wall -msoft-float -EL -fomit-frame-pointer
mips-linux-gnu-gcc -o hello hello.c -g -rdynamic -O0 -Wall -msoft-float -EL -fno-omit-frame-pointer
and i tried on my arm board, it worse, the size is 0 on arm
There is a simple example to describe my problem:
I have 3 files, main, level1.so and level2.so. (My OS is solaris11.3, gcc version is 3.4.3)
In main, it calls execute() from level1.so. And the execute() calls run() from level2.so. And the run() calls fcloseall() which is redefined in level2.so.
fcloseall() is redefined to do nothing (it will close all opened fds include stdout, stdin and stderr originally).
Now I want print something around execute() in main, but only the message before execute() is printed.
The codes are shown below:
The level2.so is compiled from level2.c and level2depend.c.
level2.c:
#include <stdio.h>
int run()
{
fcloseall();
return 0;
}
level2depend.c:
#include <stdio.h>
int fcloseall() //redefine the std c function fcloseall
{
printf("in redefined fcloseall\n");
return 0;
}
The level1.so is compiled from level1.c.
level1.c
#include <dlfcn.h>
int execute()
{
int (*sofunc)(void);
void * lib_handle = NULL;
char *errorInfo;
lib_handle = dlopen("./liblevel2.so",RTLD_LAZY);
if(!lib_handle)
{
return 0;
}
sofunc = (int(*)(void))dlsym(lib_handle,"run");
errorInfo = dlerror();
if (errorInfo != NULL){
dlclose(lib_handle);
return 0;
}
int ret = sofunc();
dlclose(lib_handle);
return 0;
}
The main is compiled from main.c.
main.c
#include <dlfcn.h>
#include <stdio.h>
int main()
{
int (*sofunc)(void);
void * lib_handle = NULL;
char *errorInfo;
lib_handle = dlopen("./liblevel1.so",RTLD_LAZY);
if(!lib_handle)
{
return 0;
}
sofunc = (int(*)(void))dlsym(lib_handle,"execute");
errorInfo = dlerror();
if (errorInfo != NULL){
dlclose(lib_handle);
return 0;
}
printf("before\n");
int ret = sofunc();
printf("after\n");
dlclose(lib_handle);
return 0;
}
The makefile is:
all:
gcc level2depend.c -o level2depend.o -c -g -fPIC
gcc level2.c -o level2.o -c -g -fPIC
gcc -shared -g level2.o level2depend.o -o liblevel2.so -fPIC
gcc level1.c -o level1.o -c -g -fPIC
gcc level1.o -o liblevel1.so -shared -fPIC
gcc main.c -o main -g -ldl
clean:
rm level2depend.o level1.o liblevel1.so level2.o liblevel2.so main
I execute main and the result is:
root#solaris#./main
before
If I change the makefile as gcc main.c -o main -g -ldl -llevel2, the result is:
root#solaris#./main
before
in redefined fcloseall
after
And this is what I want.
I want know why this happen. Thanks!
You can use the wrap function provided by ld.
gcc -Wl,-wrap,fcloseall ....
and in your source code,
int __wrap_fcloseall(void)
{...}
We have a program that links in a number of static libraries, which may or may not define a number of symbols depending on compilation options. On OS X, we use dlsym(3) with a NULL handle to obtain the symbol addresses. However, on Linux, dlsym(3) always returns NULL.
Consider a trivial program (sources below) that links in a static library containing a function and a variable and tries to print their addresses. We can check that the program contains the symbols:
$ nm -C test | grep "test\(func\|var\)"
0000000000400715 T testFunc
0000000000601050 B testVar
However, when the program is run, neither can be located:
$ ./test
testVar: (nil)
testFunc: (nil)
Is what we are trying to do possible on Linux, using glibc's implementation of dlsym(3)?
Makefile
(Sorry about the spaces)
LDFLAGS=-L.
LDLIBS=-Wl,--whole-archive -ltest -Wl,--no-whole-archive -ldl
libtest.o: libtest.c libtest.h
libtest.a: libtest.o
test: test.o libtest.a
clean:
-rm -f test test.o libtest.o libtest.a
libtest.h
#pragma once
extern void *testVar;
extern int testFunc(int);
libtest.c
#include "libtest.h"
void *testVar;
int testFunc(int x) { return x + 42; }
test.c
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, char *argv[]) {
void *handle = dlopen(NULL, 0);
void *symbol = dlsym(handle, "testVar");
printf("testVar: %p\n", symbol);
symbol = dlsym(handle, "testFunc");
printf("testFunc: %p\n", symbol);
return 0;
}
You should link your program with -rdynamic (or --export-dynamic for ld(1)) so
LDFLAGS += -rdynamic -L.
Then all the symbols are in the dynamic symbol table, the one used by dlsym
BTW, the visibility attribute could be of interest.