Посібник новачка з експлуатації компонувальника в C

(область дії – функція)

(область дії – функція)

int * p = malloc (sizeof (int));

Ймовірно, легший шлях засвоїти — це просто подивитися на приклад програми.

/* Визначення неініціалізованої глобальної змінної */

/* Визначення ініціалізованої глобальної змінної */

int x_global_init = 1;

/* Визначення неініціалізованої глобальної змінної, до якої

* можна звернутися по імені лише в межах цього C файлу */

static int y_global_uninit;

/* Визначення ініціалізованої глобальної змінної, до якої

* можна звернутися по імені лише в межах цього C файлу */

static int y_global_init = 2;

/* Оголошення глобальної змінної, яка визначена десь

* в іншому місці програми */

extern int z_global;

/* Оголошення функції, яка визначена де-небудь іншому місці

* програми (Ви можете додати попереду "extern", проте це

int fn_a(int x, int y);

/* Визначення функції. Однак, будучи поміченою як static, її можна

* викликати на ім'я тільки в межах цього C файлу. */

static 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);

return (x_global_uninit + y_local_uninit);

Що робить C компілятор

РоботаКомпілятор C полягає в конвертуванні тексту, (звичайно) зрозумілій людині, в щось, що розуміє комп'ютер. На виході компілятор видає файл. На платформах UNIX ці файли зазвичай мають суфікс .o; у Windows - суфікс .obj. Зміст об'єктного файлу – по суті дві речі:

код, що відповідає визначенню функції у файлі C

дані, що відповідають визначенню глобальних змінних у файлі C (для ініціалізованих глобальних змінних початкове значення змінної теж має бути збережено в об'єктному файлі).

Код і дані, у разі, матимуть асоційовані із нею імена — імена функцій чи змінних, із якими пов'язані визначенням.

Об'єктний код - це послідовність (відповідним чином складених) машинних інструкцій, які відповідають C інструкціям, написаних програмістом: всі ці if'и і while'и і навіть goto. Ці заклинання мають маніпулювати інформацією певного роду, а інформація має бути десь знаходиться — для цього нам і потрібні змінні. Код може також посилатися на інший код (зокрема інші функції C у програмі).

Робота компонувальника перевірити ці обіцянки. Однак що компілятор робить з усіма цими обіцянками, коли він генерує об'єктний файл?

Враховуючи це, ми можемо зобразити об'єктний файл, який відповідає програмі, наведеній вище, таким чином:

експлуатації

Аналіз об'єктного файлу

Досі ми розглядали все на найвищому рівні. Однак корисно подивитися, як це працює на практиці. Основним інструментом для нас буде команда nm, яка надає інформацію про символи об'єктного файлу на платформі UNIX. Для Windows команда dumpbin із опцією /symbols є приблизним еквівалентом. Також є портованіпід Windows інструменти GNU binutils, які включають nm.exe.

Давайте подивимося, що видає nm для об'єктного файлу, отриманого з прикладу вище:

Symbols from c_parts.o:

Name Value Class Type Size Line Section

fn_a U NOTYPE *UND*

z_global U NOTYPE *UND*

fn_b 00000000 t FUNC00000009 .text

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 .text

Результат може виглядати трохи по-різному на різних платформах (зверніться до man'ів, щоб отримати відповідну інформацію), але ключовими відомостями є клас кожного символу та його розмір (якщо є). Клас може мати різні значення:

  • Клас U означає невизначені посилання, ті самі «порожні місця», згадані вище. Для цього класу існує два об'єкти: fn_a та z_global. (Деякі версії nm можуть виводити секцію, яка була б *UND* або UNDEF у цьому випадку.)
  • Класи t та T вказують на код, який визначено; різницю між t і T у тому, чи є функція локальної (t) у файлі чи ні (T), тобто. була функція оголошена як static. Знову ж таки в деяких системах може бути показана секція, наприклад .text.
  • Класи d та D містять ініціалізовані глобальні змінні. У цьому статичні змінні належать класу d. Якщо є інформація про секції, то це буде .data.
  • Для неініціалізованих глобальних змінних ми отримуємо b, якщо вони статичні і B або C інакше. Секцією у цьому випадку буде швидше за все .bss або *COM*.

Також можна побачити символи,які є частиною вихідного C коду. Ми не будемо загострювати нашу увагу на цьому, тому що це зазвичай частина внутрішнього механізму компілятора, щоб Ваша програма все-таки змогла бути потім скомпонована.