Чтение онлайн

ЖАНРЫ

Ассемблер для процессоров Intel Pentium

Магда Юрий

Шрифт:

Несмотря на то что память в процессорах х86 имеет байтовую организацию, минимальный размер операнда, которым оперируют команды стековых операций, равен слову (2 байта). По этой причине данные в стеке отстоят друг от друга на величину, кратную двум. Например, при помещении в стек слова значение указателя стека SP (ESP) уменьшается на 2, при помещении двойного слова – на 4 и т. д. При этом младшие байты операндов помещаются в стек по младшим адресам, а старшие байты – по старшим адресам.

Для того чтобы поместить какое-либо значение в стек, нужно использовать команду push. Эта команда в качестве параметра может принимать любой 16– или 32-разрядный регистр

либо ячейку памяти. При этом содержимое указателя стека SP (ESP) уменьшается на 2 (для слова) или на 4 (для двойного слова). Команда допускает один из форматов:

push regl6/reg32

push meml6/mem32

push segreg

push immed

Здесь reg16/reg32 – один из 16– или 32-разрядных регистров, тет16/тет32 – переменная в памяти (16 или 32 разряда), segreg – один из сегментных регистров (CS, DS, ES), a immed – непосредственное значение. Команда push с непосредственным операндом (immed) в процессорах Intel Pentium недопустима.

Существуют специальные модификации команды push. Так, например, для сохранения 16-разрядного регистра флагов процессора в стеке используется команда pushf, a для сохранения 32-разрядного регистра флагов – команда pushfd. Последняя команда присутствует только в процессорах, начиная с 80386. Наконец, существуют специальные форматы команды push, позволяющие сохранить в стеке все регистры процессора:

– pusha – помещает в стек все 16-разрядные регистры (АХ, ВХ, СХ, DX, SP, BP, s1 , DI);

– pushad – помещает в стек все 32-разрядные регистры (ЕАХ, ЕВХ, ЕСХ, EDX, ESP, EBP, ESI, EDI).

Приведу несколько примеров использования команды push и ее модификаций.

Предположим, что в стеке находится единственное значение, равное 7EE3h (рис. 6.1).



Рис. 6.1. Начальное состояние стека


Выполним команды

mov BX, 2CE9h

push BX

Команда push в этом фрагменте программного кода копирует содержимое регистра ВХ в стек, при этом содержимое регистра SP уменьшается на 2 и стек начинает выглядеть так, как показано на рис. 6.2.



Рис. 6.2. Состояние стека после выполнения команды push BX


Напомню, что минимальная размерность данных, которыми оперирует стек, равна 16 бит, поэтому содержимое регистра SP (ESP) не может увеличиться или уменьшиться на 1. Это означает, что нельзя поместить в стек или извлечь из стека данные размером в 1 байт. Указатель стека увеличивается (уменьшается) на 2 или 4 (для слова или двойного слова соответственно). Например, после выполнения следующего фрагмента кода содержимое стека будет таким, как показано на рис. 6.3:



Рис. 6.3. Размещение двойного слова в стеке


После этой операции указатель стека уменьшается на 4, поскольку в него помещается двойное слово.

Извлечение данных из стека выполняется с помощью команды pop. При этом из стека извлекается слово (двойное слово) и помещается в указанный операнд. Эта команда в качестве параметра может принимать любой 16– или 32-разрядный регистр или ячейку памяти. При этом содержимое указателя стека SP (ESP) увеличивается на 2 (для слова) или на 4 (для двойного слова).

Команда pop является зеркальной по отношению к push и использует те же типы операндов, что и команда push. Кроме того, для извлечения содержимого регистра флагов из стека имеются команды popf (для 16-разрядного регистра флагов) и popfd (для 32-разрядного). Для того чтобы восстановить все регистры процессора значениями из стека, в систему команд включены инструкции рора (для 16-разрядных

регистров) и popad (для 32-разрядных). Например, следующая команда извлекает данные, помещенные в стек в предыдущем примере, и запоминает их в регистре EDX:

pop EDX

После выполнения этой команды регистр EDX будет содержать значение 4FE91A77h, a указатель стека уменьшится на 4 (рис. 6.4).



Рис. 6.4. Содержимое стека после выполнения команды pop EDX


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

mov ЕАХ, 11223344I-

push ЕАХ

pop BX

pop CX

Здесь команда push ЕАХ помещает в стек двойное слово 11223344b. После выполнения команды pop BX из стека извлекается младшее слово, равное 3344h, и помещается в регистр ВХ. Указатель стека ESP при этом уменьшается на 2. Следующая команда pop CX извлекает из стека старшее слово, равное 1122h, и помещает его в регистр СХ. При этом содержимое регистра ESP опять уменьшается на 2.



В этом примере в стек помещается значение 16-разрядной переменной ор (команда push DS : op), при этом указывается сегмент данных, в котором определена переменная (регистр DS). Указатель стека SP после выполнения этой операции уменьшается на 2. Следующая команда pop AX извлекает содержимое стека в регистр АХ и восстанавливает стек, увеличивая значение SP на 2. Таким образом, в регистре АХ будет содержаться значение 7777L

Следующий пример демонстрирует применение операций со стеком в 16-разрядном приложении. Исходный текст программы показан в листинге 6.1.


Листинг 6.1. Демонстрация стековых операций (16-разрядная версия)



Программа достаточно проста – она выводит на экран значения переменной num1 и символьных строк s1 и s2, причем вначале отображается содержимое строки s1 , затем – строки s2 и наконец – значение переменной num1. Сначала в стек помещается значение переменной num1 (команда push DS:numl), затем – адрес строки s 2:

push DS:numl

lea s1 , s2

push s2

После этих операций указатель стека уменьшается на 4, а содержимое стека становится таким, как показано на рис. 6.5.



Рис. 6.5. Содержимое стека после помещения данных программы


Затем программа выводит на экран строку si:

lea DX, s1

mov AH, 9h

int 21h

После этого из стека извлекается адрес строки s2 и помещается в регистр DX. Далее строка s 2 выводится на экран:

pop DX

int 21h

К этому моменту в стеке остается значение переменной num1, a указатель стека SP уменьшается на 2. Следующая команда pop DX извлекает переменную num1 из стека и помещает ее значение в регистр DX, при этом указатель стека еще раз уменьшается на 2. Последующие команды отображают содержимое DX на экране с учетом порядка размещения байтов в регистре:

pop DX

xchg DH, DL

mov AH, 2h

int 21h

xchg DH, DL

int 21h

Хочу сделать замечание: для временного хранения в стеке данных, представленных строками или массивами, используются их адреса или, как их еще называют, указатели. Адрес строки (или массива) одновременно является и адресом ее первого элемента. Например, адрес строки s1 из предыдущего примера совпадает с адресом символа S.

Поделиться с друзьями: