在库中隐藏符号名称 [英] Hiding symbol names in library

查看:217
本文介绍了在库中隐藏符号名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想隐藏与最后一位用户无关的符号名称,并在共享库或静态库中仅显示API。我有一个这样的简单代码:

  int f_b1(){
return 21;
}

int f_b3(){
return f_b1();
}

我应用了所有 here ,例如使用 __ attribute__( (visibility(hidden))) static 数据,但没有得到成功的结果。我的操作系统是Ubuntu和x86_64 GNU / Linux处理器。我们在使用gcc编译时使用特殊选项吗?我使用 nm 命令列出库的模块和函数。在我上面的例子中,我只想让可见的 f_b3 函数。当我使用属性hidden 时,宏编译器不会给出任何错误,但函数依然存在于由 nm 命令输出的列表中。

解决方案

visibility(hidden)属性不是
中压缩
一个符号作为目标文件,并且不能阻止符号被 nm 提取。它只是
指示动态链接器,该符号不能从包含它的
a共享库之外调用。



考虑源文件<$ c

$ p $ int f_b1(){$ b $> $ c> file.c 包含您的示例函数:

b返回21;
}

int f_b3(){
return f_b1();
}

编译文件:

  gcc -c -o file.o file.c 



<运行 nm file.o 来列出符号。输出:

  0000000000000000 T f_b1 
000000000000000b T f_b3
objdump -t file.o 以获得关于这些符号的更完整的信息。输出:

  file.o:文件格式elf64-x86-64 

符号表:
0000000000000000 l df * ABS * 0000000000000000 file.c
0000000000000000 ld .text 0000000000000000 .text
0000000000000000 ld .data 0000000000000000 .data
0000000000000000 ld .bss 0000000000000000 .bss
0000000000000000 ld .note.GNU-stack 0000000000000000 .note.GNU-stack
0000000000000000 ld .eh_frame 0000000000000000 .eh_frame
0000000000000000 ld .comment 0000000000000000 .comment
0000000000000000 g F .text 000000000000000b f_b1
000000000000000b g F .text 000000000000000b f_b3

这里我们看到 f_b1 f_b3 是全局(g)函数(F)在 .text


