
- •1.1. Память и процессор
- •1.2. Распределение адресного пространства
- •1.3. Регистры процессора
- •1.4. Сегментная структура программ
- •1.5. Стек
- •1.6. Система прерываний
- •1.7. Система ввода-вывода
- •Разница между директивами и командами Ассемблера
- •Описание сегмента — директива segment
- •Директива группирования сегментов Group
- •Директива Assume
- •Стандартные модели памяти
- •Директива model
- •Директивы упрощенного описания сегментов
- •Описание процедур
- •Описание внешних ссылок
- •Директива описания общих имен public
- •Директива описания внешних имен extrn
- •Xchg (eXcHanGe) Обмен
- •Xadd назначение,источник — обмен местами и сложение.
- •Команды условного перехода и регистр ecx/cx
- •Аппаратная реализация Кэш центрального процессора
- •Уровни кэша
- •Ассоциативность кэша
Описание процедур
Модуль на Ассемблере, как и модули на алгоритмических языках, обычно состоит из процедур. Для описания процедур используются две директивы. Визуально они похожи на соответствующие директивы описания сегмента:
имяP PROC [параметры] ; начало процедуры имяP .…………….…………….…………….…………….…………….…………… RET ; КОМАНДА возврата в точку вызова процедуры .…………….…………….…………….…………….…………….……………. имяP ENDP ; конец процедуры имяP |
У директивы PROC достаточно много параметров. С ними мы будем знакомиться постепенно, по мере необходимости.
Обратите внимание на ОБЯЗАТЕЛЬНУЮ команду RET. Она может быть в любом нужном месте процедуры и НЕ единственная. Если ее в процедуре НЕ будет, то ассемблерная программа НЕ сможет нормально работать — возникнет зависание.
Описание внешних ссылок
Как было заявлено ранее, мы будем использовать алгоритмические языки Pascal и C/C++ в качестве помощников при изучении Ассемблера. Таким образом, сразу начинаем работать с РАЗНЫМИ модулями, да еще и на разных языках! Поэтому нам не миновать ВНЕШНИХ ссылок. Что это такое? Это — использование в одном модуле имен, описанных в других модулях.
Директива описания общих имен public
PUBLIC [язык] имя1[,[язык] имя2…] |
Эта директива указывает компилятору и компоновщику, что данное имя (его адрес) должно быть доступно для других программ. Имена могут быть метками, переменными или именами подпрограмм.
Например, если мы хотим использовать в языке С/С++ функцию с именем Prim, реализованную в Ассемблере, то она в ассемблерном модуле должна быть описана следующим образом:
Public C Prim Prim Proc ……………………………………… Prim EndP |
Обратите внимание
Язык С/С++ различает регистр букв в именах. Это же должен делать и Ассемблер, для чего служит специальный ключ, определяющий чувствительность Ассемблера к РЕГИСТРУ выбора символов: ml=all (все символы), mx=globals (только глобальные), mu=none (символы к регистру НЕ чувствительны — принято по умолчанию):
TASM имя.asm[ /ml] TASM имя.asm[ /mx] TASM имя.asm[ /mu] |
В нашем случае ассемблерный модуль должен быть откомпилирован ОБЯЗАТЕЛЬНО с ключом /ml или /mx. Иначе компоновщик С/С++ НЕ сможет подключить ассемблерный модуль. Если эти рассуждения вам пока НЕПОНЯТНЫ, НЕ зацикливайтесь, — мы к этому еще вернемся на КОНКРЕТНЫХ примерах.
Директива описания внешних имен extrn
EXTRN имя1:тип1[, имя2:тип2…] |
Эта директива указывает компилятору и компоновщику, что данное имя имеет определенный тип, его предполагается использовать в данном ассемблерном модуле, но память для него выделена в другом модуле. Параметр тип может принимать следующие значения: ABS (для констант), BYTE, WORD, DWORD, QWORD, TBYTE, FAR, NEAR.
Например, в модуле на алгоритмическом языке Pascal (Borland/Turbo Pascal-5.5/6.0/7.0х) мы описали следующие глобальные переменные:
Var a, b, c : Integer; X : LongInt; |
А использовать их собираемся в ассемблерном модуле. В этом случае директива будет иметь вид:
Extrn a:Word, b:Word, c:Word, x:Dword |
Обратите внимание
Язык Pascal НЕ различает регистр букв в именах. А директива EXTRN содержит только ОДНУ гласную букву — начинающие программисты часто на этом спотыкаются…
Полный набор инструкций см в справочнике инструкций.
Лекция 4. Основные команды целочисленной арифметики IBM PC.
ТИПЫ ДАННЫХ АССЕМБЛЕРА
Любая программа предназначена для обработки некоторой информации, поэтому вопрос о том, как описать данные с использованием средств языка обычно встает одним из первых.
TASM предоставляет очень широкий набор средств описания и обработки данных, который вполне сравним с аналогичными средствами некоторых языков высокого уровня.
Простые типы данных
Для описания простых типов данных в программе используются специальные директивы резервирования и инициализации данных, которые, по сути, являются указаниями транслятору на выделение определенного объема памяти. Если проводить аналогию с языками высокого уровня, то директивы резервирования и инициализации данных являются определениями переменных.
Машинного эквивалента этим директивам нет; просто транслятор, обрабатывая каждую такую директиву, выделяет необходимое количество байт памяти и при необходимости инициализирует эту область некоторым значением.
Директивы резервирования и инициализации данных простых типов:
db — резервирование памяти для данных размером 1 байт.
dw — резервирование памяти для данных размером 2 байта.
dd — резервирование памяти для данных размером 4 байта.
df — резервирование памяти для данных размером 6 байт;
dp — резервирование памяти для данных размером 6 байт.
dq — резервирование памяти для данных размером 8 байт.
dt — резервирование памяти для данных размером 10 байт.
Напомним порядок размещения данных в памяти. Он напрямую связан с логикой работы микропроцессора с данными. Микропроцессоры Intel требуют следования данных в памяти по принципу: младший байт по младшему адресу.
Команды пересылки данных общего назначения
К этой группе относятся следующие команды:
mov <операнд назначения>,<операнд-источник>
xchg <операнд1>,<операнд2>
mov - это основная команда пересылки данных. Она реализует самые разнообразные варианты пересылки.
Отметим особенности применения этой команды:
Командой mov нельзя осуществить пересылку из одной области памяти в другую. Если такая необходимость возникает, то нужно использовать в качестве промежуточного буфера любой доступный в данный момент регистр общего назначения.
К примеру, рассмотрим фрагмент программы для пересылки байта из ячейки fls в ячейку fld:
mov al,fls
mov fld,al
Нельзя загрузить в сегментный регистр значение непосредственно из памяти. Поэтому для выполнения такой загрузки нужно использовать промежуточный объект. Это может быть регистр общего назначения или стек.
Нельзя переслать содержимое одного сегментного регистра в другой сегментный регистр. Это объясняется тем, что в системе команд нет соответствующего кода операции. Но необходимость в таком действии часто возникает. Выполнить такую пересылку можно, используя в качестве промежуточных все те же регистры общего назначения. Вот пример инициализации регистра es значением из регистра ds:
mov ax,ds
mov es,ax
Но есть и другой, более красивый способ выполнения данной операции — использование стека и команд push и pop:
push ds ;поместить значение регистра ds в стек
pop es ;записать в es число из стека
Нельзя использовать сегментный регистр cs в качестве операнда назначения. Причина здесь простая. Дело в том, что в архитектуре микропроцессора пара cs:ip всегда содержит адрес команды, которая должна выполняться следующей. Изменение командой mov содержимого регистра cs фактически означало бы операцию перехода, а не пересылки, что недопустимо.