Какова связь между файлом shared object (.so
) и объектом (.o
)?
можете ли вы объяснить пример?
Какова связь между файлом shared object (.so
) и объектом (.o
)?
можете ли вы объяснить пример?
Скажем, у вас есть следующий исходный файл C, назовите его name.c
#include <stdio.h>
#include <stdlib.h>
void print_name(const char * name)
{
printf("My name is %s\n", name);
}
При компиляции с cc name.c
вы создаете name.o
. В файле .o содержится скомпилированный код и данные для всех функций и переменных, определенных в name.c, а также индекс, связанный с их именами с фактическим кодом. Если вы посмотрите на этот индекс, скажем, с помощью инструмента nm
(доступного в Linux и многих других Unix), вы заметите две записи:
00000000 T print_name
U printf
Что это означает: есть два символа (имена функций или переменных, но не имена классов, структур или любых типов), хранящиеся в .o. Первый, помеченный T
, фактически содержит его определение в name.o
. Другой, отмеченный знаком U
, является просто ссылкой. Код для print_name
можно найти здесь, но код для printf
не может. Когда ваша настоящая программа будет запущена, вам нужно будет найти все символы, которые являются ссылками, и искать их определения в других объектных файлах, чтобы быть связанными в полную программу или полную библиотеку. Таким образом, объектный файл - это определения, найденные в исходном файле, преобразованные в двоичную форму и доступные для размещения в полной программе.
Вы можете соединять файлы .o по одному, но вы этого не делаете: их, как правило, много, и они являются деталями реализации. Вы бы предпочли, чтобы все они были собраны в пучки связанных объектов с хорошо распознанными именами. Эти пучки называются библиотеками, и они бывают двух форм: статические и динамические.
Статическая библиотека (в Unix) почти всегда суффикс с .a
(примеры включают libc.a
, которая является библиотекой ядра C, libm.a
, которая является математической библиотекой C) и так далее. Продолжая пример, вы создадите свою статическую библиотеку с помощью ar rc libname.a name.o
. Если вы запустите nm
на libname.a
, вы увидите следующее:
name.o:
00000000 T print_name
U printf
Как вы можете видеть, это, прежде всего, большая таблица объектных файлов с индексом, в котором находятся все имена. Подобно объектным файлам, он содержит оба символа, определенные в каждом .o
, и символы, на которые они ссылаются. Если вы должны были установить ссылку в другом .o(например, date.o
на print_date
), вы увидите другую запись, подобную приведенной выше.
Если вы связываете статическую библиотеку с исполняемым файлом, она вставляет всю библиотеку в исполняемый файл. Это похоже на соединение во всех отдельных файлах .o
. Как вы можете себе представить, это может сделать вашу программу очень большой, особенно если вы используете (как большинство современных приложений) множество библиотек.
Динамическая или разделяемая библиотека помещается в .so
. Он, как и его статический аналог, представляет собой большую таблицу объектных файлов, ссылаясь на весь скомпилированный код. Вы построили его с помощью cc -shared libname.so name.o
. Однако просмотр с nm
немного отличается от статической библиотеки. В моей системе он содержит около двух десятков символов, из которых только два являются print_name
и printf
:
00001498 a _DYNAMIC
00001574 a _GLOBAL_OFFSET_TABLE_
w _Jv_RegisterClasses
00001488 d __CTOR_END__
00001484 d __CTOR_LIST__
00001490 d __DTOR_END__
0000148c d __DTOR_LIST__
00000480 r __FRAME_END__
00001494 d __JCR_END__
00001494 d __JCR_LIST__
00001590 A __bss_start
w [email protected]@GLIBC_2.1.3
00000420 t __do_global_ctors_aux
00000360 t __do_global_dtors_aux
00001588 d __dso_handle
w __gmon_start__
000003f7 t __i686.get_pc_thunk.bx
00001590 A _edata
00001594 A _end
00000454 T _fini
000002f8 T _init
00001590 b completed.5843
000003c0 t frame_dummy
0000158c d p.5841
000003fc T print_name
U [email protected]@GLIBC_2.0
Разделяемая библиотека отличается от статической библиотеки одним очень важным способом: она не встраивается в ваш окончательный исполняемый файл. Вместо этого исполняемый файл содержит ссылку на эту разделяемую библиотеку, которая разрешена, а не время соединения, но во время выполнения. Это имеет ряд преимуществ:
Есть некоторые недостатки:
(Если вы думаете об этом, многие из них - это причины, по которым программы используют или не используют ссылки и указатели вместо прямого встраивания объектов класса в другие объекты. Аналогия довольно прямая.)
Хорошо, это много деталей, и я пропустил много, например, как работает процесс связывания. Надеюсь, вы сможете следовать этому. Если не просить разъяснений.
A.so аналогичен .dll на окнах. A.o в точности совпадает с .obj в Visual Studio.