Почему вы не можете статически связывать динамические библиотеки? - PullRequest
0 голосов
/ 29 января 2019

При использовании внешних библиотек вам часто приходится решать, использовать ли статическую или динамическую версию библиотеки.Как правило, вы не можете обмениваться ими: если библиотека создается как динамическая библиотека, вы не можете статически ссылаться на нее.

Почему это так?

Пример: я создаю C ++Запустите программу для Windows и используйте библиотеку, которая предоставляет небольшой файл .lib для компоновщика и большой файл .dll, который должен присутствовать при запуске моего исполняемого файла.Если код библиотеки в .dll может быть разрешен во время выполнения, почему он не может быть решен во время компиляции и непосредственно помещен в мой исполняемый файл?

1 Ответ

0 голосов
/ 31 января 2019

Почему это так?

Большинство компоновщиков (компоновщик AIX является заметным исключением) отбрасывает информацию в процессе компоновки.

Например, предположим, у вас есть foo.o с foo в нем и bar.o с bar в нем.Предположим, что foo вызывает bar.

После того, как вы свяжете foo.o и bar.o вместе в общую библиотеку, компоновщик объединяет разделы кода и данных и разрешает ссылки.Звонок с foo на bar становится CALL $relative_offset.После этой операции вы больше не можете сказать, где была граница между кодом, полученным из foo.o, и кодом, полученным из bar.o, или именем, которое CALL $relative_offset использовало в foo.o - запись перемещения была отброшена.

Предположим, теперь вы хотите связать foobar.so со своим main.o статически, и предположим, что main.o уже определяет свой собственный bar.

Если у вас было libfoobar.a, тобыло бы тривиально: компоновщик извлек бы foo.o из архива, не использовал бы bar.o из архива и разрешил бы вызов с foo.o до bar с main.o.

Но должно быть понятно, что ничего из перечисленного выше невозможно с foobar.so - вызов уже был разрешен на other bar, и вы не можете сбросить код, полученный сbar.o потому что вы не знаете, где находится этот код.

В AIX возможно (или, по крайней мере, раньше это было возможно 10 лет назад) "отсоединить" разделяемую библиотеку и превратить ее вархив, который затем может быть статически связан в другойкрасная библиотека или главный исполняемый файл.

Если foo.o и bar.o связаны в foobar.so, не имеет ли смысла, что вызов от foo до barвсегда разрешается в единицу в bar.o?

Это то место, где общие библиотеки UNIX работают совсем не так, как библиотеки Windows DLL.В UNIX (при общих условиях) вызов от foo до bar преобразуется в bar в основном исполняемом файле.

Это позволяет, например, реализовать malloc и free вmain a.out и все вызовы malloc используют эту реализацию кучи one последовательно.В Windows вы должны всегда следить за тем, «из какой реализации кучи поступила эта память».

Модель UNIX не лишена недостатков, поскольку разделяемая библиотека не является автономной, в основном герметичной единицей (в отличие от Windows DLL).

Почему вы хотите разрешить его в другой bar из main.o?

Если вы не решите вызовmain.o, в результате вы получаете совершенно другую программу, по сравнению со ссылками на libfoobar.a.

...