Ръководство за начинаещи за Linker в C
(обхват - функция)
(обхват - функция)
int*p = malloc(sizeof(int));
Вероятно най-лесният начин да научите е просто да разгледате примерната програма.
/* Дефиниране на неинициализирана глобална променлива */
/* Дефиниране на инициализирана глобална променлива */
int x_global_init = 1;
/* Дефиниране на неинициализирана глобална променлива, към която
* може да се използва само по име в този C файл */
статичен int y_global_uninit;
/* Дефиниция на инициализирана глобална променлива, към която
* може да се използва само по име в този C файл */
статичен int y_global_init = 2;
/* Деклариране на глобална променлива, която е дефинирана някъде
* другаде в програмата */
extern int z_global;
/* Деклариране на функция, която е дефинирана някъде другаде
* програми (Можете да добавите "extern" отпред, но това
int fn_a(int x, int y);
/* Дефиниция на функция. Въпреки това, ако е маркиран като статичен, може да бъде
* извикване по име само в този C файл. */
статичен int fn_b(int x)
/* Функционалният параметър се третира като локална променлива. */
int fn_c(int x_local)
/* Дефиниране на неинициализирана локална променлива */
/* Дефиниране на инициализирана локална променлива */
int y_local_init = 3;
/* Код, който има достъп до локални и глобални променливи,
* както и функции по име */
x_global_uninit = fn_a(x_local, x_global_init);
y_local_uninit = fn_a(x_local, y_local_init);
връщане (x_global_uninit + y_local_uninit);
Какво прави C компилаторът
работаРаботата на C компилатора е да преобразува текст, който (обикновено) е разбираем от човек, в нещо, което компютърът разбира. Като изход компилаторът създава обектен файл. На UNIX платформи тези файлове обикновено имат суфикс .o; на Windows, суфиксът .obj. Съдържанието на един обектен файл е по същество две неща:
дефиниция на функция за съвпадение на код в C файл
данни, съответстващи на дефиницията на глобалните променливи във файла C (за инициализирани глобални променливи първоначалната стойност на променливата също трябва да се съхранява в обектния файл).
Кодът и данните в този случай ще имат имена, свързани с тях - имената на функциите или променливите, с които са свързани по дефиниция.
Обектният код е поредица от (подходящо съставени) машинни инструкции, които съответстват на C инструкции, написани от програмиста: всички тези ifs и whiles и дори gotos. Тези заклинания трябва да манипулират някакъв вид информация и информацията трябва да е някъде - това е, за което се нуждаем от променливи. Кодът може да се отнася и до друг код (по-специално до други C функции в програмата).
Работата на линкера е да провери тези обещания. Но какво прави компилаторът с всички тези обещания, когато генерира обектен файл?
Имайки предвид това, можем да изобразим обектния файл, съответстващ на горната програма, както следва:

Разбор на обектен файл
Дотук сме обмислили всичко на високо ниво. Въпреки това е полезно да се види как това работи на практика. Основният инструмент за нас ще бъде командата nm, която дава информация за символите на обектен файл на UNIX платформата. В Windows командата dumpbin с опцията /symbols е приблизително еквивалентна. Има и пренесенипод Windows, инструментите на GNU binutils, които включват nm.exe.
Нека да видим какво извежда nm за обектния файл, получен от нашия пример по-горе:
Символи от c_parts.o:
Име Стойност Клас Тип Размер Линия Раздел
fn_a U NOTTYPE *UND*
z_global U NOTTYPE *UND*
fn_b 00000000 t FUNC00000009 .текст
x_global_init 00000000 D OBJECT00000004 .data
y_global_uninit 00000000 b OBJECT00000004 .bss
x_global_uninit 00000004 C OBJECT00000004 *COM*
y_global_init 00000004 d OBJECT00000004 .data
fn_c 00000009 T FUNC00000055 .текст
Резултатът може да изглежда малко по-различно на различни платформи (проверете страниците на ръководството за подробности), но ключовата информация е класът на всеки знак и неговият размер (ако има). Класът може да има различни стойности:
- Класът U означава неопределени препратки, тези "празни пространства", споменати по-горе. Има два обекта за този клас: fn_a и z_global. (Някои версии на nm може да изведат раздел, който би бил *UND* или UNDEF в този случай.)
- Класовете t и T сочат към кода, който е дефиниран; разликата между t и T е дали функцията е локална (t) във файла или не (T), т.е. дали функцията е декларирана като статична. Отново, на някои системи може да се покаже раздел като .text.
- Класовете d и D съдържат инициализирани глобални променливи. В този случай статичните променливи принадлежат към клас d. Ако има информация за раздел, тя ще бъде .data.
- За неинициализирани глобални променливи получаваме b, ако са статични, и B или C в противен случай. Разделът в този случай най-вероятно ще бъде .bss или *COM*.
Можете също да видите символикоито не са част от изходния код на C. Няма да се фокусираме върху това, тъй като обикновено е част от вътрешния механизъм на компилатора, така че вашата програма да може да бъде свързана по-късно.