dlsym returns NULL,即使符号存在
dlsym returns NULL, even though the symbol exists
我正在使用 dlsym 在我的程序中查找符号,但它总是 return 为 NULL,这是我没有预料到的。根据联机帮助页,如果出现某种错误,或者符号确实为 NULL,dlsym 可能 return NULL。就我而言,我遇到了一个错误。我将向您展示我今晚制作的 MCVE。
这里是instr.c的内容:
#include <stdio.h>
void * testing(int i) {
printf("You called testing(%d)\n", i);
return 0;
}
一个非常简单的东西,只包含一个不起眼的示例函数。
这里是test.c的内容:
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
typedef void * (*dltest)(int);
int main(int argc, char ** argv) {
/* Declare and set a pointer to a function in the executable */
void * handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
dlerror();
dltest fn = dlsym(handle, "testing");
if(fn == NULL) {
printf("%s\n", dlerror());
dlclose(handle);
return 1;
}
dlclose(handle);
return 0;
}
当我使用调试器逐步执行代码时,我看到 dlopen returning 一个句柄。根据联机帮助页,If filename is NULL, then the returned handle is for the main program.
所以如果我 link 一个名为 testing
的符号进入主程序,dlsym 应该找到它,对吗?
这是我编译和link运行程序的方式:
all: test
instr.o: instr.c
gcc -ggdb -Wall -c instr.c
test.o: test.c
gcc -ggdb -Wall -c test.c
test: test.o instr.o
gcc -ldl -o test test.o instr.o
clean:
rm -f *.o test
当我构建这个程序,然后执行 objdump -t test | grep testing
时,我看到符号 testing
确实存在:
08048632 g F .text 00000020 testing
然而我的程序的输出是错误的:
./test: undefined symbol: testing
我不确定我做错了什么。如果有人能阐明这个问题,我将不胜感激。
我认为您做不到,dlsym
适用于导出的符号。因为您在 NULL
(当前映像)上执行 dlsym
,所以即使符号存在于可执行 ELF 映像中,它们也不会导出(因为它不是共享库)。
为什么不直接调用它,让链接器来处理呢?使用 dlsym
从与 dlsym
调用相同的图像中获取符号是没有意义的。如果您的 testing
符号位于您使用 dlopen
链接或加载的共享库中,那么您将能够检索它。
我相信在构建可执行文件时还有一种导出符号的方法(-Wl,--export-dynamic
,正如 Brandon 在评论中提到的那样),但我不确定您为什么要这样做。
我在我的代码中遇到了类似的问题。
我做了以下导出符号的操作
#ifndef EXPORT_API
#define EXPORT_API __attribute__ ((visibility("default")))
#endif
现在,对于每个函数定义,我都使用了上述属性。
例如之前的代码是
int func() { printf(" I am a func %s ", __FUNCTION__ ) ;
我改成了
EXPORT_API int func() { printf(" I am a func %s ", __FUNCTION__ ) ;
现在可以了。
dlsym 在此之后没有给出任何问题。
希望这对你也有用。
我正在使用 dlsym 在我的程序中查找符号,但它总是 return 为 NULL,这是我没有预料到的。根据联机帮助页,如果出现某种错误,或者符号确实为 NULL,dlsym 可能 return NULL。就我而言,我遇到了一个错误。我将向您展示我今晚制作的 MCVE。
这里是instr.c的内容:
#include <stdio.h>
void * testing(int i) {
printf("You called testing(%d)\n", i);
return 0;
}
一个非常简单的东西,只包含一个不起眼的示例函数。
这里是test.c的内容:
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
typedef void * (*dltest)(int);
int main(int argc, char ** argv) {
/* Declare and set a pointer to a function in the executable */
void * handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
dlerror();
dltest fn = dlsym(handle, "testing");
if(fn == NULL) {
printf("%s\n", dlerror());
dlclose(handle);
return 1;
}
dlclose(handle);
return 0;
}
当我使用调试器逐步执行代码时,我看到 dlopen returning 一个句柄。根据联机帮助页,If filename is NULL, then the returned handle is for the main program.
所以如果我 link 一个名为 testing
的符号进入主程序,dlsym 应该找到它,对吗?
这是我编译和link运行程序的方式:
all: test
instr.o: instr.c
gcc -ggdb -Wall -c instr.c
test.o: test.c
gcc -ggdb -Wall -c test.c
test: test.o instr.o
gcc -ldl -o test test.o instr.o
clean:
rm -f *.o test
当我构建这个程序,然后执行 objdump -t test | grep testing
时,我看到符号 testing
确实存在:
08048632 g F .text 00000020 testing
然而我的程序的输出是错误的:
./test: undefined symbol: testing
我不确定我做错了什么。如果有人能阐明这个问题,我将不胜感激。
我认为您做不到,dlsym
适用于导出的符号。因为您在 NULL
(当前映像)上执行 dlsym
,所以即使符号存在于可执行 ELF 映像中,它们也不会导出(因为它不是共享库)。
为什么不直接调用它,让链接器来处理呢?使用 dlsym
从与 dlsym
调用相同的图像中获取符号是没有意义的。如果您的 testing
符号位于您使用 dlopen
链接或加载的共享库中,那么您将能够检索它。
我相信在构建可执行文件时还有一种导出符号的方法(-Wl,--export-dynamic
,正如 Brandon 在评论中提到的那样),但我不确定您为什么要这样做。
我在我的代码中遇到了类似的问题。
我做了以下导出符号的操作
#ifndef EXPORT_API
#define EXPORT_API __attribute__ ((visibility("default")))
#endif
现在,对于每个函数定义,我都使用了上述属性。
例如之前的代码是
int func() { printf(" I am a func %s ", __FUNCTION__ ) ;
我改成了
EXPORT_API int func() { printf(" I am a func %s ", __FUNCTION__ ) ;
现在可以了。
dlsym 在此之后没有给出任何问题。
希望这对你也有用。