Goto... Search.. Hext Change.. Follou Previous 3 глава




;Чйсло шагов в цикле

fill:

;Отправим число в массив

;Инкремент числа-заполнителя

; Смещение в массиве к следующему слову

;На метку fill (CX раз)

Повышение эффективности достигается за счет того, что команда за­несения числа в элемент массива оказывается короче (так как в неё не входит адрес массива) и выполняется быстрее, так как этот адрес не надо каждый раз считывать из памяти.

Базово-индексная адресация со смещением. Адресуется память (байт или слово). Относительный адрес операнда определяется как сумма со­держимого двух регистров и смещения.

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

Пусть в сегменте данных определен массив из 24 байтов, в котором записаны коды латинских и русских символов верхнего ряда клавиатуры:

Sims db "QWERTYUIOPO"

db "ЙЦУКЕНГШЩЗХЪ"

Последовательность команд

;Число байтов в строке

mov BX,12

mov SI,6

mov DL,syms[BX][SI]

загрузит в регистр DL элемент с индексом 6 из второго ряда, т.е. код ASCII буквы Г. Тот же результат можно получить, загрузив в один из регистров не индекс, а адрес массива:

mov BX,offset sym

mov SI, 6

mov DL,12[BX][SI]



Глава 2


Основы программирования



 


 

2.6. Переходы

Как уже отмечалось в гл. 1, присущий процессору алгоритм выполне­ния программы заставляет его выполнять команды программы друг за дру­гом, в том порядке, как они были описаны в исходном тексте программы и содержатся в выполнимом модуле. Однако часто программисту требует­ся нарушить этот порядок, заставив процессор обойти некоторый участок программы, перейти на выполнение другой ветви или передать управле­ние подпрограмме, имея в виду после ее завершения вернуться на пре­жнее место. Все эти операции осуществляются с помощью команд пере­ходов. Переходы разделяются на безусловные, когда передача управления в другую точку программы осуществляется в безусловном порядке, неза­висимо ни от каких обстоятельств, и условные, осуществляемые или не осуществляемые в зависимости от тех или иных условий: результатов срав­нения, анализа, поиска и т.п. Безусловные переходы подразделяются на собственно переходы (без возврата в точку перехода) и вызовы подпрог­рамм (с возвратом после завершения подпрограммы).

Операции переходов и вызовов подпрограмм, помимо их практичес­кой ценности, представляют значительный методический интерес, так как затрагивают основу архитектуры процессора — сегментную адреса­цию памяти. Многочисленные разновидности команд переходов и вызо­вов обязаны своим существованием не столько потребностям практичес­кого программирования, сколько принципиальным архитектурным осо­бенностям процессора. Отчетливое понимание этих особенностей и, соответственно, условий применения и возможностей рахчичных опера­ций переходов необходимо не только при использовании языка ассемб­лера, но и при программировании на языках высокого уровня, где иногда используется несколько иная терминология, но существо дела остается без изменения.

Безусловные переходы осуществляются с помощью команды jmp, которая может использоваться в 5 разновидностях. Переход может быть:

прямым коротким (в пределах -128...+127 байтов);

прямым ближним (в пределах текущего сегмента команд);

прямым дальним (в другой сегмент команд);

косвенным ближним (в пределах текущего сегмента команд через ячейку

с адресом перехода);

косвенным дальним (в другой сегмент команд через ячейку с адресом

перехода).

Рассмотрим последовательно структуру программ с переходами раз­ного вида.

Прямой короткий (short) переход. Прямым называется переход, в ко­манде которого в явной форме указывается метка, на которую нужно пе­рейти. Разумеется, эта метка должна присутствовать в том же программ­ном сегменте, при этом помеченная ею команда может находиться как до, так и после команды jmp. Достоинство команды короткого перехода заключается в том, что она занимает лишь 2 байт памяти: в первом байте записывается код операции (EBh), во втором — смещение к точке пере­хода. Расстояние до точки перехода отсчитывается от очередной команды,


