:: Статистика ::

 
Індекс цитування

 

 

 

 

 

Збірка програм

  Він був спритний і весь такий зібраний джентльмен, і одягнений — в самий кращий і дорожчий одяг; і все у нього було підібрано і приганяє, навіть частини тіла.
А. Тутуола

У попередньому розділі йшла мова про типів виконуваних модулів, але не говорилося ні слова про те, яким чином ці модулі виходять. Взагалі кажучи, спосіб створення завантажуваного модуля різний в різних ОС, але в даний час у всіх широко поширених системах цей процес виглядає приблизно однаково. Це зв'язано, перш за все, з тим, що ці системи використовують одні і ті ж мови програмування і правила міжмодульної взаємодії, в яких явно або неявно визначають логіку роздільної компіляції і збірки.
У більшості сучасних мов програмування програма складається з окремих слабо зв'язаних модулів. Як правило, кожному такому модулю відповідає окремий файл вихідного тексту. Ці файли незалежно обробляються мовним процесором (компілятором), і для кожного з них генерується окремий файл, званий об'єктним модулем. Потім запускається програма, - звана редактором зв'язків, компонувальником або лінкером (linker — той, хто зв'язує), яка формує із заданих об'єктних модулів цілісну програму.
Об'єктний модуль частково схожий по структурі на переміщуваний завантажувальний модуль. Річ у тому, що збірку програми з декількох модулів можна уподібнити завантаженню в пам'ять декількох програм. При цьому виникає те ж завдання перенастроювання адресних заслань, що і при завантаженні відносного завантажувального файлу (мал. 3.8). Тому об'єктний модуль повинен в тій або іншій формі містити таблицю переміщень. Можна, звичайно, зажадати, аби весь модуль був не-залежним, але це, як говорилося вище, накладає дуже жорсткі обмеження на стиль програмування, а на багатьох процесорах (наприклад Intel 8085) просто неможливо.
Окрім заслань на власні мітки, об'єктний модуль має право посилатися на символи, визначені в інших модулях. Типовий приклад такого заслання — звернення до функції, яка визначена в іншому файлі вихідного тексту (мал. 3.9 і 3.10).

Мал. 3.8. Збірка програми

Для дозволу зовнішніх заслань ми повинні створити дві таблиці: у одній перераховані зовнішні об'єкти, на які посилається модуль, в іншій — об'єкти, визначені усередині модуля, на яких можна посилатися ззовні. Зазвичай з кожним таким об'єктом асоційовано ім'я, зване глобальним символом. Як правило, це ім'я збігається з ім'ям відповідної Функції або змінної у вихідній мові.
Для кожного заслання на зовнішній символ ми повинні уміти визначити, є це заслання абсолютним або відносним, або це взагалі має бути різниця або сума два або навіть більш за адреси, і так далі Для визначення об'єкту, з іншого боку, ми повинні уміти вказати, що це абсолютний Або переміщуваний символ, або що він дорівнює іншому символу плюс заданий зсув, і так далі

