Двопрохідний Асемблер
Деякі загальні міркування щодо цієї роботи. Об'єктний код команди складається з поля коду операції та одного або кількох полів операндів. Код операції, як правило, має розмір 1 байт, кількість, формат та семантика полів операндом визначається для кожного типу команд даної апаратної платформи. У загальному випадку операндом команди може бути:
u безпосередній операнд;
u [базовий регістр]+зміщення (тут і далі квадратні дужки означають «вміст того, що взято в дужки»);
u [базовий регістр]+[індексний регістр]+зміщення;
u Асемблер «знав», який регістр він повинен використовувати як базовий;
u Асемблер «знав», яке значення міститься в базовому регістрі;
u у базовому регістрі дійсно містилося це значення.
Перші дві вимоги забезпечуються директивами, третя – машинними командами. Відповідальність за те, щоб у забезпеченні цих вимог директиви узгоджувалися з командами, лежить на програмісті. Ці вимоги по-різному реалізуються у різних обчислювальних системах. Наведемо два приклади.
В Intel Ассемблер використовує як базові сегментні регістри (DS при трансляції імен змінних, CS при трансляції міток). Для простої програми, що складається з однієї секції,
[сегментний_реєстр]+зміщення у секції
Скасування використання сегментного регістру визначається директивою:
Звернемо увагу на те, що під час трансляції команди
Знаючи зміщення іменованого осередку щодо початку програми і зміщення щодо початку програми вмісту базового регістру, Ассемблер легко може обчислити зсув іменованого осередку щодо вмісту базового регістру.
скасовує використаннярегістру як базовий.
Як базові можуть бути призначені кілька регістрів, Асемблер сам вибирає, який з них використовувати в кожному випадку.
Вище ми говорили, що Асемблер «знає» базовий регістр та його вміст. Це «знання» зберігається у таблиці базових регістрів. Зазвичай таблиця містить рядки для всіх регістрів, які можуть бути базовими та ознака, чи використовується регістр у такій якості. Формат рядка таблиці:
FБлок1: Початок 2-го проходу асемблювання.
FБлок2: Початкові установки:
u створення порожньої таблиці базових регістрів;
u відкриття проміжного файлу вихідного модуля;
u встановлення в FASLE ознаки закінчення
FБлок3: Ознака закінчення TRUE?
FБлок4: Зчитування наступного запису проміжного файлу.
FБлок6: З'ясовується, чи містить оператор команду чи директиву
FБлок7: Якщо оператор містить команду, формується байт коду операції (код вибирається з таблиці команд) в об'єктному коді.
FБлок8: Виділення наступного елемента зі списку операндів з видаленням його зі списку та з перевіркою, чи не виявлено при виділенні кінець списку операндів?
FБлок9: Якщо кінець не виявлено, обробляється виділений операнд. Перевіряється, чи не перевищила кількість операндів необхідного для цього типу команди (вибирається з таблиці команд)
FБлок10: Якщо число операндів перевищує необхідне - формування повідомлення про помилку
FБлок11: Якщо число операндів правильне, розпізнається та перевіряється тип операнда.
FБлок12: Якщо тип операнда не розпізнаний або неприпустимий для цієї команди - формування повідомлення про помилку.
FБлок13: Чи є у команді ім'я?
FБлок14: Якщо команда має ім'я, вона шукається в таблиці символів.
FБлок15: Якщо ім'я в таблиці символів не знайдено - формування повідомлення про помилку.
FБлок16: Якщо знайдено ім'я в таблиці символів, воно переводиться в «база-зміщення»
FБлок17: Якщо імені в команді немає, виконується розбір та інтерпретація операнда з перевіркою правильності його кодування.
FБлок18: Якщо виявлено помилки в кодуванні операнда — формування повідомлення про помилку.
FБлок19: Формується код поля операнда і заноситься в об'єктний код команди та обробляється наступний елемент списку операндів.
FБлок20: Якщо кінець списку операндів виявлено, перевіряється, чи не менше число операндів необхідного для цього типу команди. Якщо кількість операндів відповідає необхідному, керування переходить на виведення об'єктного коду.
FБлок21: Якщо кількість операндів менша за потрібну — формування повідомлення про помилку
FБлок22: Якщо оператор, що обробляється, є директивою, алгоритм розгалужується, залежно від того, яка це директива. При обробці будь-якої директиви проводиться розбір та аналіз її операндів і (не показано на схемі алгоритму) можливе формування повідомлення про помилку.
FБлок23: Обробка директиви типу DD включає:
u виділення елементів списку операндів;
u для кожного елемента - розпізнавання типу та значення константи;
u генерація об'єктного коду константи;
u обробка можливих коефіцієнтів повторення.
FБлок24: Обробка директиви типу BSS може вестися так само, як і DD за винятком того, що замість коду константи генеруються деякі «порожні» коди. Однак ці коди не потрібні в об'єктному модулі, вони можутьне генеруватися, у разі повинні робитися деякі дії, формують «розрив» в об'єктних кодах.
FБлок28: Обробка інших директив ведеться за своїми алгоритмами.
FБлок29: Після закінчення обробки команди або директиви сформований об'єктний код виводиться у файл об'єктного модуля.
FБлок30: Друк рядка лістингу. На цю точку управління також передається при виявленні помилок. За наявності помилки повідомлення про помилку друкується після рядка лістингу. Керування потім передається на зчитування наступного запису проміжного файлу.
FБлок31: Після встановлення ознаки закінчення роботи формуються і виводяться в об'єктний модуль коди літерального пулу, таблиці зв'язувань і переміщень.
FБлок32: Закриваються файли, звільняється виділена пам'ять.
FБлок33: Робота Асемблера завершується.
При розгляді алгоритму ми брали до уваги лише генерацію об'єктних кодів, які відповідають командам та константам. Ми не розглядали те, якою є загальна структура об'єктного модуля.