Я знаю, что объектные файлы (.o) всегда можно перемещать,
что о .a
и .so
файлы?
А .a
файл - это просто архив других файлов. Обычно это .o
файлы, ответ на которые вы уже знаете. Но они не обязательно должны быть - они вообще не обязательно должны быть объектным кодом - они могут быть буквально любыми файлами, которые вам нравятся.
А .so
файл должен быть перемещаемым для работы, поскольку он должен иметь возможность загружаться по разным адресам в разных процессах в зависимости от того, какой адрес доступен во время выполнения.
Давайте начнем с того, что является устоявшимся определением перемещаемого. Фрагмент кода можно перемещать, если его можно разместить в любом месте памяти без изменений и правильно выполнить. Таким образом, файлы .o и .a нельзя перемещать, потому что они не являются фрагментами кода (!). Файлы .o содержат фрагмент кода с сопутствующей информацией, а файлы .a - это набор любых файлов, возможно, .o.
Тогда можно ли перемещать код, содержащийся в .o? Нет, не в общем, потому что он должен быть усилен компоновщиком для заполнения адресов с использованием информации, которая поставляется с файлом .o. Например. синус вычисляется с использованием полиномиального вычислителя, который находится в какой-то другой библиотеке, о которой знает только компоновщик. Таким образом, адрес вызова полиномиального вычислителя все еще должен быть заполнен; другими словами, код не может быть выполнен как таковой.
Наконец, код в файле .so можно перемещать, потому что этот код является общим и может выполняться несколькими процессами одновременно. Было бы неудобно, если бы все эти процессы размещали код по одному адресу, по которому он выполняется правильно.
Может быть, немного поздно, но позвольте мне попробовать:
Бонус: исполняемый файл не обязательно должен быть 'pic', но если он есть, при его запуске можно использовать ASLR: https://en.wikipedia.org/wiki/Address_space_layout_randomization