Мал. 3.9. Дозвіл зовнішніх заслань (об'єктний модуль)

Мал. 3.10. Дозвіл зовнішніх заслань (зібрана програма)

Крім того, в об'єктних файлах може міститися налагоджувальна інформація, формат якої може бути дуже складним. Отже, об'єктний файл є досить складною і рихлою структурою. Розмір зібраної програми може виявитися в два або три рази менше суми довжин об'єктних модулів.
Типовий об'єктний модуль містить наступні структури даних.

  • Таблицю переміщень, тобто таблицю заслань на переміщувані об'єкти усередині модуля.
  • Таблицю заслань на зовнішні об'єкти. Інколи це називається таблицею або списком імпорту.
  • Таблицю об'єктів, визначених в цьому модулі, на яких можна посилатися з інших модулів. В деяких випадках її називають списком експорту. Інколи таблиці експорту і імпорту об'єднують і називають все це таблицею глобальних символів. В цьому випадку для кожного символу доводиться вказувати, визначений він в даному модулі чи ні, а якщо визначений, то як.
  • Різну службову інформацію, таку, як ім'я модуля, програму, яка його створила (наприклад, рядок "gcc compiled").
  • Налагоджувальну інформацію.
  • Власне код і дані модуля.

Як правило, код і дані розбиті на іменовані секції. У masm/tasm (MASM — Microsoft Assembler, Tasm — Turbo Assembler) такі секції називаються сегментами, в DЕС'овских і UNIX'oвых асемблерах — програмними секціями (psect). У готовій програмі весь код або дані, описаний в різних модулях, але що належить до однієї секції, збирається разом. Наприклад, в системах сімейства Unix програми, написані на мові З, складаються з мінімум трьох програмних секцій:

  • .text — виконуваний код (сучасні компілятори інколи поміщають в цю секцію і дані, описані як const);
  • .data — дані, що статично ініціалізували;
  • .bss — неініціалізовані дані.

Як вправа читачеві пропонується знайти ці секції в прикладі 3.7.
Деякі формати об'єктних модулів, зокрема ELF (Executable and Linking Format — формат виконуваних і збираних [модулів], використовуваний сучасними системами сімейства Unix), надають особливого типа глобального символу — слабкий (weak) символ (приклад 3.8). При збірці програми компонувальник не видає повідомлення про помилку, якщо виявляє Два різні визначення такого символу, за умови, що одне з визначень є слабким — таким чином, слабкий символ може бути легко перевизначений при необхідності. Особливо корисний цей тип при приміщенні об'єктного модуля в бібліотеку.

Приклад 3.8. Структури даних об'єктного модуля ELF (цитується по elf.h з постачання Linux 2.2.16, переклад коментарів автора)

' Заголовок файлу ELF. Знаходиться на початку кожного файлу ELF. */
#define El NIDENT (16)
typedef struct
unsigned char e_ident[EI_NIDENT]; /* Магічне число і інша інформація */
Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; Elf32_0ff e_phoff;
Elf32_0ff e_shoff; Elf32_Word e_flags; Elf32_Half e_ehsize; Elf32__Half e_phentsize;
Elf32_Half e_phnum; /* Elf32_Half e_shentsize; Elf32_Half e_shnum; /*
Elf32_Half e^shstrndx; ков секцій */
} Elf32 Ehdr;
/* Тип об'єктного файлу */
/* Архітектура */
/* Версія об'єктного файлу */
/* Віртуальна адреса точки входу */
/* Зсув таблиці заголовка програми */
/* у файлі */
/* Зсув таблиці заголовків секцій у файлі */
/* Процесорно-залежні прапори */
/* Розмір заголовка ELF в байтах */
/* Розмір елементу */
/* таблиці заголовка програми */
Лічильник елементів таблиці заголовка програми */
/* Розмір елементу таблиці заголовків секцій */
Лічильник елементів таблиці заголовків програм */
/* Індекс таблиці імен секцій в таблиці заголов-
/* Поля в масиві e_indent. Макроси Е1_* суть індекси в цьому масиві. Макроси, наступні за ка'ждым визначенням Е1_*, суть значення, які відповідний байт може приймати. */
#define EI_MAGO 0 /* Індекс нульового байта сигнатуры1 */
fdefine ELFMAGO 0x7f /* Значення нульового байта сигнатури */
#define EI_MAG1 I /* Індекс першого байта сигнатури */
#define ELFMAG1 'Е' /* Значення першого байта сигнатури */
fdefine EI_MAG2 2 /* Індекс другого байта сигнатури */
#define ELFMAG2 'L' /* Значення другого байта сигнатури */
#define EI_MAG3 3 /* Індекс третього байта сигнатури */
#define ELFMAG3 'F' /* Значення третього байта сигнатури */
1 В даному випадку — це "магічне число", код, що розміщується у визначеному місці (зазвичай на початку) файлу і підтверджуючий, що це файл даного формату.
/* об'єднання ідентифікаційних байтів, для порівняння по словах */ #define ELFMAG "\177ELF" ((define SELFMAG 4
((define EI_CLASS 4 /* Індекс байта, вказуючого клас файлу */
((define ELFCLASSNONE 0 /* Не визначено */
((define ELFCLASS32 1 /* 32-розрядні об'єкти */
((define ELFCLASS64 2 /* 64-розрядні об'єкти */ ((define ELFCLASSNUM 3
tdefine EI_DATA 5 /* Індекс байта кодування даних */
((define ELFDATANONE 0 /* Не визначено кодування даних */
((define ELFDATA2LSB 1 /* Двійкові додаткові, молодший байт перший */
#define ELFDATA2MSB 2 /* Двійкові додаткові, старший байт перший */
tdefine ELFDATANUM 3
#define EI_VERSION 6 /* Індекс байта версії файлу */ /* Значення має бути EV__CURRENT */
#define EIJDSABI 7 /*. ідентифікатор OS ABI */
tdefine ELFOSABI_SYSV 0 /* UNIX System V ABI */
«define ELFOSABI_HPUX 1 /* HP-UX */
tdefine ELFOSABI_ARM 97 /* ARM */
#define ELFOSABI_STANDALONE 255 /* Самостійне (вбудовуване) застосування * /
#define EI_ABIVERSION 8 /* версія ABI */
#define EI_PAD 9 /* Індекс байтів вирівнювання */
/* Допустимі значення для e_type (тип об'єктного файлу). */
#define ETJTONE 0 /* Не вказано тип */
#define ET_REL I /* Переміщуваний файл */
#define ET_EXEC 2 /* Здійснимий файл */
#define ET_DYN 3 /* Разделяємьй объектньй файл */
Define ET_CORE 4 /* Образ завдання */
'define ET_NUM 5 /* Кількість певних типів */
e ET_LOPROC OXFFOO /* Специфічний для процесора */
ttdefine ET_HIPROC Oxffff /* Специфічний для процесора */ /* Допустимі значення для e_machine (архітектура). */
ttdefine EM_NONE 0 /* Не вказано машина */
ttdefine Ем_м32 1 /* AT&T WE 32100 */
ttdefine EM_SPARC 2 /* SUN SPARC */
ttdefine EM_386 3 /* Intel 80386 */
ttdefine EM_68K 4 /* Motorola m68k family */
ttdefine EM_88K 5 /* Motorola m88k family */
ttdefine EM__486 6 /* Intel 80486 */
ttdefine EM_860 7 /* Intel 80860 */
ttdefine EM_MIPS 8 /* MIPS R3000 big-endian */
ttdefine EM_S370 9 /* Amdahl */
ttdefine EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */
ttdefine EM RS6000 11 /* RS6000 */
#define EM_PARISC 15 ttdefine EM_nCUBE 16 Idefine EM VPP500 17
/* HPPA */
/* nCUBE */
/* Fujitsu VPP500 */
ttdefine EM_SPARC32PLUS 18 /* Sun's "vSplus" */ ttdefine EM_960 19 /* Intel 80960 */ ttdefine EM PPC 20 /*. POWERPC */
ttdefine ttdefine ttdefine ttdefine ttdefine ttdefine ttdefine ttdefine ttdefine ttdefine ttdefine ttdefine ttdefine ttdefine ttdefine
EM_V800 36 /* NEC V800 series */ EM_FR20 37 /* Fujitsu FR20 */ EM_RH32 38 /* TRW RH32 */ EM_MMA 39 /* Fujitsu MMA */ EM^ARM 40 /* ARM */ EM_FAKE_ALPHA 41 /* Digital Alpha J
EM_SH 42 EM_SPARCV9 43 EMJTRICORE 44 EM_ARC 45 EM_H8_300 46 EM_H8_300H 47 EM_H8S 48 EM_H8_500 49 EM IA 64 50
/* Hitachi SH */ /* SPARC v9 64-bit */ /* Siemens Tricore */ /* Argonaut RISC Core */ /* Hitachi H8/300 */ /* Hitachi H8/300H */ /* Hitachi H8S */ /* Hitachi H8/500 */ /* Intel Merced */

«define EM_MIPS_X 51 /* Stanford MIPS-X */
•define EM^COLDFIRE 52 /* Motorola Coldfire */
«define EM_68HC12 53 /* Motorola M68HC12 */ ((define EM_NUM 54
/* Якщо необхідне вьщелить неофіційне значення для Ем_*, будь ласка, виділяйте великі випадкові числа (0x8523, Oxa7f2, etc.), аби зменшити вірогідність пересічення з офіційними або не-GNU неофіційними значеннями. */
((define EM_ALPHA 0x9026
/* Допустимі значення для e_version (версія). */
Idefine EV_NONE 0 /* Недопустима версія ELF */ #define EV_CURRENT I /* Поточна версія */ (tdefine EV_NUM 2
/* Елемент таблиці символів. */
typedef struct f
Elf32_Word st_name; /* Ім'я символу (індекс в таблиці рядків) */
Elf32_Addr st_value; /* Значення символу */
Elf32_Word st_size; /* Розмір символу */
unsigned char st_info; /* Тип і прив'язка символу */
unsigned char st_other; /* Значення не визначене, 0 */
Elf32_Section st_shndx; /* Індекс секції */ ) Elf32_Sym;
'* Секція syminfo, якщо присутній, містить додаткову інформацію про кожен динамічний символ. */
typedef struct I
Elf32_Half si_boundto;/* Пряма прив'язка, символ, до якого прив'язаний */ Elf32_Half si_flags; /* Прапори символу */
> Elf32 Syminfo;
/*
Допустимі значення для si boundto. */
#define SYMINFO_BT_SELF Oxffff /* tdefine SYMINFO_BT_PARENT Oxfffe /* ttdefine SYMINFO_BT_LOWRESERVE OXFFOO /*
/* Можливі бітові маски для si_flags #define SYMINFO_FLG_DIRECT 0x0001 /*
tfdefine SYMINFO_FLG_PASSTHRU 0x0002 /* тора */
tfdefine SYMINFO_FLG_COPY 0x0004 /* tdefine SYMINFO_FLG_LAZYLOAD 0x0008 /*
/* Значення версії Syminfo. */ #define SYMINFO_NONE 0 ttdefine SYMINFO_CURRENT 1 #define SYMINFO NUM 2
Символ прив'язаний до себе */ Символ прив'язаний до батька */ Початок зарезервованих записів */
Прямо прив'язуваний символ *•/ Проміжний символ для трансля-
Символ призначений для переміщення копіюванням */ Символ прив'язаний до об'єкту з відкладеним завантаженням */
/* Як витягувати інформацію і включати її в полі st_info. */

#define ELF32_ST_BIND(val) (((unsigned char) (val)) » 4) tfdefine ELF32_ST_TYPE(val) ((val) & Oxf)
ttdefine ELF32_ST_INFO(bind, type) (((bind) « 4) + ((type) & Oxf)) /* Допустимі значення для підполя STJ3IND поля st_info (прив'язка символів). */
#define STB_LOCAL Про ttdefine STB_GLOBAL 1 tdefine STB_WEAK 2 ttdefine STB_NUM 3 #define STB_LOOS 10 #define STB HIOS 12
/* Локальний символ */
/* Глобальний символ */
/* Слабкий символ */
/* К-ть певних типів. */
/* Початок залежних для ОС значень */ _ /* Кінець залежних для ОС значень */
#define STB_LOPROC 13 /* Початок процесорно-залежних значень */ tdefine STB_HIPROC 15 /* Кінець процесорно-залежних значень */
/* Допустимі значення для підполя ST TYPE поля st info (тип символу). */
#define STT_NOTYPE 0 #define STT_OBJECT 1 #define STT FUNC 2
He вказаний */
Символ — об'єкт даних */
Символ — об'єкт коди */
STT_SECTION 3 /* Символ пов'язаний з секцією */
4define STT_FILS 4 /* Ім'я символу — ім'я файлу */
*define ^тт NUM ^ /* К-ть певних типів */
»define STT LOOS 1^ /* Початок залежних для ОС значень */
«define STT_HIOS 12 /* Кінець залежних для ОС значень */
*define STT_LOPROC 13 /* Початок процесорно-залежних значень */
«define STT_HIPROC 15 /* Кінець процесорно-залежних значень */
/* Індекси таблиці символів розміщені в групах і ланцюжках хэша в секції кеш-таблиці символів. Це спеціальне значення індексу вказує на кінець ланцюжка, і означає, що в цій групі більш немає символів. */
((define STNJJNDEF 0 /* Кінець таблиці. */
/* Елемент таблиці переміщень без додаткового значення (у секціях типа SHT_REL). */
typedef struct (
Elf32_Addr r_offset; /* Адреса */
Elf32_Word r_info; /* Тип переміщення і індекс символу */ } Elf32_Rel;
/* Елемент таблиці переміщень з додатковим значенням (у секціях типа SHT_RELA). */
typedef struct (
Elf32_Addr r_offset; /* Адреса */
Elf32_Word r_info; /* Тип переміщення і індекс символу */
Elf32_Sword r_addend; /* Додаткове значення */ ) Elf32_Rela;
'•* Як витягувати інформацію і включати її в полі r_info. */
#define ELF32_R_SYM(val) ((val) » 8)
Define ELF32_R_TYPE(val) ((val) & Oxff)
#define ELF32_R_INFO(sym, type) (((sym) « 8) + ((type) & Oxff))
/* Типи переміщень для 1386 (формули узяті з
[docs.sun.com 816-0559-10] - авт.)
А — додаткове значення, використовуване при обчисленні значення переміщуваного поля.
У — базова адреса, починаючи з якої об'єкт, що розділяється, завантажується в пам'ять при виконання [програми]. Об'єкт, що зазвичай розділяється, будується з базовою віртуальною адресою, рівною Про, але адреса при виконання інший.
G — зсув запису в глобальній таблиці зсувів, де адреса переміщуваного символу знаходиться під час виконання. GOT — адреса глобальної таблиці зсувів.
L — місце (зсув в секції або адресу) розташування запису символу в процедурній таблиці скріплення (PLT). PLT перенаправляє виклик функції за справжньою адресою. Редактор зв'язків створює початкову таблицю, а редактор зв'язків часу виконання модифікує записи під час виконання.
Р — місце (зсув в секції або адресу) розташування переміщуваного елементу пам'яті (обчислюється з використанням r_offset).
S — значення символу, індекс якого знаходиться в" елементі таблиці переміщень. */
#define R_386_NONE 0 /* Не переміщати */
ttdefine R__386_32 I /* Пряме 32-розрядне - S + А */
#define R_386_PC32 2 /* 32-розрядне відносно PC-S+A-PV
^define R_386_GOT32 3 /* 32-розрядний елемент GOT - G + А */
#define R_386_PLT32 4 /* 32-розрядна адреса PLT - L + А - Р */
ttdefine R_386_COPY 5 /* Копіювати символ при виконання */
#define R_386_GLOB_DAT 6 Л Створити запис GOT - S*/
#define R_386_JMP_SLOT 7 /* Створити запис PLT - S */
tfdefine R_386_RELATIVE 8 /* Зрушити відносно бази програми -
У + А */
tdefine R_386_GOTOFF 9 /* 32-розрядний зсув GOT - S + А - GOT */ ^define R_386_GOTPC 10 /*' 32-розрядний зсув GOT відносно
РС - S + А - GOT */ /* Має бути останній запис. */ #define R 386 NUM 11

 

рекламодавці:

/ ml lfppюн Ресиверы для спутникового твSmart Enigma X5 - ресивер спутниковый в Киеве

::  Меню ::

ГОЛОВНА

Введення

Представлення даних в обчислювальних системах 

Машинні мови

Завантаження програм 

Управління оперативною пам'яттю

Сегментна і сторінкова віртуальна пам'ять

Комп'ютер і зовнішні події

Паралелізм з точки зору програміста 

Реалізація багатозадачності на однопроцесорних комп'ютерах 

Зовнішні пристрої

Драйвери зовнішніх пристроїв 

Файлові системи 

Додаток. Огляд архітектури сучасних ОС

 


:: Навігація ::

Головна

Додати у вишукане  

 

 

 


Copyright © Asentli, 2008