ПРИМЕЧАНИЕ Напомню, почему мы записываем регистры EIP/IP через косую черту.
Какой конкретно регистр будет использоваться, зависит от установ-
ленных режимов адресации
или use32. Если указано
то
используется IP, если use32 — то EIP.
Таким образом, команды передачи управления изменяют содержимое регист-
ров CS и EIP, в результате чего процессор выбирает для выполнения не следующую
по порядку команду программы, а команду в некотором другом участке програм-
мы. Конвейер внутри процессора при этом сбрасывается.
По принципу действия команды процессора, обеспечивающие организацию
переходов в программе, можно разделить на три группы.
Команды безусловной передачи управления:
безусловного перехода;
вызова процедуры и возврата из процедуры;
D вызова программных прерываний и возврата из программных прерываний.
Команды условной передачи управления:
Р перехода по результату команды сравнения;
П перехода по состоянию
флага;
П перехода по содержимому регистра ЕСХ/СХ.
Команды управления циклом:
П организации цикла со счетчиком ЕСХ/СХ;
D организации цикла со счетчиком ЕСХ/СХ с возможностью досрочного выхода
из цикла по дополнительному условию.
Возникает вопрос о том, каким образом обозначается то место, куда необходимо
передать управление. В языке ассемблера это делается с помощью меток. Метка —
это символическое имя, обозначающее определенную ячейку памяти и пред-
назначенное для использования в качестве операнда в командах передачи управ-
ления.
Подобно переменной, транслятор ассемблера присваивает любой метке три ат-
рибута:
При обсуждении архитектуры микропроцессора мы говорили, что команды извлекаются из памяти
заранее в так называемый конвейер, поэтому адрес подлежащей выборке команды из памяти и со-
держимое пары CS:E(IP) — не одно и то же. Эта пара регистров содержит адрес команды в програм-
ме, которая будет выполняться следующей, а
той команды, которая пойдет в конвейер.
Команды передачи управления
имя сегмента кода, где эта метка описана;
смещение — расстояние в байтах от начала сегмента кода, в котором описана
метка;
тип, или атрибут расстояния, метки.
Последний атрибут может принимать два значения:
near — переход на метку возможен только в пределах сегмента кода, где эта мет-
ка описана, то есть для перехода на метку физически достаточно изменить только
содержимое регистра EIP/IP;
far — переход на метку возможен только в результате межсегментной передачи
управления, для осуществления которой требуется изменение содержимого как
регистра EIP/IP, так и регистра CS.
Метку можно определить двумя способами:
оператором : (двоеточие);
директивой LABEL
Синтаксис первого способа показан на рис.
Символическое
Ц Команда ассемблера
Рис.
Синтаксис описания метки с помощью оператора
С помощью
можно определить метку только ближнего типа — near.
Определенную таким образом метку можно использовать в качестве операнда в ко-
мандах условных переходов
и безусловного перехода
CALL Эти команды,
естественно, должны быть в том же сегменте кода, в котором определена метка.
Команда ассемблера может находиться как на одной строке с меткой, так и на сле-
дующей.
Во втором способе определения меток в программе используется директива
LABEL (рис. 10.2).
Символическое имя
label
Тип
Рис. 10.2. Синтаксис директивы LABEL
Тип метки может иметь значение near или far. Обычно директиву LABEL исполь-
зуют для определения идентификатора заданного типа. Например, следующие
описания меток ближнего типа эквивалентны:
m l :
ml label near
mov
Понятно, что метка может быть только одного типа — либо near, либо far. Если
возникает необходимость использовать для одной и той же команды метки и даль-
него, и ближнего типов, то в этом случае необходимо определить две метки, при-
чем метку дальнего типа нужно описать, используя директиву
как показано
в следующем фрагменте:
Глава
Команды передачи управления
public
;сделать метку
видимой для внешних программ
m_far label far
метки дальнего типа m_far
метки ближнего типа
mov
Определив для команды mov ax,pole_l две метки, можно организовывать пере-
ход на эту команду как из данного сегмента команд, так и из других сегментов
команд, в том числе принадлежащих другим модулям. Для того чтобы сделать ви-
димым извне имя метки m_far, применяется директива PUBLIC. К более подробно-
му описанию этой директивы мы еще вернемся в главе
Другой часто встречающийся случай применения директивы LABEL — это орга-
низация доступа к области памяти, содержащей данные разных типов, например:
label byte
15
(?)
в этом фрагменте оба идентификатора относятся к одной области
памяти и дают возможность работать с ней, используя разные
имена, либо как с байтовым массивом, либо как с массивом слов
mov mas_b+10,al ;запись из
в массив байтов (в 11-й байт)
mov
из ах в первое слово области
Вспомним еще одно очень важное понятие ассемблера, имеющее прямое отно-
шение к меткам, — счетчик адреса команд. Мы уже упоминали о нем в первых гла-
вах и говорили, что транслятор ассемблера обрабатывает исходную программу
последовательно — команду за командой. При этом ведется счетчик адреса команд,
который для первой исполняемой команды равен нулю, а далее, по ходу обработки
очередной команды транслятором, увеличивается на длину этой команды. По сути,
счетчик адреса команд — это смещение конкретной команды относительно начала
сегмента кода. Таким образом, каждая команда во время трансляции имеет адрес,
равный значению счетчика адреса команд. Обратитесь к главе 6 и еще раз посмот-
рите на приведенный в нем листинг 6.2. Первая колонка в листинге — номер стро-
ки файла листинга. Вторая колонка (или третья, если присутствует колонка с уров-
нем вложенности) — смещение команды относительно начала сегмента кода или,
как мы сейчас определили, счетчик адреса. Значение, на которое он увеличивается
по мере обработки ассемблером очередной строки исходной программы, равно зна-
чению длины машинной команды в этой строке. Исходя из этого, ясно, почему
счетчик адреса увеличивается только после тех строк исходной программы, кото-
рые генерируют некоторое машинное представление (в том числе после директив
резервирования и инициализации данных в сегменте данных).
Транслятор ассемблера обеспечивает нам две возможности работы с этим счет-
чиком:
В использование меток, атрибуту смещения которых транслятор присваивает
значение счетчика адреса следующей команды;
применение для обозначения счетчика адреса команд при задании операндов
команд специального символа $, во время трансляции заменяемого текущим
численным значением счетчика адреса.
Команды передачи управления 213
Классический пример:
длины строки в сегменте данных
Str_Mes db "Займись делом - учи ассемблер ..."
После ассемблирования значение
будет равно длине строки, так как
значение символа $ в месте его появления отличается от
ровно на длину
строки.
Другое применение, избавляющее программиста от необходимости «плодить»
лишние метки в программе, — реализация близкого, буквально через следующую
или предыдущую команды, перехода. Для примера рассмотрим фрагмент програм-
мы из листинга 6.1 (см. главу 6):
cmp dl,9h ;сравнить
с
$+5 ;перейти на команду
если
или
sub dl,7h
;M1:
mov
4h в регистр
cmp
;сравнить
с 9h 28
jle $+4 ;перейти на команду add
если
или
sub
add
Как узнать правильные значения длины команд? Во-первых, по опыту, то.есть
просто догадаться. Во-вторых, из файла листинга, что не всегда дает результат, так
как конечные машинные команды (колонка файла листинга с объектным кодом)
в нем не всегда до конца сформированы. В-третьих, узнать длины команд можно,
загрузив программу в отладчик и активировав окно CPU. Последний способ самый
точный. Не будет ничего страшного, если для первого прогона исполняемого мо-
дуля программы в нем будут неверные значения для подобных относительных пе-
реходов. И еще одно
при переходе вперед необходимо учитывать дли-
ну текущей команды перехода, при переходе назад этого делать не нужно.
Кроме возможности получения значения счетчика адреса компилятор позво-
ляет при необходимости установить счетчик адреса в нужное абсолютное значе-
ние. Это делается с помощью директивы
ORG выражение
Здесь выражение должно быть таким, чтобы ассемблер мог преобразовать его
к абсолютному числу при первом проходе трансляции.
примеру, эту директиву всегда используют при создании исполняемого фай-
ла с расширением
В контексте нашего обсуждения поясним, в чем здесь суть.
В главе 5 мы
сегментацию и деление программы на сегменты. Программа
в формате СОМ состоит из одного сегмента величиной не более 64 Кбайт. Сегмент-
ные регистры CS и DS содержат одно и то же значение физического адреса, а ре-
гистр SS указывает на конец этого единственного сегмента. Программа-загрузчик
операционной системы, считывая с диска исполняемые файлы с расширениями
.ехе и
производит определенные действия. В частности, настраивает переме-
Глава
Команды передачи управления
адреса программ на их конкретные физические значения. Кроме того,
к началу каждой исполняемой программы в памяти добавляется специальная об-
ласть величиной 256 байт
— префикс программного сегмента (PSP). Он пред-
назначен для хранения различной информации о загруженном исполняемом мо-
дуле. Для программ формата СОМ блок PSP находится в начале сегмента размером
в 64 Кбайт. В исходной программе, для исполняемого файла которой планируется
формат СОМ, мы должны предусмотреть место для блока
и делается ди-
рективой org lOOh.
Чтобы закончить разговор о файлах этого типа, разберемся с тем, как получить
исполняемый модуль формата СОМ. Трансляция программы выполняется как
обычно. Далее возможны два варианта действий.
Во-первых, возможно
утилиту
с ключом /t:
/t
Этот вариант подходит только в том случае, если вы правильно оформили ис-
ходный текст программы для формата СОМ. Кроме того, наличие директивы
org lOOh предполагает:
отсутствие разделения сегментов данных и стека, то есть данные необходи-
мо описать в сегменте кода, а для их обхода использовать команду безуслов-
ного перехода
П применение директивы ASSUME для указания транслятору на необходимость
связать содержимое регистров DS и SS с сегментом кода:
codeseg segment para "code"
assume cs:
org
ml
описываем данные
ml:
;далее идут команды программы
Во-вторых, можно использовать специальную утилиту
Эта утилита
позволяет преобразовать уже полученный ранее исполняемый модуль в фор-
мате ЕХЕ в формат СОМ:
exe2bin имя_файла_ехе
Этот вариант не требует специального оформления исходного текста програм-
мы. Единственным требованием является то, чтобы исходный текст был доволь-
но мал по объему.
Интересный вариант использования директивы ORG рассмотрен в
где
с ее помощью выполняется динамическая модификация машинного кода ко-
манды.
Do'stlaringiz bilan baham: |