Stack Frames
Executables and Libraries
Пусть у нас есть 2 файла.
//p1.c
int g1 = 1;
extern int g2;
int f(void);
int main(void) { int v1=0x11; return f()+v1+g1+g2; }//p2.c
extern int g1; 
int g2 = 2;
int f(void) { int v2=0x22; return v2+g1+g2; }Скомпилируем их:
gcc -c p1.c p2.cПолучаем файлы p1.o и p2.o. Посмотрим их таблицу символов:
$ nm p1.o
                 U _f		# U = undefined, так как f не определена в p1.c
0000000000000034 D _g1		# D = data section, так как g1 определен 
0000000000000004 C _g2		# C = common symbol, почти то же, что и undefined
0000000000000000 T _main	# T = text section, так как main - функция, определенная в p1.c
$ nm p2.o
0000000000000000 T _f		# T = text section
                 U _g1		# U = undefined
0000000000000024 D _g2		# D = data sectionВ секции Text содержится код функций на ассемблере и его можно посмотреть вот так:
objdump -D p1.oВывод objdump показывает, что в обоих объектных файлах адреса начинаются с 0, а это значит, что их нужно слинковать и в процессе отрелоцировать.
В процессе работы линкера имена переменных исчезают, заменяясь адресами в памяти.
Слинкуем наши объектные файлы:
ld -o t1.bin p1.o p2.oНа маке правда пришлось указать пару дополнительных параметров:
ld -o t1.bin p1.o p2.o -lSystem -macosx_version_min 10.14 Проверим, что получилось:
$ nm t1.bin
0000000000001000 A __mh_execute_header
0000000000001fa0 T _f
0000000000002000 D _g1
0000000000002004 D _g2
0000000000001f60 T _main
                 U dyld_stub_binderКак видим, здесь все наши функции и переменные на месте.
Однако чтобы подключить все необходимые библиотеки, нужно в ld указать еще кучу всяких флагов, поэтому проще восползоваться gcc, чтобы он сам их указал:
gcc -o t1.bin p1.o p2.o`Если хотим слинковать все статически (на маке не работает ):
gcc -static -o t1.bin p1.o p2.o`Можно указать флаг -v чтобы увидеть, с какими аргум ентами вызывается ld.
Cкомпилим наш код как разделяемую библиотеку:
$ gcc -fpic -shared -o libp2.so p2.c
$ gcc -o p.bin p1.c -L"." -lp2
$ LD_LIBRARY_PATH="." ./p.bin
$ echo $?	# 57-fpic- указывает создать position-independent code, это код, который может быть загружен в память в произвольный адрес без необходимости релоцироваться-shared- указывает создать динамическую библиотеку-o libp2.so- указывает целевой файл, имя составляется по правилуlib+name+.so+.version-L"."- линкуем текущую директорию, чтобы либы-зависимости искались в ней-lp2- указывает слинковать с библиотекойlibp2.so, чье имя будет составлено автоматическиLD_LIBRARY_PATH- нужна, чтобы указать адрес, в котором искать зависимостьlibp2.so, иначе она будет искаться в стандартных папках, перечисленных в/etc/ld.so.conf.
Теперь, если сделать objdump -d p.bin или nm p.bin, то мы увидим, что в ней есть main, но нет f. 
А вот в nm libp2.so функция f есть!