Cамоучитель по Assembler

         

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




Если бы подпрограмма просто сняла со стека находящиеся там параметры, она первым делом изъяла бы из стека адрес возврата, и лишила бы себя возможности вернуться в основную программу (подробнее вопросы вызова подпрограммы и возврата из нее будут обсуждаться в последующих разделах). Поэтому в данном случае вместо команд pop удобнее воспользоваться командами mov. Подпрограмма копирует в ВР содержимое трех параметров и перехода на мое SP и использует затем этот адрес в качестве базового, модифицируя его с помощью базовой адресации со смещением.
Кстати, мы опять сталкиваемся здесь с той весьма обычной ситуацией, когда программист не имеет возможности обращаться по наглядным символическим адресам, которых в стеке, естественно, нет, а вынужден определять "вручную" смещения к интересующим его элементам стека. При этом необходимо учесть и алгоритм выполнения команды call, которая, сохраняя в стеке адрес возврата в основную программу, смещает указатель стека еще на одно слово.
В нашем фрагментарном примере мы не рассматриваем вопрос возврата в основную программу. Вдумчивый читатель мог также усомниться в правильности или, лучше сказать, в разумности текста подпрограммы. Ведь перенося параметры из стека в регистры общего назначения, подпрограмма затирает их исходное содержимое. Если же они не содержали ничего нужного, то ими можно было воспользоваться для передачи параметров в подпрограмму, а не связываться с мало наглядными операциями со стеком. Действительно, ради краткости мы опустили операции, практически необходимые в любой подпрограмме - сохранение в стеке (опять в стеке!) тех регистров, которые будут использоваться в подпрограмме. Кстати, это относится и к регистру ВР. В реальной подпрограмме эти действия следовало выполнить, что привело бы к изменению смещений при регистре ВХ, которые приняли бы значения (с учетом сохранения 4 регистров) 10, 12 и 14.
Во всех приведенных выше примерах регистр использовался для хранения базового адреса, а смещение, если оно требовалось, указывалось в виде константы. Возможна и обратная ситуация, когда в качестве смещения выступает адрес массива, а в регистре находится индекс адресуемого элемента в этом массиве. Рассмотрим относительно реальный пример такого рода.
Пусть нам надо заполнить массив из 10000 слов натуральным рядом чисел. Зарезервируем в сегменте данных место под этот массив, а в сегменте команд организуем цикл занесения в последовательные слова массива ряда нарастающих чисел. Нам придется воспользоваться несколькими новым командами (inc, add и loop), которые в дальнейшем будут рассмотрены более подробно.

;Сегмент данных


array dw 10000


;Сегмент команд


mov SI, 0 ;Начальное значение индекса элемента в массиве


mov АХ, 0 ;Первое число-заполнитель


mov СХ,10000;Число шагов в цикле (всегда в СХ)


fill: mov array[SI],AX ;Занесение числа в элемент массива


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


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


loop fill ;Возврат на метку fill (СХ раз)

Цикл начинается с команды, помеченной меткой fill (правила образования имен меток такие же, как и для имен полей данных). В этой команде содержимое АХ, поначалу равное 0, переносится в ячейку памяти, адрес которой вычисляется, как сумма адреса массива array и содержимого индексного регистра SI, в котором в первом шаге никла тоже 0. В результате в первое слово массива заносится 0. Далее содержимое регистра АХ увеличивается на 1, содержимое регистра SI - на 2 (из-за того, что массив состоит из слов), и командой loop осуществляется переход на метку fill, после чего тело цикла повторяется при новых значениях регистров АХ и SI. Число шагов в цикле, отсчитываемое командой loop, определяется исходным содержимым регистра СХ.
Базово-индексная адресация. Адресуется память (байт или слово). Относительный адрес операнда определяется, как сумма содержимого следующих пар регистров:

[ВХ] [SI] (подразумевается DS:[BX][SI])




[ВХ][DI] (подразумевается DS:[BX][DI])


[ВР] [SI] (подразумевается SS:[BP][SI])


[ВР] [DI] (подразумевается SS:[BP][DI])

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

;Сегмент данных


array dw 10000


;Сегмент команд


mov BX,offset array ;Базовый адрес массива в


;базовом регистре


mov SI, 0 ;Начальное значение индекса


;элемента в массиве


mov АХ, 0 ;Первое число-заполнитель


mov CX,10000 ;Число шагов в цикле


fill: mov [BX][SI],AX ;Отправим число в массив


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


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


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

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

sims db "QWERTYUIOP{}'


db "ЙЦУКЕНПШЦЗХЪ'

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


mov BX,12 ;Число байтов в строке


mov SI, 6


mov DL,syms[BX][SI]

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

mov BX, off set sym


mov SI,6


mov DL, 12 [BX] [SI]





Содержание  Назад  Вперед