在库中隐藏符号名称 [英] Hiding symbol names in library
问题描述
我想隐藏与最后一位用户无关的符号名称,并在共享库或静态库中仅显示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
命令输出的列表中。
中压缩一个符号作为目标文件,并且不能阻止符号被 nm
提取。它只是
指示动态链接器,该符号不能从包含它的
a共享库之外调用。
考虑源文件<$ c
$ p $ int f_b1(){$ b $> $ c> file.c
包含您的示例函数:
}
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")))
andstatic
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 withnm
command. In my example above I only want to make visiblef_b3
function. When I useattribute hidden
macro compiler does not give any error but the function still exists in list outputted bynm
command.解决方案The
visibility("hidden")
attribute does not suppress a symbol from an object file and cannot prevent a symbol being extracted bynm
. 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
andf_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
andf_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
andf_b3
from dynamic linkage in a shared library, you can usevisibility ("hidden")
as shown.If you want to conceal
f_b1
andf_b3
from static linkage in a static library, you cannot use thevisibility
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
andf_b3
are still reported as functions in the.text
section, but are now classified local (l), not global. That is internal linkage. Runnm 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 thatnm file.o
will report a symbol if it exists infile.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 thestatic
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
andf_b3
are gone, andnm file.o
reports nothing at all. Why? Becausestatic
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 usevisibility("hidden")
to mark a symbol.hidden
. Use the standardstatic
keyword to make a symbol local/internal.这篇关于在库中隐藏符号名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!