Теорія операційної системи

:: Меню ::

Головна
Представлення даних в обчислювальних системах
Машинні мови
Завантаження програм
Управління оперативною пам'яттю
Сегментна і сторінкова віртуальна пам'ять
Комп'ютер і зовнішні події
Паралелізм з точки зору програміста
Реалізація багатозадачності на однопроцесорних комп'ютерах  
Зовнішні пристрої
Драйвери зовнішніх пристроїв
Файлові системи
Безпека
Огляд архітектури сучасних ОС

:: Друзі ::

Карта сайту
 

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

 

 

 

 

 

Мови асемблера

Безпосередньо на машинній мові у наш час не програмує практично ніхто. Перший рівень, що дозволяє абстрагуватися від схеми кодування команд, — це вже згадуваний мова асемблера. У мові асемблера кожній команді машинної мови відповідає мнемонічне позначення. Всі наведені раніше приклади написані саме на мові асемблера, та і в тексті використовувалися не бінарні коди команд, а їх мнемоніки.
Зустрічаються асемблери, які надають мнемонічні позначення для часто використовуваних груп команд. Більшість таких мов дозволяють користувачеві вводити свої власні мнемонічні позначення — так звані макровизначення або макроси (macros)у тому числі і що параметризуються (приклад 2.7).
Відзнака макровизначень від процедур мов високого рівня в тому, що процедура компілюється один раз, і потім заслання на неї реалізуються у вигляді команд виклику. Макровизначення ж реалізується шляхом підстановки тіла макровизначення (із заміною параметрів) на місце заслання на нього і компіляцією отриманого тексту. Компіляція асемблерного тексту, таким чином, здійснюється в два або більш за проходи — на першому здійснюється розкриття макровизначень, на другому — власне компіляція, яка, у свою чергу, може складатися з багатьох проходів, сенс яких ми зрозуміємо далі. Частина асемблера, що реалізовує перший прохід, називається макропроцесором.

Приклад 2.7. Приклад використання макровизначень

