Скрыть символы от стороннего .a файла, который связан с .so файлом - PullRequest
2 голосов
/ 04 мая 2020

Я создаю разделяемую (.so) библиотеку, которая состоит из нескольких файлов .a и тонкого API-уровня, который их вызывает. Я хочу, чтобы мой API и внешние зависимости были видны, поэтому я строю свой код, используя «скрытую» видимость, предоставляемую G CC (-fvisibility=hidden).

Однако одна из библиотек является проприетарной сторонний файл .a (который мы заплатили за использование), и у меня есть доступ только к его двоичному файлу. Когда я статически связываю его с моим файлом .so, его символы видны в моей таблице символов Dynamo c. Я предполагаю, что это потому, что библиотека не была построена со скрытыми параметрами видимости. Я бы предпочел скрывать эти функции, чтобы управлять чувствительной частью нашего программного обеспечения, и я не хочу, чтобы третьи лица связывались с этими символами.

Есть ли способ пометить эти символы как "скрытые" после того, чтобы они не появлялись в списке символов моего .so файла? Я посмотрел на objdump и objcopy, но мне трудно с терминологией.

Другие вещи, которые я пробовал:

1 Ответ

3 голосов
/ 05 мая 2020

Вот рабочий пример решения вашей проблемы.

Это источник проприетарной библиотеки 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.
...