Структура программы на языке Ассемблер

Архитектура и система команд микропроцессора x86

Лабораторная работа 10

Начальные сведения о языке Ассемблер

Аппаратная поддержка языка

При выполнении программы, микропроцессор взаимодействует с оперативной памятью, где хранятся исполняемая программа и данные, а так же с периферийными устройствами.

Программируемая структура процессора

Для организации вычислений микропроцессор i8086 имеет в своём составе 14 шестнадцатиразрядных регистров, которые обеспечивают выполнение программы:

Регистры общего назначения     Сегмент­ные регистры   Специ­альные регистры  
AH AL AX   CS   SP Указатель стека
BH BL BX   DS   BP Указатель базы стека
CH CL CX   ES   IP Указатель инструкций
DH DL DX   SS   FLAGS Регистр флагов
SI            
DI            

Регистры общего назначения:

AX(AH, AL), BX(BH, BL), CX(CH, CL), DX(DH, DL) делятся программно на пары однобайтных регистров и могут использоваться для хранения данных. Разбиение на однобайтные регистры позволяет увеличить общее число регистров;

SP, BP – указатель и база стека, соответственно, обеспечивают доступ к данным в стеке, могут использоваться для хранения данных, но делать это не рекомендуется, так как при этом возможно нарушение адресации в стеке, особенно при использовании SP.

SI, DI – шестнадцатиразрядные регистры для хранения данных.

CS, DS, ES, SS – хранят адреса сегментов в памяти, не могут использоваться для хранения данных.

IP – регистр инструкций – хранит адрес (смещение) следующей исполняемой команды.

FLAGS – регистр флагов содержит набор битовых флагов, определяющий текущее состояние процессора и результат выполнения предыдущей команды (таблица 2.1).

Таблица 2.1
Регистр флагов процессора
Флаг Название Назначение
О Перепол­нение Переполнение при выполнении арифметических операций
D Направле­ние Направление пересылки данных при выполнении строковых команд
I Прерыва­ние Разрешает/Запрещает внешние прерывания
T Пошаговый режим Останов после выполнения каждой команды(используется отладчиками)
S Знак Знак результата выполненной команды(0 – плюс, 1 – минус)
Z Ноль Значение результата выполненной команды(0 – ненулевой, 1 – нулевой)
A Внешний перенос Используется для специальных арифметических операций
P Контроль чётности Число единиц в операнде(0 – нечётное, 1 – нечётное)
C Перенос Содержит перенос из старшего бита при выполнении арифметических операциях

Структура памяти

Память, с которой взаимодействует процессор при обработке программ, называется Оперативным Запоминающим Устройством (ОЗУ) или Random Access Memory (RAM). Она состоит из набора однобайтных ячеек, обращение к которым происходит по их номерам (физическим адресам). Число ячеек зависит от ширины шины адреса и составляет для процессора i8086 (ширина шины адреса равна 20) 220 – ячеек (1Мбайт). Для современных процессоров с шириной шины адреса 32 объём ОЗУ может доходить до 4 Гбайт.

Данные можно читать или сохранять в ОЗУ байтами, указывая номер требуемой ячейки или словами (2 байта), указывая адрес младшей ячейки памяти и вводя специальный префикс.

Сегментация памяти

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

Один из них – сегментный, он хранит адрес начала блока памяти, который и называется сегментом. Если к шестнадцати разрядам сегмента мысленно справа дописать четыре двоичных нуля(16+4=20), то получим физический адрес начала сегмента в ОЗУ. Второй регистр хранит величину смещения адреса требуемой ячейки от начала сегмента. Адрес ячейки памяти записывается в виде двойного слова (4 байта): <сегмент>:<сме­ще­ние>.

Сегмент всегда начинается с ячейки, номер которой заканчивается на 4 двоичных (или один шестнадцатеричный) нуля. Минимальная длина сегмента 16 байтов (параграф). Максимальная длина определяется длиной регистра, хранящего смещение и равна 216(64 Кбайта).

Пара регистров CS:IP(<сегмент>:<смещение>) определяют адрес следующей команды программы.

Для адресации данных используются сегментные регистры DS и ES, а в качестве регистров, хранящих смещение, используются регистры общего назначения BX, SI, DI. Для работы с сегментом стека используют сегментный регистр SS и регистр BP.

Структура программы на языке Ассемблер

Программа на языке ассемблера представляет собой текст разбитый на строки. Каждая строка либо соответствует машинной команде, либо является директивой ассемблера или макрокомандой. Команды и директивы можно набирать как большими, так и малыми латинскими буквами. Русские буквы можно использовать только в комментариях.

<имя сегмента> segment

команды или директивы

<имя сегмента> ends

[

<имя сегмента> segment

команды или директивы

<имя сегмента> ends ]

end <метка входа в программу>

Директива end < метка входа в программу> отмечает конец текста программы и указывает ассемблеру, где завершить трансляцию. Поэтому директива endдолжна присутствовать в каждой программе.

< метка точки входа > указывает инструкцию, с которой должно начинаться выполнение программы.

