Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Разработка приложений на языке ассемблер в среде MS MASM. Учебно-методическое пособие по дисциплинам «Ассемблер» и «Операционные системы и системное п

.pdf
Скачиваний:
1
Добавлен:
08.09.2026
Размер:
2 Мб
Скачать
Команда PUSH заносит в стек четырех- или двухбайтовый операнд, изменяя при этом текущее значение указателя стека ESP.
Если операнд четырехбайтовый (m32,r32), команда PUSH умень- шает значение указателя стека ESP на 4 и записывает в стек 4 байта дан­ных по адресу ESP:
ESP:=ESP-4, [SS:ESP]:=операнд
Запись [SS:ESP] означает: "содержимое памяти по адресу SS:ESP".
Если операнд двухбайтовый (m16,r16) команда PUSH умень­шает текущее значение указателя стека ESP на 2 и записывает в стек 2 байта данных по адресу ESP:
ESP:=ESP-2, [SS:ESP]:=операнд
Пример:
.STACK 40 ;ESP:=40 ... PUSH EAX ;ESP:=40-4=36 PUSH DS ;ESP:=36-2=34
6.2.2 Чтение из стека
POP операнд
Команда POP извлекает из стека четырех- или двухбайтовое содер­жимое по адресу ESP , копирует извлеченное значение в указанный опе­ранд и формирует новое значение указателя стека.
Если операнд четырехбайтовый (m32,r32), команда POP считы­вает из стека по адресу ESP 4 байта данных и помещает их в операнд, а затем увеличивает значение указателя стека ESP на 4:
операнд:=[SS:ESP], ESP:=ESP+4,
Если операнд двухбайтовый (m16,r16) команда POP считывает из стека по адресу ESP 2 байта данных и помещает их в операнд, а затем увеличивает значение указателя стека ESP на 2:
операнд:=[SS:ESP], ESP:=ESP+2.
Пример:
.STACK 40 ... MOV EAX,12345678H MOV BX,0020H ;Cодержимое стека: PUSH EAX ;ESP:=40-4=36 |xxxxxxxx|12345678| PUSH BX ;ESP:=36-2=34 |xxxx0020|12345678| POP DX ;DX:=0020H, |xxxx0020|12345678| ;ESP:=34+2=36
51
POP EBX ;EBX:=12345678H, |xxxx0020|12345678| ;ESP:=36+4=40
6.3 Создание и использование процедур
6.3.1 Описание процедуры
Для описания процедуры используются директивы PROC и ENDP:
имя_процедуры PROC
<тело процедуры>
ENDP
Директива PROC служит для определения имени процедуры и запи­сывается в ее начале. Имя процедуры выполняет роль метки, и использу-
ется для безусловного перехода на выполнение кода процедуры при вызове командой CALL. Имя процедуры определяет программист. Тело процедуры
состоит из последовательности произвольных команд ассемблера, состав­ляющих код процедуры. В последней строке процедуры записывается ди­ректива ENDP.
Процедура может быть описана:
- между директивой .code и точкой входа (меткой main:);
- после последней команды сегмента кода;
- в другом модуле (исходном файле).
6.3.2 Вызов процедуры
CALL имя_процедуры
Команда CALL производит безусловный переход на метку имя_процедуры, предварительно сохраняя в стеке текущее значение ука­зателя команд EIP. Вспомним, что EIP всегда содержит адрес следую­щей команды. В данном случае это будет адрес команды, следующей за ко-
мандой CALL. Его называют адресом возврата из процедуры, поскольку после завершения процедуры должен быть обеспечен автоматический пе-
реход по этому адресу.
6.3.3 Возврат из процедуры
RET [число]
Команда RET извлекает из стека адрес возврата, ранее записанный туда командой CALL, и обеспечивает автоматическое продолжение выпол- нения программы, начиная с команды, следующей за командой CALL. Не­обязательный параметр число позволяет дополнительно удалить из стека заданное количество байт (обычно используется для очистки стека от раз-
мещенных в нем параметров процедуры).
52
а2
EBP
+12
EBP+8
EBP
а1
. . .
а3
EIP
EBP
6.4 Организация интерфейса с процедурой
Как правило, процедура предполагает использование параметров (входных и/или выходных). Описание процедуры с параметрами на языках программирования высокого уровня выглядит примерно так:
Procedure myproc(a1,a2,a3),
где myproc - имя процедуры, a1,a2,a3 – формальные параметры. При вызове такой процедуры потребуется указать фактические значения
параметров, например, так: myproc(5,8,0)
Программисту на ассемблере необходимо позаботиться о способе пе­редачи параметров процедуре от основной (вызывающей) программы. Су­ществует несколько таких способов, но наиболее универсальным является метод передачи параметров через стек. Этот метод применяется в том числе при передаче параметров в программах, написанных на языках высокого уровня. Общий сценарий такого метода выглядит так. Вызывающая про­грамма вначале последовательно записывает значения параметров проце­дуры в стек (с помощью команды PUSH), а затем производит вызов проце-
дуры (CALL). Процедура, получив управление, извлекает значения пара­метров из стека, обрабатывает их, перед завершением работы очищает стек
и производит возврат в основную программу (RET).
Рассмотрим, как реализуется такой сценарий применительно к вызову процедуры myproc с тремя параметрами a1,a2,a3 типа DWORD (4
байта) (рисунок 6.3).
Вызывающая программа Процедура
;Вызов процедуры PUSH A1 PUSH A2 PUSH A3 CALL PR_FUNC
ESP
2
ESP
1
EBP+16
MYPROC PROС PUSH EBP MOV EBP,ESP ; EBP:=ESP
. . .
MOV EAX,[EBP+8] ; EAX:=a3 MOV EBX,[EBP+12] ; EBX:=a2 MOV ECX,[EBP+16] ; ECX:=a1
. . .
POP EBP ;убрать EBP из стека RET 12 ;убрать параметры ENDP
Рисунок 6.3 - Использование стека при передаче параметров
53
Вызывающая программа вначале записывает параметры a1,a2,a3 в стек с помощью команды PUSH. Расположение параметров в стеке пока­зано на рисунке. Команда вызова процедуры CALL помещает в стек теку- щее значение регистра EIP и передает управление процедуре. В этот мо­мент текущее значение указателя стека ESP=ESP
.
1
Теперь процедуре необходимо извлечь значения параметров из стека. Однако сделать это с помощью команды POP невозможно, поскольку на вершине стека находится сохраненный ранее адрес возврата - регистр EIP!
Метод извлечения параметров из стека основан на использовании регистра
EBP, называемого альтернативным указателем стека. В начале значение EBP спасается в стеке (на всякий случай), а потом в EBP помещается
текущее значение указателя стека ESP, равное теперь ESP2. Теперь "до­браться" до значений параметров можно с помощью обычной команды
MOV! Например, значение параметра a3 находится в стеке по смещению 8 относительно сформированного значения регистра EBP, поэтому ко­манда MOV EAX,[EBP+8] помещает в регистр EAX значение параметра
a3. Аналогично поступают с параметрами a2 (смещение EBP+12) и a3 (смещение EBP+16).
При завершении процедуры следует вначале убрать из стека EBP (возможно, и другие данные, если вы их туда положили), чтобы на вершине
оказался регистр EIP - адрес возврата из процедуры. Последняя команда процедуры RET 12 возвращает управление основной программе (по ра­нее сохраненному значению указателя команд EIP) и "очищает" стек на 12 байт, освобождая его от сохраненных ранее параметров процедуры пу-
тем прибавления к ESP числа 12.
6.5 Рабочее задание
1. Преобразовать программу, разработанную в лабораторной работе №4, представив в виде процедуры блок команд, предназначенных для об­работки одной строки матрицы A по заданному алгоритму.
В качестве входных параметров процедуры использовать:
- адрес 1-го элемента обрабатываемой строки матрицы A;
- количество элементов в строке.
В качестве выходного параметра процедуры использовать значение, рассчитанное при обработке строки в соответствии с заданным вариантом (которое будет затем записано в массив B в основной программе).
Входные параметры процедуры передаются через стек, а выходной ­через регистр (см. пример программы в п. 6.8).
2. Проверить работоспособность программы и полученные на тесто-
вом примере результаты. Подготовить для отчета исходную матрицу А и
54
результирующий одномерный массив B в десятичном формате, а также в виде скриншота дампа сегмента данных.
3. C помощью отладчика проследить за изменением состояния стека в ходе выполнения программы, заполнив таблицу 6.1. В таблицу включить только команды, воздействующие на стек, а также команды, использующие регистры - указатели стека (ESP, EBP), в той последовательности, в какой
они встречаются в программе при обработке одной строки исходной мат­рицы. Значения регистров и содержимое стека фиксируются после выпол­нения соответствующей команды. Сделать скриншот сегмента стека после выполнения последней команды записи в стек (PUSH) в процедуре так,
чтобы были видны все значения, записанные программой в стек.
6.6 Требования к отчету
1. Продемонстрируйте работающую программу преподавателю с предъявлением результатов с помощью отладчика.
2. Подготовьте отчет, включающий:
- текст варианта задания;
- укрупненную блок-схему алгоритма разработанной программы;
- текст разработанной программы с обязательными комментариями;
- результаты работы программы в отладчике виде таблицы и в виде скриншота (см. п. 2 рабочего задания);
- содержимое стека в виде заполненной таблицы 6.1 и скриншота сег­мента стека в отладчике (см. п. 3 рабочего задания).
6.7 Контрольные вопросы
1. С какой целью используют процедуры?
2. Что такое стек? Поясните работу команд PUSH и POP.
3. Почему команду CALL называют "переход с возвратом"? Как обес- печивается возврат в точку вызова?
4. Каков алгоритм выполнения команды RET.
5. Что произойдет при выполнении программы, приведенной в п. 6.8, если в процедуре SUMSTR будет отсутствовать команда RET?
6. Можно ли передавать управление в процедуру с помощью команды JMP? Что произойдет?
7. В стек последовательно были записаны двухбайтовые числа 1, 2, 3, 4, 5. Какое значение примет регистр EAX после выполнения следующих ко-
манд в указанной последовательности:
PUSH EAX POP EAX POP EBX POP ECX POP EAX
55
Таблица 6.1 – Состояние стека программы
Исходное
состояние стека
PUSH EBX PUSH EDX
...
MOV EBP,ESP
...
RET 8
ESP= ESP=
EBP= EBP= EBP= EBP=
ESP= EBP=
ESP=
ESP=
00000000
00000005
00000000
Примечания. * Выделены ячейки стека с изменившимся содержимым ** В таблицу включить только команды, воздействующие на стек, а также команды, использующие регистры ­указатели стека (ESP,EBP), в той последовательности, в какой они встречаются в программе при одном вызове
процедуры. Значения регистров и содержимое стека фиксируются после выполнения соответствующей ко­манды. *** Для каждой включенной в таблицу команды указать наблюдаемые в отладчике значения регистров - указате­лей стека (ESP,EBP), размещая эти значения напротив ячеек стека, на которые эти регистры указывают.
56
57
6.8 Пример программы
;Дан двумерный массив А(4х5). ;Сформировать одномерный массив B(4),каждый элемент которого ;равен сумме элементов соответствующей строки массива A: ; B(i)=A(i,0)+A(i,1)+...+A(i,4) i=0,1,2,3 ;Для суммирования элементов строки использовать процедуру ;================================================== .486 .model flat, stdcall option casemap: none .stack 100h ;========================================= include <\masm32\include\kernel32.inc> includelib <\masm32\lib\kernel32.lib> ;========================================= .data N equ 4 ;количество строк M equ 5 ;количество столбцов A db 1,2,-3,-4,5 db -6,7,-8,9,0 db -1,3,2,-7,4 db 6,-8,2,0,1 B dw 4 dup (?) ;================================================================ .code ;=====Процедура================================================== ;Процедура вычисления суммы элементов одномерного массива байтов ;Входные параметры (передаются через стек): ; - адрес начала массива [ebp+8] ; - количество элементов массива [ebp+12] ;Выходной параметр (передается через регистр al - сумма элементов строки) sumstr proc push ebp ;спасаем ebp mov ebp,esp ;формирование альтернативного указателя стека ebp=esp push ecx ;спасаем используемые в процедуре регистры push ebx mov al,0 ;начальное значение суммы элементов строки (вых. параметр) mov ecx,[ebp+8] ;извлечение из стека параметра 2 (число элементов массива) mov ebx,[ebp+12];извлечение из стека параметра 1 (адреса массива) ;----------------­next: ;начало цикла обработки массива add al,[ebx] ;добавить к сумме (AL) текущий элемент массива inc ebx ;установить bx на следующий элемент массива (+1) loop next ;продолжить, если выбраны не все элементы массива ;----------------­ pop ebx ;восстановить спасаемые регистры pop ecx pop ebp ret 8 ;зачистить стек от параметров и возврат из процедуры sumstr endp
;==== Основная программа=============================================== main: ;для адресации строк массива A используем регистр ; ebx - адрес (смещение) текущей строки ;для адресации элементов массива B используем регистр ; edi - смещение элемента
mov ecx,N ;счетчик строк массива A mov edx,M ;количество элементов в строке
58
mov edi,0 ;смещение эл-та массива B lea ebx,A ;адрес первой строки массива A ;----------------­stroka: ;начало цикла по строкам А ;записываем в стек входные параметры для процедуры: push ebx ;параметр 1: адрес выбранной строки массива A push edx ;параметр 2: число элементов в строке массива A call sumstr ;вызов процедуры суммирования ;----------------­ cbw ;преобразование выходного параметра AL в двухбайтовый формат (AX) mov B[edi],ax ;сумма - в массив B add ebx,M*type A ;установить ebx на начало следующей строки A (+5) add edi,type B ;установить edi на следующий элемент массива B(+2) loop stroka ;продолжить, если обработаны не все строки ;----------------­ invoke ExitProcess, 0 ;завершение программы c кодом 0 end main
59
СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ
1. Пильщиков В.Н. Программирование на языке ассемблера IBM PC. – М.: Диалог-МИФИ, 2011
2. Пирогов В.Ю. Ассемблер для Windows. – СПб.: БХВ-Петербург, 2012
3. Справочник по макроассемблеру (MASM). Режим доступа:
https://docs.microsoft.com/ru-ru/cpp/assembler/masm/microsoft-macro­assembler-reference?view=msvc-160
4. Встроенный ассемблер. Режим доступа:
https://docs.microsoft.com/ru-ru/cpp/assembler/inline/inline­assembler?view=msvc-160
5. Таненбаум Э., Остин Т. Архитектура компьютера. – СПб.: Питер, 2021
60
Учебно-методическое издание
ВАРФОЛОМЕЕВ ВИКТОР АРХИПОВИЧ
РАЗРАБОТКА ПРИЛОЖЕНИЙ НА ЯЗЫКЕ АССЕМБЛЕР В СРЕДЕ
MS MASM
Учебно-методическое пособие
Изд. № 93-21
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]