Э. Таненбаум - Архитектура компьютера (1127755), страница 205
Текст из файла (страница 205)
Использовать две повторяющиеся команды не слишком изящно, но такова цена проектного решения, основывающегося на принципе независимости кодов условий от команд перемещения. При выполнении циклов проводится приращение индексных регистров, и для этих целей флаг направления должен быть сброшен. В строках 23 и 25 кода скопированная символьная строка выводится при помощи подпрограммы згг1пдрг, имеющейся в папке ехашр!ез. Она достаточно проста, поэтому обсуждать ее здесь мы не будем. В программе вывода символьных строк в обратном порядке, показанной в листинге В.б, строка 1 кода содержит все стандартные номера системных вызовов. В строке 3 в стек помещается фиктивное значение, а в строке 4 указатель базы (ВР) начинает указывать на текущую вершину стека.
Эта программа выводит АЯСП-символы по одному, а потому в стек вводится численное значение РОТСНАВ. Обратите внимание: ВР указывает на символ, который предполагается отобразить во время вызова 5У5. В строках 2, 6 и 7 регистры 01, АЕ и СХ подготавливаются к выполнению повторяющейся команды 5СА5В. Регистр счетчика и целевой индекс загружаются так же, как это происходит в программе копирования строки, за тем лишь исключением, что в регистр АЕ вместо нуля помещается символ новой строки. Таким образом, команда 5СА5В сравнивает значения символов строки з1г с ш, а не с нулем, и в случае соответствия устанавливает нулевой бит.
Команда ВЕР 5СА5В выполняет приращение регистра 01, так что после совпадения целевой индекс указывает на символ нуля, следующий за символом новой 808 Приложение В. Программирование на языке ассемблера строки. В строке 12 выполняется отрицательное приращение 01 на 2; в результате этот регистр указывает на последнюю букву слова. Если сканирование символьной строки идет в обратном порядке, а отображается она посимвольно, значит, наша задача решена; в таком случае флаг направления в строке 10 переустанавливается, и начинается обратная регулировка индексных регистров в строковых командах.
Теперь команда Е0058 в строке кода 14 копирует символ в АЕ, а в строке 15 этот символ помещается в стек рядом с РЬТСНАй, что позволяет команде 5У5 отобразить его. Команды, находящиеся в строках 18 и 19, выводят новую строку, и программа традиционно закрывается вызовом ЕХ1Т. В текущей версии программы, впрочем, содержится ошибка. Ее можно найти путем пошаговой трассировки. Команда /зтг помещает строку з1г в поле данных трассера. Так как числовое значение адреса данных известно, мы можем выяснить, как меняются значения в индексных регистрах в отношении положения символьной строки. Ошибка, впрочем, обнаруживается только после многократного нажатия клавиши возврата каретки.
Команды трассера помогают сократить время локализации ошибки. Запустите программу трассировки и введите команду 13, которая переместит нас в середину цикла. Далее с помощью команды Ь установим контрольную точку в строке 15. Создав две новые строки, мы увидим, что в поле вывода отображается последняя буква «е». Запустив команду г, мы заставим программу трассировки работать вплоть до следующей контрольной точки или до завершения процесса, Таким образом, последовательно запуская команду г, можно видеть все буквы, пока мы не подберемся к решению проблемы. С этого момента программу трассировки можно будет перевести в пошаговый режим и проанализировать происходящее при выполнении важнейших команд. Мы также можем установить дополнительную контрольную точку в той или иной строке кода, но при этом нужно учитывать включение файла зузсз1пг.й, приводящее к смещению номеров строк кода на 20.
Следовательно, чтобы установить контрольную точку, скажем, в строке 16, нужно ввести команду 36Ь. Впрочем, от этого неуклюжего способа лучше отказаться в пользу установки глобальной метки з1агт в строке 2 перед расположенной в ней командой — тогда контрольную точку в нужной строке кода можно будет установить командой !йагт + 1«Ь К тому же такой способ установки контрольной точки позволяет не обращать внимания на размер включаемого файла. Таблицы диспетчеризации В некоторых языках программирования существуют операторы выбора, позволяющие выбирать один из нескольких возможных вариантов действий в зависимости от численного значения переменной. Подобного рода многовариантное ветвление иногда оказывается полезным и в программах на языке ассемблера. Возьмем, к примеру, набор подпрограмм системных вызовов, объединенных в программе перехвата исключений 5У5.
Пример программирования многовари- Примеры 807 антного ветвления на языке ассемблера 8088 показан в коде программы 3ипар1Ы.В, представленном в листинге В.7. Листинг В.7. Реализация многовариантного ветвления при помощи таблицы диспетчеризации 771пс1иое "..7ауаса1пг.п" 5ЕСТ .ТЕХТ 3овратггп РО5Н ьсгс МОН ВР,5Р РО5Н РК1МТЕ 5Н5 Р05Н ВЕТСНАН 1: 5Ч5 СМР АХ.5 СЕ ВТ СМРВ АС,'0' ОЕ 1Ь СМРВ АС,'9' ОЕЕ 2Г МОНВ АС,'9'+1 2: ИОЧ ВХ,АХ ЯМО ВХ.ОХТ 5АС ВХ.1 СА1 Е 161(ВХ) 3МР 1Ь 8; РО5Н 0 РО5Н ЕХ1Т 5У5 гоосо: МОЧ ЯХ,веа0 3ИР 97 гоо11: ИОЧ Ах.пеа1 3ИР 9Г гои12: МОЧ Ах,веа2 3ИР 97 гоо13 ИОЧ Ах,веаз 3МР 91 гооха: МОЧ ЯХ веаа 3ИР 91 гоо15: ИОЧ Ах,веа5 3МР 91 гоогб: ИОЧ Ах,веаб 3ИР 9Т гоо17: ИОЧ Ах,везу 3ИР 9Г гоо18: НОЧ Ах,веаз 3МР 91 егоотп ИОН Ах,евеа 9: РО5Н АХ Р05Н РК1МТЕ 5Ч5 АОО 5Р,4 ВЕТ ! 49 ! 50 ! 51 ! 52 .5ЕСТ ,ОАТА ЬЬ1: .НОНО гоиСО.гоо11,гои12,гоо13,гоота,гоо15, гоитб,гоо17,гоо18,гоо18,егоос ав50: .А5С12 "ТМ5 15 д аеголп" ава1: .А5С12 "Нов аЬоос а опедп" ! 2 ! 3 ! 5 ! 6 7 ! 8 ! 9 10 ! 12 ! 13 ! 14 ! 15 ! 16 ! 17 ! 18 ! 19 ! 20 ! 21 ! 22 ! 23 ! 24 ! 25 ! 26 ! 27 ! 28 ! 29 ! 30 ! 31 ! 32 ! 33 ! 34 ! 35 ! 36 ! 37 .
'38 ! 39 ! 40 ! 41 ! 42 ! 43 ! 44 ! 45 ! 46 ! 47 ! 48 808 Приложение В. Программирование на языке ассемблера "Уоо аакеп Тог а Снолп" "Тое ФШС нас а Спгеелп" "Уоо Ьуреб а Торг Тп" "Уоо ргегеггее а Вне Ап" "А ю х нас епсоопсегее Дп" "Тпш аа повоег аеуеп Дп" "Тща ШШС !а пое ассергее аа ап осга1дп" "Тша !а поо а Шдае. Тгу адаапдп" "Туре ап осга! Ф да! ил СЬ а геоогп 51ор оп веа2: .А5С12 веаз: .Я5С!2 веа4: .Я5С12 веа5: .А5С12 веаб: .А5С!2 еау: .Я5612 веаб: .А5С12 евеа: А5С12 аггг: Я5С12 ! 53 ! 54 ' 55 ! 56 ' 52 ! 58 ! 59 ' 60 епс ог П1елп"! 61 Программа начинается с вывода символьной строки, метка которой (зЬгс) приглашает пользователя ввести восьмеричную цифру (строки 4 — 7 кода). Затем из файла стандартного ввода считывается символ (строки 8 и 9).
Если значение АХ оказывается меньше 5, программа интерпретирует это как маркер конца файла, переходит к метке 8 в строке 22 и завершается с кодом состояния О. Если введенный символ не является маркером конца файла, исследуется введенный символ в регистре АЕ Любой символ, меньший цифры О, считается разделителем и при переходе в строке кода 13 игнорируется; после чего извлекается следующий символ.
Любой символ, больший цифры 9, считается неверным. В строке 16 он преобразуется в АБСП-символ двоеточия, который в последовательности АБСП-символов идет сразу после цифры 9. Таким образом, в строке 17 в регистре АХ находится значение в диапазоне между цифрой 0 и двоеточием. Это значение копируется в регистр ВХ. В строке 18 команда АМО маскирует все биты, кроме четырех младших, в результате остается число между 0 и 10 (это связано с тем, что нулю соответствует АЗСП-код Ох30).
Так как в таблице мы собираемся провести индексирование слов, а не байтов, значение ВХ умножается на 2 путем сдвига влево в строке 19. В строке 20 находится команда вызова. Действительный адрес определяется прибавлением значения ВХ к численному значению метки ЬЬ1, а содержимое этого объединенного адреса загружается в счетчик команд РС. Программа выбирает одну из десяти подпрограмм в зависимости от символа, извлекаемого из стандартного ввода. Каждая из этих подпрограмм размещает в стеке адрес того или иного сообщения, а затем переходит к общему для всех вызову системной подпрограммы РЙ1МТГ.
Чтобы разобраться в происходящем, следует иметь в виду, что команды 3МР и САСС загружают в регистр РС некий адрес текстового сегмента. Этот адрес представляет собой двоичное число, а в ходе ассемблирования все адреса заменя!отея соответствующими двоичными значениями.
Двоичные значения, в свою очередь, помогают инициализировать массив в сегменте данных, что и делается в строке 50. Таким образом, массив, начинающийся с метки ЬЬ1, содержит начальные адреса подпрограмм гои10, гоис1, гоос2 и т. д., по два байта в каждом. Наличие 2-байтовых адресов объясняет необходимость в сдвиге на 1 бит, произведенном в строке 19. Таблицы такого типа часто называют таблицами диспетчеризации.
Механизм работы таких программ демонстрирует подпрограмма егопс (строки 43 — 48 кода). Она обрабатывает числа, выходящие за пределы допустимого диапазона. Во-первых, в строке 43 в стек помещается адрес сообщения (в АХ). Затем в стек отправляется число системного вызова РМ1МТГ. Далее выполняется системный вызов, стек очищается, и программа выполняет возврат. Остальные десять подпрограмм — от гоиг0 до гоо18 — загружают адреса своих сообщений Примеры 809 в регистр АХ, а затем переходят ко второй строке егоц1, выводят сообщения и завершают подпрограмму.