Как опция gcc `-shared` влияет на выход?

Технически, с точки зрения содержимого файла, в чем разница между выходом gcc -fPIC -shared src.c и gcc -fPIC src.c ?

Предположим, что int main(int, char**) определен в src.c чтобы обе компиляции были успешными. Но выполнение a.out сгенерированного gcc -shared src.c , как и ожидалось, дало следующую ошибку:

-bash: ./a_shared.out: cannot execute binary file

Даже если есть main функция, это так.

Кроме того, как я могу проверить разницу в выходных файлах с помощью таких инструментов, как otool или objdump ?

Большое спасибо.

Общие библиотеки и исполняемые файлы используют один и тот же формат: оба являются загружаемыми изображениями. Тем не мение,

  1. Общие библиотеки обычно не зависят от положения, исполняемые файлы часто отсутствуют. Это влияет на генерацию кода: для независимой от позиции вам необходимо загрузить глобальные переменные или перейти к функциям с использованием относительных адресов.

  2. В исполняемых файлах есть «точка входа», в которой начинается выполнение. Обычно это не main() , потому что main() – это функция, а функции возвращаются, но выполнение не должно возвращаться из точки входа.

Теперь это не отвечает на вопрос о том, что -shared делает. Вы можете спросить GCC, используя флаг -v . Вот различия в моей системе между вызовом без и с -shared .

Параметры для collect2 без -shared :

 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.7/crtbegin.o /usr/lib/gcc/x86_64-linux-gnu/4.7/crtend.o 

Параметры для collect2 с -shared :

 -shared /usr/lib/gcc/x86_64-linux-gnu/4.7/crtbeginS.o /usr/lib/gcc/x86_64-linux-gnu/4.7/crtendS.o 

наблюдения

Похоже, что генерация кода не влияет: вам все равно придется использовать -fpic или -fPIC .

Вы можете видеть, что crt1.o («C runtime») включается только при связывании исполняемого файла. Используя nm , мы можем узнать, что он содержит:

 $ nm /usr/lib/x86_64-linux-gnu/crt1.o 0000000000000000 R _IO_stdin_used 0000000000000000 D __data_start U __libc_csu_fini U __libc_csu_init U __libc_start_main 0000000000000000 T _start 0000000000000000 W data_start U main 

Таким образом, вы можете видеть, что он, как представляется, определяет что-то _start с stdin , а также _start (что является точкой входа) и имеет неопределенную ссылку на main .

Я не уверен, что остальные файлы, но, по крайней мере, вы знаете, как их найти, и вы можете совать или посмотреть исходный код, если хотите.

В соответствии с параметром https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html#Link-Options -shared выполняется следующее

 Produce a shared object which can then be linked with other objects to form an executable. Not all systems support this option. For predictable results, you must also specify the same set of options used for compilation (-fpic, -fPIC, or model suboptions) when you specify this linker option. 

В соответствии с Разделом между -shared и -Wl -shared из параметров GCC. Передача -shared в GCC может включать или отключать другие флаги во время ссылки.

По моему пониманию, если исполняемый файл имеет общую библиотеку, размер исполняемого файла очень мал . Исполняемый файл не будет запускаться до тех пор, пока общая библиотека не будет присутствовать и не будет правильно связана. Преимущество использования разделяемой библиотеки в том, что если у нас очень большая база кода, нам не нужно постоянно создавать весь код . Нам просто нужно перестроить файл .so и связать его с исполняемым. Это экономит много времени .

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