如何使函数具有库内部链接?

2024-02-03

例如,如果我有两个文件foo.c and bar.o, and foo.c包含一个函数foo()引用一个函数bar() in bar.o:

int foo(int x) { x = bar(x); /* ... */ }

如何编译公开的静态或动态库foo(),但不暴露bar()?换句话说,我想要bar()仅在库内链接。


使用标准 C,您只能导出或不导出函数,没有“仅导出到这些文件”选项。所以基本上你必须移动bar() to foo.c并将其声明为static。如果您希望将文件分开,一个丑陋的黑客将是#include它来自foo.c(并且不编译bar.o)…

使用标准 C 范围之外的工具,您可以在链接时或链接后从库中删除公共导出。下面显示了一些链接器解决方案,使用 GCC 和 clang(在可以修改代码的情况下),您可以通过在函数前面添加非标准属性来隐藏函数:__attribute__ ((visibility ("hidden")))– 与此等效的编译单元范围将是选项-fvisibility=hidden编译时,例如bar.c.

C 解决方法

如果您可以自由编辑 C 代码,标准 C 中的解决方法是bar() static within bar.c并传递一个函数指针给它以供使用foo()通过某种方式,例如导出一个指向struct包含函数指针(以及任何其他“私有”数据),并且不暴露函数的详细信息struct在仅供您的库使用的私有标头之外。

例如:

In bar.h(私人的,不要与图书馆的用户共享):

struct bar_private_struct { int (*bar)(int); };
extern struct bar_private_struct *bar_functions;

In 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;

In foo.c:

#include "bar.h"
int foo (int x) { x = bar_functions->bar(x); /* … */ }

在此解决方案中,将有一个名为的导出指针bar_functions,但没有通过此导出揭示有关所指向的数据/函数的详细信息。无法访问bar.h库的用户必须对内容进行逆向工程才能正确调用“私有”函数。如果有多个“私有”函数,此方法还可以将它们压缩为单个导出指针,从而消除导出列表中的混乱。

链接器解决方案

通过探索特定的链接器,我找到了一种从动态库中排除特定符号的方法:

与 GNUld,创建版本脚本,如libfoobar.version:

FOOBAR {
    global: *;
    local: bar;
};

调用通过gcc:

gcc -shared -o libfoobar.so foo.o bar.o -Wl,-version-script=libfoobar.version

随着clang ld(在 OS X 上)创建未导出符号的列表,例如unexported(每行一个符号):

_bar

调用通过clang:

clang -shared -o libfoobar.dylib foo.o bar.o -Wl,-unexported_symbols_list,unexported

在这两种情况下,函数bar是隐藏的并且外部无法调用,但是foo保持运行(并调用bar内部),即使两者在各自的源(和对象)文件中具有相同的外部可见性。

测试代码,foo.c:

int bar(int x);
int foo (int x) { return bar(x) * 3; }

bar.c:

int bar (int x) { return x * 2; }

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;
}

测试用例:

# 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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使函数具有库内部链接? 的相关文章

随机推荐