dlsym与C++

先从百度百科把dlsym的简介拉过来:

功能:根据动态链接库操作句柄与符号,返回符号对应的地址;

函数定义:void*dlsym(void*handle,constchar*symbol);

函数描述:dlsym(dynamic library symbol) 根据 动态链接库 操作句柄(handle)与符号(symbol),返回符号对应的地址。使用这个函数不但可以获取函数地址,也可以获取变量地址。 handle:由dlopen打开动态链接库后返回的指针; symbol:要求获取的函数或全局变量的名称。 返回值: void* 指向函数的地址,供调用使用。

现在来看三个示例,main.c、test_C.c、test_C++.cpp:

/**************
main.c
gcc main.c -ldl -o main
**************/
#include <stdio.h>
#include <dlfcn.h>

void main() {
	void *handle;
	void(*test)();
	handle = dlopen("/home/auo/Study/C/name mangling/libtest_C.so", RTLD_NOW);
	if(!handle)
		return -1;
	test = (void(*)())dlsym(handle, "test");
	printf("test in C addr:\t%x\n", test);
	test();


	handle = dlopen("/home/auo/Study/C/name mangling/libtest_C++.so", RTLD_NOW);
	if(!handle)
		return -1;
	test = (void(*)())dlsym(handle, "test");
	printf("test in C++ addr:\t%x\n", test);
	test();
}

/**************
test_C.c
gcc test_C.c -fPIC -shared -o libtest_C.so
**************/
#include <stdio.h>

void test() {
	printf("Call test in C\n");
}

/**************
test_C++.cpp
g++ test_C++.cpp -fPIC -shared -o libtest_C++.so
**************/
#include <stdio.h>

void test() {
	printf("Call test in C++\n");
}

编译完成后得到可执行程序main,动态库文件libtest_C.so、libtest_C++.sp。在终端执行main函数结果如下:

dlsym函数并没有成功找到由g++编译后的libtest_C++.so里的函数test的地址,我们知道dlsym函数是通过查找指定动态库中的符号表来获得符号地址的,我们现在用readelf查看下libtest_C++.so的符号表:

dlsym与C++_第1张图片

清楚的看到并没有符号test的信息,而只有_Z4testv的符号信息,所以当dlsym查找符号test的时候自然就返回0了。我们再看一下libtest_C.so的符号表:

dlsym与C++_第2张图片

可以看到libtest_C.so符号表是存在test符号的。

那么,为什么g++编译器会将符号test更名为_Z4testv呢,这个就是因为name mangling机制。具体来讲就是因为C++存在函数重载,C++编译器在编译的时候会根据一个函数的名字、参数、返回值来生产一个独一无二的符号名字,这样才Link的时候,才能区分出不同的函数。extern "C" void test()可以避免name mangling(事实上,就是告诉编译器这个函数按照C的规则进行编译,自然就不会发生name mangling)。

你可能感兴趣的:(name,dlsym,mangling)