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

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


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





Вначале немного теории. Хочу напомнить, что мы работаем только с 32- разрядными приложениями. Такие приложения используют модель памяти fiat и работают только с 32-разрядными операционными системами Windows 98/Windows NT/Windows 2000/Windows XP.
Для такой модели не существует отдельных сегментов данных и кода. Пространство адресов считается линейным, и в нем располагаются код и данные, которые используют 32-разрядные смещения, а вызовы процедур и функций считаются ближними. Такой режим работы обеспечивает высокую производительность 32- разрядных приложений, т. к. нет преобразования "сегмент-смещение" в абсолютные адреса. Кроме того, 32-разрядные приложения "не видят" друг друга и выполняются в изолированном от других приложений пространстве адресов. Это очень сильно отличает их от 16-разрядных приложений, где все программы могли "видеть" друга.

Итак, основные принципы работы ассемблерных процедур в программах на языках высокого уровня мы разобрали. Далее, следуя принципу "лучший критерий истины — практика", перейдем к рассмотрению примеров программного кода. Мы будем рассматривать примеры вначале на Delphi, затем на Visual С++. Для совместной работы наших ассемблерных модулей и программ на языках высокого уровня будем использовать соглашение о передаче параметров stdcaii.

Рассмотрим следующий пример. Пусть требуется найти разность двух целых чисел и вывести результат в окно приложения. Вычисление разности суммы чисел выполним в ассемблерной процедуре, скомпилированной как отдельный модуль. Результат вычитания выведем в окно основного приложения. Назовем нашу процедуру на ассемблере subtwo.
Исходный текст процедуры subtwo приведен в листинге 3.20.
Листинг 3.20. Ассемблерная процедура subtwo, вычисляющая разность двух целых чисел, для использования в Delphi .
.386
.model flat, stdcaii
public subtwo
.data
. code
subtwo proc
push EBP
mov EBP, ESP
mov EAX, DWORD PTR [EBP+8]
sub EAX, DWORD PTR [EBP+12]
pop EBP
ret 8
subtwo endp
end

Сохраним исходный текст процедуры в файле subtwo.asm и откомпилируем программу при помощи одной из двух командных строк в зависимости от вида компилятора ассемблера:
tasm32 /ml subtwo.asm subtwo.obj
ml /с /Fo subtwo.obj subtwo.asm

Если в тексте программы нет ошибок, мы получим объектный файл subtwo.obj, готовый к употреблению.
Для передачи параметров в процедуру subwo используется стек. Для доступа к параметрам мы используем регистр ЕВР, текущее значение которого процедура сохраняет в стеке. Помним, что мы имеем дело с 32-разрядными операндами, поэтому первый параметр и будет иметь смещение в стеке на 8 (с учетом помещенного в стек ЕВР), а второй параметр 12 — смещение 12 относительно вершины стека

Расположение параметров в стеке соответствует соглашению для директивы stdcaii. Сама процедура вычитает числа и возвращает результат в регистре ЕАХ. Согласно stdcaii вызываемая процедура должна сама восстанавливать (очищать) стек. Перед последней командой ret возвращаемое значение уже находится в регистре ЕАХ, а в стеке все еще присутствуют два параметра. Хочется сделать несколько общих замечаний по работе с внешними процедурами и функциями. Они касаются не только процедуры subtwo.
1. Желательно сохранять в стеке регистры ЕВХ, ЕВР, E S I И E D I , Т. К. ОНИ могут использоваться операционной системой, и разрушение их содержимого может привести к неприятным последствиям. Регистры ЕАХ, EDX И ЕСХ можно использовать по своему усмотрению, не заботясь об их сохранении.
2. В 32-разрядных приложениях понятие "сегментный регистр" отсутствует. Если пытаться по аналогии с MS-DOS использовать регистры cs, ES И DS, то это немедленно приведет к краху программы.
3. Не забывайте освобождать стек при выходе из процедуры при использовании директив pascal, stdcaii и safecaii. Количество удаляемых байт равно количеству параметров, умноженному на 4. К примеру, для удаления из стека 3-х параметров необходимо в процедуре последней вызвать команду ret 12.

Вместо ret п можно использовать комбинацию команд:
add ESP, n
ret

Вернемся к нашему примеру. Разработаем программу на языке высокого уровня, вызывающую нашу процедуру subtwo. Начнем с Delphi 7. Наша программа будет представлять собой обычное оконное приложение Windows. Разместим на главной форме приложения три поля редактирования Edit и назовем их HEdit, i2Edit и subResuit. Поле редактирования HEdit будем использовать для ввода числа и, поле i2Edit — для ввода 12 и поле subResuit — для отображения результата вычитания 12 из 11. Слева от полей редактирования поместим три метки статического текста Label.

Разместим на форме также кнопку Button. При нажатии этой кнопки в работающем приложении в поле редактирования subResuit будет отображаться результат вычитания.
Теперь внесем изменения в исходный текст программы. В секцию implementation добавим описание нашей процедуры subtwo:
implementation
{$R *.dfm}
{$L subtwo.obj}

Последняя строка сообщает компоновщику, какой внешний модуль будет использоваться в основной программе. В данном случае это файл subtwo.obj.


 
 
 

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