使用 dlsym() 在静态链接库中查找变量

Pet*_*ett 5 c linux gcc static-libraries dlsym

我们有一个链接多个静态库的程序,这些静态库可能定义也可能不定义多个符号,具体取决于编译选项。在 OS X 上,我们使用dlsym(3)NULL 句柄来获取符号地址。但是,在 Linux 上,dlsym(3)始终返回 NULL。

考虑一个简单的程序(来源如下),该程序链接包含一个函数和一个变量的静态库,并尝试打印它们的地址。我们可以检查程序是否包含符号:

$ nm -C test | grep "test\(func\|var\)"
0000000000400715 T testFunc
0000000000601050 B testVar
Run Code Online (Sandbox Code Playgroud)

但是,当程序运行时,两者都找不到:

$ ./test
testVar: (nil)
testFunc: (nil)
Run Code Online (Sandbox Code Playgroud)

我们正在尝试在 Linux 上使用 glibc 实现的dlsym(3)?

 生成文件

(抱歉有空格)

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
Run Code Online (Sandbox Code Playgroud)

测试文件

#pragma once
extern void *testVar;
extern int testFunc(int);
Run Code Online (Sandbox Code Playgroud)

测试库

#include "libtest.h"
void *testVar;
int testFunc(int x) { return x + 42; }
Run Code Online (Sandbox Code Playgroud)

测试.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;
}
Run Code Online (Sandbox Code Playgroud)

Bas*_*tch 4

您应该将您的程序与-rdynamic(或--export-dynamicld (1) ) 链接起来,这样

LDFLAGS += -rdynamic -L.
Run Code Online (Sandbox Code Playgroud)

那么所有的符号都在动态符号表中,即所使用的符号表dlsym

顺便说一句,该visibility属性可能会令人感兴趣。

  • 对于像我这样不知道的人(从手册中):_`-rdynamic`:在支持它的目标上将标志“-export-dynamic”传递给 ELF 链接器。这指示链接器将所有符号(而不仅仅是使用过的符号)添加到动态符号表中。对于“dlopen”的某些用途或允许从程序内获取回溯,需要此选项。_ (3认同)