LINUX.ORG.RU

Проблема с функциями в динамической библиотеке .so

 , ,


4

4

Столкнулся с такой проблемой при использовании динамической либы в Си. Допустим в библиотеке используется функция

uint16_t crc16_ccitt (const void *p, size_t size);

она используется исключительно внутри библиотеки в не объявлена в экспортируемых заголовочных файлах.

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

uint16_t crc16_ccitt (size_t size, const void *p);

то есть параметры были поменяны местами и когда библиотека пыталась ее вызвать, приложение падало в segmentation fault.

Есть ли какой-то способ избежать таких эффектов и изолировать функции библиотеки от пользовательских функций с таким же именем, возможно, некоторая опция gcc?

Если нет, то как такую проблему решают в крупных проектах?

Библиотека собирается с такими опциями:

-fPIC -c -std=c11 -fplan9-extensions -Wall -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-format-zero-length

не объявлена в экспортируемых заголовочных файлах.

Export-файлы есть только в Windows, и в целом наличие прототипа функции в h-файоах никак не связана с её видимостью на уровне символов.

Есть ли какой-то способ избежать таких эффектов и изолировать функции библиотеки от пользовательских функций с таким же именем, возможно, некоторая опция gcc?

Если нет, то как такую проблему решают в крупных проектах?

Проблема решается скрытием лишнего/ненужного посредством -fvisibility=hidden и явным «экспортированием» нужных функций посредством __attribute__((__visibility__("default"))).

Так должно быть в любой приличной библиотеке, том числе на C++ несмотря на наличие namespaces.

Пример для C: сначала №1 затем №2, и для C++: сначала №1 затем №2.

Deleted ()
Ответ на: комментарий от anonymous

Какой прок от этого в C++ с нэймспейсами? Загружается быстрее?

В проектах на C++ может быть огромное кол-во externally visible символов, причем достаточно длинных. Для каждого такого символа должна быть обеспечена возможность переопределения в других so.

Т.е. если даже условный std::list:const_iterator() есть внутри exe-шника, но если он external visible, то должен быть выполнен протокол динамического связывания (с поиском по всем so-шкам в соответствующем scope). По той-же причине для external visible не может применяться бОльшая часть оптимизаций LTO.

Поэтому с -fvisibility=hidden не только грузиться быстрее, но и работает быстрее (вызовы без лишних манипуляций, просто одним call), и файлы меньше.

Если не ошибаюсь, то достаточно подробно всё описано в статьях Ulrich Drepper про so-библиотеки (этим статьям лет 15-20).

Deleted ()
Ответ на: комментарий от mittorn

Спрятанные символы никуда не деваются при линковке. Это флаг для загрузчика. Сомневаюсь что это повлияет на LTO.

Пожалуйста изучите матчать, прежде чем сомневаться или спорить.

№1, №2, №3

Deleted ()
Ответ на: комментарий от Deleted

Ulrich Drepper. «How To Write Shared Libraries». Dec 10, 2011
На самом деле статья писалась, дополнялась и переписывалась по крайней мере с 2002 г.
Есть русский перевод Н.Ромоданова от 2013 г.:
Ульрих Дреппер. Как писать разделяемые библиотеки.

ABW ★★★★★ ()