Все про Assembler українською мовою на сайті net.kr.ua

 

:: Меню ::

Головна
Введення
Архітектура реального режиму
Основи програмування
Команди і алгоритми
Розширені можливості сучасних мікропроцесорів
Система команд процесорів Intel
Книга для гостей
Контакти
Добавити у вибране

:: Друзі ::

 
 

:: Лічильники ::

=

 

 

 

 

Підготовка і відладка програми

Процес підготовки і відладки програми на мові асемблера включає етапи підготовки початкового тексту, трансляції, компоновки і відладки.
Підготовка початкового тексту програми виконується за допомогою будь-якого текстового редактора, хоч би редактора, вбудованого в програму Norton Commander, або ще зручнішого редактора Norton Editor. При використанні одного з досконаліших текстових процесорів, ніби Microsoft Word, слід мати на увазі, що ці програми додають у вихідний файл службову інформацію про формат (розмір сторінок, тип шрифту і ін.), яка буде незрозуміла транслятору. Проте практично всі текстові редактори і процесори дозволяють вивести у вихідний файл "чистий текст", без яких-небудь службових символів. Саме таким режимом і належить скористатися в нашому випадку.
В принципі для підготовки початкового тексту можна скористатися будь-яким редактором системи Windows, наприклад, програмою Wordpad або Блокнотом. Проте в цьому випадку виникнуть неприємності з російським шрифтом. Як відомо, корпорація Microsoft прийняла для своїх русифікованих продуктів власне кодування російських символів, що розходиться із стандартною, використовуваною в додатках DOS. Якщо програму, що використовує російський текст як коментарі, або що виводить його на екран, підготувати в одному з редакторів Windows, то при її перегляді і запуску в середовищі DOS замість російського тексту ви побачите безглуздий набір символів. Тому програми, призначені для виконання під управлінням MS-DOS, краще і готувати в середовищі DOS. Файл з початковим текстом повинен мати розширення .ASM.
Наступна операція полягає в трансляції початкового тексту програми, тобто в перетворенні рядків початкової мови в коди машинних команд. Ця операція виконується за допомогою транслятора з мови асемблера (тобто за допомогою програми асемблера). Відомі розробники програмного забезпечення - корпорації IBM, Borland, Microsoft і ін. пропонують свої варіанти трансляторів, декілька що розрізняються своїми можливостями і системою позначень. Проте вхідна мова будь-якого транслятора, що включає мнемоніку машинних команд і інших операторів і правила написання пропозицій асемблера, для всіх асемблерів однаковий, тому при підготовці і відладці прикладів даної книги можна з рівним успіхом скористатися будь-якій з вказаних програм. Ми, як вже наголошувалося, використовували програми пакету TASM 5.0 (фірмові назви цих програм - Turbo Assembler
Turbo Link і Turbo Debugger, а імена відповідних ним файлів - TASM.EXE, TLINK.EXE і TD.EXE).
Після трансляції утворюються два файли - лістинг трансляції і об'єктний файл з розширенням OBJ. Лістингом є текстовий файл, призначений для читання в якому-небудь редакторові, і містить початковий текст програми, що відтранслює, разом з машинними кодами команд. У разі виявлення транслятором яких-небудь помилок, в лістинг також включаються повідомлення про ці помилки.
Розглянемо елементи лістингу трансляції прикладу 1-1 з попереднього розділу. На мал. 2.1 приведений декілька скорочений текст цього лістингу, з якого видалені коментарі до окремих пропозицій.
айту. В цьому випадку слід використовувати перетягання у зворотному напрямі. А саме, розшукайте цільовий файл, наприклад, за допомогою програми Провідник, потім перетягнете його значок на карту вузла — на зображення батьківського документа.

Мал. 2.1. Лістинг трансляції програми 1-1.

