assembler. Учебник для вузов_Юров В.И_2003 -637с (862834), страница 78
Текст из файла (страница 78)
Взаимодействие Pascal—ассемблер (модуль на ассемблере)<1><2><3><4><5><б><7><8><9>«10»;prg!5_12.asro;Процедура на ассемблере, которую вызывает;программа на Pascal.;Для вывода на экран используются службы BIOS:;02п - позиционирование курсора.;09п - вывод символа заданное количество раз.MASMMODEL smallSTACK256-codeпродолжение &348Глава 15. Модульное программированиеЛистинг 15.13 (продолжение)<11><12><13><14>asmproc proc nearPUBLIC asmprocpushbpmov bp.sp;объявлена как внешняя;пролог<15>mov dh,[bp+6];номер строки для вывода<16>;символа у - в dh<17>mov dl,[bp+8];номер столбца для вывода<18>;символа х - в dl<19>mov ah,02h;номер службы BIOS<20>int 10h;вызов прерывания BIOS<21>;вызов функции 09h прерывания BIOS 10п:<22>;вывод символа из а\ на экран<23>mov ah,09h;номер службы BIOS<24>mov al,[bp+10];символ ch в al<25>mov bl,07h;атрибут символа - в Ы<26>xor bh.bh<27>mov cx,[bp+4];копичество "выводов"<28>;символа - в сх<29>int 10h;вызов прерывания BIOS<30>pop bp;восстановление bp<31>;очистка стека и возврат из процедуры<32>ret 8<33>asmproc endp;конец процедуры<34>endПроцесс организации такой связи состоит из нескольких шагов.1.
Написать процедуру на ассемблере дальнего (far) или ближнего типа (near).Назовем ее для примера asmproc. В программе на языке ассемблера (назовем ееprg!5_13.asm), в которую входит процедура asmproc, необходимо объявить имяэтой процедуры внешним с помощью директивы PUBLIC:PUBLIC asmprocДля того чтобы процедура на ассемблере при компоновке с программой на Pascalвоспринималась компилятором Borland Pascal 7.0 как far или near, недостаточно просто объявить ее таковой в директиве PROC (строка 11 листинга 15.13).Кроме того, вам нужно включить или выключить параметр компилятора, доступный через меню интегрированной среды: Options > Compiler > Force far calls.Установка этого параметра заставляет компилятор генерировать дальние вызовыподпрограмм. Альтернатива данного параметра — ключ {$F+} или {$F-} (соответственно, включено или выключено) в программе.
Это — локальные ключи, то естьв исходном тексте программы на Pascal их может быть несколько, и они могут,чередуясь друг с другом, поочередно менять форму генерируемых адресов перехода: для одних подпрограмм — дальние вызовы, для других — ближние.2. Произвести компиляцию программы prg!5_12.asm с целью устранения синтаксических ошибок и получения объектного модуля программы prg!5_12.obj:tasm /zi prg!5_12,,,3. В программе prg!5_12.pas на Pascal, которая будет вызывать внешнюю процедуруна ассемблере, следует вставить директиву компилятора {$L \nyrb\prg_15_12.obj}.Эта директива заставит компилятор в процессе компиляции программыprg!5_12.pas загрузить с диска объектный модуль программы prg!5_12.obj.В программе prg!5_12.pas необходимо объявить процедуру asmproc как внешнюю.В итоге последние два объявления в программе на Pascal будут выглядеть так:{$L my_asm}procedure asmproc(ch:char;kol,x,y:integer); external;Связь ассемблера с языками высокого уровня3494.
Если вы собираетесь исследовать в отладчике работу программы, то необходимо потребовать, чтобы компилятор включил отладочную информацию в генерируемый им исполняемый модуль. Для этого есть две возможности. Перваязаключается в использовании глобального ключа {$0+}. Этот ключ должен бытьустановлен сразу после заголовка программы на Pascal. Вторая альтернативнаявозможность заключается в установке параметра компилятора: Options > Compiler > Debug Information.5.
Выполнить компиляцию программы на Pascal. Для компиляции удобно использовать интегрированную среду. Для изучения особенностей связки Pascal —ассемблер удобно прямо в интегрированной среде перейти к работе в отладчике командой Tools > Turbo Debugger (или клавишами Shift-i-F4). Будет загруженотладчик. Его среда вам хорошо знакома; в данном случае в окне Module вы увидите текст программы на Pascal. Нажимая клавишу F7, вы в пошаговом режимебудете исполнять программу на Pascal. Когда очередь дойдет до вызова процедуры на ассемблере, отладчик откроет окно с текстом программы на ассемблере. Но наш совет вам — не ждать этого момента, так как вы пропустите некоторые интересные вещи.
Дело в том, что отладчик скрывает момент перехода изпрограммы на Pascal в процедуру на ассемблере. Поэтому лучше всего исполнять программу при открытом окне CPU отладчика. И тогда вы станете свидетелями тех процессов, которые мы будем обсуждать далее.Если бы взаимодействие программ ограничивалось только передачей и возвратом управления, то на этом обсуждение можно было бы и закончить. Но дело значительно усложняется, когда требуется передать аргументы (в случае процедуры)или передать аргументы и возвратить результат (в случае функции). Рассмотримпроцессы, которые при этом происходят.Передача аргументов при связи модулей на разных языках всегда производится через стек.
Компилятор Pascal генерирует соответствующие команды при обработке вызова процедуры ассемблера. Это как раз те команды, которые отладчикпытался скрыть от нас. Они записывают в стек аргументы и генерируют командуCALL для вызова процедуры ассемблера. Чтобы убедиться в этом, просмотрите наисполняемый код программы в окне CPU отладчика. После обработки вызова процедуры и в момент передачи управления процедуре asmproc содержимое стека будет таким, как показано на рис. 15.1, а. Для доступа к этим аргументам можно применять различные методы, наиболее удобный из них — использование регистра В Р.Регистр ВР, как уже отмечалось, специально предназначен для организациипроизвольного доступа к стеку.
Когда мы рассматривали связь ассемблерных модулей, то говорили о необходимости добавления в текст вызываемого модуля фрагментов, настраивающих его на передаваемые ему аргументы. При объединенииразноязыких модулей также нужно вставлять подобные дополнительные фрагменты кода. Они, кроме всего прочего, позволят учесть особенности конкретного языка. Фрагмент, вставляемый в самое начало вызываемого модуля, называется прологом модуля (процедуры).
Фрагмент, вставляемый перед командами передачиуправления вызывающему модулю, называется эпилогом модуля (процедуры). Егоназначение — восстановление состояния вычислительной среды на момент вызова данного модуля.350Глава 15. Модульное программированиеОперативная память000:0000 10000:OOOOJss:sp ->1IbpIPkolУkolУXXss:ffff->chДно стекаСтаршие адресаоперативной памятиаhss:ffff->chДно стекаСтаршие адресаоперативной памятибОперативная память0000:0000 Гss:sp 7> ./+2+4+6+8L+10ss:ffff->.
.bR'Pkol. ...У. .....xchДно стекаСтаршие адресаоперативной памятивРис. 15.1. Изменение содержимого стека при передаче управления в связкеPascal—ассемблерРассмотрим действия, выполняемые кодами пролога и эпилога при организации связи Pascal—ассемблер.Действия, выполняемые кодом пролога.1. Сохранить значение Ьр в стеке.
Это делается с целью запоминания контекста вызывающего модуля. Стек при этом будет выглядеть, как показано на рис. 15.1, б.2. Записать содержимое SP в ВР. Тем самым ВР теперь тоже будет указывать навершину стека (рис. 15.1, в).После написания кода пролога все обращения к аргументам в стеке можно организовывать относительно содержимого регистра ВР. Из рис.
15.1, в видно, что дляобращения к верхнему и последующим аргументам в стеке содержимое Ьр необходимо откорректировать. Нетрудно посчитать, что величина корректировки будетразличаться для процедур дальнего (far) и ближнего (near) типов. Причина понятна: при вызове процедуры типа near в зависимости от установленного режимаадресации (use!6 или use32) в стек записывается 2(4) байта в качестве адресавозврата (содержимое ip/eip), а при вызове процедуры типа far в стек записывается 4(8) байта (содержимое IP/EIP и CS)1.Таким образом, коды пролога для процедур ближнего и дальнего типа соответственно будут выглядеть следующим образом:asmproc procnear; пролог для процедуры типа nearpushbpmov bp.sp;к прологу можно добавить командукорректировки bp на 4 с тем, чтобы регистр Ьр;указывал на верхний из передаваемых аргументов в стекеadd Ьр,4;теперь Ьр указывает на kolasmproc proc farЕсли действует режим адресации ше32, то в стек записываются двойные слова.
По этой причинезапись 16-разрядного регистра cs также производится четырьмя байтами, при этом два старших байта этого значения нулевые.Связь ассемблера с языками высокого уровня351;пролог для процедуры типа farpushbpraov bp.sp;к прологу можно добавить командукорректировки bp на 6 с тем, чтобы регистр Ьр;указывал на верхний из передаваемых аргументов в стекеadd Ьр,б;теперь Ьр указывает на kolДалее доступ к переданным в стеке данным осуществляется, как показано в листинге 15.7.Как видите, все довольно просто. Но если мы вдруг решили изменить тип нашей процедуры ассемблера с far на near или наоборот, то нужно явно изменитьи код пролога. Это не совсем удобно. TASM предоставляет выход в виде директивы ARG, которая служит для работы с аргументами процедуры.