уроки асемблеру

Доброго часу доби, дорогі друзі!

Отже, продовжимо вивчення мови. Опублікую текст програми ще раз:

  • .286
    CSEG segment
    assume cs: CSEG, ds: CSEG, es: CSEG, ss: CSEG
    org 100h
    begin:
    ; Все написане вище поки опускаємо.

    mov ah, 9; Завантажуємо в регістр ah число 9 (вказуємо функцію).
    mov dx, offset helloworld; Зазначаємо, що за фразу ми будемо виводити.
    int 21h; Виводимо фразу.

    int 20h; Виходимо в DOS.

    helloworld db 'Hello, world! $'; Визначаємо змінну helloworld, доступну побайтно, з фразою
    ; "Hello, world!". В одинарних лапках, після знака "!" ставимо
    ; Знак "$".

    ; Завершення програми.
    CSEG ends
    end begin

    Зв'язка mov ah, 9 і int 21h і є по суті одна команда, якщо порівнювати з мовами високого рівня, звичайно.
    Однак на мові асемблера перша зазначена команда називається функцією, а остання - перериванням. Переривання виконує команду із заданою функцією. Є переривання і без функцій, наприклад, той же int 20h. Можливо, поки це дещо складно для сприйняття, але таку форму складання програми необхідно запам'ятати.

    У цьому ж прикладі ми зіткнулися і з іншими ключовими поняттями асемблера, такими, як регістри і шістнадцяткова система числення. Почнемо по порядку.

    Так вийшло, що в сучасних комп'ютерах мінімальної одиницею пам'яті є 8-бітний байт, значення якого зручно записувати двома шестнадцатерічнимі цифрами. Для позначення шістнадцятирічного числа ми будемо використовувати букву "h", яку будемо ставити позаду такої цифри. Це позначення загальноприйняте, хоча деякі платформи, наприклад мій улюблений ZX Spectrum, в своїх асемблерах використовували запис виду # 05B3. Нуль попереду позначається "провідним", так як число # 05B3 = # 5B3, і служить для зручності читання і називається "вирівнюванням" (зазвичай вирівнюють до одного або двох байт: # 05B3).

    Нам необхідно навчитися переводити числа з однієї системи числення в іншу. Для цієї мети прекрасно служить стандартний калькулятор "Windows" в інженерному режимі. Однак, якщо під рукою калькулятора немає, перетворення чисел, представлених в двійковій і шістнадцятковій системах числення, в десяткову виконати досить легко. Для цього необхідно записати число в розгорнутій формі і обчислити його значення. Нижче наведені алгоритми перетворення чисел з однієї системи в іншу (або можна відразу перейти до п. 2. "Регістри").

    Переклад числа з двійкової системи в десяткову. Візьмемо з вами будь-двійковечисло, наприклад 10,112. Потім запишемо його в розгорнутій формі і зробимо обчислення:

    10,112 = 1 × 2 1 + 0 × 2 0 + 1 × 2 -1 + 1 × 2 -2 = 1 × 2 + 0 × 1 + 1 × 1/2 + 1 × 1/4 = 2,7510.

    Переклад чисел з шістнадцятковій системи в десяткову. Візьмемо тепер будь-який шістнадцяткове число, наприклад 19F16. Потім запишемо його в розгорнутій формі (при цьому не забуваємо, що шестнадцатеричная цифра F відповідає десятковому числу 15) і зробимо обчислення:

    19F16 = 1 × 16 2 +9 × 16 1 + F × 16 0 = 1 × 256 + 9 × 16 + 15 × 1 = 41510.

    Переклад чисел з двійкової системи числення в шістнадцяткову. Для запису шістнадцяткових чисел використовуються шістнадцять цифр, тобто в кожному розряді числа можливі 16 варіантів запису. Вирішуємо показове рівняння:

    16 = 2 i. Так як 16 = 2 4. то i = 4 біта.

    Кожен розряд шістнадцятирічного числа завжди містить 4 біти інформації.

    Для переведення цілого двійкового числа в шістнадцяткове потрібно розбити його на групи по чотири цифри, починаючи справа, і, якщо в останній лівій групі виявиться менше чотирьох цифр, доповнити її зліва нулями. Для перекладу дрібного двійкового числа в шістнадцяткове необхідно його розбити на тетради зліва направо і, якщо в останній правій групі виявиться менше чотирьох цифр, доповнити її справа нулями.

    Потім перетворимо кожну групу в шістнадцяткову цифру, скориставшись складеної таблицею відповідності довічних зошити і шістнадцяткових цифр.

    Переведемо яке-небудь ціле двійкове число, наприклад, А2 = 1010012 в шістнадцяткове:

    Алгоритм перекладу цілих десяткових чисел в двійкову систему числення. Нехай АЦД - ціле десяткове число. Запишемо його у вигляді суми ступенів підстави 2 з двійковими коефіцієнтами. У його записи в розгорнутій формі будуть відсутні негативні ступеня підстави (числа 2):

    На першому кроці розділимо число АЦД на основу двійкової системи, тобто на 2. Частка від ділення буде одно

    а залишок - дорівнює a0.

    На другому кроці ціле приватне знову розділимо на 2, залишок від ділення буде тепер дорівнює a1.

    Якщо продовжувати цей процес поділу, то після n-го кроку отримаємо послідовність залишків:

    Легко помітити, що їх послідовність збігається зі зворотним послідовністю цифр цілого двійкового числа, записаного в згорнутої формі:

    Таким чином, досить записати залишки в зворотній послідовності, щоб отримати шукане двійкове число.

    Алгоритм перекладу цілого десяткового числа в двійкове буде наступним:

    1. Послідовно виконувати поділ вихідного цілого десяткового числа і одержуваних цілих приватних на підставу системи (на 2) до тих пір, поки не вийде приватне, менше дільника, тобто менше 2.

    2. Записати отримані залишки в зворотній послідовності.


    Переклад чисел з десяткової системи в двійкову і шістнадцяткову складніший і може здійснюватися різними способами. Розглянемо один з алгоритмів перекладу на прикладі перекладу чисел з десяткової системи в двійкову. При цьому необхідно враховувати, що алгоритми перекладу цілих чисел і правильних дробів будуть відрізнятися.

    Існують регістри загального призначення, сегментні регістри, лічильник команд і регістри прапорів. Тут ми зустрічаємося вперше з регістрами загального призначення ax і dx. Причому кожен з них складається з двох частин - старшої (ah) і молодшої (al) (для ax), про що ми вже писали:

  • H high старший
    L low молодший
    Кожне ім'я регістра несе будь-який сенс.
  • A accumulator акумулятор
    B base база
    C counter лічильник
    D data дані
    BP base pointer покажчик бази
    SI source index індекс джерела
    DI destination index індекс приймача
    SP stack pointer покажчик стека
    CS code segment сегмент команд
    DS data segment сегмент даних
    SS stack segment сегмент стека
    ES extra segment додатковий сегмент
    IP instruction pointer лічильник команд
    У нашій програмі ми використовували старшу частину регістра ax (акумулятор) і регістр dx (розмістили дані).

    Кожен регістр складається з двох байт - старшого (йде першим) і молодшого. Наприклад, число 3DEFh можна занести в регістр ax двома шляхами. Перший - прямим:

  • mov ax, 3DEFh
    і окремо до старшого і молодшого байту:
  • mov ah, 3Dh
    mov al, EFh
    Сподіваюся, з цим все ясно.

    Скомпілюємо нашу програму, створивши за допомогою Far новий файл test.asm (Shift + F4) і помістивши в каталог з ним програми MASM.EXE, ML.EXE, LINK.EXE (або прописавши відповідні системні шляхи для них. Для LINK.EXE у мене це зробити не вийшло, він залишається в папці з програмою). Не забудьте вибрати кодування файлу 866 (клавішею F8), інакше побачите на екрані кракозябри.

    Виконуємо: ML test.asm / AT

    В папці з програмою має з'явитися ще два файли - test.obj і test.com. Останній нам і потрібен.
    Запускаємо його і бачимо на екрані фразу "Hello, world!".

    Схожі статті