Gcc 在库中隐藏符号名

Gcc 在库中隐藏符号名,gcc,shared-libraries,static-libraries,Gcc,Shared Libraries,Static Libraries,我想隐藏与最后一个用户无关的符号名,并使共享或静态库中的API仅可见。我有这样一个简单的代码: int f_b1(){ return 21 ; } int f_b3(){ return f_b1() ; } 我应用了所述的所有方法,例如使用\uuuu属性((可见性(“隐藏”))和静态数据,但没有得到成功的结果。我的操作系统是Ubuntu和x86_64 GNU/Linux处理器。使用gcc编译时是否使用特殊选项?我用nm命令列出了库的模块和函数。在上面的示例中,我只想使函数可见。使用attri

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

int f_b1(){
return 21 ;
}

int f_b3(){
return f_b1() ;
}
我应用了所述的所有方法,例如使用
\uuuu属性((可见性(“隐藏”))
静态
数据,但没有得到成功的结果。我的操作系统是Ubuntu和x86_64 GNU/Linux处理器。使用gcc编译时是否使用特殊选项?我用
nm
命令列出了库的模块和函数。在上面的示例中,我只想使函数可见。使用
attribute hidden
时,宏编译器不会给出任何错误,但函数仍然存在于
nm
命令输出的列表中。

可见性(“hidden”)属性不会从 对象文件,无法阻止nm提取符号。只是 指示动态链接器不能从外部调用符号 包含它的共享库

考虑包含示例函数的源文件
file.c

int f_b1(){
return 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
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
现在运行
objdump-tfile.o
以获取有关符号的更全面信息。输出:

0000000000000000 T f_b1
000000000000000b T f_b3
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
这里我们看到
f_b1
f_b3
文本中的全局(g)函数(f)
节

现在按如下方式修改文件:

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

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

static int f_b3(void){
return f_b1() ;
}
再次运行
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
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
输出相同,只是符号
f_b1
f_b3
现在已标记
。隐藏
。例如,它们仍然具有外部(全局)链接,可以静态调用 例如,来自包含它们的库中的其他模块,但可以 不能从图书馆外被动态调用

因此,如果您想在共享空间中对动态链接隐藏
f_b1
f_b3
在库中,您可以使用
可见性(“隐藏”)
,如图所示

如果要在静态链接中隐藏
f_b1
f_b3
在库中,您根本不能使用
可见性
属性来执行此操作

在静态库的情况下,只能在给定符号时“隐藏”该符号 内部链接,而不是外部链接。方法是在 标准
静态
关键字。但内部链接意味着符号是
仅在其自己的编译单元中可见:无法从
其他模块。链接器根本无法使用它

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

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

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

static int f_b3(void){
return f_b1() ;
}
然后再次运行
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    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
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
您可以看到
f_b1
f_b3
仍然作为函数报告在
文本中
部分,但现在分类为局部(l),而不是全局。这就是内部联系。
运行
nm file.o
,输出为:

0000000000000000 t f_b1
000000000000000b t f_b3
这与原始文件相同,只是没有使用“T”标志 我们现在有了“t”旗。两个标志都表示符号位于
.text
部分, 但“T”表示它是全球性的,“T”表示它是地方性的

显然,您希望
nm
为此文件报告的内容根本不是符号。 现在您应该了解,
nm file.o
将报告一个符号,如果它存在于
file.o
,但它的存在与它是否可见无关 用于静态或动态连杆

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

gcc -c -O1 -o file.o file.c
现在,
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
f_b1
f_b3
不见了,而
nm file.o
根本不报告任何内容。为什么? 因为
static
告诉编译器只能调用这些符号 从正在编译的文件中,优化决定 没有必要提及它们;因此,编译器将它们从 目标代码。但如果它们不是链接器看不见的,没有 优化,然后我们无法优化它们

底线:无论
nm
是否可以提取符号。如果 符号是本地/内部的,不能静态或动态链接。 如果符号标记为
.hidden
,则无法动态链接。你 可以使用
可见性(“隐藏”)
标记符号
.hidden
。使用标准
static
关键字使符号成为本地/内部。

我意识到这已经是一个旧线程。但是,我想分享一些关于静态链接的事实,即使隐藏符号成为本地符号,从而防止这些符号在对象文件或静态库中(全局)静态链接。这并不意味着使它们在符号表中不可见

Mike Kingham的回答非常有用,但在以下细节方面并不完整:

如果您想在静态链接中隐藏f_b1和f_b3 在库中,您根本无法使用“可见性”属性来执行此操作

让我通过使用
file.c
中的简单代码示例并在中应用的答案来说明隐藏符号当然可以成为局部的。 在第一步中,让我们使用在
f_b1
f_b3
上可见的隐藏属性再现objdump输出。这可以通过以下命令完成,该命令为
file.c
中的所有函数提供隐藏属性:

gcc -fvisibility=hidden -c file.c
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
0000000000000000 t f_b1
000000000000000b t f_b3
这与Mike Kingham获得的中间结果完全相同。现在让我们将具有隐藏属性的符号设置为本地。这是通过使用
binutils
中的
objcopy
实现的,如下所示:

objcopy --localize-hidden --strip-unneeded file.o
使用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
同样,
nm 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
0000000000000000 t f_b1
000000000000000b t f_b3
虽然
f_b1
f_b3
在符号表中仍然可见,但它们是本地的。