Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between getting function pointers from shared library

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:

  1. 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.

  1. 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.

like image 864
user2168737 Avatar asked Nov 12 '22 09:11

user2168737


1 Answers

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.)

like image 129
rra Avatar answered Nov 15 '22 05:11

rra