ПЕРЕЛІК ДИСЦИПЛІН:
  • Адміністративне право
  • Арбітражний процес
  • Архітектура
  • Астрологія
  • Астрономія
  • Банківська справа
  • Безпека життєдіяльності
  • Біографії
  • Біологія
  • Біологія і хімія
  • Ботаніка та сільське гос-во
  • Бухгалтерський облік і аудит
  • Валютні відносини
  • Ветеринарія
  • Військова кафедра
  • Географія
  • Геодезія
  • Геологія
  • Етика
  • Держава і право
  • Цивільне право і процес
  • Діловодство
  • Гроші та кредит
  • Природничі науки
  • Журналістика
  • Екологія
  • Видавнича справа та поліграфія
  • Інвестиції
  • Іноземна мова
  • Інформатика
  • Інформатика, програмування
  • Юрист по наследству
  • Історичні особистості
  • Історія
  • Історія техніки
  • Кибернетика
  • Комунікації і зв'язок
  • Комп'ютерні науки
  • Косметологія
  • Короткий зміст творів
  • Криміналістика
  • Кримінологія
  • Криптология
  • Кулінарія
  • Культура і мистецтво
  • Культурологія
  • Російська література
  • Література і російська мова
  • Логіка
  • Логістика
  • Маркетинг
  • Математика
  • Медицина, здоров'я
  • Медичні науки
  • Міжнародне публічне право
  • Міжнародне приватне право
  • Міжнародні відносини
  • Менеджмент
  • Металургія
  • Москвоведение
  • Мовознавство
  • Музика
  • Муніципальне право
  • Податки, оподаткування
  •  
    Бесплатные рефераты
     

     

     

     

     

     

         
     
    МОВА МАКРОАССЕМБЛЕРА IBM PC
         

     

    Інформатика, програмування
    МОВА МАКРОАССЕМБЛЕРА IBM PC (Довідковий посібник)
    Укладач: В. Н. Пильщиків (МДУ, ВМК) (січень 1992 р.)
    У посібнику розглядається мова макроассеблера для персональних ЕОМ типу IBM PC
    (мова MASM, версія 4.0).
    Посібник складається з 4 розділів. У главі 1 розглянуто особливості персональних
    комп'ютерів типу IBM PC і наведені початкові відомості про мову MASM. У главі 2
    описується система команд цих комп'ютерів. Глава 3 присвячена присвячена
    власне мови MASM. У розділі 4 наведено приклади фрагментів програм та повних
    програм на MASM для вирішення різних завдань.
    У посібнику не розглядаються питання, пов'язані з обробкою двійковій-десяткових
    чисел і роботою арифметичного співпроцесора 8087 або 80287.
    Під терміном "ПК" в посібнику розуміється персональний комп'ютер типу IBM PC c
    мікропроцесором 8088/8086, 80186 або 80286.
    Розділ 1. ОСОБЛИВОСТІ ПК. ВСТУП У MASM.
    1.1. ОПЕРАТИВНА ПАМ'ЯТЬ. РЕГІСТРИ.
    1.1.1 Оперативна пам'ять
    Об'єм оперативної пам'яті ПК - 2 ^ 20 байт (1 Мб). Байти нумеруються починаючи з 0,
    номер байта називається його адресою. Для посилань на байти пам'яті використовуються
    20-розрядні адреси: від 00000 до FFFFF (у 16-річної системі).
    Байт містить 8 розрядів (бітів), кожен з яких може приймати значення 1
    або 0. Розряди нумеруються справа наліво від 0 до 7:
    -----------------< br />
    -----------------< br /> 7 6 5 4 3 2 1 0

    Байт - це найменша адресуемая комірка пам'яті. У ПК використовуються і більш
    великі осередки - слова і подвійні слова. Слово - це два сусідніх байти, розмір
    слова - 16 бітів (вони нумеруються справа наліво від 0 до 15). Адресою слова
    вважається адреса її першого байта (з меншим адресою); ця адреса може бути
    парних і непарних. Подвійне слово - це будь-які чотири сусідніх байти (два сусідніх
    слова), розмір такої комірки - 32 біта; адресою подвійного слова вважається адреса
    його першого байта.

    Байти використовуються для зберігання невеликих цілих чисел і символів, слова - для
    зберігання цілих чисел і адрес, подвійні слова - для зберігання "довгих" цілих
    чисел і т.зв. адресних пар (сегмент: зсув).
    1.1.2 Регістри
    Крім комірок оперативної пам'яті для зберігання даних (щоправда, короткочасного)
    можна використовувати і регістри - комірки, що входять до складу процесора і доступні
    з машинної програми. Доступ до регістрів здійснюється значно швидше,
    ніж до комірок пам'яті, тому використання регістрів помітно зменшує час
    виконання програм.
    Всі регістри мають розмір слова (16 бітів), за кожним з них закріплено
    певне ім'я (AX, SP і т.п.). За призначенням і способом використання регістри
    можна розбити на наступні групи:
      регістри загального призначення (AX, BX, CX, DX, BP, SI, DI, SP);

      сегментні регістри (CS, DS, SS, ES);

      лічильник команд (IP);

      регістр прапорів (Flags).

    (Розшифровка цих назв: 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 або в регістрах AX і DX (залежно від розміру операнда), а
    команди управління циклом використовують регістр CX в якості лічильника циклу.
    Регістри BX і BP дуже часто використовуються як базові регістри, а SI і DI - як
    індексні. Регістр SP зазвичай вказує на вершину стека, апаратно
    підтримуваного в ПК.
    Регістри AX, BX, CX і DX конструктивно влаштовані так, що можливий незалежний
    доступ до їх старшої та молодшої половин; можна сказати, що кожен з цих
    регістрів складається з двох байтових регістрів, що позначаються AH, AL, BH і т.д. (H
    - High, старший; L - low, молодший):
       ----------- ----------- ----------- -----------< Br /> AX AH AL BX BH BL CX CH CL DX DH DL
       ----------- ----------- ----------- -----------< Br />   15 8 7 0

    Таким чином, з кожним із цих регістрів можна працювати як з єдиним цілим, а
    можна працювати і з його "половинками". Наприклад, можна записати слово в AX, а
    потім рахувати тільки частину слова з регістру AH або замінити тільки частину в
    регістрі AL і т.д. Такий пристрій регістрів дозволяє використовувати їх для
    роботи та з числами, і з символами.
    Всі інші регістри не діляться на "половинки", тому вважати або записати
    їх вміст (16 бітів) можна тільки цілком.
    Сегментні регістри CS, DS, SS і ES не можуть бути операндами ніяких команд,
    крім команд пересилання і стекові команд. Ці регістри використовуються тільки для
    сегментування адрес (див. 1.4).
    Лічильник команд IP завжди містить адресу (зсув від початку програми) той
    команди, яка повинна бути виконана наступної (початок програми зберігається в
    регістрі CS). Вміст регістра IP можна змінити тільки командами переходу.
    1.1.3 Прапори
    І, нарешті, в ПК є особливий регістр прапорів. Прапор - це біт, що приймає
    значення 1 ( "прапор встановлений"), якщо виконано деякий умова, і значення 0
    ( "прапор скинутий") в іншому випадку. У ПК ис-
    користується 9 прапорів, кожному з них присвоєно певне ім'я (ZF, CF і т.д.).
    Всі вони зібрані в регістрі прапорів (кожен прапор - це один з розрядів регістра,
    частина його розрядів не використовується):

          -------------------------------------------------< br /> Flags x x x xOFDFIFTFSFZF xAF xPF xCF
          -------------------------------------------------< br />         15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

    Деякі прапори прийнято називати прапорами умов; вони автоматично змінюються при
    виконанні команд і фіксують ті чи інші властивості їх результату (наприклад,
    Чи він дорівнює нулю). Інші прапори називаються прапорами станів; вони змінюються з
    програми і впливають на подальшу поведінку процесора (наприклад,
    блокують переривання).
    Прапори умов:
    CF (carry flag) - прапорець перенесення. Приймає значення 1, якщо при складанні цілих
    чисел з'явилася одиниця переносу, не "влазити" в розрядну сітку, або якщо при
    віднімання чисел без знаку першим з них було менше другий. У командах зрушення в
    CF заноситься біт, що вийшов за розрядну сітку. CF фіксує також особливості
    команди множення.
    OF (overflow flag) - прапорець переповнення. Встановлюється в 1, якщо при складанні
    або віднімання цілих чисел зі знаком вийшов результат, по модулю перевершує
    допустиму величину (сталося переповнення мантиси і вона "залізла" в знаковий
    розряд).
    ZF (zero flag) - прапор нуля. Встановлюється в 1, якщо результат команди виявився
    рівним 0.
    SF (sign flag) - прапор знаку. Встановлюється в 1, якщо в операції над знаковими
    числами вийшов негативний результат.
    PF (parity flag) - прапорець парності. Дорівнює 1, якщо результат чергової команди
    містить парна кількість двійкових одиниць. Враховується звичайно тільки при
    операціях вводу-виводу.
    AF (auxiliary carry flag) - прапорець додаткового переносу. Фіксує особливості
    виконання операцій над двійковій-десятковими числами.
    Прапори станів:
    DF (direction flag) - прапорець напрямку. Встановлює напрямок перегляду
    рядків у строкових командах: при DF = 0 рядки проглядаються "вперед" (від початку
    до кінця), при DF = 1 - у зворотному напрямку.
    IF (interrupt flag) - прапорець переривань. При IF = 0 процесор перестає реагувати
    на що надходять до нього переривання, при IF = 1 блокування переривань знімається.
    TF (trap flag) - прапорець трасування. При TF = 1 після виконання кожної команди
    процесор робить переривання (з номером 1), чим можна скористатися при налагодженні
    програми для її трасування.


    1.2. ПРЕДСТАВЛЕННЯ ДАНИХ. Арифметичні операції
    Тут розглядається машинне подання цілих чисел, рядків і адрес.
    Представлення двійковій-десяткових чисел, що використовуються досить рідко, не
    розглядається. Що стосується дійсних чисел, то в ПК немає команд
    речової арифметики (операції над цими числами реалізуються програмним
    шляхом або виконуються співпроцесором) і тому немає стандартного подання
    дійсних чисел. Крім того, розглядаються деякі особливості виконання
    арифметичних операцій.
    Шістнадцяткові числа записуються з буквою h на кінці, двійкові
    числа - з буквою b (так прийнято в MASM).
    1.2.1 Представлення цілих чисел.
    У загальному випадку під ціле число можна відвести будь-яке число байтів, проте система
    команд ПК підтримує тільки числа розміром в байт і слово і частково
    підтримує числа розміром в подвійне слово. Саме ці формати і будуть
    розглянуті.
    У ПК робиться відмінність між цілими числами без знаку (невід'ємними) і з
    знаком. Це пояснюється тим, що в осередках одного і того ж розміру можна
    уявити більший діапазон беззнакових чисел, ніж невід'ємних знакових
    чисел, і якщо заздалегідь відомо, що деяка числова величина є
    невід'ємне, то вигідніше розглядати її як беззнакові, ніж як знакову.
    Цілі числа без знака.
    Ці числа можуть бути представлені у вигляді байта, слова чи подвійного слова - в
    залежно від їх розміру. У вигляді байти представляються цілі від 0 до 255
    (= 2 ^ 8-1), у вигляді слова - цілі від 0 до 65535 (= 2 ^ 16-1), у вигляді подвійного слова -
    цілі від 0 до 4 294 967 295 (= 2 ^ 32-1). Числа записуються в двійковій системі
    числення, займаючи всі розряди осередки. Наприклад, число 130 записується у вигляді
    байти 10000010b (82h).
    Числа розміром в слово зберігаються в пам'яті в "перевернутому" вигляді: молодшого (праві)
    8 бітів числа розміщуються в першому байті слова, а старші 8 бітів - у другому
    байті (у 16-річної системі: дві праві цифри - в першому байті, дві ліві цифри -
    у другому байті). Наприклад, число 130 (= 0082h) у вигляді слова зберігається в пам'яті
    так:
       -----------< br />     82 00
       -----------< br /> (Зазначимо, однак, що в регістрах числа зберігаються в нормальному вигляді:
       -----------< br /> AX 00 82
       -----------< br />     AH AL)

    "Перевернути" подання використовується і при зберіганні в пам'яті цілих чисел
    розміром в подвійне слово: у першій його байті розміщуються молодші 8 бітів числа,
    у другому байті - попередні 8 бітів і т.д. Наприклад, число 12345678h зберігається в
    пам'яті так:

    ---------------------< br /> 78 56 34 12
    ---------------------< br />
    Іншими словами, в першому слові подвійного слова розміщуються молодші (праві) 16
    бітів числа, а в другому слові - старші 16 бітів, причому в кожному з цих двох
    слів в свою чергу використовується "перевернуте" подання.
    Таке незвичайне подання чисел пояснюється тим, що в перших моделях ПК за
    раз можна було вважати з пам'яті тільки один байт і що всі арифметичні
    операції над багатозначними числами починаються з дій над молодшими цифрами,
    тому з пам'яті в першу чергу треба зчитувати молодші цифри, якщо відразу
    не можна вважати всі цифри. З огляду на це, в першу ПК і стали розміщувати молодші
    цифри числа перед старшими ціфраммі, а заради наступності таке подання
    чисел зберегли в наступних моделях ПК.
    Звичайно, "перевернуте" подання незручно для людей, однак при
    використання мови асемблера цю незручність не відчувається: в MASM всі числа
    записуються в нормальному, неперевернутом вигляді (див. нижче).
    Цілі числа зі знаком.
    Ці числа також подаються у вигляді байти, слова та подвійного слова. У вигляді
    байти записуються числа від -128 до 127, у вигляді слова числа від -32768 до 32767,
    а у вигляді подвійного слова - числа від -2147483648 до 2147483647. При цьому числа
    записуються в додатковому коді: невід'ємне число записується так само,
    як і беззнакові число (тобто в прямому коді), а негативне число-x (x> 0)
    представляється беззнакові числом 2 ^ 8-x (для байтів), 2 ^ 16-x (для слів) або
    2 ^ 32-x (для подвійних слів). Наприклад, додатковим кодом числа -6 є байт
    FAh (= 256-6), слово FFFAh або подвійне слово FFFFFFFAh. При цьому байт 10000000b
    (= 80h) трактується як -128, а не як +128 (слово 8000h розуміється як -32678),
    тому лівий біт додаткового коду завжди грає роль знакового: для
    невід'ємних чисел він дорівнює 0, для негативних - 1.
    Знакові числа розміром в слово і подвійне слово записуються в пам'яті в
    "перевернутому" вигляді (при цьому знаковий біт виявляється в останньому байті
    комірки). Але в MASM ці числа, як і беззнакові, записуються в нормальній
    формі.
    Іноді число-байт необхідно розширити до слова, тобто потрібно отримати таке ж за
    величиною число, але розміром в слово. Існує два способи такого розширення -
    без знаку і зі знаком. У будь-якому випадку вихідне число-байт потрапляє в другій (до
    "перевертання") байт слова, а ось перший байт заповнюється по-різному: при
    розширення без знака в нього записуються нульові біти (12h -> 0012h), а при
    розширення зі знаком в перший байт записуються нулі, якщо число-байт було
    невід'ємним, і записується вісім двійкових одиниць у противному випадку (81h
    -> FF81h). Іншими словами, при розширенні зі знаком в першому байті слова
    копіюється знаковий розряд числа-байти.
    Аналогічно відбувається розширення числа-слова до подвійного слова.
    1.2.2 Особливості виконання арифметичних опреацій
    У ПК є команди додавання і віднімання цілих чисел розміром в слово і байт.
    Спеціальних команд для додавання і віднімання подвійних слів немає, ці операції
    реалізуються через команди додавання і віднімання слів.
    Додавання і віднімання беззнаковаих чисел проводиться за модулем 2 ^ 8
    для байтів і 2 ^ 16 для слів. Це означає, що якщо в результаті складання
    з'явилася одиниця переносу, не вміщаються в розрядну сітку, то вона
    відкидається. Наприклад, при складанні байтів 128 і 130 виходить число 258 =
    100000010b, тому ліва двійкова одиниця відкидається і залишається число 2 =
    10b, яке і оголошується результатом складання. Помилка тут не фіксується, але
    в прапор переносу CF записується 1 (якщо переносу не було, в CF заноситься 0).
    "Зловити" таке спотворення суми можна тільки подальшим аналізом прапора CF.
    Спотворення результату відбувається і при віднімання від меншого числа більшого. І
    тут не фіксується помилка, однак першого числа дається "позика одиниці" (в
    випадку байтів це число збільшується на 256, для
    слів - на 2 ^ 16), після чого і проводиться віднімання. Наприклад, віднімання байтів
    2 і 3 зводиться до віднімання чисел 256 +2 = 258 і 3, в результаті чого виходить
    неправильна різниця 255 (а не -1). Для того щоб можна було виявити таку
    ситуацію, в прапор переносу CF заноситься 1 (якщо позики не було, в CF записується
    0).
    Додавання і віднімання знакових цілих чисел здійснюється за тими ж алгоритмами, що
    і для беззнакових чисел (у цьому одна з переваг додаткового коду):
    знакові числа розглядаються як відповідні беззнакові числа,
    проізодітся операція над цими беззнакові числами і отриманий результат
    інтерпретується як знакове число. Наприклад, складання байтових чисел 1 і -2
    відбувається так: беруться їхні додаткові коди 1 і (256-2) = 254, обчислюється
    сума цих величин 1 +254 = 255 і вона трактується як знакове число -1 (255 = 256-1).
    Якщо при такому складання виникла одиниця переносу, то вона, як завжди,
    відкидається, а прапор CF отримує значення 1. Проте в даному випадку це
    відсікання не представляє інтерес - результат операції буде правильним,
    наприклад: 3 + (-2) => 3 +254 (mod 256) = 257 (mod 256) = 1. Зате тут можлива інша
    неприємність: модуль суми (її мантиса) може перевершити допустиму межу і
    "залізти" в знаковий розряд, зіпсували його. Наприклад, при складанні байтових чисел
    127 і 2 виходить величина 129 = = 100001001b, що представляє додатковий
    код числа -127 (= 256-129).
    Хоча результат тут вийшов і неправильним, процесор не фіксує помилку, але
    зате заносить 1 в прапор переповнення OF (якщо "переповнення мантиси" не було, в
    OF записується 0). Аналізуючи потім цей прапор, можна "зловити" таку помилку.
    Таким чином, додавання (віднімання) знакових і беззнакових чисел проводиться за
    одного й того ж алгоритму. При цьому ПК не "знає", які числа (зі знаком або
    без) він складає; в будь-якому випадку він складає їх як беззнакові числа і в
    будь-якому випадку формує прапори CF і OF. А ось як інтерпретувати складові і
    суму, на якій з цих прапорів звертати увагу - це особиста справа автора
    програми.
    Що стосується множення і ділення знакових і беззнакових чисел, то вони
    виконую?? ся за різними алгоритмами, різними машинними командами. Однак і у цих
    операцій є ряд особливостей. При збільшенні байтів (слів) перший співмножники
    зобов'язаний знаходитися в регістрі AL (AX), результатом ж множення є слово
    (подвійне слово), що заноситься в регістр AX (регістри DX і AX). Тим самим
    при збільшенні зберігаються всі цифри твори. При розподілі байтів (слів)
    перший операнд (ділене) повинен бути словом (подвійним словом) і зобов'язаний перебувати
    в регістрі AX (регістрах DX і AX). Результатом поділу є дві величини
    розміром в байт (слово) - неповна приватне (div) і залишок від ділення (mod);
    неповне приватне записується в регістр AL (AX), а залишок - в регістр AH (DX).
    1.2.3 Представлення символів і рядків
    На символ відводиться один байт пам'яті, в який записується код символу - ціле
    від 0 до 255. У ПК використовується система кодування ASCII (American Standard Code
    for Information Interchange). Вона, природно, не містить кодів російських букв,
    тому в нашій країні застосовується деякий варіант цієї системи з російськими
    літерами (зазвичай це альтернативна кодування ГОСТу).
    Деякі особливості цих систем кодування:
    - Код пробілу менше коду будь-якої букви, цифри і взагалі будь-якого графічно
    представимо символу;
    - Коди цифр впорядковані за величиною цифр і не містять пропусків, тобто з
    нерівності код ('0 ') MOV AX, 0FF80h (A: =- 128)
    MOV AX, 128; => MOV AX, 0080h (A: = +128) MOV AX, 80h; => MOV AX, 0080h (A: = +128)


    1.4. СЕГМЕНТІРОВНІЕ

    1.4.1 Сегменти пам'яті. Сегментні регістри.
    Перші моделі ПК мали оперативну пам'ять об'ємом 2 ^ 16 байт (64Кб) і тому
    використовували 16-бітові адреси. У подальших моделях пам'ять була збільшена до
    2 ^ 20 байт (1Мб = 1000Кб), для чого вже потрібні 20-бітові адреси. Проте в
    цих ПК заради збереження наступності були збережені 16-бітові адреси: саме
    такі адреси зберігаються в регістрах і вказуються в командах, саме такі адреси
    утворюються в результаті модмфікаціі з базових та індексних регістрів. Як же
    вдається 16-бітовими адресами посилатися на 1Мб пам'яті?
    Ця проблема вирішується за допомогою сегментації адрес (неявного базування
    адрес). У ПК вводиться поняття "сегмент пам'яті". Так називається будь-яка ділянка
    пам'яті розміром до 64Кб і з початковим адресою, кратним 16. Абсолютний
    (20-бітовий) адреса A будь-якої комірки пам'яті можна
    представити як суму 20-бітового початкового адреси (бази) B сегмента, якому
    належить осередок, і 16-бітового зміщення D - адреси цього осередку, відраховані
    від початку сегменту: A = B + D. (Неоднозначність вибору сегмента не грає
    істотної ролі, головне - щоб сума B і D давала потрібну адресу.) Адреса B
    заноситься в деякий регістр S, а в команді, де має бути вказана адреса A,
    замість нього записується пара з регістра S і зміщення D (в MASM така пара,
    звана адресної парою або покажчиком, записується як S: D). Процесор ж
    влаштований так, що при виконанні команди він перш за все по парі S: D обчислює
    абсолютний адреса A як суму вмісту регістра S і зміщення D і тільки потім
    звертається до пам'яті за цією адресою A. Ось так, замінюючи в командах абсолютні
    адреси на адресні пари, і вдається адресувати всю пам'ять 16-бітовими адресами
    (зміщеннями).
    Як регістра S дозволяється використовувати не будь-який регістр, а тільки одна
    з 4 регістрів, званих сегментними: CS, DS, SS і ES. У зв'язку з цим
    одночасно можна працювати з 4 сегментами пам'яті: початок одного з них
    завантажується в регістр CS і всі посилання на комірки цього сегмента вказуються в
    вигляді пар CS: D, початок іншого заноситься в DS і всі посилання на його осередку задаються
    у вигляді пар DS: D і т.д. Якщо одночасно треба працювати з великим числом
    сегментів, тоді потрібно вчасно рятувати вміст сегментних регістрів і
    записувати в них початкові адреси п'ятого, шостого і т.д. сегментів.
    Відзначимо, що використовуються сегменти можуть бути розташовані в пам'яті довільним
    чином: вони можуть не перетинатися, а можуть перетинатися і навіть збігатися. Які
    сегменти пам'яті використовувати, в яких сегментних регістрах зберігати їх початкові
    адреса - все це особиста справа автора машинної програми.
    Як і всі регістри ПК, сегментні регістри мають розмір слова. Тому виникає
    питання: як вдається розмістити в них 20-бітові початкові адреси сегментів
    пам'яті? Відповідь така. Оскільки всі ці адреси кратні 16 (див. вище), то в них
    молодші 4 біта (остання 16-ковий цифра) завжди нульові, а тому ці біти
    можна не зберігати явно, а лише мати на увазі. Саме так і робиться: у сегментному
    регістрі завжди зберігаються тільки перші 16 бітів (перші чотири 16-ковий цифри)
    початкової адреси сегменту (ця величина називається номером сегмента або просто
    сегментом). При обчисленні ж повної адреси A по парі S: D процесор спочатку
    приписує справа до вмісту регістра S чотири нульових біта (іншими
    словами, множить на 16) і лише потім додає зсув D, причому підсумовування
    ведеться за модулем 2 ^ 20:
    Aабс = 16 * [S] + D (mod 2 ^ 20)
    Якщо, наприклад, в регістрі CS зберігається величина 1234h, тоді адресна пара
    1234h: 507h визначає абсолютний адреса, що дорівнює 16 * 1234h +507 h = 12340h +507 h =
    12847h.
    1.4.2 Сегментні регістри за замовчуванням
    Згідно з описаною схемою сегментації адрес, заміну абсолютних адрес на
    Адреса пари треба проводити у всіх командах, що мають операнд-адресу. Однак
    розробники ПК придумали спосіб, що дозволяє уникнути виписування таких пар в
    більшості команд. Суть його в тому, що заздалегідь домовляються про те, який
    сегментний регістр на ка-
    кой сегмент пам'яті буде вказувати, і що в командах задається тільки зміщення:
    не зазначений явно сегментний регістр автоматично відновлюється згідно
    цієї домовленості. І тільки при необхідності порушити цю домовленість треба
    повністю вказувати адресну пару.

    Що це за домовленість?

    Вважається, що регістр CS завжди вказує на початок області пам'яті, в якій
    розміщені команди програми (ця область називається сегментом команд або
    сегментом кодів), і тому при посиланнях на клітинки цієї області регістр CS можна
    не вказувати явно, він мається на увазі за умовчанням. (Відзначимо попутно, що
    абсолютний адреса чергової команди, що підлягає виконанню, завжди задається парою
    CS: IP: в лічильнику команд IP завжди знаходиться зміщення цієї команди щодо
    адреси з регістра CS.) Аналогічно передбачається, що регістр DS вказує на
    сегмент даних (область пам'яті з константами, змінними та іншими величинами
    програми), і тому у всіх посиланнях на цей сегмент регістр DS можна явно не
    вказувати, тому що він мається на увазі за умовчанням. Регістр SS, вважається,
    вказує на стек - область пам'яті, доступ до якої здійснюється за принципом
    "останнім записаний - перший лічений" (див. 1.7), і тому всі посилання на стек,
    яких явно не вказано сегментний регістр, за замовчуванням сегментуються по
    регістру SS. Регістр ES вважається вільним, він не прив'язаний ні до якого сегменту
    пам'яті і його можна використовувати на власний розсуд; найчастіше він застосовується
    для доступу до даних, які не помістилися або свідомо не були розміщені в
    сегменті даних.
    З урахуванням такого розподілу ролей сегментних регістрів машинні програми
    зазвичай будуються так: усі команди програми розміщуються в одному сегменті пам'яті,
    початок якого заноситься в регістр CS, а всі дані размещаютсяв іншому
    сегменті, початок якого заноситься в регістр DS; якщо потрібен стек, то під нього
    відводиться третій сегмент пам'яті, початок якого записується в регістр SS.
    Після цього практично у всіх командах можна вказувати не повні адресні
    пари, а лише зміщення, тому що сегментні регістри в цих парах будуть
    відновлюватися автоматично.
    Тут, правда, виникає таке питання: як по зміщенню визначити, на якій
    сегмент пам'яті воно вказує? Точну відповідь наведено нижче (див. 1.4.3), а в загальних
    рисах він такий: посилання на сегмент команд можуть бути тільки в командах переходу,
    а посилання практично в усіх інших командах (крім строкових і стекові) - це
    посилання на сегмент даних. Наприклад, у команді пересилання
    MOV AX, X
    ім'я X сприймається як посилання на даний, а тому автоматично
    відновлюється до адресної пари DS: X. У команді ж безумовного переходу по
    адресою, що знаходиться в регістрі BX,
    JMP BX
    абсолютний адреса переходу визначається парою CS: [BX].
    Отже, якщо в посиланні на якусь комірку пам'яті не вказаний явно сегментний регістр,
    то цей регістр береться за замовчуванням. Явно ж сегментні регістри треба
    вказувати, тільки якщо з якихось причин регістр за замовчуванням не підходить.
    Якщо, наприклад, у команді пересилання нам треба послатися на стек (скажімо, треба
    записати в регістр AH байт стека, позначений ім'ям X), тоді нас уже не буде
    влаштовувати домовленість про те, що за замовчуванням операнд команди MOV
    сегментується за регістром DS, і тому ми зобов'язані явно вказати інший регістр - в
    нашому випадку регістр SS, тому що саме він вказує на стек:
    MOV AH, SS: X
    Однак такі випадки зустрічаються рідко і в командах, як правило,
    вказуються тільки зміщення.
    Відзначимо, що в MASM сегментний регістр записується в самій команді
    безпосередньо перед зсувом (ім'ям змінної, міткою тощо), однак на
    рівні машинної мови ситуація дещо інша. Є 4 спеціальні
    однобайтові команди, які називаються префіксами заміни сегмента (що позначаються як
    CS:, DS:, SS: і ES:). Вони ставляться перед командою, операнд-адреса якої повинен
    бути просегментірован за регістром, відмінному від регістра, маємо на увазі по
    замовчуванням. Наприклад, наведена вище символічна команда пересилання - це на
    Насправді два машинні команди:
    SS:
    MOV AH, X

    1.4.3 Сегментування, базування та індексування адрес Оскільки
    сегментування адрес - це різновид модифікації

    адрес, то в ПК адреса, що указується в команді, в загальному випадку модифікується по
    трьох регістрів - сегментні, базових і індексних. В цілому, модифікація адреси
    проводиться в два етапи. Спочатку враховуються тільки базовий і індексний
    регістри (якщо вони, звичайно, вказані в команді), причому обчислення тут
    відбувається в області 16-бітових адрес; отриманий в результаті 16-бітовий
    адреса називається виконавчим (ефективним) адресою. Якщо в команді не
    передбачено звернення до пам'яті (наприклад, вона завантажує адреса в регістр), то
    на цьому модифікація адреси закінчується і використовується саме виконавчий
    адреса (він завантажується в регістр). Якщо ж потрібен доступ до пам'яті, тоді на другому
    етапі виконавчий адреса розглядається як зсув і до нього додається
    (помножене на 16) вміст сегментного регістра, зазначеного явно або взятого
    за замовчуванням, у результаті чого виходить абсолютний (фізичний) 20-бітовий
    адреса, за якою реально і відбувається звертання до пам'яті.
    Відзначимо, що сегментний регістр враховується тільки в "останній" момент,
    безпосередньо перед зверненням до пам'яті, а до цього робота ведеться тільки з
    16-бітовими адресами. Якщо врахувати до того ж, що сегментні регістри, як
    правило, не вказуються в командах, то можна взагалі-то вважати, що ПК працює
    з 16-бітовими адресами.
    Як уже сказано, якщо в посиланні на комірку пам'яті не вказано сегментний регістр, то
    він визначається за замовчуванням. Це робиться за такими правилами.
    1) У командах переходу адреса переходу сегментується за регістром CS і тільки по
    нього, тому що абсолютний адресу команди, яка повинна бути виконана наступної,
    завжди визначається парою CS: IP (спроба змінити в таких командах сегментний
    регістр буде безуспішною).
    Відзначимо, що сегментіорваніе за регістром CS стосується саме адреси
    переходу, а не адреси тієї комірки, де він може перебувати. Наприклад, у команді
    безумовного переходу за адресою, що знаходиться в комірці X:
    JMP X
    ім'я X сегментується за регістром DS, а ось адреса переходу, взятий з осередку X,
    вже сегментується за регістром CS.
    2) Адреси в усіх інших командах, крім строкових (STOS, MOVS, SCAS і CMPS), за
    замовчуванням сегментуються:
    - За регістром DS, якщо серед зазначених регістрів-модифікаторів немає регістра BP;
    - За регістром SS, якщо один з модифікаторів - регістр BP.
    Таким чином, адреси виду A, A [BX], A [SI], A [DI], A [BX] [SI] і A [BX] [DI]
    сегментуються за регістром DS, а адреси A [BP], A [BP] [SI] і A [BP] [DI] - по
    регістру SS, тобто адреси трьох останніх видів використовуються для доступу до осередків
    стека.
    3) У строкових командах STOS, MOVS, SCAS і CMPS, що мають дві операнда-адреси, на
    які вказують індексні регістри SI і DI, один з операндів (на який
    вказує SI) сегментується по регіструDS, а інший (на нього вказує DI) - за
    регістру ES.

    1.4.4 Програмні сегменти. Директива ASSUME
    Розглянемо, як сегментування проявляється в програмах на MASM.
    Для того, щоб вказати, що деяка група пропозицій програми на MASM
    утворюють єдиний сегмент пам'яті, вони оформлюються як програмний сегмент: перед
    ними ставиться директива SEGMENT, після них - директива ENDS, причому на початку
    обох цих директив повинно бути вказано одне і те ж ім'я, що грає роль імені
    сегмента. Програма ж в цілому являє собою послідовність таких
    програмних сегментів, в кінці якої вказується директива кінця програми
    END, наприклад:
    DT1 SEGMENT; програмний сегмент з ім'ям DT1 A DB 0
    B DW? DT1 ENDS
    ;
    DT2 SEGMENT; програмний сегмент DT2
    C DB 'hello'
    DT2 ENDS
    ;
    CODE SEGMENT; програмний сегмент CODE
    ASSUME CS: CODE, DS: DT1, ES: DT2
    BEG: MOV AX, DT2
    MOV DS, AX
    MOV BH, C
    ...
    CODE ENDS
    END BEG; кінець тексту програми
    Пропозиції програмного сегмента асемблер розміщує в одному сегменті пам'яті (у
    сукупності вони не повинні займати більш 64Кб) починаючи з найближчого вільного
    адреси, кратного 16. Номер (перші 16 бітів початкового адреси) цього сегмента
    стає значенням імені сегмента. У MASM це ім'я відноситься до константним
    виразами, а не адресним, у зв'язку з чим в команді
    MOV AX, DT2
    другий операнд є безпосереднім, тому в регістр AX буде записано
    початок (номер) сегмента DT2, а не вміст початкової комірки цього сегмента.
    Імена ж змінних (A, B, C) і мітки (BEG) відносяться до адресних виразами, і
    їм ставиться у відповідність адресу їхнього осередку щодо "свого" сегмента: імені
    A відповідає адреса 0, імені B - адреса 1, імені C - адреса 0, а мітці BEG -
    адреса 0.
    Всі посилання на пропозиції одного програмного сегмента асемблер сегментує по
    замовчуванням з одного й того ж сегментному регістру. За яким саме -
    встановлюється спеціальною директивою ASSUME. У нашому прикладі ця директива
    визначає, що всі посилання на сегмент CODE повинні, якщо явно не вказано
    сегментний регістр, сегментовано по регістру CS, всі посилання на DT1 - по
    регістру DS, а всі посилання на DT2 - за регістром ES.
    Зустрівши в тексті програми посилання на будь-яке ім'я (наприклад, на ім'я C в
    команді MOV AX, C), асемблер визначає, в якому програмному сегменті воно
    описано (у нас - в DT2), потім за інформацією з директиви ASSUME дізнається який
    сегментний регістр поставлений у відповідність цього сегмента (у нас - це ES), і
    далі утворює адресну пару ІЕ даного регістра і зміщення імені (у нас -
    ES: 0), яку і записує в сформовану машинну команду. При цьому асемблер
    враховує що використовується в ПК угоду про сегментних регістрах за замовчуванням: якщо
    в адресній парі, побудованої їм самим або явно заданої в програмі, сегментний
    регістр збігається з регістром за умовчанням, то в машинну команду заноситься лише
    зсув. Якщо, скажімо, у нашому прикладі зустрінеться команда MOV CX, B, тоді по
    імені В асемблер побудує пару DS: 1, але раз операнд-адресу команди MOV по
    замовчуванням сегментується за регістром DS, то записувати цей регістр в машинну
    команду зайве і асемблер записує в неї тільки зміщення 1.
    Таким чином, директива ASSUME позбавляє програмістів від необхідності
    виписувати повні адресні пари не тільки тоді, коли використовуються сегментні
    регістри за замовчуванням (як у випадку з ім'ям B), але тоді, коли в машинної
    команді потрібно було б явно вказати сегментний регістр (як у випадку з ім'ям C).
    У MASM сегментний регістр у посиланням на ім'я потрібно вказувати лише тоді, коли
    ім'я має з яких-небудь причин сегментувати за регістром, отличному від
    того, що поставлено у відповідність всьому сегменту, в якому це ім'я описано.
    Однак все це справедливо лише при дотриманні наступних умов. По-перше,
    директива ASSUME повинна бути вказана перед першою командою програми. В
    Інакше асемблер, що переглядає текст програми зверху вниз, не
    буде знати, як сегментувати імена з команд, розташованих до цієї
    директиви, і тому зафіксує помилку. По-друге, в директиві ASSUME слід
    кожному сегменту ставити у відповідність сегментний регістр: якщо асемблеру
    зустрінеться посилання на ім'я із сегмента, якому не відповідає ніякої
    сегментний регістр, то він зафіксує помилку. Щоправда, в обох випадках можна
    уникнути помилки, але для цього в посиланнях необхідно явно вказувати сегментний
    регістр.
    1.4.5 Початкова завантаження сегментних регістрів
    Директива ASSUME повідомляє ассмеблеру про те, з яких регістрів він повинен
    сегментувати імена з яких сегментів, і "обіцяє", що в цих регістрах будуть
    перебувати початкові адреси цих сегментів. Однак завантаження цих адрес в
    регістри сама директива не здійснює. Зробити таку завантаження - обов'язок
    самої програми, з завантаження сегментних регістрів і повинно починатися виконання
    програми. Робиться це так.
    Оскільки в ПК немає команди пересилання безпосереднього операнда в сегментний
    регістр (а ім'я, тобто початок, сегмента - це безпосередній операнд), то таку
    завантаження доводиться робити через якийсь інший, несегментний, реєстр
    (наприклад, AX):
    MOV AX, DT1; AX: = початок сегмента DT1
    MOV DS, AX; DS: = AX
    Аналогічно завантажується і регістр ES.
    Завантажувати регістр CS на початку програми не треба: він, як і лічильник команд IP,
    завантажується операційною системою перед тим, як починається виконання програми
    (інакше не можна було б почати її виконання). Що ж до регістра SS,
    використовуваного для роботи зі стеком, то він може бути завантажений так само, як і
    регістри DS і ES, проте в MASM передбачена можливість завантаження цього
    регістра ще до виконання програми (див. 1.7).
    1.4.6 Посилання вперед
    Зустрічаючи в символьної команді посилання тому - ім'я, яке описано в тексті
    програми до цієї команди, асемблер вже має необхідну інформацію про ім'я і
    тому може правильно оттрансліровать цю команду. Але якщо в команді зустрінеться
    посилання вперед, тобто ім'я, яке не було описано до команди і яке, напевно,
    буде описано пізніше, то асемблер в більшості випадків не зможе правильно
    оттрансліровать цю команду. Наприклад, не знаючи, в якому програмному сегменті
    буде описано це ім'я, асемблер не може визначити, яким сегментному
    регістру треба сегментувати ім'я, і тому не може визначити, треба чи ні
    розміщувати перед відповідної машинної командою префікс заміни сегмента і,
    якщо треба, то який саме.
    У подібній ситуації асемблер діє таким чином: якщо в команді
    зустрілася посилання вперед, то він робить деякий припущу
         
     
         
    Реферат Банк
     
    Рефераты
     
    Бесплатные рефераты
     

     

     

     

     

     

     

     
     
     
      Все права защищены. Reff.net.ua - українські реферати ! DMCA.com Protection Status