Конспект лекций (Алещенко)

advertisement
Министерство Образования и Науки РФ
Федеральное Агентство по Образованию
Государственное Образовательное Учреждение
высшего профессионального образования
Московский Авиационный Институт
Государственный Технический Университет
”МАИ”
кафедра 304.
Конспект лекций по курсу
ЯЗЫК АССЕМБЛЕРА IBM PC
Москва, 2006 год
Место языков ассемблера среди языков программирования
Языки программирования – это языки, воспринимаемые вводными
устройствами ЦВМ. Общая классификация языков программирования (ЯП)
приведена на схеме:
Языки программирования
Алгоритмические языки
(высокого уровня)
Универсальные
Проблемно-ориентированные
Машинно-зависимые
языки
ЯСК
Языки ассемблера
Машинные
Алгоритмический язык – это язык, позволяющий записать алгоритм в виде
последовательности операторов, т.е. довольно сложных конструкций, что
существенно облегчает и ускоряет процесс программирования и отладки
программ. Машинный язык содержит подробные конструкции (команды) в двоичнокодированном виде. Язык Ассемблера в основном отличается от машинного языка
использованием идентификаторов и мнемонических имён и дополнительными
возможностями, позволяющими упростить процесс программирования. Язык
Ассемблера требует хорошего знания структурных и архитектурных особенностей
процессора и ЭВМ в целом. Ассемблер – это программа, входящая в
операционную систему (ОС) и предназначенная для формирования машинных
команд путём перевода со входного языка, называемого языком Ассемблера.
Рассмотрим язык ассемблера на примере IBM-совместимых персональных
ЭВМ (ПЭВМ). К этому классу относятся

ПЭВМ, построенные на базе микропроцессоров (МП) фирмы Intel
(семейства 8086, 80x86 - i486, Pentium, Celeron, Atlon и т.п.).

МПК 1810 (ЕС 1840 и т.п.)

В настоящее время широко используются микропроцессоры таких
производителей как DEC (Digital Equipment Corporation), HP (Hewlett
Packard) и др. Эти микропроцессоры используют систему
микрокоманд и ЯА существенно отличающуюся от фирмы Intel, но при
программировании используются те же принципы.
Регистровая структура МП Intel 8086:
ПЭВМ семейства 80x86 можно представить как совокупность следующих
программно-логических элементов МП:
а) в МП:

Рабочие регистры;

Счётчик команд;

Регистры флагов;

Стек;
2
б) связанные с МП:

Память;

Система команд;

Система ввода\вывода;

Система прерывания.
Регистровая структура МП 80x86 приведена на схеме, она включает в себя
4 группы 16-разрядных регистров, которые обслуживают функционирование
операционного устройства (ОУ) и шинного интерфейса (ШИ).
Операционное устройство (ОУ)
AH
AL
Регистры
BH
BL
данных
CH
CL
DH
DL
Шинный интерфейс (ШИ)
Регистры сегментов
CS
SP
DS
Регистры-
BP
SS
указатели
SI
ES
DI
Управление
шиной
IP
очередь
команд
АЛУ
УУ
PSW
Рассмотрим подробнее:
1. Регистры общего назначения (регистры данных)
Эти регистры используются для хранения операндов, промежуточных
результатов и других видов данных и адресов. Каждый из указанных регистров
имеет еще и дополнительное специальное назначение для определенных команд
языка ассемблера.
3
AX
Аккумулятор
AH, AL
BX
Базовый регистр
BH, BL
CX
Счетчик
CH, CL
DX
Регистр данных
DH, DL
Допускается обращение к частям этих регистров, т.е. старшему байту
(вторая буква Н) и младшему байту (вторая буква L).
2. Регистровые указатели
Группа содержит непосредственно указатели
SP – указатель стека,
BP – указатель базы
и индексные регистры
SI – индекс источника,
DI – индекс приемника.
Регистры-указатели используются для работы со специальной структурой
памяти – стеком; индексные регистры используются при выборке операндов из
памяти.
3. Регистры сегментов (сегментные регистры)
Сегментация памяти позволяет укоротить адресные коды, кроме того,
каждый сегмент имеет свое предназначение, что повышает надежность программ.
CS (Code Segment) – регистр сегмента команд, определяет начало
сегмента, содержащего адрес текущей выполняемой команды;
DS (Data Segment) – регистр сегмента данных, определяет начало сегмента,
содержащего константы и данные;
SS (Stack Segment) – регистр сегмента стека, указывает на начало сегмента
стека;
ЕS (Extension Data Segment) – регистр дополнительного сегмента данных,
определяет начало сегмента, который обычно используется для запоминания
промежуточных данных или как расширение сегмента данных. В более поздних
моделях МП есть дополнительные сегменты:
FS, GS – дополнительные сегменты данных
LDTR – регистр локальной таблицы дескрипторов.
4. Указатель команд и регистр флагов
IP – указатель команд, выполняет роль счетчика команд; его содержимое –
это смещение относительно начального адреса сегмента команд (CS).
Во время выполнения программы содержимое регистра IP изменяется и
всегда хранит адрес следующей выбираемой для выполнения команды.
Flags (PSW) – регистр флагов, содержит информацию о текущем состоянии
МП. Рассмотрим структуру регистра флагов подробнее :
Flags
15
OF
DF
IF
TF
SF
ZF
AF
PF
C
F
11
10
9
8
7
6
4
2
0
4
Флаги разделяют на:
-
условные (флаги условий), отражающие результаты выполнения
предыдущей команды в АЛУ и используемые в командах условных
переходов;
-
управляющие (флаги управления), от которых зависит выполнение
специальных функций МП.
1. Условные флаги в алфавитном порядке.
AF (Auxiliary Carry flag) – флаг вспомогательного переноса,
предназначенный для обработки чисел в BCD-формате, используется при
выполнении арифметических операций над числами длиной 1 байт для индикации
переноса из младшей тетрады в старшую (или займа из старшей тетрады). Здесь
BCD (Binary Coded Decimal) – двоично-десятичное представление чисел (каждая
десятичная цифра кодируется двоичной тетрадой)
CF (Carry flag) – флаг переноса, предназначен для индикации переноса из
старшего байта, используется в операндах, разрядность которых больше 16 бит.
OF (Overflow flag) – флаг переполнения, предназначен для индикации
переполнения результатов при выполнении арифметических операций. При
сложении он устанавливается в 1, если есть перенос в старший бит, но нет
переноса из старшего бита.
PF (Parity flag) – флаг четности, используется как контрольный бит,
устанавливается в 1, если младший байт содержит четное число единиц.
SF (Sign flag) – флаг знака, равен 1 для отрицательного результата.
ZF (Zero flag) – признак нулевого результата.
Управляющие флаги устанавливаются программным путем и используются
для изменения состояния МП.
DF (Direction flag) – флаг направления, применяется в командах обработки
строк. При DF=1 обработка осуществляется от наибольшего адреса к меньшему, а
при DF=0 – от начала к концу.
Установка флага осуществляется следующими командами ассемблера:
Команда
Устанавливает значение DF
STD
1
CLD
0
IF (Interrupt-Enable flag) – разрешение прерывания, используется для
разрешения или запрета обработки внешнего маскируемого прерывания.
Устанавливается командами ассемблера
Команда
Значение IF
Результат установки
STI
1
Обработка прерывания разрешена
CLI
0
Обработка прерывания запрещена
TF (Trap flag) – трассировка, используется для осуществления покомандного
(пошагового) выполнения программы. При TF=1 МП автоматически вырабатывает
внутренние прерывания после каждой команды, что удобно для отладочного
режима выполнения программы. Изменить состояние флага TF довольно сложно.
5
Две части МП:
ОУ – операционное устройство, выполняет команды; содержит АЛУ, УУ и 10
регистров. Эти устройства обеспечивают выполнение команд, арифметических
вычислений и логических операций.
ШИ – шинный интерфейс, подготавливает команду и данные для
выполнения; содержит 3 элемента:
1) Блок управления шиной
2) Очередь команд
3) Сегментные регистры
Структура команд
Операционная часть
Адресная часть
В командах ЯА:
Мнемоника
Адресная часть
Машинные команды МП занимают от 1 до 6 байтов, причём операционная часть
занимает 1 или 2 первых байтов команды, остальное адресная часть.
Операнды могут быть указаны:

В самой команде(непосредственная адресация)

В одном из регистров, тогда в команде указывается этот регистр
(регистровая адресация)

В оперативной памяти (ОП) по адресу, который тем или иным образом
описан в команде (прямая, базовая или индексная адресация)

Некоторые команды требуют, чтобы один из операндов находился в
определённом регистре (например в AX), тогда он не указывается в
команде( подразумеваемая адресация)
Результат выполнения команды обычно помещается на место первого
операнда. Форматы команд разнообразны (в основном двухадресные).
В общем виде запишем : op1 := op1 * op2, где * - какая-то команда, заданная
МНК(мнемоникой); op1 – регистр или ячейка памяти, 1 байт или одно слово (2
байта); op2 – непосредственный операнд - регистр или ячейка памяти, 1 байт или
одно слово (2 байта).
Система команд МП Intel 80x86
Арифметические команды
1. Команды сложения и вычитания
Операции сложения и вычитания одинаково для знаковых и беззнаковых
целых. Используются две формы операндов: байт или слово, причем операнды
должны быть одинаковой длины. Операнды могут храниться в регистре или в ОП,
но второй операнд может быть непосредственным.
Перечислим команды, относящиеся к группе команд сложения и вычитания:
Группа а) ADD op1, op2
SUB op1, op2
; op1 := op1+op2
; op1 := op1 – op2
6
Сложение (вычитание) операндов в дополнительном двоичном коде,
результат помещается на место первого операнда, второй операнд не изменяется.
Команды корректируют регистр
результатом операции, а именно:
флагов
FLAGS
в
соответствии
с
ZF – нулевой рез-т,
SF – знак результата,
PF – флаг четности,
CF, AF – флаги переносов,
OF – флаг переполнения.
Примеры:
ADD AH, 12 ;
SUB z, BX ;
Группа б)
AH := AH + 12 (1Б)
z := z – BX (2Б)
ADC op1, op2
; op1 := op1+op2+CF
SBC op1, op2
; op1 := op1 – op2 – CF
Сложение (вычитание) операндов с переносом, образованным предыдущей
командой.Модифицирует флаги аналогично группе а.
Например, если требуется сложить двойные слова, расположенные в парах
регистров
(AX, BX) := (AX, BX) + (CX, DX),
причем AX, CX – старшие байты слагаемых,
BX, DX – младшие байты.
Сложение выполняется двумя командами:
ADD BX, DX
ADC AX, CX
Группа в) Специальный случай сложения – изменение операнда на единицу.
INC op ;
DEC op ;
op := op +1
op := op –1
(инкремент)
(декремент)
Операнд может быть регистр, или ячейка памяти, байт или слово.
Группа г) Десятичная коррекция
- анализ и преобразование
сложения(вычитания) для BCD кодов. BCD-операнды обрабатываются обычными
командами сложения и вычитания, а затем размещается команда десятичной
коррекции, которая обрабатывает только один байт данных, находящихся в AL,
поэтому команды десятичной коррекции операндов не имеют (подразумеваемая
адресация).
DAA; коррекция после сложения
DAS;
коррекция после вычитания.
Например:
ADD AL, y
DAA
SUB AL, DH
DAS
7
BCD-операнды,
представленные
обрабатываться побайтно.
более,
чем
одним
байтом
должны
Команды десятичной коррекции модифицирует флаги аналогично п.(а), за
исключением флагов AF и OF.
2. Дополнительные команды
Группа а) Команда сравнения
CHP op 1, op 2; op 1 - op2
Результат нигде не запоминается, команда корректирует арифметические
флаги ZF, SF,PF,CF,AF,OF.
Группа б) Команда изменения знака
NEG op ; op := -op.
Операнд может быть байт или слово в регистре или в ячейке памяти.
Пример,
MOV AH, 1 ;
AH :=
NEG AH
AH := -1
;
1
Если операнд равен нулю, то его значение не изменяется.
Команда корректирует флаги аналогично группе а; причем
CF=1, кроме случая, когда операнд равен нулю;
OF=0, кроме случая, когда op=-128 (для 1Б) = 80h (это значит, что число
заняло всю разрядность), тогда OF=1, а операнд остается без изменения.
3. Команды умножения и деления
Группа а) Умножение
;
умножение целых чисел без знака
IMUL op ;
умножение целых чисел со знаком
MUL op
Операнд может быть слово или байт в регистре или в ячейке памяти, но не
непосредственный операнд.
Команды действуют одинаково:
- для байтов AX := AL*op
- для слов
(DX,AX) := AX*op
Т.к. результат получается удвоенной разрядности относительно операндов,
то при умножении слов он располагается в стандартной паре регистров (DX,AX),
причем DX хранит старшие разряды. Команды модифицируют флаги:
СF=OF=0 , если старшая половина результата AH нулевая или совпадает по
знакам.
СF=OF=1 , если старшие разряды не нулевые.
Группа б) Деление
DIV op; деление целых чисел без знака
IDIV op; деление целых чисел со знаковом
8
где op – аналогично умножению.
Команды выполняют деление нацело и формируют два результата: целое
частное и остаток.
Деление слова на байт выполняется по схеме
АН:=АХ mod op
AL:=AX div op
(остаток)
(частное)
Деление двойного слова на слово
DX := (DX,AX) mod op
AX := (DX,AX) div op
При делении слова на байт делимое заранее должно быть размещено в
аккумуляторе и сдвинуто в сторону младшего байта в АХ или AL соответственно.
Деление является дополнительной к умножению командой.
Флаги не модифицируются, но может возникнуть ошибка «деление на ноль
или переполнение», которая возникает, если делитель нулевой или частное не
помещается в соответствующее ему место.
При появлении этой ошибки микропроцессор прекращает выполнение
программы.
4. Команды преобразования длины
Эти команды часто требуются перед делением, флаги – не модифицируют.
CBW – преобразует байт со знаком в AL, в слово со знаком в АХ путем
распространения старшего бита AL по всем разрядам AH;
CWD – преобразует слово со знаком в АХ в двойное слово со знаком в
(DX,AX) аналогично CBW.
Так же существуют команды десятичной коррекции умножения и деления
AAM, AAD
Команды обработки битов
Данная группа команд отличается отсутствием межразрядных переносов.
Команды делятся на 2 группы.
1) Логические команды
Общие черты:



Выполняют побитовую обработку операндов параллельно, без переносов;
единица трактуется как «истина», ноль – «ложь»;
модифицируют флаги, но важен только флаг ZF «нулевой результат»;
операндами могут быть байты или слова в регистрах или ячейках памяти;
второй операнд может быть непосредственным операндом.
Перечислим основные команды
NOT op; отрицание (инверсия кода). Флаги не модифицирует.
AND op1, op2; op1:= op1^ op2
Например, 0Fh ^ 15h = 05h
9
^
00001111
00010101
00000101
OR op1, op2;
Например,
op1:= op1 v op2
0Fh v 15h = 1Fh
XOR op1, op2;
Например,
op1 := op1  op2
0Fh v 15h = 1Ah
TEST op1, op2; op1^ op2 – результат не запоминается;
Эта операция называется «логическое сравнение». Цель формирование
флага ZF = 1 - если результат нулевой, иначе ZF = 0.
Как правило, второй операнд трактуется как маска, хранящая единицы в тех
разрядах, которые нужны для дальнейшей обработки.
2) Команды сдвигов
Сдвиги на n разрядов влево можно трактовать, как умножение на 2n, потому
все команды сдвигов имеют 2 операнда:
оp1 – рассматривается, как набор битов, подлежащих сдвигу влево или
вправо;
op2 – константа сдвига, т.е. целое число без знака, определяющее величину
сдвига нового операнда; может принимать значение 1 или CL. Единица означает
сдвиг на 1 разряд, а CL – содержимое регистра CL, хранящего значение n. Сдвиг с
CL выполняется как повтор однократных сдвигов, содержимое CL не меняется,
при CL=0, сдвиг блокируется. Результат записывается на место первого операнда.
Команды сдвига модифицируют флаги, кроме AF, а “уходящий” бит фиксируется в
CF.
Команды сдвига бывают логические, арифметические и циклические.
Рассмотрим их на командах однократного сдвига:
Логический сдвиг – для беззнаковых чисел может применяться для ускоренного
умножения (деления) на 2, выполняется по схеме
SHL op,1 ; сдвиг влево
CF
op
SHR op,1 ; сдвиг вправо
0
Арифметический сдвиг – применяется для ускоренного умножения (деления) на 2
чисел со знаком, выполняется по схеме
SAL op,1 ; сдвиг влево
SAR op,1 ; сдвиг вправо
CF
op
0
Циклический сдвиг – для беззнаковых целых, выполняется по схеме
ROL op,1 ; сдвиг влево
ROR op,1 ; сдвиг вправо
op
CF
Циклический сдвиг через флаг (уходящий бит возвращается в операнд и
одновременно фиксируется в CF), выполняется по схеме
RCL
RCR
ор,1 сдвиг влево
op,1 сдвиг вправо
CF
op
10
Циклические сдвиги позволяют образовать передачу числа последовательным
кодом и анализировать разряды числа. В МП 80286 и позже допускается
использование второго операнда без загрузки в CL (непосредственный операнд),
т.е. SHL AX,3 ;
Сегментация памяти
Память трактуется как одномерный массив байтов, каждый байт
ассоциируется с двоичным адресом (номером), который называется физическим
адресом.
Физический адрес – это 20-битовое беззнаковое целое от 0h до FFFFFh
(метка h обозначает 16-ричную систему счисления), которое позволяет описать
адресное пространство объемом 1 Мбайт.
Разрядность основного слова МП равна 2 Байта = 16 бит, поэтому для
вычисления физического адреса используется выделение из адресного
пространства сегментов по 64Кбайта (216), и в пределах сегмента можно
определять адрес с помощью 16-битового кода.
Сегменты в адресном пространстве должны размещаться, только начиная с
байтов, адреса которых кратны 16, т.е. 4 младших бита – нулевые. Такие адреса
называются параграфами.
Логический адрес представляет собой пару двухбайтовых беззнаковых
целых чисел, разделенных двоеточием:
-
начальный адрес сегмента (базовый),
-
смещение (эффективный адрес), указывает расстояние в байтах от
начала сегмента до адресуемой ячейки памяти.
Например, могут быть указаны регистры, хранящие соответствующие коды
CS : IP
При вычислении физического адреса МП расширяет содержимое
сегментного регистра четырьмя нулевыми битами, затем суммирует полученное
число со смещением. Получим следующую схему образования физического
адреса.
15
12
11
0
начальный адрес сегмента
DS
0000
15
0
+
смещение внутри сегмента
19
0
физический адрес байта
Ячейка памяти –
последовательных битов.
это
неделимый
в
данной
операции
набор
11
Команды передачи управления
Это наиболее важная часть системы команд, тесно связанная со структурой
ПЭВМ, и является промежуточным звеном между командами МП и командами
языка ассемблера, т.к. здесь существенна запись операндов. Команды передачи
управления вызывают нарушение линейности программы.
Рассмотрим общие аспекты передачи управления. Наиболее важная
особенность – это методы адресации, используемые для определения адреса
ячейки памяти, куда передаётся управление
Близкие и далекие переходы.
Переходы в ЯА кодируются от слова Jump. Например, безусловный переход:
JMP оp,
где ор – имя команды, которой передается управление (т.е. метка).
Команды перехода модифицируют указатель команд IP и, возможно, регистр
сегмента команд CS и бывают двух типов:

если команда изменяет только IP , т.е. передача управления внутри
сегмента, то переход называется ближний переход NEAR.

если изменяется пара регистров CS:IP, - это межсегментный переход
или далекий переход FAR.
Обычно адрес перехода ассоциируется с меткой команды. Метка – это имя
команды, которое располагается до мнемоники команды и отделяется
двоеточием. Любая программная метка (включая имя процедуры) имеет атрибут
NEAR или FAR.
Например,
АМ1: ADD AX,4
………………….
JMP AM1
Адресация переходов
а) Прямая адресация.
Команда содержит в себе базовый адрес сегмента и смещение. Это
допускается только в командах межсегментного перехода или вызова процедур.
Метка, которой передается управление, должна иметь атрибут FAR.
JMP CATS
где CATS – метка команды или имя процедуры, а JMP – аналог GOTO.
б) Косвенная адресация
Адрес перехода содержится в регистре или ячейке памяти. Это допускается
для межсегментных и внутрисегментных переходов.
JMP AX ; в АХ заранее помещен перехода
JMP NEAR COD[BX]
Во втором примере есть явное указание типа перехода (NEAR – оператор в
команде), COD[BX] – базовая адресация команды, которой передается
управление.
12
в) Относительная адресация
Место перехода указывается как некоторое расстояние от самой команды
перехода. Эффективный адрес перехода вычисляется суммированием индекса
смещения, находится в команде и текущего значения указателя команд IP.
Имеется 2 типа:
1) с
8 битовым индексным смещением, обеспечивает передачу
управления в диапазоне (-128:128Б) (SHORT)
2) с 16 битовым индексным смещением
(-32 768:32768Б) от текущей команды NEAR
Операндом является метка с атрибутом NEAR, по которой ассемблер
автоматически вычисляет значение. В команде может быть указан тип перехода:
mov w, offset L1; (в ячейку w записывается смещение L1 относительно
;
текущей команды offset – смещение)
…………………………….
JMP w или
;
JMP SHORT w ;то тогда проверяется корректность программы ;
(действительно ли short )
Команды условных переходов делятся на 2 группы:
а) операторы, анализирующие результаты предыдущей команды (флаги) –
условный переход в классическом понимании. Они имеют только 1-байтовое
смещение.
Если условный переход требует удаление более чем на 128Б (30-40
команд), то используется комбинация условного и безусловного перехода.
Например:
Требуется NEAR переход на метку ZERO по флагу ZF=1, тогда
………..
JNZ CONTINUE; if ZF<>1 then continue
JMP ZERO
CONTINUE
Т.е. используется условный переход по противоположному признаку, а по
ZF=1 получим 2-хбайтовый переход.
Мнемоника условного перехода сложна, таких переходов более 20.
Некоторые очевидны. Для образовании мнемоники используют следующие
сокращения:
E – equal (=)
N – not (не)
G – больше для знаковых целых
L – меньше для знаковых целых
A – above (выше) беззнаковых
B –below (ниже) для беззнаковых
В условных переходах используется после J от одной до трех букв (из
перечисленных выше).
Например, после сравнения чисел результат ор1<ор2, возможны 2 команды,
эквивалентные между собой для одного и того же перехода.
-
Для знаковых JL ADRES
JMGE ADRES
Для беззнаковых JB ADRES
JNA ADRES
13
б) команды управления итерацией(циклом) :
LOOP ор
Управление циклом по счетчику, где ор – метка первой команды цикла, цикл
управляется счетчиком в СХ.
Команда LOOP уменьшает содержимое СХ (dec СХ) и передает управление
в начало цикла, если содержимое СХ<>0, иначе управление передается команде
следующей за LOOP.
Обычно цикл оформляется следующим образом.
mov CX,N ; СХ = числу переходов цикла
L1: ……… начало цикла
……………….
LOOP L1;
Команда LOOP эквивалентна 3-м командам:
Dec CX
Cmp CX, 0
Jne L1
Цикл должен быть в рамках short.
Особенности команды LOOP:

