Загрузка исполнительного адреса




Команда загрузки действительного адреса LEA очень похожа на команду MOV. Но вместо пересылки данных из ячейки памяти в регистр команда LEA загружает в регистр адрес двнных. Так как набор команд микропроцессора 8088 разрешает иметь в команде только один адрес памяти, в качестве приемника результата всегда указывается регистр. Команда LEA может ссылаться на операнд источника с помощью любого типа адресации, который можно указать байтом mod=r/m.

Во многих случаях команда LEA идентична команде MOV с непосредственным операндом. Команды

MOV BX, OFFSET EXWORD
LEA BX, EXWORD

делают одно и то же. Первая команда - это непосредственнаяпересылка, которая использует смещение переменной EXWORD. Оператор OFFSET говорит ассемблеру о том, что в регистр BX надо загрузить смещение адресного значения (все адресные значения имеют две части - сегмент и смещение) переменной EXWORD. Команда LEA вычисляет действительный адрес переменной EXWORD и помещает его в регистр BX. В этом случае команды выполняют одинаковые действия.

Но если бы программа загружала в регистр BX адрес десятого байта массива, на который указывает регистр DI, команда LEA выглядела бы следующим образом

LEA BX, 10[DI]

Микропроцессор выполнил бы вычисление адреса, используя информацию из байта mod=r/m в точности, как в случае команды MOV. Затем он поместил бы вычисленное смещение, а не данные, по этому адресу в регистр BX. Аналогичной команде с непосредственнымоперандом MOV, которая могла бы выполнять ту же функцию, нет. У ассемблера здесь нет способа определения непосредственного значения, так как адрес неизвестен во время ассемблирования.

Загрузка указателя

Поскольку механизм адресации микропроцессора 8088 требует определения как сегмента, так и смещения каждой переменной, желательно загрузить всю эту адресную информацию единственной командой. Эту работу выполняют команды LDS и LES. Команда

LDS SI, EXDWORD

загружает регистровую пару DS:SI значениями сегмента и смещения, содержащимися в переменной EXDWORD. Команда LDS загружает в регистр SI значение смещения, расположенное по адресу EXDWORD, а в регистр DS - значение сегмента, расположенное по адресу EXDWORD+2. Команда LDS одна загружает два 16=битовых регистразначением указателя, взятого из некоторой ячейки памяти. Так как эта команда устанавливает и сегментный регистр, и регистр смещения, программа может сразу адресоваться к объекту, на который этот адрес указывает. Программа может организовать указатель из сегмента исмещения во время ассемблирования с помощью оператора DD, который порождает 32=битовое поле данных. Если операндом DD является адресное выражение, двухсловное поле будет содержать сегмент и смещение адресного значения в том же самом формате, который используется в командах LDS и LES.

Команда LES идентична LDS, за исключением того, что оназагружает регистр ES. С помощью одной команды записать значения сегмента и смещения нельзя. Программа должна записывать значение указателя двумя командами пересылки слов, а не одной командойзаписи указателя. Это приемлемо, так как программа обычно читает указатель гораздо чаще, чем записывает его. Обычно программа записывает указатель один раз, во время инициализации, и можетбыть, иногда меняет его во время смены режимов работы системы. А вот читается указатель, вероятно, достаточно часто. В последующих главах есть примеры, в которых значения указателей и читаются, изаписываются.

Пересылка флагов

Набор команд микропроцессора 8088 имеет команды LAHF и SAHF в первую очередь для совместимости с набором команд микропроцессора 8080. Команда LAHF берет 8 младших бит регистра флагов - а эти флаги совпадают с флагами микропроцессора 8080 - и засылает их в регистр AH. Команда SAHF действует наоборот, младший байт регистра флагов загружает из регистра AH.

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

Перекодировка

Команда перекодировки XLAT преобразует информацию из одногопредставления в другое. Команда XLAT преобразует значение в регистре AL в другое значение, выбираемое из таблицы, на которую указывает регистр BX. На Фиг.4.4 схематически показано, как работает эта команда. Регистр BX вместе с выбранным сегментным регистром определяет точку начала таблицы перекодировки в памяти. К этому адресу таблицы команда прибавляет содержимое регистра AL, значение между 0 и 255. Данные, расположенные по этому адресу, команда XLAT пересылает в регистр AL. Команда XLAT выполняет операцию просмотра таблицы.

Команду XLAT хорошо использовать при кодировании и декодировании текстовых данных. С помощью этой команды программа может организовать простую замену кодов символов. В следующем примере десять символов кода ASCII от 0 до 9 перекодируются в целях передачи. Этот метод может использоваться в системе дляперекодировки информации, передаваемой из одной машины в другую. Когда данные принимаются, другая программа возвращает закодированные символы к их первоначальному виду. На Фиг. 4.5 демонстрируется кодировка и декодировка.

