Ограничение видимости символов при связывании общих библиотек

StackOverflow https://stackoverflow.com/questions/435352

Вопрос

Некоторые платформы требуют, чтобы вы предоставили компоновщику список внешних символов совместно используемой библиотеки. Однако в большинстве unixish-систем это необязательно: все нестатические символы будут доступны по умолчанию.

Насколько я понимаю, набор инструментов GNU может по желанию ограничивать видимость только символами, явно объявленными. Как этого добиться, используя GNU ld?

Это было полезно?

Решение

GNU ld может делать это на платформах ELF.

Вот как это сделать с помощью скрипта версии компоновщика:

/* foo.c */
int foo() { return 42; }
int bar() { return foo() + 1; }
int baz() { return bar() - 1; }

gcc -fPIC -shared -o libfoo.so foo.c && nm -D libfoo.so | grep ' T '

По умолчанию все символы экспортируются:

0000000000000718 T _fini
00000000000005b8 T _init
00000000000006b7 T bar
00000000000006c9 T baz
00000000000006ac T foo

Допустим, вы хотите экспортировать только bar () и baz () . Создайте «скрипт версии» <Код> libfoo.version :

FOO {
  global: bar; baz; # explicitly list symbols to be exported
  local: *;         # hide everything else
};

Передайте его компоновщику:

gcc -fPIC -shared -o libfoo.so foo.c -Wl,--version-script=libfoo.version

Соблюдайте экспортированные символы:

nm -D libfoo.so | grep ' T '
00000000000005f7 T bar
0000000000000609 T baz

Другие советы

Я думаю, что самый простой способ сделать это - добавить -fvisibility = hidden в параметры gcc и явно сделать видимость некоторых символов общедоступной в коде (с помощью __ attribute __ ((visibility (") ; по умолчанию & Quot;))) ). См. Документацию здесь .

Может быть, это можно сделать с помощью сценариев ld linker, но я об этом немного знаю.

Код, сгенерированный для вызова любых экспортируемых функций или использования любых экспортированных глобальных переменных, менее эффективен, чем те, которые не экспортируются. Существует дополнительный уровень косвенности. Это относится к любой функции, которую можно экспортировать во время компиляции . gcc будет по-прежнему генерировать дополнительное косвенное обращение для функции, которая впоследствии не экспортируется сценарием компоновщика. Поэтому использование атрибута видимости даст лучший код, чем скрипт компоновщика.

Если вы используете libtool, есть и другой вариант, очень похожий на ответ Employed Russian.

Используя его пример, это будет что-то вроде:

cat export.sym
bar
baz

Затем запустите libtool со следующей опцией:

libtool -export-symbols export.sym ...

Обратите внимание, что при использовании -export-символов все символы НЕ экспортируются по умолчанию, а экспортируются только символы в export.sym (поэтому строка " local: * " в libfoo.version фактически подразумевается в этом подходе) .

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top