1
Лабораторная работа по курсу "Организация ЭВМ и систем"
Процедуры. Ассемблерные модули в программах на языках высокого уровня
Цель работы: Освоить создание процедур и передачу параметров через стек; научиться включать ассемблерные модули в программы на языках высокого уровня.
Задание 1. Простая процедура в ассемблерной программе
1.1. Процедура в общем модуле. Напишите 16-битную программу (работающую в реальном режиме микропроцессора Intel) prog1.asm, которая содержит процедуру sum. Процедура sum принимает в стеке три параметра - 16-битных числа, вычисляет их сумму и возвращает ее в регистре ax. Оформите по стандартным правилам пролог и эпилог процедуры. Главная программа вызывает процедуру sum(A,B,C) и записывает результат в ячейку c именем S.
Выполните программу в отладчике и проверьте содержимое стека, записанное Вами при домашней подготовке к работе. Поясните, как получить доступ к параметрам в процедуре, к локальным переменным процедуры (если бы они были)? Где происходит очистка стека в Вашей программе и при помощи каких команд? *Расшифруйте код команды call sum.
1.2. Процедура в отдельном модуле. Модифицируйте программу prog1.asm (дайте ей имя prog2.asm): перенесите процедуру sum в отдельный модуль sum.asm, изменив тип процедуры на far. При этом не забудьте указать в главной программе директиву extrn sum:far, в модуле sum.asm - директив public sum. Модуль sum.asm должен завершаться директивой end без параметров. Командная строка для компоновки программы из нескольких объектных модулей имеет следующий вид:
tlink prog2 sum или tlink prog2 sum, example
В первом случае имя исполнимого файла будет совпадать с именем первого объектного модуля (prog2.exe), во втором случае именем исполнимого файла будет example.exe.
Выполните программу в отладчике и проверьте содержимое стека, записанное Вами при домашней подготовке к работе. Объясните в отчете отличия содержимого стека от полученного в п. 1.1. *Будет ли программа работать, если присвоить процедуре sum тип near?
Задание 2. Ассемблерная процедура в приложении Delphi
2.1. Создание консольного приложения Delphi. ОС Windows работает в защищенном ре-
жиме (protected mode) микропроцессора Intel и плоской модели памяти (flat memory model). При этом ассемблерный код программ проще, чем в реальном режиме, т.к. все 32-битные адреса являются адресами типа near и в прикладных программах не нужно заботиться о содержимом сегментных регистров. Консольное приложение Windows, хотя и работает с окном консоли, напоминающим экран программ MS DOS, является полноценным 32-х битным приложеним ОС Windows, хотя и без привычного для Windows оконного интерфейса.
1.Запустите Delphi из стартового меню: Пуск|Программы|Borland Delphi 5|Delphi 5.
2.В Delphi создайте консольное приложение: File|New, выберите пункт Console Application.
3.Наберите текст программы (рис. 1), учитывая, что некоторые из этих строк уже сгенерированы Delphi. В этой программе описана функция Calc, которая принимает пять чисел A, B, C, D, E типа INTEGER, вычисляет результат по формуле (A+B)-(C+D)+E+loc, и возвращает его как значение типа INTEGER.
4.Сохраните проект в Вашей папке на диске D:\ под именем Ex1.
5.Выполните приложение: Run|Run или <F9> или кнопка на панели инструментов Delphi.
2.2. Изучение ассемблерного кода программы.
1.Запустите приложение в отладчике: Run|Trace Into или <F7> или кнопка .
2.Перейдите в окно CPU отладчика: View|Debug Windows|CPU.
3.Объясните в отчете, каким способом в Delphi осуществляется передача параметров в процедуру/функцию, как возвращается результат функции, где происходит очистка стека. Примите во внимание, что первые три переменные, A, B и C, будут находиться в главной программе в регист-
2
рах EBX, ESI и EDI соответственно. *Объясните, как следует изменить заголовок функции Calc, чтобы все параметры передавались через стек?
program Project1; |
|
{$APPTYPE CONSOLE} |
|
uses |
|
SysUtils; |
|
var |
integer; |
A, B, C, D, E: |
|
ResVal: integer; |
|
function Calc (A1,A2,A3,A4,A5: integer): integer; var
loc: integer;
begin loc := 5;
Calc := (A1 + A2) - (A3 + A4) + A5 + loc; end;
begin
WRITELN ('Enter five integer numbers'); READLN (A,B,C,D,E);
ResVal := Calc(A,B,C,D,E); ResVal := ResVal + 1; WRITELN('Result = ',ResVal); READLN;
end.
Рис. 1. Текст консольного приложения наязыке Object Pascal
2.3. Создание ассемблерного модуля.
1. Наберите текст модуля с процедурой Calc на языке ассемблера (на рис. 2). Сохраните модуль в файле Calc.asm. Запишите прокомментированный Вами текст модуля в отчет.
.386
PUBLIC Calc
CODE segment USE32 PUBLIC
Calc PROC
... ... ... ... ... ... ...
ENDP ; конец процедуры CODE ends ; конец сегмента
end ; конец модуля
Рис. 2. Шаблон для ассемблерного модуля
ПРИМЕЧАНИЕ. Тело процедуры Calc можно взять из окна отладчика.
2.4. Включение ассемблерного модуля в приложение Delphi.
1.Откомпилируйте модуль Calc.asm компилятором TASM.
2.В среде Delphi в тексте программы Ex1:
−Уберите тело функции Calc, т.к. теперь эта функция находится в модуле Calc.obj.
−Добавьте атрибут external в заголовок функции Calc. Этим мы укажем компилятору, что функция Calc находится в другом модуле:
function Calc(…): integer; external;
Перед заголовком функции Calc добавьте строку с директивой компилятора {$L Calc} или {$LINK Calc} , которая заставит компилятор в процессе компоновки присоединить к проекту объектный модуль Calc.obj. Если объектный модуль находится в другой папке, то в директиве укажите полное имя файла Calc.obj.
− Сохраните измененный проект под именем Ex2. 3. Выполните и отладьте приложение Ex2.
ПРИМЕЧАНИЕ. Если в процессе отладки Ex2 Вы измените только файл Calc.obj, то при запуске проекта Ex2 будет выполнен старый файл Ex2.exe, т.е. Вы не сможете включить в приложение
3
сделанные Вами в Calc изменения. В этом случае следует сначала выполнить в Delphi команду
Project|Build Ex2, а затем - Run|Run.
Задание 3. *Включение ассемблерного модуля в программу на языке С++
Напишите программу Ex3 на языке С++ в Borland C++ Builder или MS Visual C++,
вызывающую простую ассемблерную функцию. Функция получает два-три параметра и возвращает значение целого типа.
При включении ассемблерного модуля в проект, написанный на языке C++ следует учитывать следующее:
•В системах Borland C++ Builder / MS Visual C++ ассемблерный модуль *.asm можно включить в проект, пользуясь средствами соответствующей системы. При сборке проекта ассемблер (TASM или MASM) будет вызван автоматически, т.к. он входит в стандартную поставку системы.
•Ассемблерная функция не должна изменять содержимое регистров EBX, ESI и EDI, поскольку они используются для хранения регистровых переменных.
•Имя процедуры в ассемблерном модуле следует начинать с символа подчеркивания "_", поскольку компоновщик С ко всем внешним именам добавляет этот символ. (Это справедливо не для всех компиляторов.) Кроме того, это имя должно быть набрано с использованием того же регистра клавиатуры, что и соответствующее имя в программе на С++.
•Прототип функции в программе на С++ должен начинаться с квалификатора external "C" Этим мы указываем, что имя внешней функции должно формироваться по правилам языка С (см. выше), а не С++. Если не указать "C", то имя внешней функции будет непредсказуемым (из-за обработки перегрузки функций).
•По умолчанию параметры передаются в стеке в обратном порядке, справа налево, т.е. самым последним помещается в стек самый первый параметр. При этом многие компиляторы могут помещать часть параметров в регистры (Borland - 3 параметра, Microsoft - 2 параметра), но при явном указании квалификатора _fastcall в прототипе функции.
•Функция возвращает значение целого типа и указателя в регистре EAX, вещественного типа - в регистре сопроцессора ST0.
•Если используется соглашение по умолчанию (cdecl), то стек очищает вызывающая программа, т.е. в этом случае следует использовать команду ret без числового аргумента. Примерный вид главной программы и ассемблерного модуля:
extern "C" unsigned asmproc |
.486 |
(unsigned a, unsigned b); |
PUBLIC asmproc |
void main (void) |
CODE segment USE32 PUBLIC |
{ unsigned a; |
_asmproc proc |
a=asmproc(5,6); |
.. |
.. |
_asmproc endp |
} |
CODE ends |
|
end |
Порядок выполнения лабораторной работы
1.Выполните задания 1-2. Работу программ prog1, prog2 и Ex2 покажите преподавателю.
2.Оформите отчет и защитите работу.
Требования
1.При подготовке к лабораторной работе (дома) запишите в отчет а) прокомментированные тексты программ prog1.asm, prog2.asm + sum.asm и приложения Delphi Ex2; б) вид стека при входе в процедуру sum и после выполнения пролога (для prog1.asm и prog2.asm).
2.При выполнении работы включите в отчет все требуемые пояснения.
* Необязательные задания. Оцениваются дополнительно, если студент полностью выполнил обязательные задания.
---------------------------------------------------------------------------------------------------
© Лабораторная работа подготовлена Л.В. Илюшечкиной