现在修改这个文件:

  __属性__( (visibility(hidden)))int f_b1(void){
return 21;

$ b __attribute __((visibility(hidden)))int f_b3(void){
return f_b1();

再次运行 objdump

  file.o:文件格式elf64-x86-64 

符号表:
0000000000000000 l df * ABS * 0000000000000000 file.c
0000000000000000 ld .text 0000000000000000 .text
0000000000000000 ld .data 0000000000000000 .data
0000000000000000 ld .bss 0000000000000000 .bss
0000000000000000 ld .note.GNU-stack 0000000000000000 .note.GNU-stack
0000000000000000 ld .eh_frame 0000000000000000 .eh_frame
0000000000000000 ld .comment 0000000000000000 .comment
0000000000000000 g F .text 000000000000000b .hidden f_b1
000000000000000b g F .text 000000000000000b .hidden f_b3

输出是一样的,除了符号 f_b1 f_b3 现在标记为
.hidden 。它们仍然具有外部(全局)链接,并且可以静态地从包含它们的库中的其他模块(例如
)调用,但是
不能从该库外部以dymamically方式调用。



因此,如果你想隐藏 f_b1 f_b3 动态链接在共享
库中,您可以使用 visibility(hidden),如图所示。



如果您想隐藏 static 链接中的 f_b1 f_b3 静态
库中,您无法使用 visibility 属性来完成此操作。



在静态库的情况下,您可以隐藏一个符号,只是给它
内部而不是外部链接。做到这一点的方法是在
标准静态关键字前添加。但内部链接意味着符号
仅在其自己的编译单元中可见:它不能从
其他模块中引用。它根本不可用于链接器。



再次修改 file.c ,如下所示:

  static int f_b1(void){
return 21;
}

static int f_b3(void){
return f_b1();
}

并运行 objump 再次:

  file.o:文件格式elf64-x86-64 

符号表:
0000000000000000 l df * ABS * 0000000000000000 file.c
0000000000000000 ld .text 0000000000000000 .text
0000000000000000 ld .data 0000000000000000 .data
0000000000000000 ld .bss 0000000000000000 .bss
0000000000000000 l F .text 000000000000000b f_b1
000000000000000b l F .text 000000000000000b f_b3
0000000000000000 ld .note.GNU stack 0000000000000000 .note.GNU stack
0000000000000000 ld .eh_frame 0000000000000000 .eh_frame
0000000000000000 ld .comment 0000000000000000 .comment

您看到 f_b1 f_b3 仍被报告为 .text
部分中的函数,但现在分类为 local (l),不是全局的。这是内部联系。
运行 nm file.o ,输出结果如下:

  0000000000000000 t f_b1 
000000000000000b t f_b3

与原始文件相同,除了'T'标志
而不是'我们现在有't'标志。两个标志都表示该符号位于 .text 部分中,
,但'T'表示它是全局的,'t'表示它是本地的。



很明显,您想要 nm 报告此文件的是完全没有符号
现在你应该明白如果它存在于
file.o中, nm file.o 会报告一个符号,但它的存在与静态或动态链接是否可见
无关。



为了使函数符号消失,再次编译 file.c
(仍然带有 static 关键字) ,这次启用优化:

  gcc -c -O1 -o file.o file.c 
code>

现在, objdump 报告:

  file.o:文件格式elf64-x86-64 

符号表:
0000000000000000 l df * ABS * 0000000000000000文件。 c
0000000000000000 ld .text 0000000000000000 .text
0000000000000000 ld .data 0000000000000000 .data
0000000000000000 ld .bss 0000000000000000 .bss
0000000000000000 ld.note.GNU-stack 0000000000000000 .note。 GNU-stack
0000000000000000 ld .comment 000000 0000000000 .comment

f_b1 f_b3 不见了, nm file.o 什么也没有报告。为什么?
因为 static 告诉编译器这些符号只能从它正在编译的文件中调用
,并且优化决定了
不需要提及他们;所以编译器将它们从
目标代码中删除。但是,如果它们还没有被链接器隐藏,没有
优化,那么我们就无法优化它们。



底线:没关系无论是 nm 都可以提取符号。如果
符号是本地/内部符号,则无法静态或动态链接。
如果符号被标记为 .hidden ,那么它不能动态链接。您
可以使用 visibility(hidden)来标记符号 .hidden 。使用标准的
static 关键字来制作一个符号local / internal。


I want to hide symbol names which are not relevant to the last user and make visible only APIs in my shared or static library. I have a simple code like that:

int f_b1(){
return 21 ;
}

int f_b3(){
return f_b1() ;
}

I applied the all methods stated here such as using __attribute__ ((visibility ("hidden"))) and static data but got no successful result. My operating system is Ubuntu and x86_64 GNU/Linux processor. Do we use special options while compiling with gcc? I am listing modules and function of libraries with nm command. In my example above I only want to make visible f_b3 function. When I use attribute hidden macro compiler does not give any error but the function still exists in list outputted by nm command.

解决方案

The visibility("hidden") attribute does not suppress a symbol from an object file and cannot prevent a symbol being extracted by nm. It just instructs the dynamic linker that the symbol cannot be called from outside a shared library that contains it.

Consider a source file file.c containing your example functions:

int f_b1(){
return 21 ;
}

int f_b3(){
return f_b1() ;
}

Compile the file:

gcc -c -o file.o file.c

Run nm file.o to list the symbols. Output:

0000000000000000 T f_b1
000000000000000b T f_b3

Now run objdump -t file.o for fuller information about the symbols. Output:

file.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 file.c
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 l    d  .data  0000000000000000 .data
0000000000000000 l    d  .bss   0000000000000000 .bss
0000000000000000 l    d  .note.GNU-stack    0000000000000000 .note.GNU-stack
0000000000000000 l    d  .eh_frame  0000000000000000 .eh_frame
0000000000000000 l    d  .comment   0000000000000000 .comment
0000000000000000 g     F .text  000000000000000b f_b1
000000000000000b g     F .text  000000000000000b f_b3

Here we see that f_b1 and f_b3 are global (g) functions (F) in the .text section.

Now modify the file like this:

__attribute__((visibility ("hidden"))) int f_b1(void){
return 21 ;
}

__attribute__((visibility ("hidden"))) int f_b3(void){
return f_b1() ;
}

Run objdump again:

file.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 file.c
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 l    d  .data  0000000000000000 .data
0000000000000000 l    d  .bss   0000000000000000 .bss
0000000000000000 l    d  .note.GNU-stack    0000000000000000 .note.GNU-stack
0000000000000000 l    d  .eh_frame  0000000000000000 .eh_frame
0000000000000000 l    d  .comment   0000000000000000 .comment
0000000000000000 g     F .text  000000000000000b .hidden f_b1
000000000000000b g     F .text  000000000000000b .hidden f_b3

The output is the same, except that the symbols f_b1 and f_b3 are now marked .hidden. They still have external (global) linkage and could be statically called, for example, from other modules within a library that contains them, but could not be dymamically called from outside that library.

So, if you want to conceal f_b1 and f_b3 from dynamic linkage in a shared library, you can use visibility ("hidden") as shown.

If you want to conceal f_b1 and f_b3 from static linkage in a static library, you cannot use the visibility attribute to do that at all.

In the case of a static library, you can "hide" a symbol only be giving it internal instead of external linkage. The way to do that is by prefixing the standard static keyword. But internal linkage means that the symbol is visible only within its own compilation unit: it can't be referenced from other modules. It is not available to the linker at all.

Modify file.c again, like this:

static int f_b1(void){
return 21 ;
}

static int f_b3(void){
return f_b1() ;
}

And run objump again:

file.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 file.c
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 l    d  .data  0000000000000000 .data
0000000000000000 l    d  .bss   0000000000000000 .bss
0000000000000000 l     F .text  000000000000000b f_b1
000000000000000b l     F .text  000000000000000b f_b3
0000000000000000 l    d  .note.GNU-stack    0000000000000000 .note.GNU-stack
0000000000000000 l    d  .eh_frame  0000000000000000 .eh_frame
0000000000000000 l    d  .comment   0000000000000000 .comment

You see that f_b1 and f_b3 are still reported as functions in the .text section, but are now classified local (l), not global. That is internal linkage. Run nm file.o and the output is:

0000000000000000 t f_b1
000000000000000b t f_b3

That is the same as for the original file, except that instead of 'T' flags we now have 't' flags. Both flags mean that the symbol is in the .text section, but 'T' means it is global and 't' means it is local.

Apparently, what you would like nm to report for this file is no symbols at all. You should now understand that nm file.o will report a symbol if it exists in file.o, but its existence has got nothing to do with whether it is visible for static or dynamic linkage.

To make the function symbols disappear, compile file.c yet again (still with the static keyword), this time with optimisation enabled:

gcc -c -O1 -o file.o file.c

Now, objdump reports:

file.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 file.c
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 l    d  .data  0000000000000000 .data
0000000000000000 l    d  .bss   0000000000000000 .bss
0000000000000000 l    d  .note.GNU-stack    0000000000000000 .note.GNU-stack
0000000000000000 l    d  .comment   0000000000000000 .comment

f_b1 and f_b3 are gone, and nm file.o reports nothing at all. Why? Because static tells the compiler that these symbols can only be called from within the file it is compiling, and optimisation decides that there is no need to refer to them; so the compiler eliminates them from the object code. But if they weren't already invisible to linker, without optimisation, then we couldn't optimise them away.

Bottom line: It doesn't matter whether nm can extract a symbol. If the symbol is local/internal, it can't be linked, either statically or dynamically. If the symbol is marked .hidden then it can't be dynamically linked. You can use visibility("hidden") to mark a symbol .hidden. Use the standard static keyword to make a symbol local/internal.

这篇关于在库中隐藏符号名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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