Вот рабочий пример решения вашей проблемы.
Это источник проприетарной библиотеки stati c, которую вы не можете перекомпилировать:
$ 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
: -
$ 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
(= доступны для связи) и имеют DEFAULT
dynamici c видимость, а не HIDDEN
.
Теперь вот исходный код вашей собственной библиотеки c, 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
Теперь вы хотите связать 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
, что символы видимости HIDDEN
из libus.a
отсутствуют в таблице динамических символов, но DEFAULT
символы видимости из libtp.a
включены, что вам не нужно.
Чтобы исключить и последнее, свяжите вашу общую библиотеку следующим образом:
$ gcc -shared -o libsus.so usc.o -L. -ltp -lus -Wl,--exclude-libs=libtp.a
Затем таблица символов Dynami c становится:
$ 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
, как вы хотите.
Опция компоновщика --exclude-libs
является документированной :
- exclude-libs lib, lib, ...
Указывает список архивных библиотек, из которых символы не должны автоматически экспортироваться. Имена библиотек могут быть разделены запятыми или двоеточиями. Указание --exclude-libs ALL исключает символы из всех архивных библиотек из автоматического экспорта c. ... Для целевых портов ELF символы, затронутые этой опцией, будут считаться скрытыми.
Чтобы убедиться, что определения символов tp*
связаны , вы можете все еще видите их в полной таблице символов совместно используемой библиотеки:
$ 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
, недоступными для дальнейшего связывания. (Вы видите usc
дважды в grep
, потому что он указан как глобальный и как динамический c символ).
И, как вы можете из этого сделать, нам не нужно беспокоиться о том, чтобы скомпилировать наш собственный код us*
с помощью -fvisibility=hidden
, если мы собирались заархивировать его в libus.a
для дальнейшей связи. Мы могли бы связать разделяемую библиотеку, например:
$ gcc -shared -o libsus.so usc.o -L. -ltp -lus -Wl,--exclude-libs=libtp.a,libus.a
с тем же эффектом.
[1] Я явно указываю
-fPIC
, чтобы быть уверенным в создании независимого от позиции объекта код, который я могу связать в DSO, но это был G CC по умолчанию с G CC 6.