Ограничение видимости символов при связывании общих библиотек - PullRequest
45 голосов
/ 12 января 2009

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

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

Ответы [ 4 ]

67 голосов
/ 17 января 2009

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
38 голосов
/ 13 января 2009

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

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

6 голосов
/ 13 октября 2009

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

1 голос
/ 28 февраля 2017

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

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

cat export.sym
bar
baz

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

libtool -export-symbols export.sym ...

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

...