Розглядаючи лістинг, можна відзначити ряд корисних моментів загального характеру. Пропозиції програми з операторами assume, segment, ends, end, як вже наголошувалося раніше, не транслюються в які-небудь машинні коди і не знаходять віддзеркалення в пам'яті. Вони потрібні лише для передачі транслятору службової інформації про спосіб трансляції команд (assume), межі сегментів (segment і end) і рядок, на якому слід завершити обробку початкового тексту (end).
Кожній трансльованій пропозиції програми відповідає певний зсув, причому завдання зсувів виконується в кожному сегменті окремо. Перша команда mov Ax,data має зсув від початку сегменту команд, рівне нулю. Вона займає 3 байти, тому наступна команда починається з байта 3 і має відповідний зсув.
Транслятор не зміг повністю визначити код команди mov Ax,data. У цій команді в регістр АХ засилає сегментна адреса сегменту data. Проте ця адреса стане відома лише в процесі завантаження здійснимого файлу програми в пам'ять. Тому в лістингу на місці цієї адреси коштують нулі, помічені буквою s, що нагадує про те, що тут має бути поки невідома сегментна адреса.
Ще одна помічена команда з кодом ВА 0000 розташовується в рядку 8 лістингу. У цій команді в регістр DX заноситься зсув поля з ім'ям msg, розташоване в сегменті даних (ключове слово offset, вказане перед ім'ям поля, говорить про те, що мова йде не про вміст осередку msg, а про її зсув). Поле msg розташоване на самому початку сегменту даних, і його зсув від початку сегменту дорівнює 0, що і вказане в коді команди. Чому ж ця команда помічена буквою т, що є скороченням слова relocatable, перемістимий?
Щоб відповісти на це питання, нам доведеться розглянути, як сегменти програми розміщуються в пам'яті. Як вже мовилося, будь-який сегмент може розташовуватися в пам'яті тільки з адреси, кратної 16, тобто на межі 16-байтового блоку пам'яті (параграфа). Конкретна адреса програми в пам'яті залежить від конфігурації комп'ютера, - який розмір займає DOS, скільки завантажено резидентних програм і драйверів, а також в якому режимі запускається програма - у відладчику або без нього. Припустимо, що сегментна адреса сегменту команд опинилася рівним 1306п (мал. 2.2, а). У нашій програмі сегмент команд має розмір 11h байт (що вказане в рядку 13 лістингу), тобто займає цілий параграф плюс один байт. Сегмент даних має розмір 14h байт (рядок 19 лістингу) і теж вимагає для свого розміщення трохи більше одного парафафа. Через те, що сегмент даних повинен початися на межі параграфа, йому буде призначена сегментна адреса 1308h і між сегментами утворюється порожній проміжок розміром 15 байт.
Втрата 15 байт з пам'яті багатомегабайта, зрозуміло, не має ніякого значення, проте в деяких випадках, наприклад, при компоновці єдиної профамми з великої кількості модулів з невеликими за розміром подпрофаммамі, сумарна втрата пам'яті може виявитися значною.

Мал. 2.2. Розташування сегментів програми в пам'яті при вирівнюванні за умовчанням (а) і на байт (б).

Для того, щоб усунути втрати пам'яті, можна сегмент даних оголосити з вирівнюванням на байт:

data segment byte

