Ограничение символов в статической библиотеке Linux
Я ищу способы ограничить количество символов C, экспортированных в статическую библиотеку Linux (архив). Я хотел бы ограничить их только теми символами, которые являются частью официального API для библиотеки. Я уже использую "статический", чтобы объявлять большинство функций статическими, но это ограничивает их область действия. Я ищу способ ограничить область видимости в библиотеке.
Я могу сделать это для разделяемых библиотек, используя методы в Ulrich Drepper Как писать общие библиотеки, но я не могу применять эти методы для статические архивы. В своей предыдущей статье Good Practices in Library Design он пишет:
Единственная возможность - объединить все файлы объектов, которые необходимы некоторые внутренние ресурсы в один, используя 'ld -r', а затем ограничивают символы которые экспортируются этим объединенным объектным файлом. У компоновщика GNU есть сделайте именно это.
Может ли кто-нибудь помочь мне узнать, какие могут быть эти варианты? У меня был некоторый успех с 'strip -w -K prefix_ *', но это кажется грубым. В идеале я бы хотел найти решение, которое будет работать как с GCC 3, так и с 4.
Спасибо!
Ответы
Ответ 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.