Ассемблер для процессоров Intel Pentium
Шрифт:
mov ЕАХ, 11223344I-
push ЕАХ
pop BX
pop CX
Здесь команда push ЕАХ помещает в стек двойное слово 11223344b. После выполнения команды pop BX из стека извлекается младшее слово, равное 3344h, и помещается в регистр ВХ. Указатель стека ESP при этом уменьшается на 2. Следующая команда pop CX извлекает из стека старшее слово, равное 1122h, и помещает его в регистр СХ. При этом содержимое регистра ESP опять уменьшается на 2.
В этом примере в стек помещается значение 16-разрядной переменной ор (команда push DS : op), при этом указывается сегмент данных, в
Следующий пример демонстрирует применение операций со стеком в 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.
При выполнении операций со стеком вся ответственность за содержимое стека ложится на программиста, поэтому нужно быть очень внимательным. Если какое-либо значение помещается в стек во время работы программы, то оно должно быть извлечено из стека перед ее завершением либо стек должен быть восстановлен каким-то другим способом. Несоблюдение этих требований приводит, как правило, к краху программы. Точно так же суммарный размер операндов, извлеченных из стека, должен быть равным размеру помещенных в него данных.
Хорошо спроектированная программа перед завершением всегда восстанавливает указатель стека к тому значению, которое было перед началом ее выполнения.
Для операций с данными в стеке не
Листинг 6.2. Доступ к данным в стеке посредством регистра ЕВР (16-разрядная версия)
Здесь содержимое переменных opl и ор2 помещается в стек, причем значение opl оказывается по адресу [SP+2], а значение ор2 – по адресу [SP] (рис. 6.6).
Рис. 6.6. Содержимое стека после размещения переменных opl и ор2
Поскольку после выполнения команды mov ВР, SP регистр ВР содержит значение SP, то значение переменной opl хранится по адресу [ВР+2], а значение ор2 – по адресу [ВР]. После выполнения последних двух команд данного фрагмента кода регистр АХ будет содержать 1149h, а регистр ВХ – 0E37L
При разработке 32-разрядных приложений для процессоров Intel Pentium использовать регистр ЕВР для доступа к данным в стеке не обязательно – можно напрямую работать с указателем стека ESP. Например, с помощью следующего фрагмента программного кода вычисляется разность операндов ор2 и opl, которая затем помещается в регистр ЕАХ:
В последних двух примерах мы не акцентировали внимание на восстановлении указателя стека, хотя в ряде случаев применение обычных команд pop может оказаться неудобным или невозможным. В таких случаях можно воспользоваться еще одним способом восстановления стека – задействовать команду add:
add ESP, n
Здесь и – количество байтов, на которое следует продвинуть указатель стека SP (ESP). Следующий пример демонстрирует восстановление указателя стека после того, как в стек были помещены три двойных слова (12 байт):
Поскольку команды push помещают в стек 12 байт (три двойных слова), то для восстановления указателя стека следует продвинуть его на это же число в сторону увеличения адресов, что и делается с помощью команды add.
Далее мы проанализируем, как используется стек при выполнении подпрограмм.
6.2. Принципы организации подпрограмм
Подпрограмма, в зависимости от выполняемых ею функций, может требовать передачи из вызывающей программы определенных данных, которые принято называть аргументами или параметрами и возвращать в вызывающую программу результат вычислений. Некоторые подпрограммы могут вообще не принимать никаких параметров и не возвращать результат. Чаще всего подпрограмма (процедура) оформляется так, как показано в следующем фрагменте кода:
Как видно из приведенного фрагмента кода, в начале процедуры (перед первой выполняемой командой) должна находиться директива proc, a после последней выполняемой команды – директива endp. Процедура обязательно должна заканчиваться командой ret. В одном ассемблерном файле с расширением ASM можно размещать несколько процедур.