Таке оголошення дасть можливість системі завантажити сегмент даних так, як показано на мал. 2.2, би. Сегмент даних частково перекриває сегмент команд, починаючись на межі його останнього параграфа (у нашому випадку за адресою 1307h). Для того, щоб дані не наклалися на останні команди сегменту команд, вони зміщуються вниз так, що починаються відразу ж за сегментом команд. У нашому прикладі, де сегмент команд "виступає" за сегментну адресу 1307h всього на 1 байт, дані і треба змістити на цей 1 байт. В результаті поле msg, з якого починається сегмент даних, і яке в лістингу мало зсув 0, отримає зсув 1. Решта всіх адрес в сегменті даних також зміститься на один байт вперед. В результаті дані розташовуватимуться у фізичній пам'яті впритул за командами, без всяких проміжків, проте всі звернення в сегменті команд до даних мають бути скоректовані на величину перекриття сегментів, в нашому випадку - на 1 байт. Ця корекція виконується системою після завантаження програми в пам'ять, але ще до її запуску. Адреси, які можуть зажадати описаної корекції, і позначаються в лістингу трансляції буквою "г". Із сказаного виходить дуже важливий і декілька несподіваний вивід: коди команд програми в пам'яті можуть не збігатися з кодами, показаними в лістингу трансляції. Цю обставину необхідно враховувати при відладці програм за допомогою інтерактивного відладчика, який, природно, показує в точності те, що знаходиться в пам'яті, і що не завжди відповідає лістингу трансляції.
Повернемося до розгляду лістингу трансляції. Дані, введені нами в програму, також відтранслювалися: замість символів тексту в завантажувальний файл потраплять коди ASCII цих символів. Так, буква "П" перетворилася в код 8fh, буква "р" в код ЕО і так далі При виведенні цих код на екран відеосистема комп'ютера перетворить їх назад в зображення символів, записаних в початковому тексті програми.
З лістингу трансляції легко визначити розмір окремих складових програми. У нашому випадку довжина сегменту команд складає 11h = 17 байт, довжина сегменту даних - 14h = 20 байт, а під стек відведено рівно стільки, скільки ми запитали в програмі - 100h = 256 байт. Розмір же всієї програми опиниться більше суми довжин сегментів, по-перше, із-за порожніх проміжків між сегментами (у нас на них піде 15 + 12 = 27 байт), і, по-друге, за рахунок під'єднування до програми обов'язкового префікса програми, що має завжди розмір 256 байт.
Як ми вже відзначали, в результаті трансляції програми утворюється два файли - з лістингом і з об'єктним модулем програми.
Об'єктний файл є основним результатом роботи транслятора і є текстом програми, перетвореним в машинні коди. Хоча в цьому файлі вже присутні коди команд, він не може бути виконаний. Для того, щоб отримати здійсниму програму, об'єктний файл необхідно ськомпоновать.
Компоновка об'єктного файлу виконується за допомогою програми компонувальника (редактора зв'язків). Ця програма отримала таку назву тому, що її основне призначення - під'єднування до файлу з основною програмою файлів з підпрограмами і налаштування зв'язків між ними. Проте компонувати необхідно навіть прості програми, що не містять підпрограм. Річ у тому, що у компонувальника є і друга функція - зміна формату об'єктного файлу і перетворення його в здійснимий файл, який може бути завантажений в оперативну пам'ять і виконаний. Файл з програмою компонувальника зазвичай має ім'я LINK.EXE, хоча це може бути і не так. Наприклад, компонувальник пакету TASM названий TLINK.EXE. В результаті компоновки утворюється завантажувальний, або здійснимий файл з розширенням .ехе.
Відладку і вивчення роботи готової програми найзручніше здійснювати за допомогою інтерактивного відладчика, який дозволяє виконувати відладжувану програму по кроках або з точками останову, виводити на екран вміст регістрів і областей пам'яті, модифікувати (у відомих межах) завантажену в пам'ять програму, примусово змінювати вміст регістрів і виконувати інші дії, що дозволяють в наочній і зручній формі контролювати виконання програми.
Розглянемо коротко основні прийоми роботи з "турбоотладчиком" TD.EXE з пакету TASM. Приступаючи до роботи з відладчиком, слід переконатися, що в робочому каталозі є і завантажувальний (Р.Ехе), і початковий (P.ASM) файли, оскільки відладчик в своїй роботі використовує обидва ці файлу. Для запуску відладчика слід ввести команду

td р

На екрані з'явиться кадр відладчика, в якому видно два вікна, - вікно Module з початковим текстом відладжуваної програми і вікно Watches для спостереження за ходом зміни заданих змінних в процесі виконання програми (мал. 2.3). Вікно Watches нам не знадобиться, і його можна прибрати, клацнувши мишею по маленькому квадратику в лівому верхньому кутку вікна, або ввівши команду <Alt>+<f3>, заздалегідь зробивши це вікно активним. Перемикання (по кругу) між вікнами здійснюється клавішею <F6>.


Мал. 2.з. Початковий кадр відладчика з текстом відладжуваної програми.