; Фрагмент драйвера LCD для мікроконтроллера PIC
; (с) 1996, Дмитро Іртегов.
; Таблиця знакогенератора: 5 байт/символ.
; W містить код символу. Поки символів може бути
; лише 50, інакше виникне переповнювання.
; Scanline містить номер байта (не рядки!)
; Спочатку визначимо макрос, а то втомимося таблицю вигадувати. ; Необхідно упакувати 7 скан-строк по 5 біт в 5 байт.
Chardef macro scanl, scan2, scan3, scan4, scans, зсапб, scan7 ; Наступний символ
RETLW (scan? & Oxlc) » 2
RETLW ((scan5 E, 0x10) » 4) + ((зсапб S Oxlf) « 1) + ((scan7 & 0x3) «
6)
RETLW ((scan4 & Oxle) » 1) + ((scanb & Oxf) « 4)
RETLW ((scan2 & 0x18) » 3) + ((зсапз & Oxlf) « 2) + ( (scan4 & Oxl) « 7)
RETLW (scanl & Oxlf) + ( (scan2 & 0x7) « 5)
endm
Fetchonescanline IFNDEF Nodisplay
CLRF PCLATH
ADDWF PCL, 1
NOP ; else
RETLW 0 endif
; А ось йде власне таблиця:
Nolist
; О
Chardef В'ohio',в110001',в'10001',в'10001',в'10001',в'10001',в'01110' ; 1
Chardef В'00100',в'01100',в'00100',в'00100',в100100',в'00100',в'01110' ; 2
Chardef В'ohio',в'10001',в'00001',в'00010',в100100',в'01000',в'11111' ; 3
Chardef В'01110',в'10001',в'00001',в'00110',в100001',в110001',в'ohio' ; 4
Chardef В'00010',в'00110',в'01010',в'10010',в'11111',в'00010', В'00010' ; 5
Chardef В'11111',в'10000',в'11110',в'00001',в'00001',в110001',в1ohio' ; би
Chardef В'ohio1,840001',в' 10000',в' НВО',в' 10001',в'10001',в'ohio1 ; 7
Chardef В'11111',в'00001',в'00010',в'00100',в'01000',в'01000',в'01000'
; 8
Chardef В'ohio', В'10001',в'10001',в'ohio', В'10001', В'10001',в'ohio' ; 9
Chardef В'ohio', В'10001', В'10001',в'01111',в'00001',в'10001',в'ohio' 4 Зек Х(
Constant CHARACTERA = Oxa
Chardef В ' 00100 ', У ' 01010 ', У ' 10001', В110001',841111', В' 10001',в' 10001' Ifndef No_alphabet ; У Constant CHARACTERW = Oxb
Chardef В'11110',в'10001',b'10001',в'11110',в'10001',в'10001',в'11110' else ; Р — для аона
Chardef В' 11110 ',840001', В '10001', В '10001', В' 11110 ',840000', В '10000' endif ; З
Chardef В'01110',в'10001',в'10000',вчоооо',в'10000',в110001',в'01110' ; о
Chardef В' 11110 ',в' 10001 ',в' 10001 ',в' 10001 ',840001', В' 10001 ',841110' ; Е
Chardef B'lllll',вч0001', В'10000', В'11110 ',в'10000', В'10001',в'11111' ; F
Chardef В'11111',в'10001',в'10000',в'11110',в'10юоо',в'10000',в'10000'
; пропуск Constant Space_character = 0x10
Chardef В'00000',в'ооооо',в'ооооо',в'00000',в'00000',в100000',в'00000'
Constant Dash_character = Oxll
Chardef В'00000',в'00000',в'00000',в'11111',в'00000',в'ооооо',в'ооооо'
List

Макропроцесор, окрім розкриття макросів, зазвичай надає також директиви умовної компіляції — залежно від умов, ті або інші ділянки коди можуть передаватися компілятору чи ні. Умови, звичайно ж, мають бути відомі вже на етапі компіляції. Наприклад, залежно від типа цільового процесора одна і та ж конструкція може реалізуватися як в одну команду, так і емулюючою програмою. Залежно від використовуваної операційної системи можуть застосовуватися різні системні виклики (це частіше трапляється при програмуванні на мовах високого рівня), або залежно від значень параметрів макровизначення, макрос може породжувати зовсім різний код.
Макрозасоби є не лише в асемблерах, але і в багатьох мовах високого рівня (ЯВУ). Найбільш відомий препроцесор мови С. Насправді, багато засобів, що надаються мовами, що претендують на більшу, ніж в З, "високоуровневость" (що б під цим не малося на увазі), також реалізуються за принципом макрообробки, тобто за допомогою текстових підстановок і компіляції результату: шаблони (template) C++, типи Ada, що параметризуються, і так далі
Уміле використання макропроцесора полегшує читання коди і збільшує можливості його повторного використання в різних ситуаціях. Зловживання ж макрозасобами (як, втім, і багатьма іншими потужними і виразними мовними конструкціями) або просто нетямуще їх вживання може приводити до абсолютно незрозумілого коду і помилок, що важко діагностуються, тому багато теоретиків програмування виступали за повну відмову від використання макропроцесорів.
Сучасні методи оптимізації в мовах високого рівня — перевірка константних умов, розгортання циклів, inlme-функции — часто стирають відмінності між макрообробкою і власне компіляцією.
Окрім позбавлення програміста від необхідності запам'ятовувати коди команд, асемблер виконує ще одну, мабуть, навіть важливішу функцію: він дозволяє забезпечувати символічними іменами (мітками) або (символами) команди або елементи пам'яті, призначені для даних. Значення цієї можливості для практичного програмування важко переоцінити.
Розглянемо простий приклад з життя: ми написали програму, яка містить команду переходу (бувають і програми, які жодної команди переходу не містять, але це вироджений випадок). Потім, в процесі тестування цієї програми або уточнення специфікацій ми зрозуміли, що між командою переходу і крапкою, в яку перехід здійснюється, необхідно вставити ще два десятки команд. Для вставки необхідно перерахувати адресу переходу. На практиці, вставка навіть однієї лише інструкції часто зачіпає і приводить до необхідності перераховувати адреси безлічі команд переходу, тому можливість автоматизувати цей процес украй важлива.
Важливе вживання міток — організація заслань між модулями в програмах, що збираються з декількох окремо компільованих файлів. Зміна об'єму коди або даних в будь-якому з модулів приводить до необхідності перерахунку адрес у всіх останніх модулях. У сучасних програмах, що збираються з сотень окремих файлів і містять тисячі об'єктів, що індивідуально адресуються, виконувати такий перерахунок уручну неможливо. Способи автоматичного рішення цієї задачі обговорюються в разд. Збірка програм.
Фаза зіставлення символів з реальними адресами присутня і при компіляції мов високого рівня — компілятор генерує символи не лише для змінних, процедур і міток, які можуть бути використані в операторові goto але і для реалізації "структурних" умовних операторів і циклів. Нерідко в описі компілятора цю фазу так і називають — асемблювання.
Багато компіляторів як старі, так і сучасні, наприклад, популярний компілятор GNU З, навіть не виконують фазу асемблювання самостійно, а замість цього генерують текст на мові асемблера і викликають зовнішній асемблер. Засоби межпроцессного взаємодії сучасних ОС дозволяють передавати цей проміжний текст, не створюючи проміжного файлу, тому для кінцевого користувача ця деталь реалізації часто виявляється непомітною.
Компілятори, що мають вбудований асемблер, такі, як Microsoft C/c++ або Watcom, часто можуть генерувати асемблерне представлення породжуваної коди. Це буває корисно при відладці або написанні підпрограм на асемблері, які повинні взаємодіяти з кодом, що відкомпілювався.


:: Реклама ::

 

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


 

 

 


Copyright © Kivik, 2017