Подтвердить что ты не робот

Ограничение символов в статической библиотеке Linux

Я ищу способы ограничить количество символов C, экспортированных в статическую библиотеку Linux (архив). Я хотел бы ограничить их только теми символами, которые являются частью официального API для библиотеки. Я уже использую "статический", чтобы объявлять большинство функций статическими, но это ограничивает их область действия. Я ищу способ ограничить область видимости в библиотеке.

Я могу сделать это для разделяемых библиотек, используя методы в Ulrich Drepper Как писать общие библиотеки, но я не могу применять эти методы для статические архивы. В своей предыдущей статье Good Practices in Library Design он пишет:

Единственная возможность - объединить все файлы объектов, которые необходимы некоторые внутренние ресурсы в один, используя 'ld -r', а затем ограничивают символы которые экспортируются этим объединенным объектным файлом. У компоновщика GNU есть сделайте именно это.

Может ли кто-нибудь помочь мне узнать, какие могут быть эти варианты? У меня был некоторый успех с 'strip -w -K prefix_ *', но это кажется грубым. В идеале я бы хотел найти решение, которое будет работать как с GCC 3, так и с 4.

Спасибо!

4b9b3361

Ответ 1

Статические библиотеки не могут делать то, что вы хотите для кода, скомпилированного с помощью GCC 3.x или 4.x.

Если вы можете использовать общие объекты (библиотеки), компоновщик GNU делает то, что вам нужно, с функцией, называемой версией script. Обычно это используется для указания точек входа, зависящих от версии, но вырожденный случай просто различает публичные и частные символы без какого-либо управления версиями. Версия script указана с параметром командной строки -version- script= для ld.

Содержимое версии script, которая делает точки входа foo и bar общедоступными и скрывает все другие интерфейсы:

{ global: foo; bar; local: *; };

Смотрите ld doc по адресу: http://sourceware.org/binutils/docs/ld/VERSION.html#VERSION

Я большой сторонник разделяемых библиотек, и эта способность ограничить видимость глобалов - одна из их великих достоинств.

Документ, который предоставляет больше преимуществ общих объектов, но написанных для Solaris (Грегом Нахимовским из счастливой памяти), находится в http://developers.sun.com/solaris/articles/linker_mapfiles.html

Надеюсь, это поможет.

Ответ 2

Я не считаю, что у GNU ld есть такие возможности; Ульрих, должно быть, имел в виду objcopy, который имеет много таких опций: --localize-hidden, --localize-symbol=symbolname, --localize-symbols=filename.

В частности, --localize-hidden позволяет очень точно контролировать, какие символы выставлены. Рассмотрим:

int foo() { return 42; }
int __attribute__((visibility("hidden"))) bar() { return 24; }

gcc -c foo.c
nm foo.o
000000000000000b T bar
0000000000000000 T foo

objcopy --localize-hidden foo.o bar.o
nm bar.o
000000000000000b t bar
0000000000000000 T foo

Итак bar() больше не экспортируется из объекта (хотя он все еще присутствует и может использоваться для отладки). Вы также можете удалить bar() вместе с objcopy --strip-unneeded.

Ответ 3

Достоинства этого ответа будут зависеть от того, почему вы используете статические библиотеки. Если это позволит компоновщику сбросить неиспользуемые объекты позже, тогда мне нечего добавить. Если это с целью организации - сведение к минимуму количества объектов, которые должны быть переданы для связи приложений, это может быть полезным для использования русского языка.

Во время компиляции видимость всех символов внутри единицы компиляции может быть установлена ​​с помощью:

-fvisibility=hidden
-fvisibility=default

Это означает, что можно скомпилировать один файл "interface.c" с видимостью по умолчанию и большим количеством файлов реализации со скрытой видимостью без аннотирования источника. Затем перемещаемая ссылка создаст один объектный файл, в котором функции non-api будут "скрыты":

ld -r interface.o implementation0.o implementation1.o -o relocatable.o

Теперь объединенный объектный файл может быть подвергнут objcopy:

objcopy --localize-hidden relocatable.o mylibrary.o

Таким образом, у нас есть один объектный файл "библиотека" или "модуль", который предоставляет только предполагаемый API.


Вышеупомянутая стратегия взаимодействует умеренно хорошо с оптимизацией времени ссылки. Скомпилируйте с -flto и выполните перемещаемую ссылку, передав -r в компоновщик через компилятор:

gcc -fuse-linker-plugin -flto -nostdlib -Wl,-r {objects} -o relocatable.o

Используйте objcopy, чтобы локализовать скрытые символы, как прежде, затем вызовите компоновщик в последний раз, чтобы удалить локальные символы и любой другой мертвый код, который он может найти в объекте post-lto. К сожалению, relocatable.o вряд ли сохранил какую-либо информацию, связанную с lto:

gcc -nostdlib -Wl,-r,--discard-all relocatable.o mylibrary.o

Текущие реализации lto оказываются активными во время перемещаемого этапа ссылки. Когда lto on, скрытые = > локальные символы были разделены конечной перемещаемой ссылкой. Без lto скрытые = > локальные символы пережили окончательную перемещаемую ссылку.

Будущие реализации lto, похоже, скорее всего сохранят требуемые метаданные через этап перемещаемой ссылки, но в настоящее время результат перемещаемой ссылки представляется простым старым объектным файлом.

Ответ 4

Мой способ сделать это - отметить все, что нельзя экспортировать с помощью INTERNAL, включают в себя защиту всех файлов .h, компиляцию dev с помощью -DINTERNAL = и компиляцию выпусков с помощью одного файла .c, который включает в себя все другие файлы библиотеки .c с -DINTERNAL = static.