Какова связь между общим объектом (.so
) файлом и объектом (.o
)?Связь между объектным файлом и файлом общего объекта
не могли бы вы объяснить на примере?
Какова связь между общим объектом (.so
) файлом и объектом (.o
)?Связь между объектным файлом и файлом общего объекта
не могли бы вы объяснить на примере?
A .so аналогичен .dll на окнах. A .o в точности совпадает с .obj в Visual Studio.
Допустим, у вас есть следующий исходный файл 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 и многих других Unixes) вы увидите две записи:
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
Разделяемая библиотека отличается от статической библиотеки в одном очень важном аспекте: не встраивать себя в своем окончательном исполняемый файл. Вместо этого исполняемый файл содержит ссылку на эту разделяемую библиотеку, которая разрешена, а не время соединения, но во время выполнения. Это имеет ряд преимуществ:
Есть некоторые недостатки:
(Если вы думаете об этом многие из них являются программы причин использовать или не использовать ссылки и указатели вместо непосредственного вложения объектов класса в другие объекты. Аналогия довольно прямая.)
Хорошо, это много деталей, и я пропустил много, например, как работает процесс связывания. Надеюсь, вы сможете следовать этому. Если не просить разъяснений.
Следует отметить, что общие библиотеки являются обычным способом реализации плагинов. Плагин - это способ расширения функциональности приложения без его изменения. Приложение может загружать общую библиотеку, вызывая в dlopen() путь к библиотеке a аргумент, а затем dlsym(), чтобы найти конкретный символ в библиотеке (например, функция). Затем приложение вызывает функцию для выполнения функций из библиотеки. – dimba
Хорошее знакомство с миром погрузки и связи :) +1 – xtofl
Красивые объяснения :) +1 –