Mat*_*att 4 c linker gcc compilation ld
举例来说,如果我有两个文件foo.c
和bar.o
,并foo.c
包含一个函数foo()
引用的函数bar()
中bar.o
:
int foo(int x) { x = bar(x); /* ... */ }
Run Code Online (Sandbox Code Playgroud)
如何编译暴露foo()
但不暴露的静态或动态库bar()
?换句话说,我想bar()
只在库内链接.
使用标准C,您只能导出函数,没有"仅导出到这些文件"选项.所以基本上你必须转移bar()
到foo.c
并声明它static
.如果你希望将文件分开,那么一个丑陋的黑客将#include
来自foo.c
(而不是编译bar.o
)...
使用标准C范围之外的工具,您可以在链接或链接后从库中删除公共导出.下面显示了一些链接器解决方案,并且使用GCC和clang(在您可以修改代码的情况下),您可以通过在前面添加非标准属性来隐藏函数:__attribute__ ((visibility ("hidden")))
- 编译单元范围内的等价物将是-fvisibility=hidden
编译时的选项,例如bar.c
.
如果你可以自由编辑C代码,标准C中的一个解决方法是bar()
static
在其中生成bar.c
并传递一个函数指针,以便foo()
通过某种方式使用它,例如,将指针导出到struct
包含函数指针(以及任何其他"私有"). "数据",并且不公开struct
仅由您的库使用的私有标头的外部细节.
例如:
在bar.h
(私人,不与图书馆的用户共享):
struct bar_private_struct { int (*bar)(int); };
extern struct bar_private_struct *bar_functions;
Run Code Online (Sandbox Code Playgroud)
在bar.c
:
#include "bar.h"
static int bar (int x) { /* … */ return x; }
static struct bar_private_struct functions = { bar };
struct bar_private_struct *bar_functions = &functions;
Run Code Online (Sandbox Code Playgroud)
在foo.c
:
#include "bar.h"
int foo (int x) { x = bar_functions->bar(x); /* … */ }
Run Code Online (Sandbox Code Playgroud)
在此解决方案中,将会有一个名为的导出指针bar_functions
,但不会通过此导出显示有关指向的数据/函数的详细信息.如果不访问bar.h
库的用户,则必须对内容进行反向工程以正确调用"私有"函数.在多个"私有"函数的情况下,这种方法也可以将它们压缩为单个导出指针,从导出列表中消除混乱.
探索特定的链接器,我找到了一种从动态库中排除特定符号的方法:
使用GNU ld
,创建一个版本脚本,例如libfoobar.version
:
FOOBAR {
global: *;
local: bar;
};
Run Code Online (Sandbox Code Playgroud)
调用gcc
:
gcc -shared -o libfoobar.so foo.o bar.o -Wl,-version-script=libfoobar.version
Run Code Online (Sandbox Code Playgroud)
使用clang
ld
(在OS X上)创建未导出符号的列表,例如unexported
(每行一个符号):
_bar
Run Code Online (Sandbox Code Playgroud)
调用clang
:
clang -shared -o libfoobar.dylib foo.o bar.o -Wl,-unexported_symbols_list,unexported
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,该函数bar
都是隐藏的,外部不可foo
调用bar
,但仍然可操作(并在内部调用),即使它们在各自的源(和对象)文件中具有相同的外部可见性.
测试代码,foo.c
:
int bar(int x);
int foo (int x) { return bar(x) * 3; }
Run Code Online (Sandbox Code Playgroud)
bar.c
:
int bar (int x) { return x * 2; }
Run Code Online (Sandbox Code Playgroud)
main.c
(在删除导出之前链接到库bar
):
#include <stdio.h>
int foo(int x);
int bar(int x);
int main () {
(void) printf("foo(2) = %d\n", foo(2));
(void) printf("bar(2) = %d\n", bar(2));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
测试用例:
# before unexporting bar:
$ nm -gU libfoobar.dylib
0000000000000f70 T _bar
0000000000000f50 T _foo
$ ./main
foo(2) = 12
bar(2) = 4
# after unexporting bar:
$ nm -gU libfoobar.dylib
0000000000000f50 T _foo
$ ./main
foo(2) = 12
dyld: lazy symbol binding failed: Symbol not found: _bar
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1434 次 |
最近记录: |