mus*_*vuz 9 gcc shared-libraries static-libraries
我想隐藏与最后一个用户无关的符号名称,并在我的共享库或静态库中仅显示可见的API.我有一个简单的代码:
int f_b1(){
return 21 ;
}
int f_b3(){
return f_b1() ;
}
Run Code Online (Sandbox Code Playgroud)
我应用了此处所述的所有方法,例如使用__attribute__ ((visibility ("hidden")))和static数据但未获得成功结果.我的操作系统是Ubuntu和x86_64 GNU/Linux处理器.在使用gcc编译时我们是否使用特殊选项?我用nm命令列出了库的模块和功能.在我上面的例子中,我只想制作可见的f_b3功能.当我使用attribute hidden宏编译器时不会给出任何错误但该函数仍然存在于nm命令输出的列表中.
Mik*_*han 30
该visibility("hidden")属性不会抑制目标文件中的符号,也不能阻止符号被提取nm.它只是指示动态链接器无法从包含它的共享库外部调用该符号.
考虑一个file.c包含示例函数的源文件:
int f_b1(){
return 21 ;
}
int f_b3(){
return f_b1() ;
}
Run Code Online (Sandbox Code Playgroud)
编译文件:
gcc -c -o file.o file.c
Run Code Online (Sandbox Code Playgroud)
运行nm file.o以列出符号.输出:
0000000000000000 T f_b1
000000000000000b T f_b3
Run Code Online (Sandbox Code Playgroud)
现在运行objdump -t file.o有关符号的更全面信息.输出:
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
Run Code Online (Sandbox Code Playgroud)
在这里我们看到f_b1并且f_b3是该.text
部分中的全局(g)函数(F).
现在修改文件如下:
__attribute__((visibility ("hidden"))) int f_b1(void){
return 21 ;
}
__attribute__((visibility ("hidden"))) int f_b3(void){
return f_b1() ;
}
Run Code Online (Sandbox Code Playgroud)
再跑objdump一次:
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
Run Code Online (Sandbox Code Playgroud)
输出是相同的,除了符号f_b1和f_b3现在标记
.hidden.它们仍然具有外部(全局)链接,并且可以静态调用,例如,来自包含它们的库中的其他模块,但不能从该库外部进行动态调用.
所以,如果你想隐瞒f_b1,并f_b3从动态链接的共享
库,你可以使用visibility ("hidden"),如图所示.
如果你想隐瞒f_b1,并f_b3从静态链接的静态
库,你不能使用visibility属性来做到这一点的.
对于静态库,您可以"隐藏"符号,只是将其赋予内部而不是外部链接.这样做的方法是在标准static关键字前加上前缀.但内部链接意味着符号仅在其自己的编译单元中可见:它不能从其他模块引用.链接器根本不可用.
file.c再次修改,如下所示:
static int f_b1(void){
return 21 ;
}
static int f_b3(void){
return f_b1() ;
}
Run Code Online (Sandbox Code Playgroud)
并objump再次运行:
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
Run Code Online (Sandbox Code Playgroud)
您可以看到f_b1并且f_b3仍然在该.text
部分中报告为函数,但现在分类为local(l),而不是global.这是内部联系.运行nm file.o,输出是:
0000000000000000 t f_b1
000000000000000b t f_b3
Run Code Online (Sandbox Code Playgroud)
这与原始文件相同,除了我们现在有't'标志而不是'T'标志.两个标志都表示符号在该.text部分中,但"T"表示它是全局的,"t"表示它是本地的.
显然,您要nm为此文件报告的内容根本不是符号.您现在应该理解,nm file.o如果符号存在,它将报告符号
file.o,但它的存在与静态或动态链接是否可见无关.
要使函数符号消失,file.c再次编译(仍然使用static关键字),这次启用了优化:
gcc -c -O1 -o file.o file.c
Run Code Online (Sandbox Code Playgroud)
现在,objdump报道:
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
Run Code Online (Sandbox Code Playgroud)
f_b1并且f_b3已经消失了,nm file.o根本没有报道.为什么?因为static告诉编译器这些符号只能从它正在编译的文件中调用,而优化决定不需要引用它们; 所以编译器将它们从目标代码中删除.但是如果链接器没有看到它们,没有优化,那么我们就无法优化它们.
底线:是否nm可以提取符号无关紧要.如果符号是本地/内部的,则无法静态或动态链接.如果符号已标记.hidden,则无法动态链接.您可以使用visibility("hidden")标记符号.hidden.使用standard
static关键字将符号设置为local/internal.
我意识到这已经是旧线程了。但是,我想分享一些有关静态链接的事实,即将隐藏的符号设置为本地,从而防止这些符号与目标文件或静态库中的(全局)静态链接发生联系。这并不意味着使它们在符号表中不可见。
迈克·金厄姆的答案非常有用,但在以下细节上并不完整:
如果要在静态库中的静态链接中隐藏f_b1和f_b3,则根本无法使用visible属性来执行此操作。
让我展示一下,通过使用中的简单代码示例,file.c并在使用Xcode / gcc构建的静态库中的“ 符号隐藏”中应用ypsu的答案,可以肯定地将隐藏符号设置为局部。第一步,让我们再现objdump输出,其中的隐藏属性在和上可见。这可以通过以下命令完成,该命令在hidden属性中提供了所有功能:f_b1f_b3file.c
gcc -fvisibility=hidden -c file.c
Run Code Online (Sandbox Code Playgroud)
objdump -t file.o给定的输出
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 0000000000000010 .hidden f_b3
Run Code Online (Sandbox Code Playgroud)
这与Mike Kingham获得的中间结果完全相同。现在让我们将具有hidden属性的符号设置为局部。这是通过使用objcopyfrom 来实现的binutils:
objcopy --localize-hidden --strip-unneeded file.o
Run Code Online (Sandbox Code Playgroud)
使用objdump,给出
file.o: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 l F .text 000000000000000b .hidden f_b1
000000000000000b l F .text 0000000000000010 .hidden f_b3
0000000000000000 l d .data 0000000000000000 .data
0000000000000000 l d .bss 0000000000000000 .bss
0000000000000000 l d .comment 0000000000000000 .comment
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame
Run Code Online (Sandbox Code Playgroud)
同样,nm file.o给
0000000000000000 t f_b1
000000000000000b t f_b3
Run Code Online (Sandbox Code Playgroud)
尽管f_b1和f_b3在符号表中仍然可见,但是它们是本地的。因此,函数f_b1和f_b3都无法通过静态链接隐藏!
我还想添加一个声明静态函数的注释,并可以将其从符号表中完全删除。首先,可以确定地执行删除操作,而不必依赖于使用来优化编译器objcopy。
objcopy --strip-unneeded file.o
Run Code Online (Sandbox Code Playgroud)
的静态函数f_b1和f_b2不再位于的符号表中file.o。
其次,使用声明函数static来使它们从符号表中消失的这种用法仅在单个源文件C项目中有效。只要一个C项目由许多组件和文件组成,就只能通过将所有C源文件和-header文件合并到一个源文件中并声明所有内部接口(函数)为静态的(全局变量除外)为静态来完成此操作。 (顶部)界面。如果无法实现,则可以使用ypsu最初描述的方法(可能还有许多其他方法-例如,参见Linux静态库中的限制符号)。