LINUX.ORG.RU

Библиотеки Linux/Win

 


0

3

Доброго времени суток!

Рассуждали с товарищем на днях о сходствах и различиях библиотек в Linux (use gcc)/Windows (use MSVS).

Основным предметом спора было различие функций LoadLibraryA/W и dlopen, и утверждение, что LoadLibrary, якобы быстрее грузит функции из библиотеки (в отличие от классического метода линковки), потому, что загружает из нее не все функции, а только нужные. Также встал вопрос, зачем под виндами нужен костыль в виде прописывания в .def файле имен используемых функций из библиотеки? Хз, насколько это правда (поверил другу наслово), но он аргументировал создание такого списка тем, что так проще всего сказать компилятору, какие функции можно будет экспортировать из библиотеки. С другой стороны, в никсах достаточно добавить слово extern к функции, чтобы сделать ее видимой из библиотеки и никакие списки не нужны...

P.S. Вероятно, здесь написано много бреда, посему прошу расставить все по полочкам человеку, наглухо забывшему винду и другому человеку, не знающему совсем никсов.

Если кратко, то список вопросов таков:

1) В чем отличие функций LoadLibrary+GetProcAddress от аналогичной dlopen+dlsym, кроме названия?

2) Как они загружают функции из библиотеки - действительно ли только необходимые функции, в чем я сильно сомневаюсь, или же сначала подгружают целиком файл библиотеки в память, а только потом ищут нужные функции?

3) .def-файлы под MSVS - это что за костыль и почему не понравился мелкомягким способ через extern?

★★

Последнее исправление: aido (всего исправлений: 2)

2. Исполняемый файл присоединяется к адресному пространству процесса (mmap), так что никакие функции не выбираются.

3. Потому что extern - это к раздельной компиляции нескольких файлов, а не экспорт/импорт имён из разделяемой библиотеки. Аналог def-файлов для не-Windows систем - это атрибут visibility, поддерживаемый gcc. См. тут.

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

спасибо. то, что надо!

2. А по скорости динамическая загрузка библиотек от линковки с этой библиотекой сильно отличается для linux/win систем?

aido ★★
() автор топика

Вот тебе одно из самых серьезных различий: под виндой разделяемые библиотеки не должны иметь неопределенных символов.

buddhist ★★★★★
()

способ через extern

Ты явно что-то путаешь. extern нужен лишь в случае, если у тебя нет заголовочного файла с нужной переменной или функцией.

Eddy_Em ☆☆☆☆☆
()

У меня тоже вопрос: а зачем это обсуждать, зачем пипирками мериться? Есть ли практическая польза от подобных сведений?

I-Love-Microsoft ★★★★★
()
Ответ на: комментарий от I-Love-Microsoft

Ну мне интересно узнать, как оно внутри работает.

aido ★★
() автор топика

1) В чем отличие функций LoadLibrary+GetProcAddress от аналогичной dlopen+dlsym, кроме названия?

Если не учитывать различия в работе dynamic linker-а под разными системами, то эти пары функций семантически эквивалентны.

2) Как они загружают функции из библиотеки - действительно ли только необходимые функции, в чем я сильно сомневаюсь, или же сначала подгружают целиком файл библиотеки в память, а только потом ищут нужные функции?

Библиотека грузится целиком через механизм memory mapped files, если ещё не была загружена.

3) .def-файлы под MSVS - это что за костыль и почему не понравился мелкомягким способ через extern?

extern недостаточно. Под вендой любой символ всегда определяется в рамках какого-то модуля, соответственно нужно как-то сопоставить сишное имя символа и пару (имя модуля, имя символа в модуле).

anonymous
()

Нельзя загрузить из библиотеки только нужные функции, потому что не известно, как у неё внутри код устроен. Он может использовать явно или не очень другие части библиотеки, которые тоже необходимо загрузить. К тому же позиционнонезависимый код, как и релокации работают только в рамках секций. То есть ни в PE, ни в ELF недостаточно информации для того, чтобы вырезать кусок из секции. Секции можно перемещать только целиком.

def-файлы нужны, потому что в Windows каждая функция грузится из конкретной библиотеки. В Linux же есть только список библиотек, которые надо подгрузить, а пространство имён общее на все библиотеки. Это позволяет делать вкусные штуки типа подмены системных функций штатными средствами (используется всякими отладчиками) без костылей.

Есть альтернатива def-файлам. Например, в Pascal имеется синтаксическая конструкция, позволяющая указать, из какой библиотеки надо взять функцию, при описании прототипа.

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 1)

Докину ещё про загрузку только необходимых функций. Как уже сказали выше, нельзя загрузить только необходимые функции, ибо неизвестно, как внутри устроена библиотека. Зато можно загрузить только необходимые библиотеки, если какие-то из прилинкованных библиотек вдруг оказались не нужны.

Динамическая линковка в целом работает как-то так: в ассемблерном коде вместо call f происходит call [linked_f], где f - это имя функции, а linked_f - ячейка памяти, куда линкер положит известный только ему адрес загруженной функции f. Если библиотека уже загружена, в linked_f лежит адрес загруженной функции. Если же нет, там лежит адрес некоторой «заглушки», которая вызывает линкер с нужными аргументами, и в итоге происходит загрузка нужной библиотеки. В реальности всё происходит чуть-чуть по-другому, но общая суть та же.

Таким образом, если ни одна функция из библиотеки не была ни разу вызвана, то и библиотека не загрузится. Это иногда даёт выигрыш, например, если загружаемые библиотеки весьма жирные, а программа по каким-то причинам завершилась очень быстро (например, ей передали некорректные аргументы при запуске, и она сразу определила это и завершилась с ошибкой). Но в целом это практически ничего не ускоряет.

Это я всё про линукс, если что. Не знаю, как оно там под виндой.

devsdc ★★
()
Последнее исправление: devsdc (всего исправлений: 1)

Linkers&Loaders by John R. Levine

anonymous
()

Лет 10 назад .DEF-файл был нужен лишь в паре случаев:

  • когда пишешь DLL и хочешь избавиться от декорирования имен (_foo@8) - например, если эта DLL будет использоваться не из C-программ.
  • когда пишешь DLL и хочешь экспортировать функции только по ординалам, а не по именам (использовалось всякими кулхацкерами).

В остальных случаях __declspec(dllimport), __declspec(dllexport) - .DEF-файл не нужен.

bigbit ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.