隐藏来自第 3 方的符号 .a 链接到 .so 文件的文件
Hide symbols from a 3rd party .a file that is linked into a .so file
我正在构建一个共享 (.so) 库,它由几个 .a 文件和一个调用它们的薄 API 层组成。我只希望我的 API 和外部依赖项可见,因此我使用 GCC (-fvisibility=hidden
) 提供的 "hidden" 可见性构建我的代码 (-fvisibility=hidden
)。
但是,其中一个库是专有的第三方 .a 文件(我们已付费使用),我只能访问其二进制文件。当我 link 它静态地进入我的 .so 文件时,它的符号在我的 .so 的动态符号 table 中是可见的。我猜这是因为库不是用隐藏的可见性选项构建的。我宁愿隐藏这些功能作为管理我们软件的敏感部分,我不希望第三方 link 使用这些符号。
有没有什么办法可以在事后将这些符号标记为 "hidden",这样它们就不会出现在我的 .so 文件的符号列表中?我看过 objdump
和 objcopy
,但我很难理解这些术语。
我尝试过的其他事情:
- 从 .a 中提取 .o 并尝试按照此处所述重新编译:
这是一个解决问题的示例。
这是您无法重新编译的专有静态库的源代码:
$ cat tpa.c
int tpa(void)
{
return 2;
}
$ cat tpb.c
int tpb(void)
{
return 3;
}
图书馆,libtp.a
,一定是这样建造的1:
$ gcc -fPIC -c -O1 tpa.c tpb.c
$ ar rcs libtp.a tpa.o tpb.o
tpa.o
和tpb.o
的符号table是:-
$ readelf -s libtp.a
File: libtp.a(tpa.o)
Symbol table '.symtab' contains 10 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS tpa.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 6
7: 0000000000000000 0 SECTION LOCAL DEFAULT 7
8: 0000000000000000 0 SECTION LOCAL DEFAULT 4
9: 0000000000000000 10 FUNC GLOBAL DEFAULT 1 tpa
File: libtp.a(tpb.o)
Symbol table '.symtab' contains 10 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS tpb.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 6
7: 0000000000000000 0 SECTION LOCAL DEFAULT 7
8: 0000000000000000 0 SECTION LOCAL DEFAULT 4
9: 0000000000000000 10 FUNC GLOBAL DEFAULT 1 tpb
你看到函数符号 tpa
和 tpb
都是 GLOBAL
(= 适用于 link 年龄)并具有 DEFAULT
动态可见性,而不是 HIDDEN
。
下面是您自己的静态库的源代码,libus.a
$ cat usa.c
int usa(void)
{
return 5;
}
$ cat usb.c
int usb(void)
{
return 7;
}
你这样构建的:
$ gcc -fPIC -c -O1 -fvisibility=hidden usa.c usb.c
$ ar rcs libus.a usa.o usb.o
libus.a
中的函数符号也是GLOBAL
,但它们是动态的
能见度为 HIDDEN
:-
$ readelf -s libus.a
File: libus.a(usa.o)
Symbol table '.symtab' contains 10 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS usa.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 6
7: 0000000000000000 0 SECTION LOCAL DEFAULT 7
8: 0000000000000000 0 SECTION LOCAL DEFAULT 4
9: 0000000000000000 10 FUNC GLOBAL HIDDEN 1 usa
File: libus.a(usb.o)
Symbol table '.symtab' contains 10 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS usb.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 6
7: 0000000000000000 0 SECTION LOCAL DEFAULT 7
8: 0000000000000000 0 SECTION LOCAL DEFAULT 4
9: 0000000000000000 10 FUNC GLOBAL HIDDEN 1 usb
这是您的共享库的源代码:
$ cat usc.c
extern int tpa(void);
extern int tpb(void);
extern int usa(void);
extern int usb(void);
int usc(void)
{
return tpa() * tpb() * usa() * usb();
}
你编译的是:-
$ gcc -fPIC -c -O1 usc.c
现在您想要 link usc.o
、libtp.a
和 libus.a
在您的共享库 libsus.so
中。如果你
照常做:
$ gcc -shared -o libsus.so usc.o -L. -ltp -lus
然后你发现:
$ readelf --dyn-syms libsus.so
Symbol table '.dynsym' contains 8 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __cxa_finalize
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
5: 0000000000001139 38 FUNC GLOBAL DEFAULT 12 usc
6: 000000000000115f 10 FUNC GLOBAL DEFAULT 12 tpa
7: 0000000000001169 10 FUNC GLOBAL DEFAULT 12 tpb
来自 libus.a
的 HIDDEN
可见性符号在动态中不存在
符号 table,但包含来自 libtp.a
的 DEFAULT
个可见性符号,
你不想要的。
要排除后者,link您的共享库如下:
$ gcc -shared -o libsus.so usc.o -L. -ltp -lus -Wl,--exclude-libs=libtp.a
则动态符号table变为:
$ readelf --dyn-syms libsus.so
Symbol table '.dynsym' contains 6 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __cxa_finalize
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
5: 00000000000010f9 38 FUNC GLOBAL DEFAULT 10 usc
随心所欲。
linker 选项 --exclude-libs
是 documented:
--exclude-libs lib,lib,...
Specifies a list of archive libraries from which symbols should not be automatically exported.
The library names may be delimited by commas or colons. Specifying --exclude-libs ALL excludes symbols in all archive libraries from automatic export.
...
For ELF targeted ports, symbols affected by this option will be treated as hidden.
为了确保 tp*
符号定义 已经 link 编辑,您
仍然可以在共享库的完整符号 table 中看到它们:
$ readelf -s libsus.so | egrep 'FUNC.*(us|tp)(a|b|c)'
5: 00000000000010f9 38 FUNC GLOBAL DEFAULT 10 usc
41: 0000000000001133 10 FUNC LOCAL DEFAULT 10 usa
44: 000000000000111f 10 FUNC LOCAL DEFAULT 10 tpa
46: 000000000000113d 10 FUNC LOCAL DEFAULT 10 usb
48: 0000000000001129 10 FUNC LOCAL DEFAULT 10 tpb
50: 00000000000010f9 38 FUNC GLOBAL DEFAULT 10 usc
就像显式隐藏的 us*
符号一样,它们变成 LOCAL
,无法再使用 linkage。 (您在 grep
中看到两次 usc
,因为它被列为全局符号和动态符号)。
从这里可以推断,我们不必费心去编译我们的
拥有 us*
代码和 -fvisibility=hidden
,只要我们要存档
它在 libus.a
进一步 link 年龄。我们可以像这样 link 编辑共享库:
$ gcc -shared -o libsus.so usc.o -L. -ltp -lus -Wl,--exclude-libs=libtp.a,libus.a
效果相同
[1] 我明确指定 -fPIC
以确保生成位置无关的
我可以在 DSO 中 link 的目标代码,但这一直是 GCC 的默认设置
海湾合作委员会 6.
我正在构建一个共享 (.so) 库,它由几个 .a 文件和一个调用它们的薄 API 层组成。我只希望我的 API 和外部依赖项可见,因此我使用 GCC (-fvisibility=hidden
) 提供的 "hidden" 可见性构建我的代码 (-fvisibility=hidden
)。
但是,其中一个库是专有的第三方 .a 文件(我们已付费使用),我只能访问其二进制文件。当我 link 它静态地进入我的 .so 文件时,它的符号在我的 .so 的动态符号 table 中是可见的。我猜这是因为库不是用隐藏的可见性选项构建的。我宁愿隐藏这些功能作为管理我们软件的敏感部分,我不希望第三方 link 使用这些符号。
有没有什么办法可以在事后将这些符号标记为 "hidden",这样它们就不会出现在我的 .so 文件的符号列表中?我看过 objdump
和 objcopy
,但我很难理解这些术语。
我尝试过的其他事情:
- 从 .a 中提取 .o 并尝试按照此处所述重新编译:
这是一个解决问题的示例。
这是您无法重新编译的专有静态库的源代码:
$ cat tpa.c
int tpa(void)
{
return 2;
}
$ cat tpb.c
int tpb(void)
{
return 3;
}
图书馆,libtp.a
,一定是这样建造的1:
$ gcc -fPIC -c -O1 tpa.c tpb.c
$ ar rcs libtp.a tpa.o tpb.o
tpa.o
和tpb.o
的符号table是:-
$ readelf -s libtp.a
File: libtp.a(tpa.o)
Symbol table '.symtab' contains 10 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS tpa.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 6
7: 0000000000000000 0 SECTION LOCAL DEFAULT 7
8: 0000000000000000 0 SECTION LOCAL DEFAULT 4
9: 0000000000000000 10 FUNC GLOBAL DEFAULT 1 tpa
File: libtp.a(tpb.o)
Symbol table '.symtab' contains 10 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS tpb.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 6
7: 0000000000000000 0 SECTION LOCAL DEFAULT 7
8: 0000000000000000 0 SECTION LOCAL DEFAULT 4
9: 0000000000000000 10 FUNC GLOBAL DEFAULT 1 tpb
你看到函数符号 tpa
和 tpb
都是 GLOBAL
(= 适用于 link 年龄)并具有 DEFAULT
动态可见性,而不是 HIDDEN
。
下面是您自己的静态库的源代码,libus.a
$ cat usa.c
int usa(void)
{
return 5;
}
$ cat usb.c
int usb(void)
{
return 7;
}
你这样构建的:
$ gcc -fPIC -c -O1 -fvisibility=hidden usa.c usb.c
$ ar rcs libus.a usa.o usb.o
libus.a
中的函数符号也是GLOBAL
,但它们是动态的
能见度为 HIDDEN
:-
$ readelf -s libus.a
File: libus.a(usa.o)
Symbol table '.symtab' contains 10 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS usa.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 6
7: 0000000000000000 0 SECTION LOCAL DEFAULT 7
8: 0000000000000000 0 SECTION LOCAL DEFAULT 4
9: 0000000000000000 10 FUNC GLOBAL HIDDEN 1 usa
File: libus.a(usb.o)
Symbol table '.symtab' contains 10 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS usb.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 6
7: 0000000000000000 0 SECTION LOCAL DEFAULT 7
8: 0000000000000000 0 SECTION LOCAL DEFAULT 4
9: 0000000000000000 10 FUNC GLOBAL HIDDEN 1 usb
这是您的共享库的源代码:
$ cat usc.c
extern int tpa(void);
extern int tpb(void);
extern int usa(void);
extern int usb(void);
int usc(void)
{
return tpa() * tpb() * usa() * usb();
}
你编译的是:-
$ gcc -fPIC -c -O1 usc.c
现在您想要 link usc.o
、libtp.a
和 libus.a
在您的共享库 libsus.so
中。如果你
照常做:
$ gcc -shared -o libsus.so usc.o -L. -ltp -lus
然后你发现:
$ readelf --dyn-syms libsus.so
Symbol table '.dynsym' contains 8 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __cxa_finalize
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
5: 0000000000001139 38 FUNC GLOBAL DEFAULT 12 usc
6: 000000000000115f 10 FUNC GLOBAL DEFAULT 12 tpa
7: 0000000000001169 10 FUNC GLOBAL DEFAULT 12 tpb
来自 libus.a
的 HIDDEN
可见性符号在动态中不存在
符号 table,但包含来自 libtp.a
的 DEFAULT
个可见性符号,
你不想要的。
要排除后者,link您的共享库如下:
$ gcc -shared -o libsus.so usc.o -L. -ltp -lus -Wl,--exclude-libs=libtp.a
则动态符号table变为:
$ readelf --dyn-syms libsus.so
Symbol table '.dynsym' contains 6 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __cxa_finalize
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
5: 00000000000010f9 38 FUNC GLOBAL DEFAULT 10 usc
随心所欲。
linker 选项 --exclude-libs
是 documented:
--exclude-libs lib,lib,...
Specifies a list of archive libraries from which symbols should not be automatically exported. The library names may be delimited by commas or colons. Specifying --exclude-libs ALL excludes symbols in all archive libraries from automatic export. ... For ELF targeted ports, symbols affected by this option will be treated as hidden.
为了确保 tp*
符号定义 已经 link 编辑,您
仍然可以在共享库的完整符号 table 中看到它们:
$ readelf -s libsus.so | egrep 'FUNC.*(us|tp)(a|b|c)'
5: 00000000000010f9 38 FUNC GLOBAL DEFAULT 10 usc
41: 0000000000001133 10 FUNC LOCAL DEFAULT 10 usa
44: 000000000000111f 10 FUNC LOCAL DEFAULT 10 tpa
46: 000000000000113d 10 FUNC LOCAL DEFAULT 10 usb
48: 0000000000001129 10 FUNC LOCAL DEFAULT 10 tpb
50: 00000000000010f9 38 FUNC GLOBAL DEFAULT 10 usc
就像显式隐藏的 us*
符号一样,它们变成 LOCAL
,无法再使用 linkage。 (您在 grep
中看到两次 usc
,因为它被列为全局符号和动态符号)。
从这里可以推断,我们不必费心去编译我们的
拥有 us*
代码和 -fvisibility=hidden
,只要我们要存档
它在 libus.a
进一步 link 年龄。我们可以像这样 link 编辑共享库:
$ gcc -shared -o libsus.so usc.o -L. -ltp -lus -Wl,--exclude-libs=libtp.a,libus.a
效果相同
[1] 我明确指定
-fPIC
以确保生成位置无关的
我可以在 DSO 中 link 的目标代码,但这一直是 GCC 的默认设置
海湾合作委员会 6.