На Фиг.4.5 изображены две таблицы перекодировки, одна для передачи, а другая для приема. Чтобы передать значение 5, программа находит значение 5 в таблице передачи (а), из которой извлекает значение 6, которое передает. Когда это значение принимается, программа декодирования ищет 6 в таблице приема (b), чтобы перекодировать его в истинное значение 5.

На Фиг. 4.6 показана подпрограмма, которая производит это декодирование. Подпрограмма перекодирования читает начальное значение из порта ввода-вывода, и возвращает кодированное или декодированное значение в вызывающую программу через регистр AL. Одна и та же программа выполняет как кодирование, так и декодирование, меняя таблицы кодировки.

С начала подпрограмма читает данные из вводного порта 40H в регистр AL. Затем она вычитает значение "0" в коде ASCII из значения данных, чтобы получить цифровое значение. Это означает, что символ "0" дает значение 0 в регистре AL, символ "1" дает 1, и т.д. Команда LDS загружает указатель нужной таблицы в пару регистров DS:BX. Загружая этот указатель из ячейки памяти - в

Microsoft (R) Macro Assembler Version 5.00 1/1/80 04:00:38Фиг. 4.6 Пример перекодировки Page 1-1 PAGE,132 TITLE Фиг. 4.6 Пример перекодировки0000 CODE SEGMENT ASSUME CS:CODE, DS:CODE ; Эта программа вводит значение из порта 040H и; декодирует его, используя таблицу перекодировки.; Так как одна и та же программа используется как для; кодировки, так и декодировки, указатель TABLE_POINTER; указывает на соответсвующую таблицу перекодировки.; Вызывая подпрограмму, необходимо установить; этот указатель на соответствующую таблицу.0000 TRANSLATE PROC NEAR; Подпрограмма TRANSLATE0000 E4 40 IN AL,040H; Ввод значения из порта0002 2C 30 SUB AL,"0"; Значение относительно символа 0,; т.е. относительно начала таблицы0004 C5 1E 000A R LDS BX,TABLE_POINTER; (DS,BX) указывает на таблицу0008 D7 XLAT XMIT_TABLE; Перекодировка числа0009 C3 RET000A 000E ---- R TABLE_POINTER DD XMIT_TABLE000E 35 37 39 31 33 36 38 XMIT_TABLE DB '5791368024' 30 32 340018 37 33 38 34 39 30 35 RECV_TABLE DB '7384905162' 31 36 320022 TRANSLATE ENDP0022 CODE ENDS END Фиг. 4.6 Пример перекодировки

примере TABLE_POINTER - подпрограмма может использовать любую таблицу перекодировки. В этой программе имеются две табдицы, одна из них для передачи, названная XMIT_TABLE, которая соответствует Фиг.4.5(а), другая - таблица приема, названная RECV_TABLE, - соответствует Фиг.4.5(б). Перед вызовом подпрограммы головная программа должна записать нужный адресный указатель в переменную TABLE_POINTER. Если головная программа принимает коды, она должна поместить адрес таблицы RECV_TABLE в переменную TABLE_POINTER. Заметим, что эта подпрограмма может проделать любую перекодировку, поскольку таблицу перекодировки назначает вызывающая программа.

Команда XLAT выполняет перекодировку по таблице, на которую указывает пара регистров DS:BX. В регистре AL находится значение между 0 и 9. Команда XLAT складывает это значение с содержимым указателя и загружает перекодированное значение в регистр AL. Команда RET возвращает управление в вызывающую программу. Другим обычным случаем использования команды XLAT является смена кода представления символов в одной машине на код представления в другой машине. IBM PC, работает в коде ASCII, а большинство машин фирмы IBM используют код EBCDIC (Extended Binary=Coded=Decimal Interchange Code - расширенный двоично=кодированный десятичный код обмена информации). Чтобы связываться с такими машинами, в программе надо перекодировать символы, и команда XLAT естественным образом подходит для этой функции.

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

Операции со стеком

В гл.3 обсуждалось, как реализован стек в микропроцессоре 8088. Микропроцессор 8088 адресует стек с помощью регистровой пары SS:SP. Помещение объектов в стек приводит к тому, что он растет в сторонуменьших адресов памяти. Стек, кроме всего прочего, служит и длязапоминания адресов возврата из подпрограмм. В этом разделе рассматриваются некоторые команды, которые непосредственно работают со стеком.