счетчик цикла находится только в CX;

начальное значение загружается в CX>0 до входа в цикл;

команды прохода цикла выполняются хотя бы один раз;

LOOP осуществляет переход типа SHORT, поэтому проход цикла не
должен занимать 128Б (30-40 команд); если нужен более длинный проход
цикла, то используется сочетание условных и безусловных переходов;

CX может использоваться как операнд в цикле, но не должен изменяться
другими командами.
Есть и другие команды управления циклом. Например, команды перехода по
циклу с дополнительным условием, а именно с учетом флага ZF. Можно
использовать 2 эквивалентные записи:
LOOPE op
LOOPZ op
Здесь цикл повторяется CX раз, пока сохраняется ZF=1, что соответствует
сложному условию передачи управления
CX<>0 AND ZF=1. Эти команды
управления циклом обычно используются для решения задач поиска в
последовательностях, их основной недостаток состоит в том, что неочевидна
причина выхода их цикла, и требуется дополнительный анализ по окончании
цикла.
14
Представление данных в ПЭВМ
1. Целые числа
ЭВМ поддерживает работу с числами, длиной в :
- байт (1Б);
- слово (2Б);
- двойное слово (4Б);
Выделяются 2 типа целых чисел:
- беззнаковые (неотрицательные);
- числа со знаком.
Это позволяет использовать 2 диапазона чисел. Например, для 1 байта
 беззнаковое целое от 0 до 255 (28 – 1),
 целое со знаком по модулю от 0 до 127 (27 – 1).
а) Беззнаковые числа представляются в двоичной системе, занимая все
разряды ЯП.
Например, для десятичного числа 98 = 62h = 01100010B требуется 1Б,
можно использовать слово 0062h (2Б). Слово в памяти располагается в польской
инверсной записи, а в регистрах – в естественном порядке байтов.
Для чисел длиной в двойное слово – аналогично.
Например, число 12345678h
располагается следующим образом:
y
y+1
78
56
в оперативной памяти по адресу w
y+2
y+3
34
12
б) Целые числа со знаком представляются в дополнительном коде, т.е.
 Х, Х>0
Х доп.=  2к-|X|, X<0 ,

где k – разрядность ЯП.
Например, для числа -98 = 9Eh (1 Б)= FF9Eh (слово 2Б).
Для облегчения перевода в дополнительный код используется алгоритм:
- все цифры, кроме младшей заменяются инверсией, т.е. для 16-ричной
системы счисления (15 – {цифра});
- последняя (младшая) цифра заменяется дополнением, т.е. (16 – {цифра});
- правые нулевые разряды не изменяются, и младшим разрядом считается
самый правый ненулевой разряд.
Обратный перевод в прямой код из дополнительного выполняется по тому
же алгоритму.
В памяти числа длиной в слово или двойное слово хранятся в польской
инверсной записи, причем знаковый разряд попадает в последний байт.
15
2. Двоично-десятичные числа (BCD)
Существуют классы задач, для которых характерен ввод и выводом
больших массивов числовых данных с последующим применением небольшого
числа арифметических операций. Для этого случая используется двоичнодесятичное представление чисел (BCD – Binary Coded Decimal), которое
образуется следующим образом:
 каждая десятичная цифра представляется двоичной тетрадой, т.е.
используются цифры от 0 до 9, а цифры от A до F - не используются.
Имеется 2 разновидности BCD-формата:
а) неупакованный формат – в каждом байте в младшей тетраде
размещается код десятичной цифры, а значение старшей тетрады байта
игнорируется. Этот формат используется при вводе и выводе чисел, и
содержимое старшей тетрады определяется в соответствии с ASCI I.
Например, для положительного числа получим код
9806  хххх1001хххх1000хххх0000хххх0110 (4 Б);
б) упакованный формат – в каждом байте хранятся две цифры.
Например, для того же числа получим код
9806  1001100000000110 (2 Б).
Отрицательные числа в BCD представляются в дополнительном коде.
Алгоритм формирования дополнительного кода описан выше, но для BCD
формата имеет вид:
- все цифры, кроме младшей заменяются инверсией, т.е. (9 – {цифра});
- последняя (младшая) цифра заменяется дополнением, т.е. (10 – {цифра});
- правые нулевые разряды не изменяются, и младшим разрядом считается
самый правый ненулевой разряд.
Знак хранится и обрабатывается в отдельном байте, который заполнен
нулями, кроме старшего бита, который для отрицательного числа устанавливается
в 1.
Например, для числа 561 в упакованном формате получим
561  00000101 01100001 (2 Б)
для отрицательного числа
[-567]доп = 10000000 1001 0100
знак
9
4
0011 1001
3
9
В памяти числа хранятся в польской инверсной записи(LEM)
3. Символьные данные
Символьные данные хранятся в памяти ПЭВМ в двоично-кодированном
виде, причем каждый символ кодируется одним байтом, что позволяет
закодировать 256 различных символов.
Используется система кодирования ASCI I (American Standard Code for
Information Interchange) – американский стандартный код для информационного
обмена.
Основные особенности кодировки ASCI I:
-
код пробела меньше кода любого графически представляемого символа
и не является нулевым байтом;
16
коды цифр упорядочены по возрастанию и идут без пропусков
код(i) = код(‘0’)+i,
где i - цифра от 1-9,
код(‘0’) <> нулю (т.е. не нулевой байт);
- коды заглавных латинских букв упорядочены по алфавиту без пропусков;
- то же верно для малых латинских букв;
Для кодирования кириллицы используются несколько альтернативных
кодировок.
Например, в кодировке CP1251, широко используемой в системах Microsoft
Windows коды букв кириллицы (заглавных и строчных) также упорядочены по
алфавиту.
-
Строки символов, т.е. их последовательности размещаются в оперативной
памяти в естественном порядке, начиная с определенного адреса.
Например: строка ‘Ав_с»’ будет представлена в памяти по адресу x
последовательностью байтов
x
x+1
x+2
x+3
код(‘A’)
код(‘в’)
код(‘_’)
код(‘с’)
4. Вещественные данные
Вещественные данные обрабатываются сопроцессором Intel 8087
(вспомогательным процессором). Современные МП типа Pentium имеют
встроенный сопроцессор. Сопроцессор позволяет выполнить дополнительный
набор арифметических команд над числами разных типов:







целые со знаком (2Б);
короткие целые со знаком (4Б);
длинные целые со знаком (8Б);
упакованные BCD-формата (10Б);
короткие вещественные (4Б);
длинные вещественные (8Б)
временные вещественные (10Б).
В упакованном BCD-формате число занимает 10 байтов, причем первый
байт – знак числа, остальные 9Б могут хранить 18 цифр.
Например: числа в сопроцессоре представлены в виде
00 00 00 00 00 12 34 56 78 90 - положительное число,
80 99 99 99 99 87 65 43 21 00 - отрицательное число.
При вводе знак “+“ не требуется, достаточно записать все значащие цифры
числа.
Вещественные числа представляются в экспоненциальной форме
А = М * 2Р ,
где М – мантисса числа,
р – двоичный порядок числа.
Порядок определяет положение дробной точки в числе. Для упрощения
арифметики используется смещенный порядок (характеристика) числа р*. Нулевой
порядок смещается на 127, тогда порядок числа вычисляется по формуле
p = р*-127
Мантисса представляется в нормализованном виде в двоичной системе
счисления так, чтобы старшая цифра находилась в разряде целых единиц. Т.к. эта
цифра присутствует всегда к=1, то ее наличие подразумевается, а в памяти ее не
хранят.
17
Для вещественных чисел используют 3 формата:
31
- короткое вещественное (4Б)
30
22
23
0
характеристика
мантисса
- длинное вещественное (8Б)
62
51
52
0
характеристика
мантисса
- временное вещественное
78
63
64
0
характеристика
мантисса
знак
63
знак
79
знак
В сопроцессоре есть восемь 10-байтовых регистров. Набор этих регистров
чаще всего используется в режиме стека, но можно обращаться к конкретному
регистру по имени от ST(0) до ST(7).
Работа со стеком
Стек – это область оперативной памяти, запись и чтение данных в которой
основан на принципе LIFO (Last input first output, т.е. «последним пришел – первым
ушел»).
Последовательность данных, которая загружена в стек, может быть считана
только в обратном порядке. Стек используется в ПЭВМ для временного хранения
данных, необходимых для организации процедур, для передачи параметров в
процедуры, а так же для хранения некоторых промежуточных данных. Считывание
и загрузка в стек осуществляется двухбайтовыми словами.
Стек организуется программно в памяти, для стека можно отвести любую
область памяти, удовлетворяющую двум требованиям:
 максимальная емкость 64КБ (32К слов),
 конечный адрес должен быть кратным 16 (параграф).
Стек занимает один сегмент памяти, называемый сегментом стека, с
сегментным регистром SS, указывающим на начало, т.е. базу стека. Для работы
со стеком обычно используют косвенную адресацию через регистр SP – указатель
стека, указывающий на текущую ячейку стека, называемую вершиной стека.
В начале работы с SP указывают на последнюю ячейку сегмента стека. При
загрузке числа автоматически производится декремент SP := SP–2.
Считывание числа из стека сопровождается автоматическим инкрементом:
SP := SP+2, причем считается, что ячейка стека свободна и готова для
последующего использования, но ее содержимое после считывания не
изменяется.
18
Для дополнительного обращения к элементам стека (не через вершину)
можно использовать регистр ВР, называемый дополнительным указателем
стека. Доступ к элементам стека через BP осуществляется на основе
определённого расстояния о нужного слова до вершины стека и базовой
адресацией:
mov BP,SP ; настройка на вершину стека
mov AX,[BP+4] ; эквивалентно mov AX,SS:[BP+4]
BP по умолчанию относится к сегменту стека, а не к сегменту данных!!!Если в
программе нет явного использования стека, то необходимо его зарезервировать в
объеме 128Б для автоматического использования.
Стековые команды
а)
PUSH op; запись слова в стек, флаги не модифицируются
ор – может быть в регистре (в том числе и в сегментном) или в ячейке
памяти, но не непосредственный операнд.
Алгоритм выполнения:
декремент значения SP:=SP–2;
пересылка содержимого ор на сводную ячейку стека с адресом [SS:SP] (в
польской инверсной записи).
Пример:
-
PUSH AX
Примечания:
- SP используется по умолчанию
- Записать можно только слово
- Если организуется стековый сегмент в максимальном объеме (64КБ), то
при полном заполнении, происходит разрушение ранее записанной информации
SS
SP
- Если стек имеет меньший размер, то при полном его заполнении каждое
новое обращение разрушает область памяти вне стекового сегмента
SS
б) РОР ор ;
128Б
чтение слова из стека
ор – аналогично PUSH.
Алгоритм выполнения:
слово из ячейки стека
восстанавливается),
- инкремент SP := SP +2
Пример:
POP CX
-
пересылается
в
ор
(порядок
байтов
19
Примечание: Если пытаться считывать из пустого стека, то ошибка не
фиксируется, а считывается слово, следующее за сегментом стека.
в) PUSHF ; копирование слова из регистра FLAGS в стек
;
POPF
копирование слова из стека в регистр FLAGS
ор отсутствует, флаги не изменяются.
Эти команды позволяют модифицировать флаг TF. Т.к. другого пути
воздействия на TF нет, то нужно выполнить засылку флага в стек, затем изменить
8-й бит и записать новое значение из стека в регистр FLAGS.
Доступ к элементам стека с помощью регистра ВР
Доступ к любому слову, хранящемуся в стеке, осуществляется на основе
определения расстояния от нужного слова до вершины стека и базовой
адресации.
Например:
MOV BP,SP ; BP := SP
MOV AX,[BP+4] ; эквивалентно MOV AХ, SS:[BP+4]
ВР по умолчанию относится к сегменту стека, а не к сегменту данных!!!
Конструкции языка Ассемблера
Любой язык программирования имеет стандартную структуру, которая
позволяет осуществлять структурированное изучение языка.
Все конструкции языка делятся на 4 уровня:




