符号可见性无法按预期工作

时间:2016-06-21 01:55:22

标签: c linker clang

我有一个这样的示例程序:

#include <stdio.h>

#if 1
#define FOR_EXPORT __attribute__ ((visibility("hidden")))
#else
#define FOR_EXPORT
#endif

FOR_EXPORT void mylocalfunction1(void)
{
    printf("function1\n");
}

void mylocalfunction2(void)
{
    printf("function2\n");
}

void mylocalfunction3(void)
{
    printf("function3\n");
}

void printMessage(void)
{
    printf("Running the function exported from the shared library\n");
}

使用

编译它
gcc -shared -fPIC -fvisibility=hidden -o libdefaultvisibility.so defaultvisibility.c

编译结束后,我做了:

$ nm libdefaultvisibility.so
nm libdefaultvisibility.so 
0000000000000eb0 t _mylocalfunction1
0000000000000ed0 t _mylocalfunction2
0000000000000ef0 t _mylocalfunction3
0000000000000f10 t _printMessage
                 U _printf
                 U dyld_stub_binder

就我所知,尽管-fvisibility=hidden所有符号都被导出,但这意味着。我所关注的这本书声称只应导出标有FOR_EXPORT的函数。

我看了几个其他资源,但是对于我正在进行的简单测试-fvisibility=hidden应该足够了。

我的铿锵版:

$ clang -v
clang -v
Apple LLVM version 7.3.0 (clang-703.0.31)
Target: x86_64-apple-darwin15.0.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

2 个答案:

答案 0 :(得分:8)

您误解了nm的输出。滚动浏览man nm,您就可以了 读取t标志表示符号是本地(静态)符号 text部分。链接器无法看到它。如果它是全球的(外部的) 标志为T。所以你的所有四个功能都是本地的。

对比:

$ clang -shared -fPIC -fvisibility=hidden -o libdefaultvisibility.so defaultvisibility.c
$ nm libdefaultvisibility.so | grep ' t '
0000000000000570 t deregister_tm_clones
0000000000000600 t __do_global_dtors_aux
0000000000200e08 t __do_global_dtors_aux_fini_array_entry
0000000000000640 t frame_dummy
0000000000200e00 t __frame_dummy_init_array_entry
0000000000000670 t mylocalfunction1
0000000000000690 t mylocalfunction2
00000000000006b0 t mylocalfunction3
00000000000006d0 t printMessage
00000000000005b0 t register_tm_clones   

删除-fvisibility=hidden

$ clang -shared -fPIC -o libdefaultvisibility.so defaultvisibility.c
$ nm libdefaultvisibility.so | grep ' t '
0000000000000600 t deregister_tm_clones
0000000000000690 t __do_global_dtors_aux
0000000000200e08 t __do_global_dtors_aux_fini_array_entry
00000000000006d0 t frame_dummy
0000000000200e00 t __frame_dummy_init_array_entry
0000000000000700 t mylocalfunction1
0000000000000640 t register_tm_clones
$ nm libdefaultvisibility.so | grep ' T '
0000000000000780 T _fini
00000000000005b0 T _init
0000000000000720 T mylocalfunction2
0000000000000740 T mylocalfunction3
0000000000000760 T printMessage

然后只有明确隐藏的mylocalfunction1仍然是本地的,而且 其他三个现在都是全球性的。

您不应期望标有__attribute__ ((visibility("hidden")))的符号 在任何情况下都将由共享库导出。属性意味着精确 它将,是否明确应用于符号,如本例所示, 或者在链接器选项-fvisibility=hidden存在的情况下默认获取。

如果您想通过visibility归因导出示例中的那个功能 你会:

#define FOR_EXPORT __attribute__ ((visibility("default")))

然后:

$ clang -shared -fPIC -fvisibility=hidden -o libdefaultvisibility.so defaultvisibility.c
$ nm libdefaultvisibility.so | grep ' T '
0000000000000720 T _fini
0000000000000550 T _init
00000000000006a0 T mylocalfunction1

它是全局的,因为显式归因会覆盖命令行选项, 你所有的其他职能都是本地的。也许是令人困惑的default可见度 总是公开

你可以在不诉诸visibility归属的情况下实现这一目标 不可移植 - 只需声明您想要导出为static的所有功能。然后是编译器 首先不会将它们暴露给链接器:

<强> foo.c的

#include <stdio.h>

void mylocalfunction1(void)
{
    printf("function1\n");
}

static void mylocalfunction2(void)
{
    printf("function2\n");
}

static void mylocalfunction3(void)
{
    printf("function3\n");
}

static void printMessage(void)
{
    printf("Running the function exported from the shared library\n");
}

再次获得: -

$ clang -shared -fPIC -o libfoo.so foo.c
$ nm libfoo.so | grep ' T '
00000000000006c0 T _fini
0000000000000550 T _init
00000000000006a0 T mylocalfunction1

虽然这种区别并没有在你的例子中感受到 应该理解,虽然链接器看不到本地/静态符号,并且(因此)动态链接不可用,但是全局/外部符号 可能会或可能不会可用于动态链接。 visibility 仅控制动态链接的全局符号的可用性。

答案 1 :(得分:2)

根据可见性的GCC Wiki,你应该:

  

在输出的DSO [动态共享对象]上使用nm -C -D进行前后比较   它的不同之处。

正如nm手册中所述:

  

-D将显示动态符号而不是普通符号

如果我完全按照您的方式编译代码,我会得到以下对象:

$ nm -C -D libdefaultvisibility.so
nm -C -D libdefaultvisibility.so
0000000000200a68 B __bss_start
                 w __cxa_finalize
0000000000200a68 D _edata
0000000000200a70 B _end
00000000000006c8 T _fini
                 w __gmon_start__
0000000000000518 T _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 w _Jv_RegisterClasses
                 U puts

如果我在没有-fvisibility=hidden选项的情况下编译它,我会得到对象:

$ nm -C -D libdefaultvisibility.so
nm -C -D libdefaultvisibility.so
0000000000200ae8 B __bss_start
                 w __cxa_finalize
0000000000200ae8 D _edata
0000000000200af0 B _end
0000000000000748 T _fini
                 w __gmon_start__
00000000000005a0 T _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
                 w _Jv_RegisterClasses
0000000000000712 T mylocalfunction2
0000000000000724 T mylocalfunction3
0000000000000736 T printMessage
                 U puts