Каждая программа содержит сегменты данных и команд, но минимально должна содержать сегмент команд.

Строка программы, в общем случае, состоит из четырех полей:

Поле метки   Поле операции Поле операндов Поле комментария
M1: Add AX, BX ; сложение

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

Директивы ассемблера

Директивой называется команда транслятору для выполнения определённых данной директивой действий, сама директива в текст транслированной программы не включается.

1. Директива задания исходных данных:

[<имя>] d<тип> <константа>[,<константа>, <константа>, . . .]

· <имя> - имя массива данных, по которому к ним можно обратиться из команды;

· d(define)– определяет начало массива данных;

· <тип> - размер констант, входящих в массив:

b байт,
w Слово (два байта),
d двойное слово,
q учетверённое слово,
t десять байтов;

· <константа> - числовой или символьный элемент массива дан­ных.

В ассемблере используется несколько типов констант:

десятичные – последовательность цифр от 0 до 9;

шестнадцатеричные – последовательность шестнадцатеричных цифр от 0 до 9 и от А или а до F или f завершающаяся буквой H или h, первой должна быть десятичная цифра или 0;

восьмеричные – последовательность цифр от 0 до 7, завершающаяся буквами Q или q;

двоичные – последовательность цифр от 0 до 1, завершающаяся буквой B или b;

символьные – символ или группа символов, заключённые в кавычки;

знак ? – используется для резервирования места для данных.

Например,

data1 db 123, 0a2h, 75q, 110011b, 'a', 'пример', ?, ?

Для заполнения больших массивов используется директива dup (duplicate):

<число повторений> dup(<образец>)

<число повторений> - задаёт количество размещаемых в памяти данных, определяемых образцом;

<образец> - любая допустимая группа констант.

Например,

data2 db 23 dup(1, 2, 'x')

выделяет в памяти 23 · 3=69 байтов и заносит в них образец 1, 2, 'x', 1, 2, 'x', … .

2. Директива использования сегментных регистров по умолчанию:

assume<имя сегментного регистра>:<имя сегмента или nothing>[, <имя сегментного регистра>:<имя сегмента или nothing>, …]

Как отмечалось выше, для задания адреса в памяти требуется два регистра, один из них всегда сегментный, поэтому в команде при обращении к памяти приходится набирать имя сегментного регистра, часто одного и того же. Директива assumeпозволяет избежать этого. Транслятор сопоставляет имя массива данных и автоматически подставляет сегментный регистр, заданный для сегмента, в котором расположен данный массив. Слово nothingпоказывает, что данный сегментный регистр не адресуется по умолчанию. Директива assume может использоваться в программе при каждом изменении сегмента для данного сегментного регистра, но обязательно в начале сегмента, где она задаёт по умолчанию сегментный регистр для сегмента кодов.

Например,

assumecs:code, ds:data1, es:nothing

Здесь code и data1 – имена сегментов кодов и данных, соответственно.

Режимы адресации

1. Регистровая прямая - операнд находится в регистре.

Обозначение - <регистр>,

< регистр > - АХ, ВХ, СХ, DX, SI, DI, BP, SP, AL, BL, СL, DL, AH, BH, CH, DH.

Пример:

mov АХ,SI ; переслать содержимое регистра SI в регистр АХ.

2. Непосредственная -непосредственный операнд (константа) присутствует в команде.

Обозначение - < константное выражение > .

Пример:

mov AX, 093Ah ; занести константу 093Ah в регистр АХ.

3. Прямая - исполнительный адрес операнда присутствует в команде.

Обозначение - < переменная >+/-< константное выражение >.

Пример:

mov AX, WW ; переслать в АХ слово памяти с именем WW

mov BX, WW+2 ; переслать в ВХ слово памяти отстоящее от переменной с именем WW на 2 байта.

4. Регистровая косвенная - регистр содержит адрес операнда.

Обозначение - [< регистр >],

< регистр > - ВХ. ВР. SI, DI.

Пример:

mov [ BX ], CL ; переслать содержимое регистра CL по адресу, находящемуся в регистре ВХ.

5. Регистровая относительная - адрес операнда вычисляется как сумма содержимого регистра и смещения.

Обозначение - < переменная >[< регистр >] или [< регистр >]< кон­с­та­н­т­ное выражение >,

< регистр > - SI или DI индексная адресация, ВХ или ВР - базовая адресация.

Пример:

mov АХ, WW[SI] ; переслать в АХ слово из памяти, адрес которого вычисляется как сумма содержимого регистра SI и смещения WW.

6. Индексно - базовая - адрес операнда вычисляется как сумма содержимых базового и индексного регистров и смещения.

Обозначение - [< базов. регистр>][< индексн. регистр>] или <переменная >[<базов. регистр >][< индекс. регистр >] или [<базов. регистр >][< индекс. регистр >]< константное выражение,

где < индекс. регистр > - SI или DI, < базов. Регистр > - ВХ или ВР.

Пример:

mov [BX+ SI+ 2], CL; переслать содержимое регистра CL по адресу, вы­числяемому как сумма содержимого регистров ВХ, SI и константы 2.

Наши рекомендации