您的位置:首页 > 其它

GCC编译之如何控制共享文件导出符号

2012-10-24 17:49 615 查看

2012-05-19 11:21
191人阅读 评论(0)
收藏
举报

目录(?)[+]

背景
全局符号介入
控制共享文件的导出符号
参考

背景

前不久在调试一个与导出符号相关的bug,问题大概如此:

模块A.so在堆上构造了一个对象即
CTest *one = new CTest; , CTest在A.so定义,后来使用one->AMemFunc();,即调用一个成员函数时崩溃。原来在另一个模块B.so(比A.so先加载)中,也有一个同名的CTest定义,但是却没有一个叫AMemFunc的成员函数,因此崩溃。

那为什么A.so的CTest会被解析到B.so呢?

全局符号介入

这种一个共享对象里面的全局符号被另一个共享对象的同名全局符号覆盖的现象又被称为共享对象全局符号介入(Global Symbol Interpose)。对于全局符号介入这个问题,linux下的动态连接器是这样处理的:它定义了一个规则,那就是当一个符号需要被加入全局符号表时,如果相同的符号名已经存在,则后加入的符号被忽略。

其实,在上述的情形里,B.so的CTest是不需要导出的,GCC编译的so默认是导出所有符号,这与MS
VS刚好相反。如何控制so文件的导出符号呢?

控制共享文件的导出符号

常用方法有两种:

1.使用GCC 的C++ visibility
支持。

把__attribute__ ((visibility ("default"))) 放置在你希望导出的struct,class,function的声明处,然后修改你的GCC构建参数,使用-fvisibility=hidden参数编译每一个源代码文件。GCC编译源代码文件的visibility默认属性是public,所以默认所有符号都导出来了,设置为hidden后然后在需要导出的地方加__attribute__
((visibility ("default"))),以达到控制导出符号的目的。在跨平台代码的编写中,常使用下面类似的宏定义来简化上述过程。

#if defined _WIN32 || defined __CYGWIN__
#ifdef BUILDING_DLL
#ifdef __GNUC__
#define DLL_PUBLIC __attribute__ ((dllexport))
#else
#define DLL_PUBLIC __declspec(dllexport) // Note: actually gcc seems to also supports this syntax.
#endif
#else
#ifdef __GNUC__
#define DLL_PUBLIC __attribute__ ((dllimport))
#else
#define DLL_PUBLIC __declspec(dllimport) // Note: actually gcc seems to also supports this syntax.
#endif
#endif
#define DLL_LOCAL
#else
#if __GNUC__ >= 4
#define DLL_PUBLIC __attribute__ ((visibility ("default")))
#define DLL_LOCAL __attribute__ ((visibility ("hidden")))
#else
#define DLL_PUBLIC
#define DLL_LOCAL
#endif
#endif

extern "C" DLL_PUBLIC void function(int a);
class DLL_PUBLIC SomeClass
{
int c;
DLL_LOCAL void privateMethod(); // Only for use within this DSO
public:
Person(int _c) : c(_c) { }
static void foo(int a);
};
2.使用链接参数 --retain-symbols-file
控制静态符号表,--version-script 控制动态符号表,后面都是接含有导出符号的文件的名字。这两个参数在移植windows下的动态库很有用,windows下的DEF文件能控制导出符号,我们可以在linux下的构建脚本中解析DEF生成一个导出符号文件,然后作为retain-symbols-file,version-script的参数。示例如下:

这是a1.c文件

[cpp]
view plaincopyprint?

#include <stdio.h>
#include <stdlib.h>

void func_1()
{
printf("a1 :: func_1\n");

}

void func_2()

{
printf("a1 :: func_2\n");

}

void func_3()
{
printf("a1 :: func_3\n");

}

#include <stdio.h>
#include <stdlib.h>

void func_1()
{
printf("a1 :: func_1\n");
}

void func_2()
{
printf("a1 :: func_2\n");
}

void func_3()
{
printf("a1 :: func_3\n");
}

这是a1.sym文件,控制静态导出符号

[cpp]
view plaincopyprint?

func_1 func_3
func_1
func_3

这是a1.map文件,控制动态导出符号

global表示要导出的符号,local表示不导出的,*表示都不导出

[cpp]
view plaincopyprint?

{ global: func_1; func_2; local: *; };
{
global:
func_1;
func_2;
local: *;
};

生成共享库

[cpp]
view plaincopyprint?

gcc a1.c -shared -o liba1.so -Wl,--retain-symbols-file=a1.sym -Wl,--version-script=a1.map
gcc a1.c -shared -o liba1.so -Wl,--retain-symbols-file=a1.sym -Wl,--version-script=a1.map

查看符号表

[cpp]
view plaincopyprint?

readelf -s liba1.so

readelf -s liba1.so