Фиг.4.7 иллюстрирует ассемблированные стековые команды. Мнемоника команд очевидна; за кодами операций PUSH и POP следует имя регистра для указания операнда. Единственным исключением является помещение и извлечение из стека регистра флагов, которые используют мнемонику PUSHF и POPF соответственно. Содержимое любой ячейки памяти, которую программа может адресовать, используя возможные способы адресации, также может быть помещено или извлечено из стека.

При любых действиях со стеком в микропроцессоре 8088 базовой единицей информации является 16-битовое слово. Длина любого объекта, помещаемого в стек либо извлекаемого из стека, составляет одно или несколько слов. Байтовых команд, связанных с засылкой данных или извлечением их из стека, не существует. Если, например, программе необходимо сохранить содержимое регистра AL а стеке, она должна поместить содержимое регистра AX, так как не существует способа сохранения только содержимого регистра AL.

Основное назначение стека - временное хранение информации. Как мы уже видели, стек используется для сохранения адреса возврата; программа также может сохранять данные. Если программа хочет использовать регистр, пусть даже сохранить текущие данные, она может послать значение этого регистра в стек. Эти данные сохраняются в стеке и позже могут быть восстановлены. Например,

Microsoft (R) Macro Assembler Version 5.00 1/1/80 04:00:43Фиг. 4.7 Операции со стеком Page 1-1 PAGE,132 TITLE Фиг. 4.7 Операции со стеком0000 CODE SEGMENT ASSUME CS:CODE,DS:CODE0000 EXWORD LABEL WORD0000 50 PUSH AX; Поместить регистр в стек0001 56 PUSH SI0002 0E PUSH CS; Можно поместить в стек сегментный регистр0003 FF 36 0000 R PUSH EXWORD; Можно также поместить в стек ячейку памяти0007 8F 06 0000 R POP EXWORD; Можно извлечь то, что в помещено в стек000B 07 POP ES; Можно извлечь в другое место000C 5F POP DI000D 5B POP BX000E 9C PUSHF; Другая мнемоника для флагов000F 9D POPF;----- Пример, демонстрирующий передачу параметров0010 50 PUSH AX0011 53 PUSH BX0012 51 PUSH CX0013 52 PUSH DX0014 E8 0017 R CALL SUBROUTINE; Передача управления;...; Продолжение программы0017 SUBROUTINE PROC NEAR0017 8B EC MOV BP, SP; Занесение в BP адреса стека0019 8B 46 02 MOV AX, [BP+2]; Выборка последнего параметра (DX)001C 8B 5E 04 MOV BX, [BP+4]; Выборка третьего параметра (CX)001F 8B 4E 06 MOV CX, [BP+6]; Выборка второго параметра (BX)0022 8B 56 08 MOV DX, [BP+8]; Выборка первого параметра (AX);...0025 C2 0008 RET 8; Возврат с уничтожением поля параметров0028 SUBROUTINE ENDP0028 CODE ENDS END Фиг. 4.7 Операции со стеком

программе нужно ввести код из порта ввода-вывода 3DAH, а в регистре DX находятся важные данные. Следующая последовательность команд

PUSH DXMOV DX, 3DAHIN AL, DXPOP DX

сохраняет регистр DX в стеке на то время, пока он нужен впрограмме для выполнения команды IN.

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

Помните о том, что стек - это структура типа LIFO. Если в вашей программе выполняется последовательность команд

PUSH BXPUSH CXPOP BXPOP CX

то результирующим эффектом будет обмен значений в регистрах BX и CX. Только тот факт, что в команде PUSH был указан регистр BX, не означает, что команда POP, указывающая на тот же регистр, восстанавливает первоначальное содержимое регистра BX. Еще одним важным моментом является то, что команды PUSH и POP должны быть сбалансированы, т.е. каждой команде PUSH должна соответствовать команда POP. Точно так же, как и в случае скобок в арифметическом выражении, если посылки и извлечения из стека не сбалансированы, результаты будут неверны. Более того, несбалансированные команды PUSH/POP обычно приводят к возврату из подпрограмм по адресу значения данных, а не значения указателя команд из-за того, что микропроцессор 8088 записывает в стек адрес возврата. Обычно это вынуждает микропроцессор выполнять программу, которую программист никогда не писал. Поэтому баланс стековых команд обязателен. Будьте особенно внимательны в тех случаях, когда в программе есть условный переход вокруг стековых операций; можно легко выпустить из виду один из вариантов выполнения, что оставит стек несбалансированным.

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

MOV AX,CS;переслать значение регистра CS в регистр AXMOV DS,AX;загрузить это значение в регистр DS

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

PUSH CS; регистр CS поместить в стекPOP DS;

