c - 从共享库获取函数指针的区别

标签 c shared-libraries

问题是如何从共享库(UNIX/LINUX)获取函数地址?

我用 C 编写了一些测试用例(见下文),在 Ubuntu 10.04 (amd64) 和 FreeBSD-8.2 (amd64) 上编译和运行。我没有感觉到任何不同,但我想更多地了解可能出现的问题。

他们在这里:

  1. 测试 1

库文件

char* f0(void) {
    return "Hello, World!";
}

主.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;
}

现在构建它:

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

打印库函数f0()的地址和执行结果。

  1. 测试 2

lib.h(这里定义动态链接库的标准接口(interface))

#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(库本身)

#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!";
}

主.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;
}    

现在编译它(没有 -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

这个printf和Test 1一样:库函数foo()的地址和执行结果。

我试图展示如何获取共享库函数地址,但我在第二次测试中是否正确?我会遇到一些麻烦吗?

注意:在 FreeBSD-8.2 中不需要使用 -ldl 参数,所有 dlfcn.h 例程都在 libc 库中。

分别等待任何解释。

最佳答案

这对我来说看起来相当标准。您正在使用的唯一可能带来一些问题的是您正在使用 gcc 属性为共享库创建构造函数和析构函数。那可能不完全便携;这取决于您关心的平台。

请注意,在这种特定情况下,无需执行如此复杂的操作。您在第二个示例中从共享库返回的信息在编译时都是已知的,因此您可以使用该信息创建一个静态结构,然后使用 dlsym 检索该结构的地址,然后从主程序或调用已知函数返回结构。 (后者在某些极端情况下稍微灵活一些,但两者都相当灵活。)

关于c - 从共享库获取函数指针的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15405614/

相关文章:

c - 如何通过终止符跳出循环?

c - 二进制字符指针中的字节数

c - 为什么我在动态内存中得到错误的值?

java - 使用 java.io.file 的 jenkins 管道始终引用 master

c++ - 是否对空指针未定义的行为执行算术?

c - 编写余弦定律计算

创建独立的 C 可执行文件

php - 如何使用 SWIG 在 OS X 上编译 PHP 扩展

c - 如何在 C 的共享库中使用外部符号

java - android多个项目共享同一个库问题