В процесі відладки програми на екран доводиться виводити багато додаткових вікон; вони перекриваються і часто приховують один одного. Щоб побачити їх всіх одночасно, розмір вікон доводиться зменшувати, а самі вікна переміщати по екрану. Режим зміни розмірів і положення вікна включається командою <Ctrl>+<f5>, після чого клавіші із стрілками переміщають вікно по екрану, а ті ж клавіші при натиснутій клавіші <Shift> дозволяють змінювати його розмір. Вихід з режиму налаштування вікна здійснюється натисненням клавіші <Enter>.
Початкове вікно відладчика дає дуже мало інформація для відладки програми. У нім можна виконувати програму по частинах до місцеположення курсора (клавіша <F4>) і команда за командою (клавіша <F8>); можна також за допомогою вікна Watches спостерігати зміни заданих полів даних. Проте для відладки програми на рівні мови асемблера необхідно контролювати всі регістри процесора, включаючи регістр прапорів, а також, у багатьох випадках, поля даних поза програмою (наприклад, вектори переривань або системні таблиці). Набагато більш інформативним є "вікно процесора", яке викликається за допомогою пункту Vicw>cpu верхнього меню або командою <Alt>+<v>+<c> (мал. 2.4).

Мал. 2.4. Вікно процесора з внутрішніми вікнами.

