Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Финогенов-основы_языка_ассемблера.doc
Скачиваний:
46
Добавлен:
17.09.2019
Размер:
3.35 Mб
Скачать

Глава 2

Основы^рограттрования

79

бут исходного текста программы, а программы операционной системы транслировались не нами и присутствуют в компьютере только в виде вы­полнимых модулей. А вот адреса каких-то характерных точек системных программ определить можно, хотя бы из векторов прерываний. Для обра­щения по абсолютным адресам надо воспользоваться командами косвен­ных переходов, которые, как и прямые, могут быть ближними и дальними. Косвенный ближний (внутрисегментный) переход. Б отличие от команд прямых переходов, команды косвенных переходов могут использовать различные способы адресации и, соответственно, иметь много разных вариантов. Общим для них является то, что адрес перехода не указывается явным образом в виде метки, а содержится либо в ячейке памяти, либо в одном из регистров, Это позволяет при необходимости модифицировать адрес перехода, а также осуществлять переход по известному абсолютно­му адресу. Рассмотрим случай, когда адрес перехода хранится в ячейке сегмента данных. Если переход ближний, то ячейка с адресом состоит из одного слова и содержит только смещение к точке перехода.

code segment

jmp DS:go_addr ;Код FF 26 dddd go: ;Точка перехода

code ends data segment

go_addr dw go ;Адрес перехода (слово) data ends

Точка перехода go может находиться в любом месте сегмента команд. В коде команды dddd обозначает относительный адрес слова go_addr в сегменте данных, содержащем эту ячейку.

В приведенном фрагменте адрес точки перехода в слове go_addr задан однозначно указанием имени метки go. Такой вариант косвенного пере­хода выполняет фактически те же функции, что и прямой (переход по единственному заданному заранее адресу), только несколько более запу­танным образом. Достоинства косвенного перехода будут более наглядны, если представить, что ячейка go_addr поначалу пуста, а по ходу выполне­ния программы в нее, в зависимости от каких-либо условий, помещается адрес той или иной точки перехода:

mov mov mov

go_addr,gol go_addr,go2 go_addr,go3

Разумеется, приведенные выше команды должны выполняться не друг за другом, а альтернативно. В этом случае создается возможность перед выполнением перехода определить или даже вычислить адрес перехода, требуемый в данных условиях.

Ассемблер допускает различные формы описания косвенного перехо­да через ячейку сегмента данных:

jmp DS:go_addr jmp word ptr go_addr jmp go_addr

В первом варианте, использованном в приведенном выше фрагменте, указано, через какой сегментный регистр надлежит обращаться к ячейке go_addr, содержащей адрес перехода. Здесь допустима замена сегме'нта, если сегмент с ячейкой go_addr адресуется через другой сегментный ре­гистр, например, ES или CS.

Во втором варианте подчеркивается, что переход осуществляется через ячейку размером в одно слово и, следовательно, является ближним. Ячейка go_addr могла быть объявлена с помощью директивы dd и содержать пол­ный двухсловный адрес перехода, требуемый для реализации дальнего пе­рехода. Однако сю можно воспользоваться и для ближнего перехода. Описа­тель word ptr перед именем ячейки с адресом перехода заставляет трансля­тор считать, что она имеет размер 1 слово (независимо от того, как она была объявлена), и что переход, следовательно, является ближним.

Наконец, возможен и самый простой, третий вариант, который со­впадает по форме с прямым переходом, но, тем не менее, является кос­венным, так как символическое обозначение go_addr является именем поля данных, а не программной меткой. В этом варианте предполагается, что сегмент, в котором находится ячейка go_addr, адресуется по умолча­нию через регистр DS, хотя, как и во всех таких случаях, допустима заме­на сегмента. Тип перехода (ближний или дальний) определяется, исходя из размера ячейки go_addr. Однако этот вариант не всегда возможен. Для его правильной трансляции необходимо, чтобы транслятору к моменту обработки предложения

jmp go_addr

было уже известно, что собой представляет имя go_addr. Этого можно добиться двумя способами. Первый — расположить сегмент данных до сег­мента команд, а не после, как в приведенном выше примере. Второй — заставить транслятор обрабатывать исходный текст программы не один раз, как он это делает по умолчанию, а несколько. Число проходов для трансля­тора TASM можно задать при его вызове с помощью ключа /т#, где # — требуемое число проходов. В нашем случае достаточно двух проходов.

В приведенных примерах адрес поля памяти с адресом точки перехода задавался непосредственно в коде команды косвенного перехода. Однако этот адрес можно задать и в одном из регистров общего назначения (ВХ, SI или DI). Для приведенного выше примера косвенного перехода в точку

so