поместить это значение в регистр DS. Результирующий эффект этой последовательности команд тот же, регистр DS загружается из регистра CS. Здесь длина программы - всего два байта, и к тому же не требуется промежуточный регистр. Однако эти две команды занимают больше времени, так как нужны дополнительные циклы чтения и записи в стек. Это - метод потери в скорости выполнения ради уменьшения размера объектного кода.

Передача параметров

Стек также служит удобным местом для передачи информации в подпрограммы и из них. Обычно программа передает параметры в подпрограмму, помещая их в регистры, однако в некоторых случаях число параметров превышает размеры регистрового пространства. В таких случаях програииа может поместить параметры в стек до выполнения команды CALL (вызов подпрограммы). Как мы увидим в гл. 10, стек является единственным средством передачи параметров в подпрограммы, написанные на языке ассемблера, из языков высокого уровня Бейсик и Фортран.

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

MOV BP, SP

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

Конструкторы микропроцессора 8088 определенно помнили об описанном выше методе передачи параметров, так как при доступе к данным регистр BP использует по умолчанию регистр стекового сегмента SS в качестве сегментного регистра. Во всех других нормальных случаях доступа к данным микропроцессор использует регистр DS. Поскольку стек находится в стековом сегменте, регистровую пару SS:BP очень естественно использовать для адресации информации в стеке.

На Фиг. 4.7 изображен пример, демонстрирующий использование регистра BP для доступа к параметрам, переданным через стек. В этом примере головная программа перед выполнением команды CALL поместила четыре слова в стек. Подпрограмма загружает в BP указатель данных в стеке. Заметим, что смещения, используемые для доступа к данным в стеке, учитывают тот факт, что адрес возврата также был записан в стек в результате выполнения команды CALL.

В подпрограмме этого примера в вершине стека лежит адрес возврата, и регистр BP содержит смещение этой ячейки. Двумя байтами ниже в стеке лежит помещенный последним параметр, регистр DX; далее, через двухбайтовые интервалы - регистры CX, BX и AX. Таким образом, правильным адресом для чтения параметра, содержащегося в регистре DX, будет [BP+2], а другие адреса следуют через двухбайтовые интервалы. В данном примере значение, находившееся в регистре DX, попадает в регистр AX, CX в BX и т.д.

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

Многим подпрограммам в течение их выполнения также необходима локальная память, и подпрограммы могут динамически расположить ее в стеке. Всякий раз, когда программа вызывается, она может вычесть размер этой области памяти из содержимого указателя стека. Так как стек растет по направлению к младшим адресам, вычитание числа из регистра SP идентично помещению в стек такого же количества данных - за исключением тех данных, которые не инициализированы. После этого подпрограмма может использовать регистр BP для адресации такой области памяти. Когда наступает момент возврата, подпрограмма может прибавить соответствующее значение к указателю стека, и тем самым восстановить его прежнее значение. Динамическая организация х означает, что программа использует область памяти только тогда, когда она необходима для работы, и не занимает эту память все остальное время, поэтому программу можно выполнять на машине с малым объемом памяти, что невозможно при другой организации данных. Но лучшим является то, что программист не должен создавать сложную подсистему управления памятью, так как все находится под управлением стековой структуры.

Оператор возврата из подпрограммы на Фиг. 4.7 демонстрирует еще одну возможность набора команд микропроцессора 8088. Команда возврата из подпрограммы RET может иметь операнд, который представляет собой значение, прибавляемое микропроцессором к содержимому указателя стека после извлечения адреса возврата. В примере используется значение 8; это означает, что восемь байт, или четыре слова данных должны быть удалены из стека после возврата. Эти значения исчезают навсегда. Результат тот же, какой был бы в итоге извлечения значений из стека, чтобы уничтожить их; команда возврата уже сделала это автоматически.

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

Подпрограмма может возвратить в стеке некоторую информацию вызывающей программе. Если вызывающая программа помешает параметры в стек, подпрограмма может изменить их значения и оставить в стеке, а вызывающая программа может извлечь их после возврата. Если подпрограмма возвращает только один параметр, но вызывалась с тремя параметрами в стеке, то выполнить возврат она может с помощью команды RET 4. При этом последние два параметра извлекаются из стека и только возвращаемый параметр остается в стеке.

В гл. 10, где мы используем подпрограммы на языке ассемблера с языками высокого уровня, головная программа помещает параметры в стек. Но эти параметры - адреса данных, а не собственно данные. Это означает, что ассемблерная подпрограмма не должна возвращать параметры в стеке и обязана извлечь все параметры из стека при возврате.

 



Поделиться:




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

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


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