какова связь между файлом общего объекта (.so
) и файлом объекта (.o
)?
не могли бы вы объяснить на примере?
какова связь между файлом общего объекта (.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 __cxa_finalize@@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 printf@@GLIBC_2.0
Общая библиотека отличается от статической в одном очень важном отношении: она не встраивается в ваш окончательный исполняемый файл. Вместо этого исполняемый файл содержит ссылку на эту разделяемую библиотеку, которая разрешается не во время компоновки, а во время выполнения. Это дает ряд преимуществ:
Есть некоторые недостатки:
(Если задуматься, многие из этих причин являются причинами, по которым программы используют или не используют ссылки и указатели вместо того, чтобы напрямую встраивать объекты класса в другие объекты. Аналогия довольно прямая.)
Хорошо, это много деталей, и я многое пропустил, например, как на самом деле работает процесс связывания. Я надеюсь, ты сможешь следить за этим. Если нет, попросите разъяснений.
cc name.c
, ld
не удастся: /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crt1.o: In function '_start': (.text+0x20): undefined reference to 'main'
- person Drew Noakes; 31.01.2013
.So аналогичен .dll в Windows. .O - это то же самое, что .obj в Visual Studio.