алфавит;
элементарные конструкции (лексемы);
предложения;
программные единицы.
1. Алфавит
Алфавит языка программирования – это набор символов, который
используется в конструкциях языка, а не только в комментариях. Алфавит ЯА
будем изучать постепенно, рассматривая лексемы.
2. Лексемы
Лексемы – это элементарные конструкции языка, т.е. слова. В ЯА лексемы
представлены пятью классами:
Элементарные конструкции
Идентификаторы
Метки
Целые числа
Ключевые слова
Символьные данные
Имена
ВЫРАЖЕНИЯ
20
1. Идентификаторы – это последовательность латинских букв, цифр и
символов . ? @ _ $
Особенности применения имен в ЯА:
 длина идентификатора не ограничена, но значащими являются только
первые 31 символ;
 идентификатор не может начинаться с цифры;
 точка может быть только первым символом идентификатора; например,
возможен идентификатор
.ABR
 в идентификаторе одноименные заглавные и строчные буквы считаются
эквивалентными;
 идентификаторы не могут совпадать с зарезервированными (ключевыми)
словами.
Идентификаторы делятся на два вида:
а) Имя – ссылка на адрес первого байта, содержащего данные (константы
или переменные). Имена описываются директивой декларации.
Пример:
FATAL DB 13
Это имя имеет атрибут (тип) BYTE, WORD и т.д.
б) Метка – идентификатор инструкций или директивы, которая используется
для передачи управления.
Метки сегментов и процедур:
LAD SEGMENT
………………….
ENDS
FUN PROC
……………
ENDP.
Метки команд (инструкции) располагаются в начале строки и отличаются от МНК
двоеточием. Метка имеет атрибут NEAR или FAR.
В языке ассемблера
допускается только одна метка на строке, но можно
поместить метку на отдельной строке, что позволяет пометить инструкцию,
расположенную на следующей строке. Запрещены метки, состоящие из одного ?
или $.
Одну и ту же инструкцию можно выполнять дважды:
NACHALO:
LAB:ADD AX,DX
…………………..
JMM NACHALO
………………….
JMP LAB.
21
2. Ключевые (зарезервированные) слова – это сочетания символов,
которые имеют определенный смысл и соответственно воспринимаются
Ассемблером.
Например,
.286 – директива, позволяющая использовать в программе команды МП
i80286;
AND – мнемоника команды;
AX – имя регистра;
.ERR – директива генерации кода ошибки.
3. Целые числа могут быть записаны в десятичной, восьмеричной или 16ричной системах счисления, на это указывает буква в конце числа, называемая
спецификатором
Основание
ПСС
Спецификатор
Примеры
10
D или ничего
25, -387, +4d
2
B
101b, -1001B
8
O или Q
16
H
74q, -22Q
1A3h, -0B4H
Примечания:
 для 16-чной ПСС, если число начинается с цифры от A до F, то перед
ней записывается ноль,
 в числах можно использовать заглавные или строчные латинские буквы.
4. Символьные данные
заключаются в одинарные либо двойные
кавычки, но левый и правый ограничители должны быть одинаковыми.
Примечания:
 в качестве символов можно использовать любые изображаемые
символы и буквы;
 заглавные и строчные буквы различаются;
 если внутри строки символов нужно использовать кавычки, то есть 2
возможности:
или удвоить символ, например, ‘Don’’t’;
или использовать другой вариант ограничителя строки ,
например, «Don’t» или ‘кафе «МИР»’
5.
Выражения в языке ассемблера состоят из чисел и\или символов,
обозначающих числа. Выражение определяет операнд или его адрес.
Например, в декларациях Alpha EQU 10/4 ; константа Alpha равна 2.
Возможные операции в выражениях: + - * / mod () not k (подразумевается
инверсия k)
High n – старший байт числа n
22
Low n – младший байт числа n и т.д.
Выражением считается список констант в декларациях, например:
Area DB 2, -8, 7.
В инструкциях выражения используются только для вычисления адресов
операндов, при этом возможны виды адресации:
- Косвенная
- Индексная
- Базовая
- Базово – индексная
В программе можно записать эти адресации разными записями:
Название адреса
Обозначение операнда
Формирование адреса
в инструкции
Косвенная
[Рг B]
[Рг B]
[Рг U]
[Рг U]
disp [Рг U]
Индексная
[Рг B]+ disp
disp + [Рг U]
disp [Рг B]
Базовая
[Рг B] + disp
disp + [Рг B]
disp [Рг B] [Рг U]
Базово-индексная
disp [Рг B] + [Рг U]
disp + [Рг B] + [Рг U]
disp [Рг B + Рг U]
Где disp – смещение в байтах, которое может быть константой или выражением.
[Рг B] – содержимое базового регистра (BP или BX).
[Рг U] – содержимое индексного регистра (C или D)
Между индексными или базовыми регистрами (способами адресации) разницы
нет, но они выделены, т.к. в базово-индексной адресации можно использовать
только пары из разных групп, например:
mov AX, 2[DI] ; AX := ОП[[DI] + 0002h]
mov [BX], AL ; ОП[BX] := [AL].
Предложения языка Ассемблера
Предложения ЯА
Комментарии
Инструкции
Директивы
Программа на ЯА – это последовательность предложений, каждое из
которых занимает отдельную строку. Максимальная длина строки – 131 символ.
Переносить предложения на следующую строку или записывать 2 предложения на
одной строке запрещено.
23
Правила расстановки пробелов:
- пробел обязателен, чтобы отделять стоящие рядом имена или числа;
- внутри имен или чисел пробелы не допускаются;
- в остальных случаях пробелы используются произвольно;
- количество пробелов подряд безразлично.
Предложения ЯА делятся на три вида: комментарии, инструкции и директивы.
1. Комментарии не влияют на смысл программы, при трансляции
Ассемблер их игнорирует. Комментарием считается любая строка или конец
строки, начиная с точки с запятой, либо пустая строка.
Например,
; начало процесса
ADD BX, 20;
BX := BX + 20d
Можно организовать комментарий, состоящий из нескольких строк, он
должен начинаться с директивы
COMMENT {маркер} {текст}
…
{текст}{маркер} [{текст}]
где {маркер} – любой символ, кроме пробела, расположенный после
COMMENT,
прямоугольными скобками оформляются необязательные элементы.
Последней строкой комментария считается строка, содержащая тот же
маркер в любой позиции.
Это позволяет временно исключить фрагмент программы из обработки.
2.
Инструкции ЯА были в основном рассмотрены выше.
Общий вид инструкции ЯА:
[{метка}:] {мнемоника} [{операнды}] [;{комментарий}]
где {мнемоника} – является обязательной частью инструкции, она относится
к ключевым словам;
{операнды} – если они есть, то разделяются запятыми, обычно
записываются в виде выражений, содержащих указания на режим адресации.
Например,
SYM:
mov
mov
add
AH, S[SI+2]; AH := содержимое ОП по адресу [S+[SI]+2]
CX, [126h]; CX := содержимое ОП по адресу [126h]
Z, -300; Z := Z + (- 300d)
Выражения в квадратных скобках позволяют вычислить адрес операнда как
смещение относительно DS.
Непосредственный операнд не может быть представлен выражением.
3. Директивы не порождают машинные коды и используются на этапе
ассемблирования.
Директивы в ЯА бывают трех видов:
 директивы определения данных и резервирования памяти;
 директивы определения имен;
24
 директивы управления ассемблированием (т.е. трансляцией программы).
Общий вид директивы ЯА
[{имя}] {название директивы} [{операнды}]
а) Директивы определения данных и резервирования памяти
используются для определения и инициализации основных единиц памяти:
DB – (declare byte) декларация последовательности байтов;
DW – (declare word) декларация последовательности слов;
DD – (declare double word) декларация последовательности двойных слов.
Рассмотрим эти директивы на примере декларации байтов
[{имя}] DB {начальные значения}
где
{имя}
переменной
заменяет
численное
значение
адреса
распределяемых ячеек памяти, если оно есть, то относится к первому байту
данной области ОП (ООП).
DB – позволяет определить один или несколько последовательно
расположенных в ОП байтов, содержащих значения, перечисленные в поле
начальных значений.
Например,
Line DB
M
DB
DB
‘SYMBOL
буквы‘; описана последовательность 12 байтов
2
-4
Две последние декларации описывают общую ООП из 2 байтов.
Начальные значения разделяются запятыми, если отдельному байту на
присваивается начальное значение, то в списке начальных значений
записывается «?».
Например,
A DB 0f2h,-2,?,’*’ ; описываются 4 байта, содержащие следующую
информацию:
F2h
FEh
А
А+1
Что
было
А+2
2Ah
Код ’*’
б) Директивы определения имен.
Директива EQU (equal) позволяет присвоить символическое имя часто
используемой конструкции.
Общий вид : {имя} EQU {выражение}
где {имя}- может быть определено только один раз в программе, оно
сохраняет свое значение во всей программе, если не будет отменено директивой
PURGE;
{выражение} – может определять константы, мнемоники, регистры, адреса.
Ассемблер автоматически заменяет имя выражением(его значением).
Например,
K EQU 1024; K=1024
Stap EQU xor ax, ax ; Stap замещается текстом команды
25
Prop EQU ‘type enter’ ; Prop замещается текстом сообщения
Существует другой вид той же директивы :
{имя} = {константное выражение}
Константа, описанная таким образом, может менять свое значение в разных
частях текста программы.
Например,
X = 10
A DW X ; эквивалентно A DW 10
…
X = X+4
B DB X ; A DW 14d
Директива PURGE используется для удаления имени из таблицы имен,
которую формирует ассемблер, и для его переопределения.
Общий вид: PURGE {имя}
Например,
PURGE Stap ; После этой директивы имя Stap можно переопределить.
Директива LABEL создает новое имя для любых ячеек памяти, независимо
от содержимого и предполагаемого использования, т.е. переопределяет атрибут
имени, расположенного непосредственно после этой декларации.
Общий вид
{имя} LABEL {тип} , где




{тип}  




 BYTE 
 WORD 
 DWORD
 NEAR 
 FAR 
три первых атрибута используются для имен ячеек памяти с данными, а два
последних - для меток команд.
Например,
Barb LABEL BYTE
Barw DW 253Bh
…
mov AL, Barb; AL := ОП[Barb] (размер - 1 байт)
mov BX, Bar W; BX := ОП[Barb W] - слово
Таким образом можно обращаться как к слову целиком, так и к отдельному
байту.
в) Директивы
директивы
управления
ассемблированием
Перечислим основные директивы
оформления программы на ЯА:
этой
группы,
или
структурные
необходимые
для
SEGMENT – определение сегмента;
ENDS – конец сегмента;
END – конец исходного файла;
26
ASSUME – определение сегментных регистров;
PROC – определение процедуры;
ENDP – конец текста процедуры.
Эти директивы на примере необходимого оформления структуры
программы. Кроме того есть директивы набора команд (инструкций) для
конкретных МП :
.8086 – используются по умолчанию
.8087
.286 – 286 процессора набор команд
.286p ; защищенный режим
.287 и т.д.
Эти директивы могут быть помещены в начале исходного файла программы и
гарантируют ассемблирование всех команд в текущем файле. Более поздние
версии МП включают в себя команды предыдущих версий.
Структура программы на языке Ассемблера
Исходный файл на ЯА состоит из сегментов. В простейшем случае это –
один сегмент, который содержит обязательные элементы.
{мет. сегм.} SEGMENT ’code’
ASSUME CS:{ мет. сегм.}, DS:{ мет. сегм.}
{мет. начала} MOV AX, { мет. сегм.};
MOV DS,AX;
………………
MOV AX,{код функции};
INT 21h
……………
… DW …
… DB …
{ мет. сегм.} ENDS
END { мет. начала}
Рассмотрим директивы оформления программы:
1) директива SEGMENT для ассемблеров MASM или TASM имеет
одинаковую структуру
{мет. сегм.} SEGMENT [{счетн.}] [{комб.}] [‘{класс}’] ,где
{мет. сегм.}
- это имя сегмента, которое трактуется как метка, т.к.
используется для передачи управления. Атрибуты необязательны, но, если они
есть, то очередность должна сохраняться.
{счетн.} – определяет
начальный адрес сегмента.
метод
выравнивания
данного
сегмента,
т.е.
27
Возможны следующие варианты:
Значение
атрибута
Граница
Название
Нач. адрес
Byte
Байт
Word
Использование
MASM
TASM
Любой
+
+
Слово
Четный
+
+
Para
Параграф
Кратный 16
+
+
Page
Страница
Кратный
256
+
+
Dword
Двойное
слово
Кратный 4
_
+
Примечания
Не
рекомендуется
По умолчанию
{комб.} – показывает, как данный сегмент должен объединяться с другим,
имеющим ту же метку, но из другого исходного файла.
Ограничение: размер области ОП, которая получается в результате
объединения сегментов, не должна превышать 64 Кбайта. Если нет атрибута
{комб.}, то сегмент не объединяется с другими.
Возможны варианты атрибута: PRIVATE, PUBLIC, COMMON, STACK и др.
‘{класс}’ – указывается в апострофах, помогает компоновщику определить
нужный порядок расположения сегментов при сборке из разных модулей. При этом
все сегменты с одинаковым классом объединяются в один последовательно, а с
различными классами – располагаются, как правило, в алфавитном порядке.
Часто используются классы:
‘Code’ – сегмент команд;
‘Stack’ – сегмент команд;
‘Data’ – сегмент данных.
Класс сегмента необходимо указывать для правильной обработки файла.
Например, MASM требует наличия класса ‘Code’, т.к. без этого не может
работать отладчик Code View (CV), а компоновщик TLINK, входящий в TASM, не
инициализирует сегмент стека, если не объявлен класс ‘Stack’.
2) директива ASSUME нужна для выполнения команд программы, которые
неявно ссылаются на сегментные регистры МП (т.е. в примере – DS и CS). Она
обеспечивает передачу адресов сегментов с соответствующими именами в
сегментные регистры.
Общий вид
ASSUME CS:{ мет.}[, {сег. рег.}:{ мет.}]
В приведенном примере эта директива означает, что DS и CS указывают на
один и тот же сегмент, причем в CS адрес начала сегмента загружается
автоматически, а в DS для этого требуются обычно две инструкции в самом
начале сегмента:
mov AX,{метка}
mov DS,AX
ASSUME может быть расположен
до начала первого сегмента.
многосегментных программах ASSUME может описывать следующие сегменты
Сег.рег.
Сегмент
Загрузка адреса
CS
Рг сегмента команд
автоматическая
В
28
Рг сегмента данных
DS
ES
Рг
доп.
данных
сегмента
Рг сегмента стека
SS
в программе
в программе
автоматическая
3) Директива ENDS указывает на конец текста сегмента. Общий вид
{ мет. сегм.} ENDS
4) Директива END указывает на конец текста исходного модуля (ИМ). Общий
вид
END { мет. начала}
где { мет. начала} – пусковой адрес, т.е. метка первой выполняемой строки
ИМ, которой передается управление после компоновки.
Эта директива нужна, т.к. декларации описания ООП (DB, DW …) могут
располагаться в начале или в конце сегмента команд, причем рекомендуется – в
начале. Декларации можно вставлять и в текст между командами, но это – не
корректно.
Обычно программы состоят из 3-х сегментов (возможно 4-х): команд, данных
и стека. Расположение сегментов в принципе свободное, но рекомендуется:
1) сегмент данных,
2) дополнительный сегмент данных,
3) сегмент команд,
4) сегмент стека, т.к. он может быть описан без расхода памяти.
Например,
Stack
SEGMENT stack
‘stack’
DW 128 dup(?)
Stack ENDS
Объем стека обычно указывается в словах и не должен превышать 64КБ. Здесь
имя сегмента совпадает с атрибутами, что не запрещено; далее stack –
комбинаторный атрибут, который позволяет компоновщику объединить стековые
сегменты из разный ИМ (исходных модулей) в один стековый сегмент. Кроме того,
при загрузке программы выполняется автоматическая инициализация регистров
SS и SP.
‘Stack’ - класс сегмента для TLINK.
Использование прерываний
Система прерываний – важнейшая часть персонального компьютера,
позволяющая быстро реагировать на события, обработка которых должна
выполняться немедленно.
Существует 3 вида прерываний:
- Аппаратные (от машинных таймеров, клавиатуры и т.д.)
- Внутренние (возбуждаются в самом МП: деление на 0, несуществующая
команда)
- Программные (вызываются командой int (от interrupt - прерывать) с числовым
аргументом, который рассматривается как номер вектора прерывания, который
обычно представляет собой два слова)
29
Схема организации прерываний
0
IP обр.прер.0
2
CS обр.прер.0
4
IP обр.прер.1
6
МП
вектор прерывания 0
CS обр.прер.1
…………………….
(2)
IP обр.прер.n
CS обр.прер.n
…………………
IP
IP
CS
FLAGS
Вектор прерв. процесса
CS
(1)
FLAGS
…………………..
SP в момент прерывания
Обработка прерываний n – обработчик прерываний, указывает адреса, в которых
хранятся программы диспетчеры, открывающие доступ к большим гркппам
подпрограмм обслуживающих конкретное прерывание.
Сигналы аппаратных прерываний, возникающие во внешних устройствах,
поступают в МП через два контроллера прерываний, при этом по линиям данных
передаётся номер вектора прерываний. Самое начало ОП отводится под векторы
прерываний (адреса от 00000h до 003FFh), именно поэтому начальные адреса
недоступны никому кроме системы (ПЗУ).
Векторы прерываний делят на группы:
- Внутренние прерывания (от 00h до 06h)
- Аппаратные прерывания (от 08h до 0Fh и от 70h до 77h)
Разные устройства имеют разные адреса:
- BIOS(10h, 13h, и д.р.)
- DOS(21h, 22h, и д.р.)
- Адреса системы таблиц BIOS(1Dh,1Eh, и д.р.)
30
Рассмотрим программные прерывания:
Общий вид: INT{номер прерывания}, где {номер прерывания} может принимать
значения от 0 до 255, и соответствовать ситуации обслуживания конкретным
прерыванием.
Прерывания вызываемые DOS называются прерываниями нижнего уровня;
прерывания верхнего уровня используются в прикладных программах.
Номер
Ситуация или выполняемое действие
10-чный
16-чный
32
20h
Нормальное завершение программы
33
21h
Обращение к функциям DOS
34
22h
Вызов подпрограммы обработки завершения
задачи
Особенно важно прерывание 21h, которое может выполнять множество функций
DOS по обслуживанию стандартных устройств и файловой системы.
№
Выполняемая операция
функции
0
Завершение программы (аналог 20h)
1
Ввод символа с клавиатуры с эхо на экране
2
Вывод символа на дисплей
5
Вывод символа на печать
8
Ввод символа с клавиатуры без эхо на экране
9
Вывод строки символов на экран
3Fh
Чтение из файла или ввод с устройства
40h
Запись в файл или вывод на устройство
4Ch
Завершение программы с возвратом управления DOS
4Dh
Выдача кода завершения программы
Номер функции заносится в AH до вызова прерывания. Например,
MOV AH, {номер функции}
INT 21h
Кроме того, в другие регистры вызывающая программа должна поместить
аргумент выполняемой операции, если они нужны, а по окончании обработки из
регистров могут быть получены результаты операции.
Ниже приведен пример программы из трех сегментов для вывода на экран
строки.
Text SEGMENT
Hello DB “Здравствуйте!$”
; программа
Prim SEGMENT
ASSUME CS:Prim, DS:text
Start MOV AX, Text
MOV DS,AX
MOV AH, 9; функция вывода строки
31
MOV DX, OFFSET Hello
INT 21h
MOV AH, 4Ch; выход из программы
INT 21h
Prim ENDS
Stak SEGMENT ‘stack’
DW 128 dup(?)
Stak ENDS
END Start
Здесь для вывода сообщения в DX записывается начальный адрес ООП с
именем Hello.
Оператор OFFSET позволяет определить эффективный
(относительный) адрес переменной или метки внутри сегмента данных. Общий
вид оператора
OFFSET {переменная или метка}
Этот оператор используется обычно в командах MOV . Заметим, что для
загрузки эффективный адреса в регистр существует специальная команда МП.
Общий вид
LEA op1, op2
Где op1 – регистр для слова (2Б);
Op2 – описывает адрес в ОП
Например,
LEA SI, [BX+2]; SI := [BX]+2
LEA BX,Q
; BX := адрес Q
MOV DX,Q
; DX := содержимое Q
Операторы в инструкциях ЯА.
Операторы позволяют уточнить (модифицировать) команды; считается, что
операторы можно разделить на 2 группы:
- операторы атрибута,
- операторы, возвращающие значение, т.е. определяющие его.
1) Операторы атрибута:
PTR – используется совместно с атрибутами типа Byte, Word, Dword для
локальной отмены типов (определенных декларациями DB, DW или DD) или с
атрибутами Near или Far для отмены значения дистанции по умолчанию.
Например,
Fd DW 322h
…
MOV AH, Byte PTR FD+1; пересылка 2-го Байта
SHORT – модификация атрибута Near в команде JMP
Например,
JMP Short L1
2) Операторы, возвращающие значение:
DUP – оператор повторения начального значения, например:
32
MASSIV DW 100 DUP(0); создание и обнуление массива размером 100.
LENGTH – возвращает число элементов, определенных оператором DUP.
Например,
Tabl DW 10 DUP(?)
…
MOV DX, LENGTH Tabl ; DX := 000Ah
Если DUP отсутствует, то возвращаемое значение – 0001.
OFFSET – возвращает относительный адрес переменной или метки.
Используется обычно в команде mov. Существует аналогичная инструкция LEA
op1, op2. Где op1 – регистр для слова (2Б), op2 – идентификатор или другое
описание адреса ООП.
LEA BX,Q ; BX := адрес Q
LEA SI,[BX+2] ; SI := [BX] + 2
mov DX,Q ; DX := содержимое ячейки Q
SEG – возвращает адрес сегмента, в котором располагается данная
переменная или метка; используется обычно в программах, состоящих из
нескольких отдельно ассемблированных сегментов.
Например,
MOV DX, seg FLDW ; DX := адрес сегмента данных
TYPE – возвращает число байтов, соответствующее определению имени в
декларациях:
Определение
Возвращаемое значение
DB
1
DW
2
DD
4
DQ
8
DT
10
STRUC
Число Байтов, определенных в STRUC
NEAR {метка}
FFFFh
FAR {метка}
FFFEh
Например, для Tabl, описанной выше, можно записать
MOV AX, Type Tabl; AX := 0002h
SIZE – возвращает произведение длины LENGTH и типа TYPE
(подсчитывает число байтов, потраченных на запись) и полезен при ссылках на
переменную с оператором DUP.
Для использованного выше примера можно записать
MOV BX, Size Tabl ; BX := 0014h
Блочная структура программы. Процедуры.
33
Часто в больших программах используются подпрограммы для реализации
вспомогательных алгоритмов. В ЯА подпрограммы оформляются в виде процедур.
Описание процедур
{имя проц.} PROC {параметр}
{тело проц.}
[RET]
{имя проц.} ENDP
где {имя проц.} – должно повторяться дважды и используется для
обращения к процедуре;
{параметр} может принимать одно из двух значений - <NEAR> (по
умолчанию) или <FAR>.
К близкой (внутренней) процедуре можно обращаться только из того
сегмента команд, где она описана. К дальней (внешней) процедуре можно
обращаться из любых сегментов команд программы, в том числе и из того, где она
описана.
Имена и метки, описанные в процедуре, не локализуются внутри нее,
поэтому должны быть уникальными в программе.
Хотя в АЯ можно описать одну процедуру внутри другой, никакой выгоды
это не дает и обычно не используется.
Вызов процедур
На ЯА все переходы между основной программой и процедурой нужно
организовывать самим. Если из процедуры возможен возврат в DOS, то ее можно
вызвать командой перехода на имя процедуры
JMP {имя проц.}
Если нужен возврат в вызывающую программу, то проще всего использовать
команду обращения
CALL {имя проц.}
Тогда в теле процедуры должна быть команда возврата
RET
Есть другая возможность: запомнить адрес возврата с использованием стека и
организовать возврат командами переходов.
При вызове процедуры следует учитывать параметры, передаваемые процедуре,
и ее расположение относительно точки вызова, т.е. тип перехода в команде CALL
определяется автоматически, например (для процедуры p).
P
CALL P
Если это – близкий вызов (NEAR), то производятся следующие действия:
Stack := AB, IP := offset P
где АВ – адрес возврата, т.е. эффективный адрес команды, следующей за
вызовом;
Дальний вызов (FAR) обеспечивает действия:
Stack := CS, Stack := AB, CS := seg P, IP := offset P
Если описание процедуры находится в сегменте ниже команды вызова, то
следует указать атрибут перехода оператором PTR. Например,
34
CALL FAR PTR P; дальний вызов P
Расположение процедур в сегменте
1. Внутренние процедуры находятся в одном сегменте с вызывающей
программой.
При этом возможны 3 варианта расположения:
а) Все процедуры размещены раньше основной (вызывающей) программы,
которая может быть также оформлена в виде процедуры.
Например:
Text SEGMENT ‘code’
ASSUME CS: text, DS: data, SS: stack
A1 PROC
…
RET
A1 ENDP
Main PROC
MOV AX, data
MOV DS, AX
…
CALL A1
…
MOV AX, C400h
INT 21h
Main ENDP
Text ENDS
Data SEGMENT
…
Data ENDS
Stack SEGMENT ‘stack’
…
Stack ENDS
END Main
б) все процедуры – ниже точки вызова.
в) процедуры – внутри основной процедуры, возможно даже, что процедура
внутри другой процедуры (хотя никакой выгоды это не даёт)
Например,
…
Main PROC
…
CALL A1
…
MOV AX, C400h
INT 21h
A1 PROC
…
RET
A1 ENDP
Main ENDP
Text ENDS
35
2) Внешние процедуры – располагаются в других сегментах или в других
файлах.
Например, текст основной программы находится в файле P.asm
Text SEGMENT public ‘code’
; объединение модулей последовательно
; в общий сегмент
ASSUME CS: text, DS: data, SS: stack
EXTRN stop: proc;
объявление внешнего имени
Main PROC
…
CALL Stop
…
Main ENDP
Text ENDS
Data SEGMENT
…
Data ENDS
Stack SEGMENT ‘stack’
…
Stack ENDS
END Main
Исходный текст процедуры находится в файле P1.asm
Text SEGMENT public ‘code’
ASSUME CS: text
PUBLIC stop; объявление имени доступным извне
Stop proc
…
RET
stop ENDP
text ENDS
END ; конец файла без точки входа
Объединение этих файлов происходит на шаге компоновки, т.е. требуется
раздельная трансляция. Например, для MASM
MASM/ZI
PR
MASM/ZI
P1
где ZI – опция, позволяющая поместить в объектный файл полную
информацию о номерах строк и символах исходного модуля (ИМ).
После образования PR.obj и
загрузочный файл
P1.obj их нужно скомпоновать в единый
LINK/C0 PR P1, COMPOZ
где С0 – опция, передающая в загрузочный файл символьную информацию,
позволяющую отладчику CV выводить на экран полный текст ИМ, включая метки и
комментарии.
Модуль COMPOZ.exe готов к исполнению.
Можно подключить процедуру
сегментами ИМ помещается директива
из
библиотеки.
Для
этого
перед
INCLUDE {имя файла библиотеки}
Например, для подключения файла IO.asm следует записать
36
INCLUDE IO.asm
S SEGMENT ‘stack’
…
S ENDS
D SEGMENT ‘data’
…
D ENDS
C SEGMENT ‘code’
ASSUME CS:C, SS:S, DS:D
Begin: …
…
C ENDS
END Begin
Передача параметров между процедурами (организуется по желанию
программиста)
1. Передача параметров через регистры МП
Передавать значения фактических параметров можно через регистры МП по
желанию программиста. Например,
; процедура вычисления AX := max {AX, BX}
max proc far
CMP AX, BX
JGE Max1
MOV AX, BX
Max1: RET
max endp
…
; в основной процедуре
…
MOV AX, A ; подготовка параметров
MOV BX, B ; к вызову процедуры
CALL max
MOV C, AX ; сохранение результата
…
2. Передача параметров по ссылке означает передачу адреса (имени)
ячейки
памяти,
соответствующей
фактическому
параметру
(передача
именованного значения из ассемблера в Pascal). Для этого можно использовать
имя ячейки памяти или загрузить адрес перед вызовом процедуры в регистр (BX,
BP, SI или DI, т.к. в процедуре можно использовать эти регистры для адресации ).
Например, командой
LEA BX, B
CALL……
3. Передача параметров через стек.
Передача параметров через регистры ограничена их небольшим
количеством. Если параметров много (больше 5-ти), их передают через стек
следующим образом:
- Основная программа записывает в стек фактические параметры (значения
или адреса);
- В процедуре используются параметры, записанные в стек.
37
Например:
; вызов p(a1,…, ak)
PUSH a1
…
PUSH ak
CALL p
…
В процедуре можно использовать дополнительный указатель стека BP, но в
начале процедуры следует сохранить значение BP, которое использовалось в
вызывающей программе, т.е.
; начало процедуры Р
P proc
PUSH BP ; сохранение BP
MOV BP, SP ; настройка BP на вершину стека
…
Затем можно использовать базовую адресацию. Например, для близкого
вызова
[BP + 2] – адрес возврата, занесенный в стек автоматически,
[BP + 4] – адрес последнего параметра ak.
До возврата из процедуры следует восстановить BP командой
POP BP
затем очистить стек от передаваемых параметров, чтобы он не
перегружался при многократном вызове процедур, т.е. установить в SP значение,
на 2*k больше, чем было после вызова процедуры.
Есть 2 возможности корректного возврата из процедуры.
а) корректировать SP в вызывающей программе
; конец процедуры
POP BP
RET
P ENDP
б) использовать команду возврата
для близкого вызова
; в вызывающей программе
CALL p
ADD SP, 2*k ; коррекция SP
…
с восстановлением стека, имеющую вид
RET {cnt}
где {cnt} – счетчик (константное выражение ), размером слово.
Команда выполняет следующие действия:
IP := Stack
SP := SP + {cnt}
Тогда конец процедуры имеет вид:
POP BP
RET 2*k
p ENDP
Для дальнего вызова процедуры команда возврата имеет вид
RET {cnt}
и выполняет следующие действия:
IP := Stack
CS := Stack
SP := SP + {cnt}
При таком возврате из процедуры
дополнительные действия не требуются.
в
вызывающей
программе
38
4. Проблема сохранения регистров при обращении к процедуре
Чтобы процедура не портила значения регистров, которые использовались в
вызывающей программе, требуется в тексте процедуры перед использованием
какого-либо регистра сохранить его «старое» значение в стеке, а в конце
процедуры все сохраненные значения восстановить.
Например, если в процедуре будет использоваться регистр CH, то его
следует сохранить в стеке, но стек запоминает только со слова, поэтому в
процедуре будет фрагмент:
PUSH CX
; сохранение «старого» CX
MOV CX, 0 ; использование
CX в процедуре
…
; перед выходом из процедуры
POP CX
; восстановление «старого» CX
Таким образом, получится обобщенная схема близкой (NEAR) процедуры с
параметрами, передаваемыми через регистры и через стек
{имя проц} proc
PUSH BP
mov BP, SP
PUSH
для обслуживания
стека
сохранение регистров,
используемых в процедуре
тело проц.
РОР ...
РОР ВР
восстановление регистров
восстановление BP
RET {cnt}
{имя проц} ENDP
Основные средства обработки программ на ЯА
Программные пакеты MASM и TASM
Процесс подготовки и отладки программы на ЯА включает в себя этапы
подготовки исходного модуля (ИМ), трансляции, компоновки и отладки.
39
1. Подготовка исходного модуля (текста программы) может выполняться
с помощью любого текстового редактора. Файл с исходным текстом должен иметь
расширение .ASM.
Следует использовать редакторы, формирующие выходной файл в
формате
ASCII
без
дополнительных
символов,
которые
вставляют
специализированные текстовые редакторы (например, MS Word). Рекомендуются
редакторы Norton Editor, WordPad.
При работе в интегрированных средах можно пользоваться редакторами,
строенными в эти среды. Например, программные пакеты фирмы Borland, такие
как C, C++, Pascal, содержат средства создания ассемблерных программ и
фрагментов.
2. Трансляция ИМ состоит в преобразовании строк исходного языка в
коды машинных команд и выполняется с помощью транслятора (ассемблера).
Можно пользоваться трансляторами
MASM фирмы Microsoft или
TASM фирмы Borland.
Ассемблеры различаются в основном в чести написания макросредств, но
входной язык для всех ассемблеров одинаков. После трансляции образуется
объектный модуль (ОМ), т.е. файл с расширением .OBJ.
Трансляторы вызываются командами MS DOS
MASM name
TASM name
где name – имя файла ИМ без расширения.
Ассемблер формирует ОМ с тем же именем, кроме того, формируются
файлы:
- листинга .LST (list)
- перекрестных ссылок .CRF (Cross reference).
В команде ассемблирования можно указать путь к файлу или при помощи
опций трансляции внести изменения.
Например,
MASM D:\SRC\bild
Здесь обрабатывается файл bild.asm из папки SRC.
Общий вид команды ассемблирования на примере MASM:
MASM {ИМ} [,{ОМ} [,{list}[,{cross}]]] [/{опции}]
Имена {ИМ} ,{ОМ} ,{list},{cross} могут указываться без расширения или с ним;
можно отменить формирование одного из файлов или их группы. Т.К. порядок
файлов фиксирован, то исключение из середины списка обозначается появление
двух запятых подряд, а отключение конца списка обозначается точкой с запятой.
Например,
TASM FIL1
эквивалентно
TASM FIL1;
Для MASM возможны три эквивалентные записи:
MASM FIL1.asm, FIL1.obj, FIL1.lst, FIL1.crf
40
MASM FIL1,,,
MASM FIL1, FIL1, FIL1, FIL1
Опции управляют работой ассемблера и форматом генерируемых файлов.
Опции предваряются знаком «/» или «-». Набор опций варьируется в зависимости
от пакета TASM или MASM, а также от версии.
Ниже приведен список общих опций:
/А – упорядочить сегменты в алфавитном порядке
/С – формировать файл перекрестных ссылок
/L – формировать файл листинга
/ML – считать заглавные и строчные латинские буквы в именах различными
/T – отменить сообщение об успешном ассемблировании
/Zi - воспроизводить на экране ошибочные строки
Опций может быть несколько, они разделяются пробелами и размещаются:
- в MASM – в любом месте списка,
- в TASM – в начале перед списком имен.
Например,
TASM /L /Zi P,P1
Здесь обрабатывается файл P.asm, формируются файлы P.lst и P1.obj
MASM /Zi St,,Stest
Обрабатывается файл St.asm, формируется файл Stest.lst
3. Компоновка ОМ выполняется с помощью компоновщика (редактора
связей), вызывается командами MS DOS
LINK name – совместимо с MASM
TLINK name – совместимо с TASM
Основное назначение – подключение к файлу с основной программой
файлов с подпрограммами и настройка связей, изменение формата ОМ и
преобразование его в загрузочный файл (.EXE).
Полный формат команды на примере LINK:
LINK {ОМ} [,{загр.}[,{карта}[,{библ.} ]]] [/{опции}]
где {ОМ} – имя файла или их последовательность, разделенная знаком
«плюс» или пробелами;
{загр.} – имя загрузочного файла;
{карта} – имя файла, содержащего т.н. карту сборки, описывающую все
общие символы, с расширением .MAP;
{библ.} - имя файла библиотеки или их последовательность, разделенная
знаком «плюс» или пробелами.
Имена файлов могут указываться без расширения.
Опции в LINK и TLINK не совпадают!
Примеры:
TLINK P1;
формируются файлы P1.exe, P1.map
LINK P1;
формируется файл P1.exe
Использование опций:
LINK/MAP P1;
формируются файлы P1.exe, P1.map
LINK/C0 P1+P2,P3,P3,LIB1+LIB2
41
Компоновка и подключение библиотек, опция /C0 была рассмотрена ранее в
разделе «расположение процедур».
В TASM можно подключить библиотеки в программе и нет необходимости
указывать файлы в команде TLINK. В этом случае используется директива
INCLUDE.
После компоновки загрузочный файл с расширением .EXE можно запускать.
4. Отладчики – это специальные программы, облегчающие отладку
программ на ЯА. Наибольшее распространение получили три отладчика:
Debug – отладчик, входящий в MS DOS,
CV (Code View) – фирмы Microsoft, входит в пакет MASM,
TD (Turbo Debugger) – фирмы Borland, входит в пакет TASM.
Вызов на примере Debug производится командой
Debug P[.exe]
Общее требование – наличие загрузочного файла.
Рассмотрим подробнее использование отладчиков.
а) Debug позволяет записать программу на ЯА или в машинных кодах,
запускать ее в разных режимах (с точками останова или без них, а также в
пошаговом режиме), просматривать области памяти, регистры и при
необходимости вносить изменения;
б) Code View – интерактивный отладчик, вся работа с ним осуществляется в
непрерывном диалоге с пользователем;
в) Turbo Debugger – также интерактивный отладчик.
CV и TD имеют общие свойства, а именно они:
- имеют систему многооконного изображения на экране, позволяющую при
выполнении программы видеть изменение содержимого регистров МП, флагов,
выбранных ячеек памяти;
- позволяют запускать программу в пошаговом режиме, по участкам или по
циклам;
- позволяют в ходе отладки вносить изменения в содержимое регистров МП
и областей памяти.
Основное общее неудобство отладчиков CV и TD состоит в том, что нельзя
вносить изменения в текст программы, хотя он и отражается на экране монитора.
Изменения в текст приходится вносить в редакторах, затем необходимы
ассемблирование и компоновка, после чего можно проверять исправленную
программу на отладчике или без него.
Модели памяти
Пакет TASM дает возможность упрощенного описания сегментной структуры
программ на ЯА. Для этого введено понятие «модели памяти», которое
объединяет
особенности
автоматического
распределения
памяти
при
ассемблировании.
Модель памяти определяет следующие параметры:
- количество сегментов, их расположение, перекрытие и т.п.;
- размерности и свойства переменных и предопределенных значений в
программе (например, тип процедур NEAR или FAR).
Обычно модель памяти используется по умолчанию и определяется
ассемблером в зависимости от числа сегментов, но можно задать модель памяти
42
с помощью директивы ЯА, располагаемой в начале файла с программой, что
позволяет использовать упрощенные формы описания сегментов. Общий вид
директивы
.MODEL {тип}
где {тип} – может принимать следующие значения:
а) tiny – ИМ состоит из одного сегмента, т.е. регистры CS, DS и SS имеют
одно и то же значение; наиболее компактная программа, занимающая 64КБ, все
переходы – типа NEAR;
б) small – сегмент кода отделен от сегментов данных и стека, последние
объединены в одну группу, т.е. DS и SS имеют одно и то же значение; наиболее
распространенная модель памяти, все переходы – типа NEAR;
в) compact – используется один сегмент кодов и несколько сегментов
данных, все переходы – типа NEAR, а обращение к данным – с указанием
сегментного регистра, но сегменты данных и стека объединены в одну группу;
г) medium – несколько сегментов кодов и общий сегмент данных со стеком,
доступ к процедурам – типа FAR, а обращение к данным указывает только
смещение;
д) large – наиболее общий случай; несколько сегментов кодов и данных, вся
адресация – с помощью сегментных регистров;
е) huge – аналогичен large, но предназначен для совмещения с
программами на языках высокого уровня, разрешается работа с данными,
занимающими >64КБ памяти.
Список значений параметра {тип} приведен не полностью, кроме того
существуют другие параметры директивы
.MODEL, но мы их здесь не
рассматриваем.
При использовании данной директивы ИМ может иметь различную
структуру.
Например,
. MODEL small
Stack 256
.Data
{данные}
.Code
ASSUME DS:@data, ES:@data
Main:
…
END Main
Создание файлов типа .EXE и .COM.
Для программы типа .EXE компоновщик автоматически генерирует определённый
формат и при сохранении его на диске предворяет под программы специальным
блоком размером ≥ 512 Б. Можно писать и выполнять программы типа .COM.
Приимущество этих программ – меньший размер по сравнению с программами
типа .EXE и более лёгкая адаптация к применению.
Существенные различия между программами типа .EXE и типа .COM включают в
себя:
1) Размер программы
Программы типа .COM используют единый сегмент для инструкций и данных,
ограниченный размером 64 КБ включая префикс сегмента программы. PSP –
43
это 256 Б(100h) блок, который загрузчик программ вставляет
непосредственно перед программами при загрузке их в память диска. В .EXE
есть ещё заголовок, который содержит информацию о перемещаемых
адресах.
2) Сегментация
Рассмотрим сегментную структуру файлов в памяти:
EXE
COM
ES
заголовок
DS
ES
PSP
CS
SS
Стек
CS
Сег. данных
DS
Сег. кода
PSP
Сегмент
кода
Стек
SS
Для программ типа .EXE необходимо явно определить сегменты данных и
стека. Для программ типа .COM описание стека следует опустить.
2) Инициализация
Когда загрузчик программ загружает для выполнения программу типа .COM он
автоматически инициализирует CS, DS и ES адресом PSP. Поскольку PSP
имеет размер 100h Б, то адресация программы начинается со смещения 100h,
для чего требуется в текст программы внести директиву ORG 100h сразу за
описанием сегмента. Эта директива приказывает ассемблеру установить
счётчик положения в значения 100h – это адрес начала кода программы.
Примеры программ, описанных в соответствии с требованиями формата .СОМ:
1) Title A05 COM
Codes Segment para ‘code’
ASSUME CS : codes, DS : codec, SS : codes, ES : codes
ORG 100h
BEGIN : JMP main
FLDD DW 215 ; определение данных
FLDE DW 125
FLDF DW ?
main proc NEAR
…………………..
mov AX, 4C00h
int 21h
main endp
codes ends
end BEGIN ; программа для MASM и для .СОМ формата файла.
2) Title A05 COM2
.model TINY
44
.code
ORG 100h
BEGIN : JMP main
FLDD DW 215 ; определение данных
FLDE DW 125
FLDF DW ?
main proc NEAR
…………………..
main endp
end BEGIN.
Макросы
Каждая инструкция ЯА генерирует одну команду в машинных кодах. В
языках высокого уровня одной инструкции (оператору) соответствует несколько
машинных команд. С этой точки зрения языки высокого уровня можно
рассматривать как набор макрокоманд. Ассемблер содержит механизмы,
позволяющие создавать и использовать в программах макросы, вызываемые при
помощи макрокоманд. Макрокоманды позволяют вставлять в текст программы
последовательности строк (которые могут быть данными или командами) и
привязывать их к контексту места вставки. В общем случае можно говорить, что
транслятор ассемблера состоит из двух частей – непосредственно транслятора,
формирующего ОМ, и макроассемблера.
Обработка программы на ЯА с использованием макросредств неявно
осуществляется в 2 фазы :
ИМ, содержащий
макросы
1-ая фаза:
макроассемблер
ИП во внутреннем
представлении
компилятора без
макросов
2-ая фаза:
ассемблер
TASM.EXE
На
первой
фазе
макроассемблер
генерирует
макрорасширения,
содержащие
символьные
аналоги
машинных
команд МП. Макрокоманда – это
строка,
содержащая
некоторое
символическое
имя
(имя
макрокоманды), предназначенная для
того, чтобы быть замещенной одной
или несколькими другими командами;
кроме того макрокоманда может
содержать аргументы.
ОМ
45
Определение макросов
Макроопределение – это описание (шаблон,
содержимого макрокоманды. Общий вид:
описание
макроса)
{имя макроса} MACRO [{список форм. аргументов}]
{тело макроса}
ENDM
где {имя макроса} – должно быть уникальным как в программе, так и в
используемых библиотеках.
Для включения макросов в программу сначала их нужно определить или
скопировать из библиотеки.
Возможны варианты размещения макроопределений:
- В начале ИМ до сегментов кодов и
используется только в данной программе;
данных, если макроопределение
- В отдельном файле (для нескольких программ); чтобы сделать
доступными эти макросы в конкретной программе, нужно в начале ИМ записать
директиву
INCLUDE {имя файла с макросом}
Например,
. MASM
.MODEL small
INCLUDE show.inc
Data segment
…………………….
- В макробиблиотеке (тоже файл типа .inc). Особенность – в исходный текст
программы включаются все макросы из библиотеки. Чтобы бороться с этим нужно
использовать директиву PURGE {список имен макросов}
Например,
INCLUDE iomac.inc
PURGE outstr, exit.
Простые определения макросов
Используются, например, для инициализации сегментных регистров в
программе:
Например,
Initz MACRO
Mov AX, @data
Mov DS,AX
ENDM
причем INITZ – имя макроса, а AX, @data и DS должны быть определены
где-то в вызывающей программе. Ассемблер обнаруживает в тексте программы
имя макроса – это макровызов, например
Initz
Ассемблер вставляет на место макровызова тело макроса, создавая
макрорасширение.
Например, для макроса
Finish MACRO
mov AX,4C00h
46
Int 21h
ENDM
программа до трансляции имеет вид
Title A21MAC
INITZ MACRO
mov AX, @data
mov DS,AX
ENDM
Finish MACRO
mov AX,4C00h
Int 21h
ENDM
.MODEL small
.Stack 64
.Data
Message DB ‘Test of macro?’,13,10,’$’
.code
begin PROC far
Initz ; вызов макроса для вывода строки
mov AH,09h ;
Lea DX, message ;
Int 21h
Finish
Begin ENDP
END begin.
Использование параметров в макросах
Чтобы сделать макрос модифицируемым, необходимо
формальные аргументы(ФА).
ввести
Например, для вывода на экран сообщений, составим следующий макрос:
Prompt MACRO Mess
MOV AH, 09h
LEA DX, Mess
INT 21h
ENDM
При обращении
Например,
к
макросу
используются
фактические
аргументы.
PROMPT Message2
и где-то в программе есть декларация
Message2 DB ‘Enter the date mm/dd/yy’,’$’
Тогда при формировании макрорасширения во все команды макроса
подставляется Message2 вместо Message.
Полный синтаксис формального аргумента имеет вид
{имя ФА} [: {тип}]
где {тип} может принимать значения:
- REC – требуется
умолчанию);
обязательное задание ФА при макровызове (по
47
- =<{любая строка}> – если аргумент при макровызове на задан, то в
соответствующие места макрорасширения будет вставлено значение по
умолчанию, указанное в < >.
Не всегда ассемблер может распознать в теле макроса ФА. Для
уверенности последовательность символов, образующих ФА, предваряется
символом «&». Этот прием часто используется для задания модифицируемых
имен и кодов операций.
Например, определим макрос генерации в программе некоторой таблицы,
причем параметры этой таблицы можно задавать с помощью аргументов.
…
def_table MACRO Type=<b>, len
table_&type d&type len dup(0)
ENDM
…
. data
def_table b,10
def_table w,5
После трансляции получим
Table_b
DB
10 dup(0)
Table_w
DW
5 dup(0)
Комментарии в макросах
Т.к. по умолчанию в листинг после трансляции включаются только команды,
генерирующие только объектный код ассемблера, не включающий в
макрорасширение комментарии из макросов. Что бы комментарии попали в
листинг существующей директивы управления листингом необходимо:
.LALL (List all) – вывести всё (помещается перед макровызовом), например:
.LALL
Promt Message1.
.XALL (по умолчанию) – подавляет комментарии в макрорасширениях. Если
какой-то комментарий не должен попасть в макрорасширение при директиве
.LALL, то перед ним ставят ;;
.SALL (Super all) – подавляет включение в листинг макрорасширений и
позволяет уменьшить размер листинга, но не влияет на размер содержимого ОМ.
Директива управления листингом действует в программе пока в тексте
программы не встретится директива LOCAL.
Некоторые программы включают в себя метки и переходы, но при
многократном макровызове в одной программе может получится дублирование
меток (ошибки), что бы создаваемые в макрорасширениях имена были уникальны,
после директивы MACRO помещается директива LOCAL и {список имён}. Таких
директив может быть несколько. В результате в каждом экземпляре
макрорасширения сгенерируются уникальные имена для всех идентификаторов
перечисленных в списке. Эти уникальные имена формируются автоматически и
имеют вид ??ХХХХ, где ХХХХ – 16-ричное представление числа, и тогда получаем
??0000 – 1 раз
??0001 – 2 раз
??0002 – 3 раз и т.д.
48
Защитные режимы МП
Любой современный МП в реальном режиме работы позволяет работать с так
называемыми пользовательскими регистрами. Начиная с i486 и Pentium их 16:
- 8 32-разрядных РОН(регистров общего назначения) EAX/AX/AH/AL, EBX, ECX,
EDX, EBP\BP, ESi\Si, EDi\Di, ESP\SP
- 6 16-разрядных сегментных регистра CF, DF, SF, EF, SS, GS
- регистры состояния и управления EFLAGS\FLAGS, EiP\iP
Существуют ещё 16 системных регистров. Защищённый режим МП позволяет
полностью использовать все возможные атрибуты для многозадачного режима.
При этом сегментация памяти усложняется. Любой сегмент памяти в ЗР имеет
следующие атрибуты:
- Расположение сегментов в памяти
- Размер сегмента
- Уровень привилегий, определяющий права этого сегмента относительно
других
- Тип доступа (определяет назначение сегмента) и некоторые другие…
Перечисленные атрибуты показывают, что в ЗР МП поддерживает два типа
защиты по привилегиям и по доступу к памяти в отличие от реального режима
работы.
Ключевым объектом ЗР является специальная структура – дескриптор сегмента,
которая представляет собой 8 байтовую структуру, содержащую перечисленные
выше атрибуты.
Любая область ОП, которая логически может быть сегментом данных, стека или
кода должна быть описана дескриптором. Все дескрипторы собираются вместе в
одну из трёх дескрипторных таблиц, соответствующего назначения. Адрес
размещения дескрипторных таблиц может быть любым; он хранится в
специальном регистре.
Системные регистры МП:
- 4 регистра управления
- 4 регистра системных адресов
- 8 регистров отладки
1. Регистры управления предназначены для общего управления системой и
доступны только для программ с уровнем привилегий 0 (Cr 0, Cr1, Cr2, Cr3).
Cr 1 – зарезервирован для спец использования и не доступен.
Cr 0 – содержит системные флаги, управляющие режимами работы МП и
отражающие его состояние глобально, независимо от конкретно выполняющихся
задач. Используется при страничной организации памяти.
Рассмотрим некоторые системные флаги:
- PE(Project Enable), бит 0; при PE=0 – реальный режим , в противном
случае ЗР
- MP(Math Present), бит 1; при MP=1 – указывается на наличие
сопроцессора
- TS(Task Switched), бит 3; переключение задач (автоматически изменяется
при переключении на выполнеие другой задачи)
49
- AM(Alignment Mask), бит 18; маска выравнивания. При AM=1 – разрешён
контроль выравнивания, в противном случае - запрет
- CD(Cash Disable), бит 30; При CD=1 – запрещена кеш-память
- PG(PaGin), бит 31; При PG=1 – разрешено страничное преобразование.
Cr 2 - используется при страничной организации памяти в ситуации, когда текущая
команда обратилась по адресу, содержащемуся на странице, отсутствующей в
данный момент в ОП. Тогда в МП возникает прерывание и 32 битовый адрес
команды записывается в Cr 2 и обработчик определяет нужную страницу,
определяет её в ОП и возобновляет нормальную работу программы.
Регистр Cr 3 используется так же при страничной организации памяти. Это
регистр каталога страниц первого уровня. Он содержит 20 битовый физический
базовый адрес каталога страниц текущей задачи. Этот каталог содержит 1024 32
битовых дескриптора, каждый из которых содержит адрес таблицы страниц
второго уровня. В свою очередь, каждая из таблиц страниц второго уровня
содержит 1024 32 битовых дескриптора, адресующих страничные кадры памяти
размером по 4 КБ.
2. Регистры системных адресов (регистры управления памятью)
предназначены для защиты программ и данных в мультизадачном режиме работы
МП. В ЗР адресное пространство делится на:
- Глобальное (общее для всех задач)
- Локальное (отдельная для каждой задачи).
Поэтому в МП существуют следующие системные регистры:
-
GDTR (Global Description Table Register) – его размер 48 бит, 32 из
которых (с 16 по 47 ) базовый адрес глобальной дескрипторной таблицы
CDT и 16 бит (с 0 по 15) – значение предела, т.е.размер таблицы GDT в
байтах
-
LDTR (Local Description Table Register) – регистр таблицы локальных
дескрипторов размером в 16 бит. Содержит, так называемый, селектор
дескриптора LDT, который является указателем таблицы GDT, которая
описывает сегмент, содержащий LDT.
-
IDTR (Interrupt Description Table Register) – регистр дескриптора
прерываний, размер 48 бит. Предназначен для таблиц IDT, аналогичен
GDTR.
-
TR (Task Register) – регистр задачи размером 16 бит, подобно LDTR
содержит селектор, т.е. указатель на дескриптор в таблице GDT, который
описывает текущий сегмент состояния задачи.
TSS – этот сегмент создаётся для каждой задачи в системе, имеет жёстко
регламентированную структуру и содержит контекст или текущее состояние
задачи. Основное назначение сегментов TSS – сохранить текущее
состояние задачи в момент переключения на другую задачу.
3.
Регистры отладки предназначены для аппаратной отладки. Реально из 8
регистров МП используются 6 (все они 32 битовые):
Dr 0, Dr 1, Dr 2, Dr 3 – предназначены для задания линейных адресов четырёх
контрольных точек прерывания, при этом используется механизм : любой,
формируемы текущей программой, адрес сравнивается с адресами в регистрах
Dr 0 , Dr 3 и при совпадении генерируется “исключения отладки №1”.
Dr 6 – регистр состояния отладки, биты этого регистра устанавливаются в
соответствии с причинами прерывания.
50
Dr 7 – регистр управления отладкой. В нём для каждого из регистров Dr 0 …Dr 3
имеются поля, с помощью которых можно уточнить следующие условия, при
которых генерируются прерывания:
- Место регистрации контрольной точки (только в текущей или любой
задаче ) – это младшие 8 бит (по 2 бита на каждую контрольную точку)
- Тип доступа, по которому инициируются прерывания (только при выборе
команды, при записи или чтении команды тип доступа хранится в старшей части
регистра).
Большинство из системных регистров – программно-доступные.
Структуры данных ЗР.
Так как в ЗР запрос к памяти со стороны программ должен быть санкционирован,
то МП аппаратно контролирует доступ к любому адресу называемому целевым. В
отличие от реального режима, в сегментных регистрах вместо адреса начала
сегмента, в ЗР загружается, так называемый, селектор, в котором хранится
указатель на 8 байтовый блок памяти называемый дескриптором.
Схема обращения к дескриптору.
15
is
+
1
0
i i ………..i e p p
1 1 ……….1 0 0 0
31
0
адрес таблицы дескриптора
адрес дескриптора сегмента памяти
Дескриптор:
63
Б7
База(31..24)
31
Б6
48 47
GD04Предел(19..16)
Б3
Б2
16 15
База сегмента(15..0)
Б5
pddatttA
Б1
Б4
31
База (23..16)
Б0
0
Предел сегмента (15..0)
Таблица дескрипторов может быть:
- Глобальной (GDT)
- Локальной (LDT)
- Прерываний (IDT)
Адрес таблицы дескрипторов выбирается в соответствии с битом L, который при
равенстве 1 LDTR, в случае равенства 0 - GDTR.
Поля дескрипторов используются следующим образом:
1. Базовый адрес занимает Б2, Б3, Б4, Б7 и определяет начальный адрес
сегмента в линейном адресном пространстве размером 4 ГБ.
2. 20 битовое поле предела расположенное в Б0, Б1 и частично в Б6 и
определяет границу сегмента.
51
3. Б5 называется AR(Access Raights) в нём закодированы права доступа к
сегменту.
4. В старшей части Б6 находятся ещё 3 управляющих бита:
D – бит размера, если D=0, то данные представлены 16 битами, если 1,
то данные 32 битные.
U – бит пользователя, предназначен для системы, МП его не
использует.
G – бит поля гранулярности, определяет размер сегмента. При G=0 –
размер в Байтах, при G=1 – размер указывается в страницах и, так как
страница 4 КБ, то максимальный размер 1М * 4КБ = 4 ГБ.
52
53
Download