[cpp]
view plaincopyprint?

Symbol table '.dynsym' contains 7 entries:

Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.1.3 (2)

2: 00000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.0 (3)

3: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
4: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses

5: 00000400 20 FUNC GLOBAL DEFAULT 11 func_2
6: 000003ec 20 FUNC GLOBAL DEFAULT 11 func_1

Symbol table '.symtab' contains 27 entries:

Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000114 0 SECTION LOCAL DEFAULT 1
2: 00000138 0 SECTION LOCAL DEFAULT 2
3: 0000015c 0 SECTION LOCAL DEFAULT 3
4: 000001cc 0 SECTION LOCAL DEFAULT 4
5: 00000232 0 SECTION LOCAL DEFAULT 5
6: 00000240 0 SECTION LOCAL DEFAULT 6
7: 00000270 0 SECTION LOCAL DEFAULT 7
8: 000002c0 0 SECTION LOCAL DEFAULT 8
9: 000002d0 0 SECTION LOCAL DEFAULT 9
10: 00000300 0 SECTION LOCAL DEFAULT 10
11: 00000330 0 SECTION LOCAL DEFAULT 11
12: 00000468 0 SECTION LOCAL DEFAULT 12
13: 00000482 0 SECTION LOCAL DEFAULT 13
14: 000004ac 0 SECTION LOCAL DEFAULT 14
15: 000004d8 0 SECTION LOCAL DEFAULT 15
16: 00001f0c 0 SECTION LOCAL DEFAULT 16
17: 00001f14 0 SECTION LOCAL DEFAULT 17
18: 00001f1c 0 SECTION LOCAL DEFAULT 18
19: 00001f20 0 SECTION LOCAL DEFAULT 19
20: 00001fe8 0 SECTION LOCAL DEFAULT 20
21: 00001ff4 0 SECTION LOCAL DEFAULT 21
22: 00002008 0 SECTION LOCAL DEFAULT 22
23: 0000200c 0 SECTION LOCAL DEFAULT 23
24: 00000000 0 SECTION LOCAL DEFAULT 24
25: 00000414 20 FUNC LOCAL DEFAULT 11 func_3
26: 000003ec 20 FUNC GLOBAL DEFAULT 11 func_1

Symbol table '.dynsym' contains 7 entries:
Num:    Value  Size Type    Bind   Vis      Ndx Name
0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
1: 00000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@GLIBC_2.1.3 (2)
2: 00000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.0 (3)
3: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
4: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
5: 00000400    20 FUNC    GLOBAL DEFAULT   11 func_2
6: 000003ec    20 FUNC    GLOBAL DEFAULT   11 func_1

Symbol table '.symtab' contains 27 entries:
Num:    Value  Size Type    Bind   Vis      Ndx Name
0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
1: 00000114     0 SECTION LOCAL  DEFAULT    1
2: 00000138     0 SECTION LOCAL  DEFAULT    2
3: 0000015c     0 SECTION LOCAL  DEFAULT    3
4: 000001cc     0 SECTION LOCAL  DEFAULT    4
5: 00000232     0 SECTION LOCAL  DEFAULT    5
6: 00000240     0 SECTION LOCAL  DEFAULT    6
7: 00000270     0 SECTION LOCAL  DEFAULT    7
8: 000002c0     0 SECTION LOCAL  DEFAULT    8
9: 000002d0     0 SECTION LOCAL  DEFAULT    9
10: 00000300     0 SECTION LOCAL  DEFAULT   10
11: 00000330     0 SECTION LOCAL  DEFAULT   11
12: 00000468     0 SECTION LOCAL  DEFAULT   12
13: 00000482     0 SECTION LOCAL  DEFAULT   13
14: 000004ac     0 SECTION LOCAL  DEFAULT   14
15: 000004d8     0 SECTION LOCAL  DEFAULT   15
16: 00001f0c     0 SECTION LOCAL  DEFAULT   16
17: 00001f14     0 SECTION LOCAL  DEFAULT   17
18: 00001f1c     0 SECTION LOCAL  DEFAULT   18
19: 00001f20     0 SECTION LOCAL  DEFAULT   19
20: 00001fe8     0 SECTION LOCAL  DEFAULT   20
21: 00001ff4     0 SECTION LOCAL  DEFAULT   21
22: 00002008     0 SECTION LOCAL  DEFAULT   22
23: 0000200c     0 SECTION LOCAL  DEFAULT   23
24: 00000000     0 SECTION LOCAL  DEFAULT   24
25: 00000414    20 FUNC    LOCAL  DEFAULT   11 func_3
26: 000003ec    20 FUNC    GLOBAL DEFAULT   11 func_1


显而易见:动态符号表中是函数func_2,func_1,静态符号表中是func_3,func_1
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: