Подтвердить что ты не робот

Связь между объектным файлом и файлом общего объекта

Какова связь между файлом shared object (.so) и объектом (.o)?

можете ли вы объяснить пример?

4b9b3361

Ответ 1

Скажем, у вас есть следующий исходный файл 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

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

  • Ваш исполняемый файл намного меньше. Он содержит только код, явно связанный через объектные файлы. Внешние библиотеки являются ссылками, и их код не входит в двоичный файл.
  • Вы можете разделить (отсюда название) одну библиотеку бит между несколькими исполняемыми файлами.
  • Если вы внимательно относитесь к бинарной совместимости, обновите код в библиотеке между прогонами программы, и программа подберет новую библиотеку, не требуя ее изменения.

Есть некоторые недостатки:

  • Требуется время, чтобы связать программу вместе. В общих библиотеках часть этого времени откладывается до каждого запуска исполняемого файла.
  • Процесс более сложный. Все дополнительные символы в общей библиотеке являются частью инфраструктуры, необходимой для соединения библиотеки во время выполнения.
  • Вы рискуете тонкой несовместимостью между различными версиями библиотеки. В Windows это называется "DLL ад".

(Если вы думаете об этом, многие из них - это причины, по которым программы используют или не используют ссылки и указатели вместо прямого встраивания объектов класса в другие объекты. Аналогия довольно прямая.)

Хорошо, это много деталей, и я пропустил много, например, как работает процесс связывания. Надеюсь, вы сможете следовать этому. Если не просить разъяснений.

Ответ 2

A.so аналогичен .dll на окнах. A.o в точности совпадает с .obj в Visual Studio.