Windows DLL或者Linux SO库中定义的函数分为内部函数和导出函数,导出的函数供其它程序模块调用。
在DLL中,在导出函数声明时,在函数前面加上_declspec(dllexport)关键字即可导出函数。
在SO中,也有类似的控制参数: -fvisibility=default|internal|hidden|protected
需要了解的是,在Linux下,源文件中的所有函数都有一个默认的visibility属性为public,在编译命令中加入-fvisibility=hidden参数,会将所有默认的public的属性变为hidden。此时,如果对函数设置__attribute__ ((visibility("default")))参数,使特定的函数仍然按默认的public属性处理,则-fvisibility=hidden参数不会对该函数起作用。
所以,设置了-fvisibility=hidden参数之后,只有设置了__attribute__ ((visibility("default")))的函数才是对外可见的,如此则效果等同于Visual Studio下的__declspec(dllexport)定义。
下面看一个例子:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
extern int test (int i);
__attribute ((visibility("default"))) int test2 (int i)
{
test(i);
printf("this is test2/n");
}
int test3 (int i)
{
printf("this is test 3/n");
}
此时调用以下命令编译:
gcc -shared -o test.so -fvisibility=hidden test.c
可以获得test.so文件,用以下命令查看so文件属性:
readelf -s test.so
得到以下结果:
Symbol table '.dynsym' contains 12 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
2: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
3: 00000000 0 NOTYPE GLOBAL DEFAULT UND test
4: 00000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.0 (2)
5: 00000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.1.3 (3)
6: 00002014 0 NOTYPE GLOBAL DEFAULT ABS _end
7: 0000200c 0 NOTYPE GLOBAL DEFAULT ABS _edata
8: 0000049c 31 FUNC GLOBAL DEFAULT 12 test2
9: 0000200c 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
10: 00000380 0 FUNC GLOBAL DEFAULT 10 _init
11: 00000508 0 FUNC GLOBAL DEFAULT 13 _fini
Symbol table '.symtab' contains 56 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 000000f4 0 SECTION LOCAL DEFAULT 1
2: 00000118 0 SECTION LOCAL DEFAULT 2
3: 0000015c 0 SECTION LOCAL DEFAULT 3
4: 00000198 0 SECTION LOCAL DEFAULT 4
5: 00000258 0 SECTION LOCAL DEFAULT 5
6: 000002e0 0 SECTION LOCAL DEFAULT 6
7: 000002f8 0 SECTION LOCAL DEFAULT 7
8: 00000328 0 SECTION LOCAL DEFAULT 8
9: 00000370 0 SECTION LOCAL DEFAULT 9
10: 00000380 0 SECTION LOCAL DEFAULT 10
11: 000003b0 0 SECTION LOCAL DEFAULT 11
12: 000003e0 0 SECTION LOCAL DEFAULT 12
13: 00000508 0 SECTION LOCAL DEFAULT 13
14: 00000524 0 SECTION LOCAL DEFAULT 14
15: 00000544 0 SECTION LOCAL DEFAULT 15
16: 00001f04 0 SECTION LOCAL DEFAULT 16
17: 00001f0c 0 SECTION LOCAL DEFAULT 17
18: 00001f14 0 SECTION LOCAL DEFAULT 18
19: 00001f18 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: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
26: 00001f04 0 OBJECT LOCAL DEFAULT 16 __CTOR_LIST__
27: 00001f0c 0 OBJECT LOCAL DEFAULT 17 __DTOR_LIST__
28: 00001f14 0 OBJECT LOCAL DEFAULT 18 __JCR_LIST__
29: 000003e0 0 FUNC LOCAL DEFAULT 12 __do_global_dtors_aux
30: 0000200c 1 OBJECT LOCAL DEFAULT 23 completed.7021
31: 00002010 4 OBJECT LOCAL DEFAULT 23 dtor_idx.7023
32: 00000460 0 FUNC LOCAL DEFAULT 12 frame_dummy
33: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
34: 00001f08 0 OBJECT LOCAL DEFAULT 16 __CTOR_END__
35: 00000544 0 OBJECT LOCAL DEFAULT 15 __FRAME_END__
36: 00001f14 0 OBJECT LOCAL DEFAULT 18 __JCR_END__
37: 000004d0 0 FUNC LOCAL DEFAULT 12 __do_global_ctors_aux
38: 00000000 0 FILE LOCAL DEFAULT ABS test.c
39: 00001ff4 0 OBJECT LOCAL HIDDEN ABS _GLOBAL_OFFSET_TABLE_
40: 00002008 0 OBJECT LOCAL HIDDEN 22 __dso_handle
41: 00001f10 0 OBJECT LOCAL HIDDEN 17 __DTOR_END__
42: 000004bb 20 FUNC LOCAL HIDDEN 12 test3
43: 00000497 0 FUNC LOCAL HIDDEN 12 __i686.get_pc_thunk.bx
44: 00001f18 0 OBJECT LOCAL HIDDEN ABS _DYNAMIC
45: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
46: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
47: 00000508 0 FUNC GLOBAL DEFAULT 13 _fini
48: 0000049c 31 FUNC GLOBAL DEFAULT 12 test2
49: 0000200c 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
50: 00000000 0 NOTYPE GLOBAL DEFAULT UND test
51: 00002014 0 NOTYPE GLOBAL DEFAULT ABS _end
52: 00000000 0 FUNC GLOBAL DEFAULT UND puts@@GLIBC_2.0
53: 0000200c 0 NOTYPE GLOBAL DEFAULT ABS _edata
54: 00000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@@GLIBC_2.1
55: 00000380 0 FUNC GLOBAL DEFAULT 10 _init
可以看出,so文件中包含test2()和test3()这两个函数,并且test2()的属性为default(即可见),而test3()的属性则为hidden(不可见)。
参考博客:
https://www.linuxidc.com/Linux/2013-04/82653.htm
如下这段定义,就是一个跨平台的库,同时定义了windows dll和linux so库下导出函数的方法:
#ifndef ASTRA_DEFINES_H
#define ASTRA_DEFINES_H
#ifdef __cplusplus
#define ASTRA_BEGIN_DECLS extern "C" {
#define ASTRA_END_DECLS }
#else
#define ASTRA_BEGIN_DECLS
#define ASTRA_END_DECLS
#endif
#if defined (_MSC_VER)
#define ASTRA_EXPORT __declspec(dllexport)
#define ASTRA_IMPORT __declspec(dllimport)
#define ASTRA_PUBLIC
#define ASTRA_LOCAL
#define ASTRA_CALLBACK __cdecl
#else
#if __GNUC__ >= 4 || defined (__clang__)
#define ASTRA_PUBLIC __attribute__ ((visibility ("default")))
#define ASTRA_LOCAL __attribute__ ((visibility ("hidden")))
#define ASTRA_EXPORT ASTRA_PUBLIC
#define ASTRA_IMPORT
#if defined(__x86_64__) || defined(__ANDROID__)
#define ASTRA_CALLBACK
#else
#define ASTRA_CALLBACK __attribute__ ((__cdecl__))
#endif
#else
#define ASTRA_PUBLIC
#define ASTRA_LOCAL
#define ASTRA_EXPORT
#define ASTRA_IMPORT
#define ASTRA_CALLBACK
#endif
#endif
#ifndef ASTRA_API
#ifdef ASTRA_BUILD
#define ASTRA_API ASTRA_PUBLIC ASTRA_EXPORT
#else
#define ASTRA_API ASTRA_IMPORT
#endif
#endif
#ifndef ASTRA_API_EX
#ifdef ASTRA_BUILD_EX
#define ASTRA_API_EX ASTRA_EXPORT
#else
#define ASTRA_API_EX ASTRA_IMPORT
#endif
#endif
#endif /* ASTRA_DEFINES_H */