У статті будуть розглянуті основи мови асемблер стосовно до архітектури win32. Він являє собою символічну запис машинних кодів. У будь-електронно-обчислювальній машині найнижчим рівнем є апаратний. Тут управління процесами відбувається командами або інструкціями на машинній мові. Саме в цій області асемблера призначено працювати.
Програмування асемблер
Написання програми на асемблері – вкрай важкий і витратний процес. Щоб створити ефективний алгоритм, необхідно глибоке розуміння роботи ЕОМ, знання деталей команд, а також підвищена увага і акуратність. Ефективність – це критичний параметр для програмування асемблер.
Головна перевага мови асемблер в тому, що він дозволяє створювати короткі і швидкі програми. Тому використовується, як правило, для вирішення вузькоспеціалізованих завдань. Необхідний код, який працює ефективно з апаратними компонентами, чи потрібна програма, вимоглива до пам’яті або часу виконання.
Регістри
Регістрами в мові асемблер називають комірки пам’яті, розташовані безпосередньо на кристалі з АЛУ (процесор). Особливістю цього типу пам’яті є швидкість обігу до неї, яка значно швидше оперативної пам’яті ЕОМ. Вона також називається надшвидкої оперативною пам’яттю (СОЗУ або SRAM).
Існують наступні види регістрів:
Є 8 регістрів загального призначення, кожен розміром в 32 біта.
Доступ до регістрів EAX, ECX, EDX, EBX може здійснюватися в 32-бітовому режимі, 16-бітовому – AX, BX, CX, DX, а також 8-бітовому – AH і AL, BH і BL і т. д.
Буква “E” у назвах регістрів означає Extended (розширений). Самі імена пов’язані з їх назвами англійською:
- Accumulator register (AX) – для арифметичних операцій.
- Counter register (CX) – для зрушень і циклів.
- Data register (DX) – для арифметичних операцій і операцій вводу/виводу.
- Base register (BX) – для покажчика на дані.
- Stack Pointer register (SP) – для покажчик вершини стека.
- Stack Base Pointer register (BP) – для індикатора підстави стека.
- Source Index register (SI) – для покажчика відправника (джерела).
- Destination Index register (DI) – для одержувача.
Спеціалізація РОН мови асемблер є умовною. Їх можна використовувати в будь-яких операціях. Однак деякі команди здатні застосовувати тільки певні регістри. Наприклад, команди циклу використовують ESX для зберігання значення лічильника.
Регістр прапорів. Під цим мається на увазі байт, який може приймати значення 0 і 1. Сукупність всіх прапорів (їх близько 30) показують стан процесора. Приклади прапорів: Carry Flag (CF) – Прапор переносу, Overflow Flag (OF) – переповнення, Nested Flag (NT) – прапор вкладеності завдань та багато інших. Прапори поділяються на 3 групи: стан, управління і системні.
Покажчик команд (EIP – Instruction Pointer). Цей регістр містить адресу інструкції, яка повинна бути виконана наступній, якщо немає інших умов.
Регістри сегментів (CS, DS, SS, ES, FS, GS). Їх наявність в асемблері продиктовано особливим управлінням оперативною пам’яттю, щоб збільшити її використання в програмах. Завдяки ним можна було керувати пам’яттю розміром до 4 Гб. В архітектурі Win32 необхідність в сегментах відпала, але назви регістрів збереглися і використовуються по-іншому.
Стек
Це область пам’яті, що виділена для роботи процедур. Особливість стека полягає в тому, що останні дані, записані в нього, доступні для читання першими. Або іншими словами: перші записи стека витягуються останніми. Уявити собі цей процес можна як башти з шашок. Щоб дістати шашку (нижню шашку в основу вежі або будь-яку в середині) потрібно спочатку зняти все, що лежать зверху. І, відповідно, остання покладена на вежу шашка, при розборі вежі знімається першої. Такий принцип організації пам’яті і роботи з нею продиктований її економією. Стек постійно очищається і в кожен момент часу одна процедура використовує його.
Ідентифікатори, цілі числа, символи, коментарі, еквівалентність
Ідентифікатор в мові програмування асемблер має такий же зміст, як і в будь-якому іншому. Допускається використання латинських літер, цифр і символів “_”, “.”, “?”, “@”, “$”. При цьому великі та малі букви еквівалентні, а точка може бути тільки першим символом ідентифікатора.
Цілі числа в асемблері можна вказувати в системах відліку з підставами 2, 8, 10 і 16. Будь-яка інша запис чисел буде розглядатися компілятором асемблера в якості ідентифікатора.
В запису символьних даних допускається використовувати як апострофи, так і лапки. Якщо в символьній рядку потрібно вказати один з них, то наступні правила:
- у рядку, укладену в апострофи, лапки зазначаються один раз, апостроф – двічі: ‘can”t’, ‘ he said “to be or not to be” ‘;
- для рядка, взятим у лапки, зворотне правило: дублюються лапки, апострофи зазначаються як є: “couldn’t”, ” My favourite bar is “”Black Cat”” “.
Для вказівки коментування в мові асемблера використовується символ крапка з комою – “;”. Допустимо використовувати коментарі як на початку рядків, так і після команди. Закінчується коментар переведенням рядка.
Директива еквівалентності використовується схожим чином, як в інших мовах вказують константные вираження. Еквівалентність вказується наступним способом:
<name> EQU <operand>
Таким чином в програмі всі входження <name> будуть замінюватися на <operand>, на місці якого допустимо вказувати ціле число, адреса, рядок або інше ім’я. Директива EQU схожа по своїй роботі на #define у мові С++.
Директиви даних
Мови високого рівня (C++, Pascal) є типізованими. Тобто, в них використовуються дані, які мають певний тип, є функції їх обробки і т. д. В мові програмування асемблер подібного немає. Існує всього 5 директив для визначення даних:
Буква D означає Define.
Будь-яка директива може бути використана для оголошення будь-яких даних і масивів. Однак для рядків рекомендується використовувати DB.
Синтаксис:
<name> DQ <operand>[, <operand>]
В якості операнда допустимо використовувати цифри, символи і знак питання “?”, позначає змінну без ініціалізації. Розглянемо приклади:
real1 DD 12.34
char db ‘c’
ar2 db ‘123456’,0 ; масив з 7 байт
num1 db 11001001b ; двійкове число
num2 dw 7777o ; вісімкове число
num3 dd -890d ; десяткове число
num4 dd 0beah ; шістнадцяткове число
var1 dd ? ; мінлива без початкового значення
ar3 dd 50 dup (0) ; масив з 50 ініціалізований ел-тів
ar4 dq 5 dup (0, 1, 1.25) ; масив з 15 ел-тів, ініційовану повторами 0, 1 і 1.25
Команди (інструкції)
Синтаксис команд асемблера або інструкцій асемблера виглядає наступним чином:
<label>: <instruction operands> [;Comment]
Мітка (label:) обов’язково завершується двокрапкою і може розташовуватися в окремому рядку. Мітки використовуються для того, щоб посилатися на команди всередині програми.
Інструкції вказують операцію, яка повинна бути виконана. В асемблері операції представлені у вигляді буквених скорочень для полегшення розуміння. Інструкції також можуть називатися мнемокодами.
У ролі операндів команди можуть виступати:
- регістри, звернення до яких відбувається по їх іменах;
- константи;
- адреси.
Детальніше про адреси
Адреса може передаватися кількома способами:
В асемблері адреса передається через квадратні дужки. Зважаючи на те, що змінна є також адресою, вона може використовуватися як з квадратними дужками, так і без.
Крім цього, в асемблер існують скорочення: r – для регістрів, m – для пам’яті і i – для операнда. Ці скорочення використовуються з числами 8, 16 і 32 для вказівки розміру операнда: r8, m16, i32 і т. д.
add i8/i16/i32, m8/m16/m32 ;підсумовування операнда з коміркою пам’яті
Команда mov чи пересилання
Дана інструкція є основною серед команд асемблера. Вона дозволяє записувати в регістр значення іншого регістру або комірки пам’яті або константи. Вона ж здійснює запис у комірку пам’яті значення регістра або константи. Синтаксис команди:
MOV <op1>, <op2>
В процесорі існує і інші команди для реалізації пересилання. Наприклад, XCHG – команда обміну значеннями операндів. Але з точки зору програміста, всі вони реалізовані через команду базову MOV. Розглянемо приклади:
MOV i, 0 ; Записати в i значення 0
MOV ECX, EBX ; Пересилання значення EBX в ECX
У вигляді операнда може виступати як регістр, так і комірка пам’яті. Однак якщо вміст двох регістрів можна переставити, то двох комірок пам’яті – немає. Слід уважно стежити за тим, щоб операнди мали однаковий розмір. Також зауважимо, що команда MOV, не змінює значення прапорів.
Інструментарій
Подальше теоретичне вивчення асемблера може бути важким, тому варто задуматися про інструменти, що використовуються для розробки програм з його допомогою. Тут буде наведено лише короткий список популярних засобів:
- Borland Turbo Assembler (TASM) – один із найпопулярніших інструментів. Добре підходить для розробки під DOS і погано – під Windows.
- Microsoft Macro Assembler (MASM) – це пакет для розробки на асемблері в середовищі Windows. Існує як окремо, так і у вигляді вбудованої функції в середовищі Visual Studio. Асемблер та мови високого рівня часто сумісні. У тому сенсі, що останні можуть використовувати асемблер безпосередньо. Наприклад, С++.
- Netwide Assembler (NASM) – популярний вільний асемблер для архітектури Intel.
Існує безліч інструментів. При цьому слід зробити особливу позначку про те, що немає єдиного стандарту синтаксис асемблера. Є 2 найбільш застосовних: AT&T-синтаксис, орієнтований на процесори виробництва Intel, і, відповідно, Intel-синтаксис.
Незважаючи на гадану складність, асемблер є простою мовою програмування, зрозуміти який не становить праці. Тому можна сміливо використовувати навчальну літературу на подобі “асемблер для чайників” і вивчати цей чудовий мову.