т.е. команды, следующей за командой jmp. Поскольку требуется обеспе­чить переход как вперед, так и назад, смещение рассматривается, как число со знаком и, следовательно, переход может быть осуществлен мак­симум на 127 байт вперед или 128 байт назад. Прямой короткий переход оформляется следующим образом:

code segment

jmp short go;Код ЕВ dd
go:

code ends

Если программа транслируется ассемблером TASM, и в строке вызова транслятора указано, что трансляция следует выполнить в два прохода

tasm /m2 p,p,p

то описатель short можно опустить, так как ассемблер сам определит, что расстояние до точки перехода укладывается в короткий переход, даже если метка go расположена после строки с командой jmp. При использо­вании транслятора MASM указание описателя short обязательно (если метка go расположена после команды jmp). Здесь проявляются незначительные различия ассемблеров разных разработчиков.

В комментарии указан код команды; dd (от displacement, смещение) обозначает байт со смещением к точке перехода от команды, следующей за командой jmp.

При выполнении команды прямого короткого перехода процессор при­бавляет значение байта dd к младшему байту текущего значения указателя команд IP (который, как уже говорилось, всегда указывает на команду, следующую за выполняемой). В результате в IP оказывается адрес точки перехода, а предложения, находящиеся между командой jmp и точкой перехода, не выполняются. Между прочим, конструкция с прямым перехо­дом вперед часто используется для того, чтобы обойти данные, которые по каким-то причинам желательно разместить в сегменте команд.

Прямой ближний (near), или внутрисегментный переход. Этот переход отличается от предыдущего только тем, что под смещение к точке пере­хода отводится целое слово. Это дает возможность осуществить переход в любую точку 64-кбайтного сегмента.

code segment

jmp go;Код Е9 dddd
go:

code ends



Глава 2


Основы программирования



 


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

При выполнении команды прямого ближнего перехода процессор должен прибавить значение слова dddd к текущему значению указателя команд IP и сформировать тем самым адрес точки перехода. Что пред­ставляет собой смещение dddd? Какая это величина, со знаком или без знака' Если рассматривать смещение как величину без знака, то переход будет возможен только вперед, что, конечно, неверно. Если же смещение является величиной со знаком, то переход возможен не более, чем на полсегмента вперед или на полсегмента назад, что тоже неверно. В дей­ствительности, рассматривая вычисление адреса точки перехода, следует иметь в виду явление оборачивания, суть которого можно кратко выра­зить такими соотношениями:

FFFFh+0001h=OOOOh

OOOOh-0001h=FFFFh j

i

Если последовательно увеличивать содержимое какого-либо регистра или ячейки памяти, то, достигнув верхнего возможного предела FFFFh, число «перевалит» через эту границу, станет равным нулю и продолжит нарастать в области малых положительных чисел (1, 2, 3, и т.д.). Точно так же, если последовательно уменьшать некоторое положительное чис­ло, то оно, достигнув нуля, перейдет в область отрицательных (или, что то же самое, больших беззнаковых) чисел, проходя значения 2, 1, О, FFFFh, FFFEh и т.д.

Таким образом, при вычислении адреса точки перехода смещение следует считать числом без знака, но при этом учитывать явление обора­чивания. Если команда jmp находится где-то в начале сегмента команд, а смещение имеет величину порядка 64 К, то переход произойдет вперед, к концу сегмента. Если же команда находится в конце сегмента команд, а смещение имеет ту же величину порядка 64 К, то для определения точки перехода надо двигаться по сегменту вперед, дойти до его конца и про­должать перемещаться от начала сегмента по-прежнему вперед, пока не будет пройдено заданное в смещении число байтов. Для указанных усло­вий мы попадем в точку, находящуюся недалеко от команды jmp со сто­роны меньших адресов.

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

Прямой дальний (far), или межсегментный переход. Этот переход позво­ляет передать управление в любую точку любого сегмента. При этом, оче­видно, предполагается, что программный комплекс включает несколько сегментов команд. Команда дальнего перехода имеет длину 5 байт и вклю­чает, кроме кода операции EAli, еще и полный адрес точки перехода, т.е.


