Реклама:

В некоторых языках программирования существуют операторы выбора, позволяющие выбирать один из нескольких возможных вариантов действий в зависимости от численного значения переменной. Подобного рода многовариантное ветвление иногда оказывается полезным и в программах на языке ассемблера. Возьмем, к примеру, набор подпрограмм системных вызовов, объединенных в программе перехвата исключений SYS. Пример программирования многовариантного ветвления на языке ассемблера 8088 показан в коде программы jumptbl.s, представленном в листинге В.7.

Листинг В.7- Реализация многовариантного ветвления при помощи таблицы диспетчеризации

#iinclude ". ./syscalnr.h"

! 1

.SECT .TEXT

! 2

jumpstrt:

! 3

PUSH strt

! 4

MOV BP.SP

! 5

PUSH PRINTF

! 6

SYS

! 7

PUSH GETCHAR

! 8

1: SYS

! 9

CMP AX,5

! 10

JL 8f

! 11

CMPB AL.'0'

! 12

JL lb

! 13

CMPB AL,'9'

! 14

JLE 2f

! 15

MOVB AL,'9'+l

! 16

2: MOV BX.AX

! 17

AND BX.OXf

! 18

SAL BX.l

! 19

CALL tbl(BX)

! 20

JMP lb

! 21

8: PUSH 0

! 22

PUSH EXIT

! 23

SYS

! 24

routO: MOV AX.mesO

! 25

JMP 9f

! 26

routl: MOV AX.mesl

! 27

JMP 9f

! 28

rout2: MOV AX,mes2

! 29

JMP 9f

! 30

rout3: MOV AX,mes3

! 31

JMP 9f

! 32

rout4: MOV AX,mes4

! 33

JMP 9f

! 34

rout5: MOV AX,mes5

! 35

JMP 9f

! 36

rout6: MOV AX.mes6

! 37

JMP 9f

! 38

rout7: MOV AX,mes7

! 39

JMP 9f

! 40

rout8: MOV AX,mes8

! 41

JMP 9f

! 42

erout: MOV AX,ernes

! 43

9: PUSH AX

! 44

PUSH PRINTF

! 45

SYS

! 46

ADD SP.4

! 47

RET

! 48

.SECT .DATA

! 49

tbl: .WORD routO,routl,rout2,rout3,rout4,rout5,

 

rout6,rout7,rout8,rout8,erout

! 50

mesO: .ASCIZ "This is a zero.Xn"

! 51

mesl: .ASCIZ "How about a one.\n"

! 52

Таблицы диспетчеризации

Программа начинается с вывода символьной строки, метка которой (strt) приглашает пользователя ввести восьмеричную цифру (строки 4-7 кода). Затем из файла стандартного ввода считывается символ (строки 8 и 9). Если значение АХ оказывается меньше 5, программа интерпретирует это как маркер конца файла, переходит к метке 8 в строке 22 и завершается с кодом состояния 0.

Если введенный символ не является маркером конца файла, исследуется введенный символ в регистре AL. Любой символ, меньший цифры 0, считается разделителем и при переходе в строке кода 13 игнорируется; после чего извлекается следующий символ. Любой символ, больший цифры 9, считается неверным. В строке 16 он преобразуется в ASCII-символ двоеточия, который в последовательности ASCII-символов идет сразу после цифры 9.

Таким образом, в строке 17 в регистре АХ находится значение в диапазоне между цифрой 0 и двоеточием. Это значение копируется в регистр ВХ. В строке 18 команда AND маскирует все биты, кроме четырех младших, в результате остается число между 0 и 10 (это связано с тем, что нулю соответствует ASCII-код 0x30). Так как в таблице мы собираемся провести индексирование слов, а не байтов, значение ВХ умножается на 2 путем сдвига влево в строке 19.

В строке 20 находится команда вызова. Действительный адрес определяется прибавлением значения ВХ к численному значению метки tbl, а содержимое этого объединенного адреса загружается в счетчик команд PC.

Программа выбирает одну из десяти подпрограмм в зависимости от символа, извлекаемого из стандартного ввода. Каждая из этих подпрограмм размещает в стеке адрес того или иного сообщения, а затем переходит к общему для всех вызову системной подпрограммы _PRINTF.

Чтобы разобраться в происходящем, следует иметь в виду, что команды JMP и CALL загружают в регистр PC некий адрес текстового сегмента. Этот адрес представляет собой двоичное число, а в ходе ассемблирования все адреса заменяются соответствующими двоичными значениями. Двоичные значения, в свою очередь, помогают инициализировать массив в сегменте данных, что и делается в строке 50. Таким образом, массив, начинающийся с метки tbl, содержит начальные адреса подпрограмм routO, routl, rout2 и т. д., по два байта в каждом. Наличие 2-байтовых адресов объясняет необходимость в сдвиге на 1 бит, произведенном в строке 19. Таблицы такого типа часто называют таблицами диспетчеризации.

Механизм работы таких программ демонстрирует подпрограмма erout (строки 43-48 кода). Она обрабатывает числа, выходящие за пределы допустимого диапазона. Во-первых, в строке 43 в стек помещается адрес сообщения (в АХ). Затем в стек отправляется число системного вызова _PRINTF. Далее выполняется системный вызов, стек очищается, и программа выполняет возврат. Остальные десять подпрограмм - от routO до rout8 - загружают адреса своих сообщений в регистр АХ, а затем переходят ко второй строке erout, выводят сообщения и завершают подпрограмму.

Один из способов адаптировать программу к таблицам диспетчеризации - изменить ее таким образом, чтобы из вводимых символов формировалось осмысленное сообщение. К примеру, все символы, кроме восьмеричных цифр, могут составить сообщение об ошибке.

Обработка символьных строк и строковые команды || Оглавление || Буферизованный и произвольный доступ к файлам