Почему это так?
Большинство компоновщиков (компоновщик 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
.