Кафедра "Програмне забезпечення"
Лекції з курсу "Проектування асемблерів, компонувальників, макропроцесорів
Зв'язування - це зв'язування двох або більше окремих програм, що відтранслюються.
- розподіл ВП;
- переміщення програми;
- зв'язування модулів;
- завантаження програм у ВП та запуск на виконання.
Розподіл ВП
Переміщення програми
Зв'язування модулів
Види завантажувачів
Завантажувачі типу «компіляція-виконання»
Одним з можливих способів виконання функції завантажувача може бути така організація роботи асемблера, при якій асемблер, працюючи в одній частині пам'яті, поміщає машинні команди та дані в міру асемблювання безпосередньо у виділені для них клітинки пам'яті. Після завершення компіляції асемблер передає управління в точку входу отриманої програми. Це дуже просте рішення, що дозволяє обійтися без додаткових процедур. Така схема називається "компіляція-виконання", а "завантажувач" складається з однієї команди, яка передає управління асембльованій програмі.
Однак ця схема має ряд недоліків:
- деяка частина пам'яті може бути використана, т.к. зайнята асемблером пам'ять недоступна для об'єктної програми;
- при кожному новому прогоні доводиться заново транслювати програму користувача;
- важко організувати роботу кількох сегментів програми, особливо, якщо вихідні тексти написані різними мовами, т.к. кожна мова створює своє середовище у ВП.
- розподіл пам'яті виконується автоматично;
- одна і та ж програма-компілятор виконує функції переміщення та зв'язування, завантаження та запуску.
Абсолютний завантажувач
Загальна схемазавантаження
Враховуючи недоліки завантажувачів типу «компіляція-виконання», видно, що доцільним буде організувати зберігання результатів трансляції на певному зовнішньому носії для того, щоб завантажити їх, коли знадобиться виконати отриману програму. При цьому асембльована програма може бути завантажена в ту саму область, яку раніше займав асемблер. Ця форма висновку називається об'єктною програмою. Тоді робота завантажувача полягатиме в тому, що він приймає на вході асембльовані команди та інформацію, представлену у вигляді об'єктної програми, а сам у свою чергу поміщає в пам'ять машинні команди, дані у машинній формі, що здійснюється. Цей тип завантаження усуває основні недоліки розглянутого раніше типу.
Абсолютні завантажувачі прості у реалізації, але мають низку особливостей:
- задачу розподілу ВП виконує програміст (за допомогою директиви встановлення початкового значення ВП);
- завдання переміщення програми виконує компілятор;
- зв'язування модулів – вирішується програмістом (call 600);
- завантаження програм у ВП та запуск на виконання.
- менший обсяг завантажувача (за величиною пам'яті);
- поділ фази компіляції та завантаження, що скорочує час на обробку модулів;
- можливість використання кількох мов програмування, т.к. структури створюваних об'єктних модулів ідентичні.
Структура об'єктного файлу абсолютного завантажувача
Інформаційний запис складається з:
Керуючий запис складається з:
Робота простого абсолютного завантажувача:
Завантажувач, що настроює
Щоб уникнути необхідності повторного асемблювання всіх підпрограм при внесенні зміни до однієї з них, а також щоб звільнити програміста відзадач розподілу пам'яті та здійснення зв'язку підпрограм, були розроблені так звані завантажувачі. Цей завантажувач допускає наявність у програмі кількох програмних сегментів та одного сегмента даних (загального сегмента). Асемблер транслює кожен сегмент окремо і передає завантажувачу текст та інформацію, що стосується переміщень та перехресних посилань між сегментами.
Виходом асемблера за такої схеми є об'єктна програма та інформація про всі інші програми, до яких у цій програмі є звернення. Крім того, є інформація про місця, які повинні бути змінені при завантаженні (інформація про переміщення), тобто. про осередки, вміст яких залежить від розташування програми в пам'яті.
Такий завантажувач має ряд недоліків:
- вектор переходів не цілком зручний для завантаження та збереження зовнішніх даних (розташованих в іншому програмному сегменті);
- вектор переходів підвищує довжину об'єктної програми;
- завантажувач працює з програмними сегментами, але не полегшує доступ до сегментів даних, які можуть використовуватися спільно кількома підпрограмами.
Безпосередньо зв'язуючий завантажувач
Безпосередньо зв'язуючий завантажувач найбільше повно забезпечує можливість переміщення в пам'яті програм і даних і в даний час найбільш поширений. Такий завантажувач має ту перевагу, що допускає використання великої кількості програмних сегментів, так і сегментів даних і дає програмісту повну свободу звернення до даних, що знаходяться в інших сегментах, допускаючи при цьому роздільну трансляцію.
Асемблер (транслятор) повинен передати завантажувачу наступну інформацію з кожним сегментом програми та даних:
Динамічний завантажувач
Укожній із розглянутих схем передбачалося, що всі необхідні підпрограми завантажуються на згадку одночасно. Якщо загальна кількість пам'яті, потрібна для підпрограм менше доступної пам'яті машини, виникають труднощі. Ці труднощі долаються застосуванням схеми динамічного завантаження із послідовним використанням об'єднувача та завантажувача. Ця схема полягає в тому, що зазвичай різні підпрограми потрібні в час і можуть взаємно виключати себе. Використовуючи явне визначення того, яка підпрограма містить звернення до інших підпрограм, можна задати так звану структуру з перекриттям (оверлейну структуру), яка вказує взаємовиключні підпрограми.
Формується завантажувальний модуль. Він переміщується, у ньому має бути таблиця переміщень. Також у структурі завантажувального модуля має бути інформація про зв'язки. Завантажувач повинен містити таку частину, як диспетчер оверлєєв, він відбирає із завантажувальних модулів саме ті, які є стартовими, у процесі роботи організує завантаження в ОП необхідних модулів.
Трапляються випадки, коли для ефективності використання пам'яті машини здійснюється динамічне зв'язування підпрограм, що проводиться вже під час виконання програми. Тобто підпрограми завантажуються на згадку лише у міру їх виклику. Це може бути вигідним, т.к. за певних умов у програмі деякі підпрограми можуть взагалі не знадобитися. Розглянемо приклад:
Багато гілок буде пропущено, і не доведеться завантажувати в ОП, наприклад, підпрограму 2 при невиконанні умови 2. У такому разі завантажувач повинен працювати одночасно з програмою і виконувати функції зв'язування та завантаження підпрограм.