Ассемблер для процессоров Intel Pentium
Шрифт:
Листинг 4.3. Программа, вызывающая процедуру seg_ex
#include <stdio.h>
exterr "С" char* seg_ex(void);
int main(void)
{
printf(«EXTERNAL MODULE EXAMPLE: %s\n», seg_ex);
return 0;
}
Здесь процедура segex является внешней, поэтому объявлена как extern. Результатом выполнения программы будет строка на экране дисплея
EXTERNAL MODULE EXAMPLE: Test STRING To Copy+
Глава 5Организация вычислительных циклов
Большинство программ, независимо от того, на каком языке они написаны, в процессе работы требуют изменения линейной последовательности выполнения операторов
Подобные операторы или группы операторов называют логическими структурами. Принципиально, существует два типа логических структур, на основе которых можно создать все остальные логические выражения и вычислительные алгоритмы:
– Структура, основанная на сравнении каких-либо величин и выборе варианта продолжения программы в зависимости от результата сравнения. Такую логическую структуру можно описать выражением «если А, то В, иначе С». В языках высокого уровня ее аналогом является оператор if ... else. Кроме того, существуют и расширенные варианты оператора if ... else, например switch ... case.
– Структура, в основе которой лежит алгоритм повторяющихся вычислений. Такой алгоритм выполняется при соблюдении определенных условий, которые проверяются в начале или в конце каждой итерации. Такие логические структуры в языках высокого уровня реализованы как операторы while, do ... while, for, repeat ... until и т. д.
Логические структуры языков высокого уровня придают особую гибкость и мощь этим языкам и позволяют относительно легко строить самые сложные алгоритмы. А как обстоят дела с языком ассемблера, ведь здесь нет подобных операторов? Несмотря на отсутствие подобных операторов, ассемблер обладает довольно мощными командами, позволяющими строить любые сколь угодно сложные логические структуры, в том числе и такие, которые довольно трудно, а иногда и невозможно реализовать в языках высокого уровня.
Хочу сразу же оговориться: мы не будем брать во внимание псевдомакросы логических структур, такие, как .IF и .WHILE, включенные в популярные языки ассемблера (в данном случае MASM). Псевдомакросы имитируют логические структуры высокого уровня, например if ... else, но значительно уступают им по возможностям, хотя и улучшают читабельность кода. Если внимательно посмотреть на программный код макросов, то вы увидите, что они содержат команды ассемблера, которые вполне можно написать самостоятельно. Кроме того, псевдомакросы скрывают механизм операции, что может быть полезно для программирования, но не для изучения алгоритмов функционирования. По этим причинам я сознательно отказался от использования псевдомакросов и макрорасширений ассемблера при рассмотрении программного кода.
Посмотрим, как можно создать логические структуры на языке ассемблера и использовать их в программах. В подавляющем большинстве случаев для создания логических структур и выражений на ассемблере, таких, например, как if ... else, while и так далее, требуется два условия:
– установить один или несколько битов в регистре флагов процессора;
– проверить состояние бита (группы битов) с помощью команд условного перехода и передать управление на соответствующую ветвь программы.
Большинство команд ассемблера после выполнения
Для передачи управления можно использовать и команды безусловного перехода; мы рассмотрим такую возможность позже.
Таким образом, для построения вычислительных алгоритмов необходимо анализировать состояние битов регистра флагов EFLAGS центрального процессора. Девять из 16 бит регистра являются активными и определяют текущее состояние машины и результатов выполнения команд. Многие арифметические команды и команды сравнения изменяют состояние флагов. Напомню назначение отдельных битов регистра флагов:
– CF (Carry Flag – флаг переноса) – содержит значение переносов (0 или 1) из старшего разряда при арифметических операциях и некоторых операциях сдвига и циклического сдвига;
– PF (Parity Flag – флаг четности) – проверяет младшие 8 бит результатов выполнения операций над данными. Нечетное число битов приводит к установке этого флага в 0, а четное – в 1. Не следует путать флаг четности с битом контроля на четность;
– AF (Auxiliary Carry Flag – дополнительный флаг переноса) – устанавливается в 1, если арифметическая операция приводит к переносу четвертого справа бита (бит 3) в регистровой однобайтовой команде. Данный флаг имеет отношение к арифметическим операциям над ASCII-символами и к полям, содержащим десятичные упакованные числа;
– ZF (Zero Flag – флаг нуля) – устанавливается после выполнения арифметических команд и команд сравнения. Ненулевой результат операции приводит к установке этого флага в 0, а нулевой – к установке флага в 1. Этот флаг проверяется при помощи команд условного перехода je и jz;
– SF (Sign Flag – знаковый флаг) – устанавливается в соответствии со знаком результата (старшего бита) после выполнения арифметических операций: при положительном результате флаг устанавливается в 0, а при отрицательном – в 1. Этот флаг проверяется при помощи команд условного перехода jg и jl;
– TF (Trap Flag – флаг пошагового выполнения) – если этот флаг установлен в 1, то процессор переходит в режим пошагового выполнения команд, то есть в каждый момент выполняется одна команда под управлением пользователя;
– IF (Interrupt Flag – флаг прерывания) – при нулевом состоянии этого флага прерывания запрещены, а при единичном – разрешены;
– DF (Direction Flag – флаг направления) – используется в строковых операциях для определения направления передачи данных. При нулевом состоянии команда увеличивает содержимое регистров s1 (ESI) и DI (EDI), a при ненулевом уменьшает содержимое этих регистров;
– OF (Overflow Flag – флаг переполнения) – фиксирует арифметическое переполнение, то есть перенос в старший бит или из старшего (знакового) бита при знаковых арифметических операциях.
Чаще всего в программах используются флаг переноса CF, флаг знака SF, флаг нуля ZF, немного реже – флаг четности PF, флаг направления DF, флаг переполнения OF и флаг дополнительного переноса AF. Еще реже, преимущественно в специальных случаях, используются флаги TF и IF.
Рассмотрим некоторые примеры, демонстрирующие методику выполнения условных переходов в программах.