Вікно процесора полягає, у свою чергу, з 5 внутрішніх вікон для спостереження тексту програми на мові асемблера і в машинних кодах, регістрів процесора, прапорів, стека і вмісту пам'яті. За допомогою цих вікон можна повністю контролювати хід виконання відладжуваної програми. Для того, щоб можна було працювати з конкретним вікном, наприклад, прокручувати його вміст, треба зробити його активним, клацнувши по ньому мишею. Перейти з вікна у вікно можна також за допомогою клавіатури, натискаючи клавішу Tab. Подивимося, які відомості можна витягувати з вмісту вікна процесора.
Вміст сегментних регістрів DS і ES однаково і складає Hf5h. Ета означає, що програма завантажена в пам'ять, починаючи з фізичної адреси 11F50, тобто приблизно з 70-го кілобайта. Чим зайняті перші 70 Кбайт пам'яті? Зазвичай комп'ютер конфігурується так, що в звичайній пам'яті розміщується тільки мала частина DOS (близько 16 Кбайт), драйвери обслуговування розширеної пам'яті і резидентна частина COMMAND.COM. Основна частина DOS, решта драйверів і необхідних резидентних програм (наприклад, русифікатор) переносяться в розширену пам'ять. В цьому випадку системні області на початку пам'яті займають всього 20 - 25 Кбайт. Проте наша програма починається не з 25-го, а з 70-го кілобайта. Відбулося це через те, що програма запущена під управлінням відладчика, який спочатку завантажується в пам'ять сам, і лише потім завантажує відладжувану програму. Але звідси витікає, що якби ми запустили програму без відладчика, вона потрапила б на інше місце в пам'яті, набагато ближче до її початку. В більшості випадків ця обставина не має особливого значення, оскільки будь-яка програма винна однаково успішно виконуватися в будь-якому місці пам'яті, проте необхідно віддавати собі звіт, що відладчик змінює операційне середовище програми (зокрема, переносить її на інше місце в пам'яті). Строго кажучи, програма під управлінням відладчика виконується не зовсім так, як вона виконувалася б безпосередньо в DOS.
Ще один приклад "самодіяльності" відладчика можна побачити в тому ж вікні регістрів процесора. Вміст всіх регістрів загального призначення (АХ, ВХ, СХ, DX, SI, DI і ВР) дорівнює 0. Звідси можна зробити вивід, що DOS, завантажуючи програму в пам'ять, очищає регістри процесора. Проте насправді це зовсім не так! Регістри очищає не DOS, а відладчик. При звичайному запуску програми початковий вміст регістрів практично непередбачувано, і у жодному випадку не можна розраховувати, що в них будуть нулі. Іноді можна зіткнутися і з тоншим впливом відладчика на хід виконання програми, аж до того, що деякі види програм, наприклад, керівники підключеною до комп'ютера апаратурою, у відладчику виконуватимуться просто невірно.
Отже, після завантаження програми в пам'ять вміст регістрів DS і ES виявився однаковим. Це цілком природно, якщо пригадати, що перед виконанням обидва регістри указують на префікс програми (см, мал. 1.9). Услід за префіксом розташовується сегмент команд і оскільки префікс завжди займає точно looh байт (тобто 10h параграфів по 16 байт), той вміст CS в нашому випадку має бути рівне Hf5h + 10h = 1205h. Так воно і є (див. мал. 2.4).
У нашому прикладі програма повинна почати виконуватися з мітки begin, оскільки саме цю мітку ми вказали як операнд завершуючої директиви end. Ета мітка відноситься до найпершої команди сегменту команд і її значення (або, що те ж саме, зсув першої команди програми) має дорівнювати 0. Тому початкове значення покажчика команд, як це видно з мал. 2.4, теж рівне 0. Надалі, у міру виконання команд, значення IP зростатиме. Виконаємо дві перші команди програми, двічі натиснувши клавішу <F8>. Стан програми після цієї операції показаний на мал. 2.5.

Мал. 2.5. Стан програми після виконання двох перших команд.

Видно, що покажчик команд набув значення 5 і показує на чергову (що ще не виконувалася) команду mov Ah,09h, відносна адреса якої дорівнює 5. Сегментний регістр DS набув значення 1207h, що повинне відповідати сегментній адресі сегменту даних. Пригадаємо, що сегмент команд у нас займає 11h байт і вимагає в пам'яті 2 параграфи. Сегмент команд має сегментна адреса 1205h, отже, сегментна адреса сегменту даних має бути рівний 1207h, що ми і отримали.
Звернемо увагу на найправішу колонку у вікні процесора, в якій відображаються стани прапорів процесора. Як вже мовилося, стани прапорів наново встановлюються процесором після виконання кожної команди, і по ним можна певною мірою судити про результат команди. Із самого початку у нас був встановлений тільки прапор IF (i у вікні відладчика), що свідчить про включений механізм апаратних переривань; решта прапорів скинута. Після виконання двох перших команд стан регістра прапорів не змінився. Відбулося це тому, що команда пересилки mov не змінює стану прапорів. Оскільки в нашій програмі немає ніяких команд, окрім mov і hit, а команда hit теж стану прапорів зазвичай не змінює, то спостерігати за допомогою нашого прикладу функціонування регістра прапорів не вдасться.
Розглянемо тепер стік. Сегмент даних має у нас розмір 14h байт, і під нього в пам'яті належить виділити 2 параграфи. Це пояснює вміст сегментного регістра стека SS - 1209п. Під стек відведене 256 байт, тому початкове положення SP (під дном стека) відповідає зсуву l00h.
Нарешті, варто ще звернути увагу на нижню половину вікна команд, заповнену дивними командами add [bx+si],al. Таких команд, та ще в такій кількості, в нашій програмі немає, їх "придумав" відладчик, намагаючись деассембліровать проміжок між сегментом команд і сегментом даних, заповнений нулями. Код 0000h відповідає команді add [bx+si],al, яку і зобразив відладчик.
Таким чином, розглянувши інформацію, надану відладчиком, ми підтвердили всі попередні міркування про розташування в пам'яті сегментів програми і про ініціалізацію регістрів процесора при завантаженні програми в пам'ять.
Звернемося тепер до вікна дампу. При запуску відладчика у вікно дампу виводиться вміст пам'яті, починаючи з адреси Ds:0000h, тобто початок префікса програми (див. мал. 2.4 і 2.5). Для того, щоб вивести на екран що-небудь інше, треба скористатися командою <Alt>+<f10>, яка для кожного внутрішнього вікна процесора відкриває додаткове меню. Вид цього меню залежить від того, яке вікні було активним у момент введення команди. На мал. 2.6 показано додаткове меню вікна дампу.

Мал. 2.6. Додаткове меню вікна дампу пам'яті.

Найчастіше доводиться користуватися першим пунктом цього меню Goto, за допомогою якого можна задати будь-яку адресу (що входить або не входить в сегменти програми), і отримати дамп цієї ділянки.. На мал. 2.7. зображений вміст вікна дампу після введення початкової адреси у вигляді Ds:0 (той же результат дасть початкова адреса Ds:msg, а так само і просто msg, оскільки за умовчанням сегментна адреса береться з DS). Як і слід було чекати, за цією адресою розташоване наше єдине дане - рядок тексту, що виводиться програмою на екран. До речі, у вікні дампу видно початок проміжку між сегментами (даних і стека), заповненого нулями.

Мал. 2.7. Дамп сегменту даних.

-

:: Наша кнопка ::

Отримати код:

Підтримайте наш сайт і розмістіть нашу кнопку на своєму ресурсі.


:: Популярне ::

-


:: Посилання ::

-


 

 

 


Copyright © net.kr.ua, 2019-2025 (assem.us)