сегментный адрес и смещение. Транслятору надо сообщить, что этот пе­реход — дальний (по умолчанию команда jmp транслируется, как коман­да ближнего перехода). Это делается с помощью описателя far ptr, указы­ваемого перед именем точки перехода.

codel segment

assume CS:codel;Сообщим транслятору, что это сегмент команд

jmp far ptr go;Код EA dddd ssss

codel ends

code 2 segment

assume CS:code2;Сообщим транслятору, что это сегмент команд

go:

code2 ends

Метка go находится в другом сегменте команд этой двухсегментной программы. В коде команды ssss — сегментный адрес сегмента code2, a dddd — смещение точки перехода go в сегменте команд code2.

Заметим, что при наличии в программе нескольких сегментов команд, каждый из них необходимо предварять директивой ассемблера assume СВ:1шя_сегмента, которая сообщает транслятору о том, что начался оче­редной сегмент команд. Это поможет транслятору правильно обрабаты­вать адреса меток, встречающихся в этом сегменте.

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

Все виды прямых переходов требуют указания в качестве точки пере­хода программной метки. С одной стороны, это весьма наглядно; просмат­ривая текст программы, можно сразу определить, куда осуществляется переход. С другой стороны, такой переход носит статический характер — его нельзя настраивать по ходу программы. Еще более серьезный недоста­ток прямых переходов заключается в том, что они не дают возможность Перейти по известному абсолютному адресу, т.е. не позволяют обратиться ни к системным средствам, ни вообще к другим загруженным в память Программам (например, резидентным). Действительно, программы опе­рационной системы не имеют никаких меток, так как метка — это атри-



Глава 2


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



 


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

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


Глава 2


Основы программирования



 


go, адрес которой находится в ячейке go_addr в сегменте данных, пере­ход с использованием косвенной регистровой адресации может выглядеть следующим образом:

mov BX,offset go_addr jmp [BX]

;B ВХ смещение поля с адресом перехода;Переход в точку go

Особенно большие возможности предоставляет методика косвенного перехода с использованием базово-индексной адресации через пары ре­гистров, например, [BX][SI] или [BX][DI]. Этот способ удобен в тех случа­ях, когда имеется ряд альтернативных точек перехода, выбор которых за­висит от некоторых условий. В этом случае в сегменте данных создается не одно поле с адресом, а таблица адресов переходов. В базовый регистр ВХ загружается адрес этой таблицы, а в один из индексных регистров — оп­ределенный тем или иным способом индекс в этой таблице. Переход осу­ществляется в точку, соответствующую заданному индексу. Структура про­граммы, использующий такую методику, выглядит следующим образом:

