Загрузка...

Фрагмент программы


Рассмотрим следующий фрагмент программы, где в регистр AL также загружается девятый символ CharString:

mov bx,OFFSET CharString+8

mov al,[bx]

В данном примере для ссылки на девятый символ используется регистр BX. Первая инструкция загружает в регистр BX смещение CharString (вспомните о том, что операция OFFSET возвращает сме-щение метки в памяти), плюс 8. (Вычисление OFFSET и сложение для этого выражения выполняется Турбо Ассемблером во время ассембли-рования.) Вторая инструкция определяет, что AL нужно сложить с содержимым по смещению в памяти, на которое указывает регистр BX (см. Рис. 5.3).

mov al,[108]

как показано на Рис. 5.2.

| |

|—————|

99 | ? |

|—————|

CharString —————> 100 | ‘A’ |

|—————|

101 | ‘B’ |

|—————|

102 | ‘C’ |

|—————|

103 | ‘D’ |

|—————|

104 | ‘E’ |

|—————|

105 | ‘F’ |

|—————|

106 | ‘G’ |

|—————|

107 | ‘H’ |——-

———— |—————| |

BX | 108 | ————> 108 | ‘I’ | |

———— |—————| V

109 | ‘J’ | ———

|—————| | |

110 | ‘K’ | ———

|—————| AL

111 | ‘L’ |

|—————|

112 | ‘M’ |

|—————|

113 | 0 |

|—————|

114 | ? |

|—————|

Рис. 5.3 Использование регистра BX для адресации к строке CharString.

Квадратные скобки показывают, что в качестве операнда-источ-ника должна быть использоваться ячейка, на которую указывает ре-гистр BX а не сам регистр BX. Не забывайте указывать квадратные скобки при использовании BX в качестве указателя памяти. Напри-мер:

mov ax,[bx] ; загрузить AX из ячейки памяти,

; на которую указывает BX

и

mov ax,bx ; загрузить в AX содержимое

; регистра BX

это две совершенно различные инструкции.

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

Предположим, вы хотите определить последний символ завершаю-щейся нулем строки CharString. Чтобы это сделать, вы должны, на-чиная с первого символа строки CharString, найти завершающий строку нулевой байт, затем вернуться назад на один символ и счи-тать этот последний символ. Это невозможно сделать с помощью не-посредственной адресации, так как строка может иметь произвольную длину. Использование регистра BX значительно облегчает задачу:

mov bx,OFFSET CharString ; указывает на строку FindLastCharLoop:

mov al,[bx] ; получить следующий

; символ строки

cmp al,0 ; это нулевой байт?

je FoundEndOfString ; да, вернуться на

; один символ

inc bx

jmp FilnLastCharLoop ; проверить следующий

; символ

FoundEndOfString:

dec bx ; снова указывает на

; последний символ

mov al,[bx] ; получить последний

; символ строки

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

BX — это не единственный регистр, который можно использовать для ссылка на память. Допускается также использовать вместе с не-обязательным значением-константой или меткой регистры BP, SI и DI. Общий вид операндов в памяти выглядит следующим образом:

[базовый регистр + индексный регистр + смещение]

где базовый регистр — это BX или BP, индексный регистр — SI или DI, а смещение — любая 16-битовая константа, включая метки и вы-ражения. Каждый раз, когда выполняется инструкция, использующая операнд в памяти, процессором 8086 эти три компоненты складывают-ся. Каждая из трех частей операнда в памяти является необязатель-ной, хотя (это очевидно) вы должны использовать один из трех эле-ментов, иначе вы не получите адреса в памяти. Вот как элементы операнда в памяти выглядят в другом формате:

BX SI

или + или + Смещение

BP DI

(база) (индекс)

Существует 16 способов задания адреса в памяти:

[смещение] [bp+смещение]

[bx] [bx+смещение]

[si] [si+смещение]

[di] [di+смещение]

[bx+si] [bx+si+смещение]

[bx+di] [bx+di+смещение]

[bp+si] [bp+si+смещение]

[bp+di] [bp+di+смещение]

где смещение — это то, что можно свести к 16-битовому постоянному значению.

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

.DATA

CharString DB ‘ABCDEFGHIJKLM’,0

.CODE

mov ax,@Data

mov ds,ax

mov si,OFFSET CharString+8

mov al,[si]

mov bx,8

mov al,[Charstring+bx]

mov ..,OFFSET CharString

mov al,[bx+8]

mov si,8

mov al,[CharString+si]

mov bx,OFFSET CharString

mov di,8

mov al,[bx+di]

mov si,OFFSET CharString

mov bx,8

mov al,[si+bx]

mov bx,OFFSET CharString

mov si,7

mov al,[bx+si+1]

mov bx,3

mov si,5

mov al,[bx+CharString+si]

Все эти инструкции ссылаются на одну и ту же ячейку памяти — [CharString]+8.

В данном примере можно найти несколько интересных моментов. Во-первых, вы должны понимать, что знак плюс (+), используемый внутри квадратных скобок, имеет специальное значение. Во время ассемблирования Турбо Ассемблер складывает все постоянные значе-ния (константы) внутри квадратных скобок, поэтому инструкция:

mov [10+bx+si+100],cl

принимает вид:

mov [bx+si+111],cl

После этого при реальном выполнении инструкции (во время прогона программы) операнды в памяти складываются вместе процес-сором 8086. Если регистр BX содержит значение 25, а SI содержит 52, то при выполнении инструкции MOV CL записывается по адресу памяти 25 + 52 + 111 = 188. Ключевой момент состоит в том, что базовый регистр, индексный регистр и смещение складываются вместе процессором 8086 при выполнении инструкции. Таким образом, Турбо Ассемблер складывает константы во время ассемблирования, а про-цессор 8086 складывает содержимое базового регистра, индексного регистра и смещения во время действительного выполнения инструк-ции.

Как вы можете заметить, ни в одном из примеров мы не исполь-зовали регистр BP. Это связано с тем, что поведение регистра BP несколько отличается от регистра BX. Вспомните, что в то время как регистр BX используется, как смещение внутри сегмента данных, регистр BP используется, как смещение в сегменте стека. Это озна-чает, что регистр BP не может обычно использоваться для адресации к строке CharString, которая находится в сегменте данных.

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

(На самом деле регистр BP можно использовать и для адресации к сегменту данных, а BX, SI и DI — для адресации к сегменту сте-ка, дополнительному сегменту или сегменту кода. Для этого исполь-зуются префиксы переопределения сегментов (segment override pre-fixes). О некоторых из них мы расскажем в Главе 10. Однако в большинстве случаев они вам не понадобятся, поэтому пока мы прос-то забудем об их существовании.)

Наконец, квадратные скобки, в которые заключаются непос-редственные адреса, являются необязательными. То есть инструкции:

mov al,[MemVar]

и

mov al,MemVar

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

Вы можете использовать также такую форму адресации к памяти:

mov al,CharString[bx]

или даже

mov al,CharString[bx][si]+1

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

mov al,[charString+bx+si+1]

Здесь снова нужно выбрать ту форму записи, которая вам боль-ше нравится, и придерживаться ее.

Квадратные скобки, в которые заключаются регистры, указываю-щие на ячейки памяти, являются обязательными. Без этих скобок, BX, например, интерпретируется, как операнд, а не как ссылка на операнд.

Загрузка...