
- •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
- •Аппаратная реализация Кэш центрального процессора
- •Уровни кэша
- •Ассоциативность кэша
Разница между директивами и командами Ассемблера
В языке Ассемблера существуют команды и директивы, формат которых практически одинаков. В командах Имя интерпретируется как метка, поэтому за ней всегда ставится символ двоеточия ':'. Для Ассемблера в качестве имени (идентификатора) допускаются следующие символы:
Латинские буквы от A(a) до Z(z) — РЕГИСТР БЕЗРАЗЛИЧЕН. Ассемблер сам по себе НЕ различает ПРОПИСНЫЕ и строчные буквы. Но при использовании ассемблерных модулей в программе на алгоритмическом языке, чувствительном к регистру букв, например, в С/С++, буквы в разных регистрах будут разными.
Цифры от 0 до 9.
Специальные символы: ? . @ _ $.
Имя в Ассемблере может начинаться с любого допустимого символа, кроме цифры. Если имя содержит символ точки '.', то он должен быть ПЕРВЫМ символом. Имя НЕ может быть зарезервированным в Ассемблере словом (имя машинной команды или директивы).
При ассемблировании между директивами и командами существует одно принципиальное различие. Директивы (псевдооператоры, псевдокоманды) управляют работой компилятора или компоновщика, а НЕ микропроцессора. Они используются, например, для сообщения компилятору, какие константы и переменные применяются в программе и какие имена мы им дали, какой сегмент является кодовым, а какой — сегментом данных или стека, в каком формате выводить листинг исходного кода программы и прочее. Большинство директив НЕ генерирует машинных команд (объектный код).
Команда Ассемблера всегда генерирует машинный код.
Директивы имеют разный синтаксис в режимах MASM (поддерживается компиляторами Microsoft Assembler — masm и Borland (Turbo) Assembler — tasm) и Ideal (поддерживается компилятором tasm).
При описании синтаксиса директив и команд обычно используют специальный язык, известный всем профессиональным программистам, — язык Бэкуса-Наура (названный так в честь этих двух достойных ученых). Мы будем использовать его упрощенный вариант:
Терминальные элементы языка (название директив и команд, разделительные знаки) будем выделять жирным шрифтом.
Нетерминальные элементы (название параметров, операндов и других атрибутов) выделим курсивом.
Комментарии будем писать обычным шрифтом.
Необязательные элементы заключаются в квадратные скобки []. В синтаксисе языка Ассемблера есть и терминальный элемент квадратные скобки [] — в этом случае это будет особо ПОДЧЕРКНУТО.
Повторяющиеся элементы синтаксической структуры описываются многоточием (…).
Директив достаточно много. Практически каждая версия компилятора что-то из директив добавляет или немного изменяет синтаксис. Для определенности мы в данной главе остановимся на синтаксисе основных директив в более универсальном формате MASM для компиляторов masm-6.12 (или выше) и tasm-3.1 (или выше). Кроме того, известные компиляторы с языка программирования С/С++ (Borland C++, Visual C++) выдают ассемблерный листинг именно в формате MASM. И очень скоро мы научимся его читать…
Описание сегмента — директива segment
Любые ассемблерные программы содержат, по крайней мере, один сегмент — сегмент кода. В некоторых программах используется сегмент для стековой памяти и сегмент данных (основной и дополнительный) для определения данных.
Универсальная директива для описания сегмента имеет следующий формат: имяС SEGMENT [параметры] ; начало СЕГМЕНТА имяС . . . имяС ENDS ; конец СЕГМЕНТА имяС |
Имя сегмента (имяС) должно обязательно присутствовать, быть уникальным и соответствовать соглашениям для имен в Ассемблере или в другом алгоритмическом языке, для стыковки с которым делается ассемблерный модуль. Например, при стыковке Ассемблера с Turbo/Borland Pascal имяС должно быть СТРОГО определенным:
для сегмента кода CSEG или CODE;
для сегмента данных DSEG или DATA;
для сегмента стека STACK.
Директива ENDS обозначает конец сегмента. Обе директивы SEGMENT и ENDS должны иметь одинаковые имена имяС.
В одном модуле можно открывать и закрывать сегмент с одним и тем же именем имяС несколько раз, но пересекаться (вкладываться друг в друга) разные сегменты НЕ должны. Компилятор просматривает ассемблерный модуль и объединяет вместе все части сегментов с одинаковым именем в том порядке, в каком он их обнаруживает (сверху-вниз).
Директива SEGMENT может содержать три основных типа необязательных параметров, определяющих выравнивание (align), объединение (combine) и класс ('class'), между которыми должен быть хотя бы один пробел в качестве разделителя. Параметры имеют смысл при разработке БОЛЬШИХ ассемблерных программ.
1. Выравнивание (align). Этот параметр сообщает компоновщику, чтобы он разместил данный сегмент, начиная с указанной границы. Это может быть ОЧЕНЬ важно, т.к. при правильном выравнивании данные загружаются процессором с большей скоростью. При попытке сосчитать невыравненные данные процессор сделает одно из двух: либо возбудит исключение, либо сосчитает их в несколько приемов (конечно, при этом быстродействие программы снизится).
Таблица 4.1. Параметр выравнивания (align)
Параметр |
Значение |
BYTE |
Выравнивание НЕ выполняется. Сегмент размещается, начиная со следующего байта. |
WORD |
Начало сегмента выравнивается на границу слова (четный адрес, кратный 2) |
DWORD |
Начало сегмента выравнивается на границу двойного слова (четный адрес, кратный 4) |
PARA |
Начало сегмента выравнивается на границу параграфа (четный адрес, кратный 16). Это значение принято по умолчанию. |
PAGE |
Начало сегмента выравнивается на границу страницы (четный адрес, кратный 256) |
MEMPAGE |
Начало сегмента выравнивается на границу страницы памяти (четный адрес, кратный 4K) |
2. Объединение (combine). Настоящий элемент предназначен для указания компоновщику, каким образом объединять сегменты, находящиеся в разных модулях и имеющие одинаковые имена, или как соединить данный сегмент с другими сегментами в процессе компоновки после ассемблирования.
3. Класс ('class'). Данный элемент, заключенный в апострофы, используется для группирования сегментов при компоновке. Компоновщик группирует вместе все сегменты с ОДИНАКОВЫМ классом.
Таблица 4.2. Параметр объединения (combine)
Параметр |
Значение |
PRIVATE |
Сегмент НЕ будет объединяться с сегментами с тем же именем, находящимися в других модулях. Это значение принято по умолчанию. |
PUBLIC |
Сегмент будет объединяться с сегментами с тем же именем, находящимися в других модулях или в том же модуле, в один сегмент. |
MEMORY |
Параметр подобен PUBLIC, но для сегмента стека.
|
COMMON |
Размещает данный сегмент и все сегменты с тем же именем по ОДНОМУ и тому же адресу. Получаются перекрывающиеся сегменты (overlay), занимающие разделяемую область памяти (shared memory). |
VIRTUAL |
Описывает сегмент специального вида, который должен объявляться ВНУТРИ другого сегмента (общая область памяти). |
AT xxx |
Устанавливает сегмент по абсолютному адресу параграфа xxx для получения доступа по идентификаторам к фиксированным адресам памяти (например, видеобуфер, таблица векторов прерываний – см. прил.6) |
Например, сегмент стека, в котором зарезервировано 100*8 = 800 байтов (со словом My Stack — 8 символов) может быть описан следующим образом:
SStack SEGMENT PARA PUBLIC 'Stack' DB 100 dup ('My Stack') SStack ENDS |