code segment mov BX,offset go_tbl mov SI,4 jmp [BX][SIj gol: go2: go3: code ends data segment go_tbl label word gol_addrdw gol go2_addrdw go2 go3_addrdw go3 data ends

;3агружаем в ВХ базовый адрес таблицы

вычисленное каким-то

;образом смещение в таблице

;Если индекс =4, переход в точку go3

;1-я точка перехода;2-я точка перехода;3-я точка перехода

;Таблица адресов переходов

;Адрес первой альтернативной

;точки перехода

;Адрес второй альтернативной

;точки перехода

;Адрсс третьей альтернативной

;точки перехода

Приведенный пример носит условный характер; в реальной програм­ме индекс, помещаемый в регистр SI, должен вычисляться по результа­там анализа некоторых условий.

Наконец, существует еще одна разновидность косвенного перехода, в котором не используется сегмент данных, а адрес перехода помещается непосредственно в один из регистров общего назначения. Часто такой


переход относят к категории прямых, а не косвенных, однако это вопрос не столько принципа, сколько терминологии.

Применительно к обозначениям последнего примера такой переход будет выглядеть, например, следующим образом:

mov BX,oflset gol jmp BX

Здесь, как и в предыдущих вариантах, имеется возможность вычисле­ния адреса перехода, однако нельзя этот адрес индексировать.

Косвенный дальний (межсегментный) переход. Как и в случае ближ­него перехода, переход осуществляется по адресу, который содержится в ячейке памяти, однако эта ячейка имеет размер 2 слова, и в ней содер­жится полный (сегмент плюс смещение) адрес точки перехода. Програм­ма в этом случае должна включать по меньшей мере два сегмента команд. Структура программы с использованием косвенного дальнего перехода может выглядеть следующим образом:

codel segment

assume CS:code 1,DS:data

jmp DS:go_addr; Код FF 2E dddd

codel ends code2 segment assume CS:code2

go: code 2 data

;Точка перехода в другом сегменте команд

ends segment

go_addr dd go Двухсловный адрес точки перехода

data

ends

Точка перехода go находится в другом сегменте команд этой двухсег-ментной программы. В коде команды dddd обозначает относительный ад­рес слова go_addr в сегменте данных. Ячейка go_addr объявляется дирек­тивой dd (define double, определить двойное слово) и содержит двухслов­ный адрес точки перехода; в первом слове содержится смещение go в сегменте команд codel, во втором слове сегментный адрес code2. Оба ком­понента адреса перехода могут быть вычислены и помещены в ячейку go_addr по ходу выполнения программы.

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



Глава 2


Основы программирования


S3


 


jmp DS:go_addr;Возможна имена сегмента

jmp dword ptr go_addr;Если поле go_addr объявлено

;операторами dw
jmp go_addi Характеристики ячейки должны

;быть известны

Для дальнего косвенного перехода, как и для ближнего, допустима адресация через регистр общего назначения, если в него поместить адрес поля с адресом перехода:

mov BX,offset go_addr jmp [BX]

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

2.7. Вызовы подпрограмм

Практически в любой программе, независимо от се содержания, встре­чаются участки, которые требуется выполнять (возможно, с небольшими изменениями) несколько раз по ходу программы. Такие повторяющиеся участки целесообразно выделить из общей программы, оформить в виде подпрограмм и обращаться к ним каждый раз, когда в основной програм­ме возникает необходимость их выполнения.

Подпрограмма, в зависимости от выполняемых ею функций, может требовать передачи из вызывающей программы определенных данных (на­зываемых аргументами, или параметрами), возвращать в вызывающую про­грамму результаты вычислений или обходиться и без того, и без другого.

Подпрограмма может быть оформлена в виде процедуры, и тогда имя этой процедуры будет служить точкой входа в подпрограмму:

drawline proc

; Подпрограмма -про цедура

ret endp

;Тело подпрограммы

;Команда возврата в вызывающую программу

drawlme

С таким же успехом можно обойтись без процедуры, просто пометив первую строку программы некоторой меткой:

drawline:; Под программа, начинающаяся с метки

;Тело подпрограммы

ret;Команда возврата в вызывающую программу Продолжение основной программы или;другие подпрограммы

В любом случае вызов подпрограммы осущестшшется командой call. Подпрограмма должна завершаться командой ret, служащей для возврата управления в ту точку, откуда подпрограмма была вызвана.

Вопросы использования подпрограмм, передачи в них параметров и возвращения результата будут рассмотрены в следующей главе. Здесь мы остановимся только на таких принципиальных архитектурных вопросах,


как механизм выполнения и возможности команд call и ret. При этом надо иметь в виду, что синтаксические особенности и закономерности исполь­зования команд call и jmp во многом совпадают, и значительная часть пояснений к командам перехода справедлива и для команд вызова.

Команда вызова подпрограммы call может использоваться в 4 разно­видностях. Вызов может быть:

прямым ближним (в пределах текущего сегмента команд);

прямым дальним (в другой сегмент команд);

косвенным ближним (в пределах текущего сегмента команд через ячей­ку с адресом перехода);

косвенным дальним (в другой сегмент команд через ячейку с адресом

перехода).

Рассмотрим последовательно перечисленные варианты.

code segment main proc call

Прямой ближний вызов. Как и в случае прямого ближнего перехода, в команде прямого вызова в явной форме указывается адрес (смещение) точки входа в подпрограмму; в качестве этого адреса можно использовать как имя процедуры, так и имя метки, характеризующей точку входа в подпрограмму. В код команды, кроме кода операции E8h, входит смеше­ние к вызываемой подпрограмме. В приведенном ниже примере подпрог­рамма оформлена в виде процедуры.

;Основная программа;Код Е8 dddd

sub

Подпрограмма;Код СЗ

main endp.

sub proc near

ret

sub endp code ends

Про цедура-программа находится в том же сегменте команд, что и вызывающая программа. В коде команды dddd обозначает смещение в сег­менте команд к точке входа в подпрограмму. При выполнении команды call процессор помещает адрес возврата (содержимое регистра IP) в стек выполняемой программы (рис. 2.16), после чего к текущему содержимому IP прибавляет dddd. В результате в IP оказывается адрес подпрограммы. Команда ret, которой заканчивается подпрограмма, выполняет обратную процедуру — извлекает из стека адрес возврата и заносит его в IP.

•\ Состояние стека после входа в подпрограмму

4 — Исходное состояние SP

Рис. 2.16. Участие стека в механизме вызова ближней подпрограммы.



Глава'2


Основы программирования



 


 


Участие стека в механизме вызова подпрограммы и возврата из нее является решающим. Поскольку в стеке хранится адрес возврата, под­программа, сама используя стек, например, для хранения промежуточ­ных результатов, обязана к моменту выполнения команды ret вернуть стек в исходное состояние. Команда ret, естественно, никак не анализирует состояние или содержимое стека. Она просто снимает со стека верхнее слово, считая его адресом возврата, и загружает это слово в указатель команд IP. Если к моменту выполнения команды ret указатель стека ока­жется смещенным в ту или иную сторону, команда ret по-прежнему будет рассматривать верхнее слово стека, как адрес возврата, и передаст по нему управление, что неминуемо приведет к краху системы.

; Основная программа far ptr subr;Код 9А dddd ssss
;Объявляем подпрограмму.;дальней;Код СВ — дальний возврат

Прямой дальний вызов. Этот вызов позволяет обратиться к подпрог­рамме из другого сегмента. В код команды, кроме кода операции 9Ah, входит полный адрес (сегмент плюс смещение) вызываемой подпрог­раммы. Обычно в исходном тексте программы с помощью описателя far ptr указывается, что вызов является дальним, хотя, если транслятор на­строен на трансляцию в два прохода, этот описатель не обязателен. Струк­тура программного комплекса, содержащая дальний вызов подпрограм­мы, может выглядеть следующим образом:

 

codel assume segment CS:codel
main proc call far
main codel endp ends
code 2 assume segment CS:code2
subr proc far
  ret
subr code 2 cndp ends

Процедура-подпрограмма находится в другом сегменте команд той же программы. В коде команды dddd обозначает относительный адрес точки входа в подпрограмму в ее сегменте команд, a ssss — ее сегментный адрес. При выполнении команды call процессор помещает в стек сначшга сегмен­тный адрес вызывающей программы, а затем относительный адрес возвра­та (рис. 2.17). Далее в сегментный регистр CS заносится ssss (у нас это значе­ние code2), а в IP — dddd (у нас это значение subr). Поскольку процедура-подпрограмма атрибутом far объявлена датьней, команда ret имеет код, отличный от кода аналогичной команды ближней процедуры и выполняет­ся по-другому: из стека извлекаются два верхних слова и переносятся в IP и CS, чем и осуществляется возврат в вызывающую программу, находящу­юся в другом сегменте команд. В языке ассемблера существует и явное мне­моническое обозначение команды дальнего возврата — retf.


 

^— Состояние стека после входа в подпрограмму

^— Исходное состояние SP Рис. 2.17. Участие стека в механизме вызова дальней подпрограммы.

Косвенный ближний вызов. Адрес подпрограммы содержится либо в ячейке памяти, либо в регистре. Это позволяет, как и в случае косвенного ближнего перехода, модифицировать адрес вызова, а также осуществлять вызов не с помощью метки, а по известному абсолютному адресу. Струк­тура программы с косвенным вызовом подпрограммы может выглядеть следующим образом:

code main
segment proc

;Основная программа



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-02-16 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: