Обучающие курсы:

Обучение профессии "Разработчик C#" + стажировка в Mail.ru
Обучение профессии "Разработчик Python" + трудоустройство
Обучение профессии "Веб-разработчик" + стажировка в Mail.ru


Главная страница
Библиотека (скачать книги)
Скачать софт
Введение в программирование
Стандарты для C++
Уроки по C#
Уроки по Python
HTML
Веб-дизайн
Ассемблер в среде Windows
ActiveX
Javascript
Общее о Линукс
Линукс - подробно
Линукс - новое
Delphi
Паскаль для начинающих
Турбопаскаль
Новости
Партнеры
Наши предложения
Архив новостей





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

push ЕВР
mov EBP, ESP

Если необходимо сохранить регистры при вызове подпрограммы, то следует учитывать соответствующее смещение указателя стека. Большинство Windows-приложений должны сохранять в стеке регистры ЕВХ, E S I И E D I . Тогда исходный текст процедуры SumTwo выглядел бы так, как показано в листинге 2.3.

Листинг 2.3. Процедура SumTwo с сохранением регистров
SumTwo proc
push ЕВХ
push ESI
push EBP
mov EBP, ESP
mov EAX, DWORD PTR [EBP+20]
add EAX, DWORD PTR [EBP+16]
pop EBP
pop ESI
pop EBX
ret
SumTwo endp

На этом анализ работы нашей процедуры можно было бы закончить, если бы не одно "но". Приложение, использующее процедуру SumTwo, при выполнении завершится аварийно. В чем здесь дело? Еще раз внимательно проанализируем исходный текст фрагмента, где используется наша процедура:
push DWORD PTR II push DWORD PTR 12
call SumTwo
mov SUM, EAX

После завершения выполнения SumTwo в стеке остаются два значения переменных II и 12. При выходе из процедуры мы не восстановили стек, что в 100% случаев приводит к краху программы. Очистить стек можно одним из двух способов. Первый заключается в том, чтобы использовать следующую команду:
add ESP, 8
Второй способ — использовать команду ret 8. Первый способ обычно используется вызывающей программой, второй — вызываемой процедурой.
Далее показаны исправленные фрагменты программного кода для обоих вариантов.
1. Восстановление стека вызывающей программой:
push DWORD PTR II
push DWORD PTR 12
call SumTwo
mov SUM, EAX
add ESP, 8
2. Восстановление стека вызываемой процедурой:
SumTwo proc
push EBP
mov EBP, ESP
mov EAX, DWORD PTR [EBP+12]
add EAX, DWORD PTR [EBP+8]
pop EBP
ret 8
SumTwo endp

Большинство языков высокого уровня используют описанную методику для работы с внешними процедурами, и мы вернемся к этой теме при рассмотрении интерфейсов ассемблерных подпрограмм с языками высокого уровня.
Параметры в вызываемую процедуру могут передаваться не только через стек, но и через регистры. Покажем, как можно модифицировать предыдущий пример, если использовать для передачи параметров регистры ЕВХ И ЕСХ. Фрагмент кода вызывающей программы представлен в листинге 2.4.
Листинг 2.4. Передача параметров в процедуру через регистры
.data
SUM DD О
11 DD 32
12 DD -43
.code
start:
push EBX
push ECX
mov EBX, DWORD PTR II
mov ECX, DWORD PTR 12
call SumTwo
mov SUM, EAX
pop ECX
pop EBX

Исходный текст программного кода процедуры SumTwo (листинг 2.5) также изменится.
1 Листинг 2.5. Процедура SumTwo при передаче параметров через регистр
SumTwo proc
mov EAX, EBX
add EAX, ECX
ret
SumTwo endp

Как видите, в этом примере передача параметров через стек обладает преимуществом перед регистровым методом. Это обусловлено тем, что вызывающая программа практически всегда должна сохранять в стеке содержимое регистров, используемых при вызове процедуры. Производительность программы, использующей регистры для передачи параметров, может несколько снизиться, особенно при циклически выполняемых вычислениях.
Параметры процедур в наших примерах представляют собой значения переменных. Однако в большинстве случаев программисты передают параметры через указатели. Указатель на переменную представляет собой адрес, по которому эта переменная размещена в памяти. Как и переменные, указатели представляют собой 32-битовые величины в Windows. Использование указателей значительно упрощает работу с массивами переменных и во многих случаях является более эффективным, чем передача в процедуру значений переменных.


 
 
 

Библиотека программиста. 2009.
Администратор: admin@programmer-lib.ru