основи асемблера
Коли ви пишете програму на асемблері, ви просто пишете команди процесора. Команди процесора - це просто коди або коди операцій або опкоди. Опкоди - фактично "читається текст" - версії шістнадцятирічних кодів. Через це, асемблер вважається самим низькорівневим мовою програмування, все в асемблері безпосередньо перетворюється в шістнадцяткові коди. Іншими словами, у вас немає компілятора, який перетворює мову високого рівня в мову низького рівня, асемблер тільки перетворює коди асемблера в дані.
У цьому уроці ми обговоримо кілька опкодов, які мають відношення до обчислення, порозрядним операціями, і т.д. Інші опкоди: команди переходу, порівняння і т.д, будуть обговорені пізніше.
Числа в асемблері можуть представлятися в двійковій, десятеричной або шістнадцятковій системі. Для того, щоб показати в якій системі використано число треба поставити після числа букву. Для бінарної системи пишеться буква b (приклад: 0000010b, 001011010b), для десятеричной системи можна нічого не вказувати після числа або вказати букву d (приклади: 4589, 2356d), для шістнадцятковій системи треба вказувати букву h, шістнадцяткове число треба обов'язково писати з нулем на початку (приклади: 00889h, 0AC45h, 056Fh, неправильно F145Ch, С123h).
Найперша команда буде добре всім відома MOV. Ця команда використовується для копіювання (не звертайте уваги на ім'я команди) значення з одного місця в інше. Це 'місце' може бути регістр, елемент пам'яті або безпосереднє значення (тільки як початкове значення). Синтаксис команди:
Ви можете копіювати значення з одного регістра в інший.
наприклад: ця команда - НЕ допустима:
Цей опкод намагається помістити DWORD (32-бітове) значення в байт (8 бітів). Це не може бути зроблено mov командою (для цього є інші команди).
А ці команди правильні, тому що у них джерело і приймач не відрізняються за розміром:
Ви також можете отримати значення з пам'яті і помістити его в регістр. Для прикладу візьмемо таку схему пам'яті:
(Кожен блок являє байт)
Значення зміщення позначено тут як байт, але насправді це це - 32-розрядне значення. Візьмемо для прикладу 3A, це також - 32-розрядне значення: 0000003Ah. Тільки, щоб з економити простір, деякі використовують маленькі зміщення.
Подивіться на зміщення 3A в таблиці вище. Дані на цьому зміщенні - 25, 7A, 5E, 72, EF, і т.д. Щоб помістити значення з зміщення 3A, наприклад, в регістр, ви також використовуєте команду mov:
Чи означає: помістити значення з розміром DWORD (32-біт) з пам'яті зі зміщенням 3Ah в регістр eax. Після виконання цієї команди, eax буде містити значення 725E7A25h. Можливо ви помітили, що це - інверсія того що знаходиться в пам'яті: 25 7A 5E 72. Це тому, що значення зберігаються в пам'яті, використовуючи формат little endian. Це означає, що наймолодший байт зберігається в найбільш значущу байті: порядок байтів задом на перед. Я думаю, що ці приклади покажуть це:
- dword (32-біт) значення 10203040 шестнадцатиричное зберігається в пам'яті як: 40, 30, 20, 10
- word (16-біт) значення 4050 шестнадцатиричное зберігається в пам'яті як: 50, 40
Повернемося до прикладу вище. Ви також можете це робити і з іншими розмірами:
Ви, напевно, вже зрозуміли, що префікс ptr позначає, що треба брати з пам'яті деякий розмір. А префікс перед ptr позначає розмір даних:
Іноді розмір можна не вказувати:
Так як eax - 32-розрядний регістр, асемблер розуміє, що йому також потрібно 32-розрядне значення, в даному випадку з пам'яті зі зміщенням 403045h.
Можна також безпосередні значення:
Ця команда просто запише в регістр edx, значення 5006. Дужки, [і], використовуються, для отримання значення з пам'яті (в дужках знаходиться зміщення), без дужок, це просто безпосереднє значення.
Можна також використовувати регістр як осередок пам'яті (він повинен бути 32-розрядних в 32-розрядних програмах):
В mov cx, [eax], процесор спочатку дивиться, яке значення (= комірці пам'яті) містить eax, потім яке значення знаходиться в тій комірці пам'яті, і поміщає це значення (word, 16 біт, тому що приймач, cx, є 16- розрядних регістром) в CX.
- 1: помістити 100 в ecx
- 2: помістити 200 в eax
- 3: розмістити значення з ecx (= 100) в стеку (розміщується першим)
- 4: розмістити значення з eax (= 200) в стеку (розміщується останнім)
- 5/6/7: виконання операцій над ecx, значення в ecx змінюється
- 8: витяг значення з стека в ebx: ebx стане 200 (останнє розміщення, перше витяг)
- 9: витяг значення з стека в ecx: ecx знову стане 100 (перше розміщення, останнім витяг)
Щоб дізнатися, що відбувається в пам'яті, при розміщенні та витягу значень в стеку, см. На малюнок нижче:
(Стек тут заповнений нулями, але в дійсності це не так, як тут). ESP варто в тому місці, на яке він вказує)
Одне важливе зауваження: регістр eax майже завжди використовується для зберігання результату процедури.
Це також може бути застосовано до функцій windows. Звичайно, ви можете використовувати будь-який інший регістр в ваших власних процедурах, але це стандарт.
Ось і скінчився черговий урок. На наступному уроці ми напишемо першу програму на асемблері.
З приводу 0 на початку шістнадцяткових чисел. Ось що з цього приводу написано в Зубкова ( "Асемблер для DOS, Windows і Unix", 1.2.3. Шістнадцяткова система числення):
У ассемблерних програмах при записі чисел, що починаються з А, В, С, D, E, F, на початку приписується цифра 0, щоб не можна було сплутати таке число з назвою змінної або іншим ідентифікатором. Після шістнадцятирічних чисел ставиться буква «h»