如何使函数具有库内部链接? [英] How can I make a function have library-internal linkage?

查看:0
本文介绍了如何使函数具有库内部链接?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

例如,如果我有两个文件foo.cbar.o,并且foo.c包含引用bar.o中的函数bar()的函数foo()

int foo(int x) { x = bar(x); /* ... */ }
如何编译公开foo()但不公开bar()的静态或动态库?换句话说,我希望bar()仅在库内链接。

推荐答案

使用标准C时,您只能导出函数或不导出,没有"仅导出到这些文件"选项。因此,基本上您必须将bar()移动到foo.c,并将其声明为static。如果您希望将文件分开,一个难看的方法是从foo.c(而不编译bar.o)…中删除该文件

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

C解决办法

如果您可以自由编辑C代码,则标准C中的一个解决办法是在bar.c内创建bar()static,并通过某些方法将函数指针传递给foo()中使用,例如,将指针导出到包含函数指针(和任何其他"私有"数据)的struct,并且不要在仅由您的库使用的私有标头之外公开struct的详细信息。

例如:

bar.h(私有,不与库用户共享):

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

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;

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

使用clangld(在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
", foo(2));
    (void) printf("bar(2) = %d
", 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

这篇关于如何使函数具有库内部链接?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