assembler. Учебник для вузов_Юров В.И_2003 -637с (862834), страница 79
Текст из файла (страница 79)
Синтаксис директивы ARG иллюстрирует рис. 15.2.Н ARGАргумент:Н Аргумент Ь|-|—тЧЭ—| Аргумент |- Ц=Ь-| Идентификатор^I©<=1Рис. 15.2. Синтаксис директивы ARGНесколько слов об обозначениях на рисунке:я имя — идентификатор переменной, который будет использоваться в процедурена ассемблере для доступа к соответствующей переменной в стеке;* тип — тип данных аргумента (по умолчанию WORD для use!6 и DWORD для use32);i* значение_1 определяет количество аргументов с данным именем. Место в стекедля них будет определено, исходя из расчета:значение_1 • значение_2 • размерjnuna.По умолчанию значение_1 — 1;ш значение_2 определяет, сколько элементов данного типа задает данный аргумент.
По умолчанию его значение равно 1, но для типа byte значение_2 = 2, таккак стековые команды не работают с отдельными байтами. Хотя, если явно задать значение_2 = 1, то транслятор действительно будет считать, что в ячейкустека помещен один байт;я идентификатор — имя константы, значение которой присваивает транслятор.Об идентификаторе мы подробно поговорим чуть позже.Таким образом, директива ARG определяет аргументы, передаваемые в процедуру.
Ее применение позволяет обращаться к аргументам по их именам, а не посмещениям относительно содержимого ВР. К примеру, если в начале рассматриваемой нами процедуры на ассемблере asmproc задать директиву ARG в виде argkol:word,y:word, x:word,chr:byte, то к аргументам процедуры можно будет обращатьсяпо их именам, без подсчета смещений. Ассемблер сам выполнит всю необходимую352Глава 15. Модульное программированиеработу. В этом можно убедиться, запустив программу в отладчике. Обратите внимание: порядок следования аргументов в директиве arg является обратным порядку их следования в описании процедуры (строка procedure asmproc(ch:char;x,y,koltinteger); external; в программе на Pascal).
Процедура asmproc с директивой argпредставлена в листинге 15.14.Листинг 15.14. Использование директивы arg{prg!5_14.pas}{Программа на Pascal, вызывающая процедуру на ассемблере, полностьюсовпадает с листингом 15.12};prg!5_14.asmMASMMODEL smallSTACK256.codemain:asmproc proc near;обьявление аргументов:arg kol:WORD,y:WORD,x:WORD,chr:BYTE=a_sizePUBLIC asmprocpushbpсохранение указателя базыmov bp.sp;настройка bp на стек через spmov dh.byte ptr у ; у в dhmov dl.byte ptr x ; x в dlmov ah,02h;номер службы BIOSint 10h;вызов прерывания BIOSmov ah,09h;номер службы BIOSmov al.chr;символ - в almov bl,07h;маска вывода символахог bh.bhmov ex,kol;kol в схint 10h;вызов прерывания BIOSpop bp;эпилогret a_sizeasmproc endpend main;будет ret 8 и выход из процедуры;конец процедуры;конец программыПосле того как решена проблема передачи аргументов в процедуру и выполнены все необходимые действия, возникает очередной вопрос: как правильно возвратить управление? При возврате управления в программу на Pascal нужнопомнить, что соглашения этого языка требуют, чтобы вызываемые процедуры самостоятельно очищали за собой стек.
Программа на ассемблере также должна удовлетворять этому требованию и заботиться об очистке стека перед своим завершением. Для этого необходимо составить эпилог.Действия, выполняемые кодом эпилога для связи Pascal—ассемблер.1. Записать содержимое bp в sp командой mov sp,bp. Это действие восстанавливает в sp значение, которое было на момент входа в процедуру. Необходимостьв этом действии возникает в том случае, если в процедуре производилась работа со стеком. В листинге 15.13 такой работы не было, поэтому код эпилога реализует только следующие два действия.2.
Восстановить сохраненный в стеке регистр ВР.3. Удалить из стека переданные процедуре аргументы.Для удаления из стека аргументов можно использовать различные способы.Связь ассемблера с языками высокого уровня353И Можно явно скорректировать значение SP, переместив указатель стека на необходимое количество байтов в положительную сторону. Это — не универсальный способ, к тому же он чреват ошибками, особенно при частых модификациях программы.11 Можно использовать в директиве arg после записи последнего аргумента операнд, состоящий из символа равенства (=) и идентификатора, указанного за нимв следующей синтаксической конструкции:идентификаторВ этом случае TASM при обработке директивы arg подсчитает количество байтов, занятых всеми аргументами, и присвоит их значение идентификатору.В нашем случае директиву arg можно определить так:arg c h : b y t e ; x : w o r d ; y : w o r d ; k o l : w o r d = a _ s i z eTASM после обработки данной директивы присвоит имени a_size значение8 (байт).
Это имя впоследствии нужно будет указать в качестве операнда команды ret:ret a_sizeЕсть еще одна возможность организации данных Pascal—ассемблер — использовать операнды директивы MODEL. Вы помните, что она позволяет задать модельпамяти и учесть соглашения языков высокого уровня о вызове процедур. Для связи Pascal—ассемблер ее можно задавать в видеMODELlarge,pascalЗадание в таком виде директивы MODEL позволяет:ii описать аргументы процедуры непосредственно в директиве ргос:asmproc proc near c h : b y t e , x : w o r d , y : w o r d , k o l : w o r dш автоматически сгенерировать код пролога и эпилога в процедуре на ассемблере;* для доступа к аргументам, объявленным в PROC, использовать их имена (в этомотношении данный вариант является аналогом предыдущего варианта с директивой ARG).Листинг 15.15 демонстрирует, как отражаются особенности данного вариантана тексте процедуры ассемблера.
Обратите внимание на то, что пролога уже нет,так как он формируется транслятором автоматически; вместо эпилога обязательно нужно задавать команду RET, только без операндов. Интересно изучить текстлистинга 15.16, который получается в результате трансляции листинга 15.15. В немвидны сформированные транслятором коды пролога и эпилога. Кроме того, транслятор заменил команду RET без операндов командой ret 0008, которая, в соответствии с требованиями к взаимодействию с программами на Pascal, удалит из стекааргументы, переданные вызываемой процедуре.Листинг 15.15. Использование директивы MODEL{prg!5_15.pas}{Программа на Pascal, вызывающая процедуру на ассемблере, полностьюсовпадает с листингом 15.12};prg!5_15.asmMASMMODELlarge,pascal12 Ззк. 256продолжение &354Глава 15.
Модульное программированиеЛистинг 15.15 (продолжение)STACK256.codeasmproc proc near chr :BYTE,x:WORD,y:WORD,kol:WORDPUBLIC asmproc; у в dhmov dh.byte ptr у; x в dlmov dl.byte ptr x;номер службы BIOSmov ah,02h;вызов прерывания BIOSint 10h;номер службы BIOSmov ah,09h;символ - в almov al,chr;маска вывода символаmov bl,07hxor bh.bh;kol в схmov ex,kol;вызов прерывания BIOSint 10hretasmproc endpend;конец процедуры;конец программыЛистинг 15.16. Результат трансляции листинга 15.15Turbo AssemblerVersion 4.117/04/98 22:30:57Page 1prg!4_82.asm;prg!4_92.asmMASM0000 MODELlarge,pascal2560000 STACK0000 .code00000000 asmproc procnear chr:BYTE,x:WORD,y:WORD,kol:WORDPUBLIC asmproc19PUSH0000 55BP1 100001 SB EC MOV BP, SP1 11у в dh0003 8A 76 06 mov dh, byte ptr у120006 8A 56 08 mov dl, byte ptr xx в dlmov ah.
02h0009 B4 0213номер службы BIOS14000B CD 10int lOhвызов прерывания BIOSmov ah, 09h15000D B4 09номер службы BIOS16000F 8A 46 0A mov al, chrсимвол - в al170012 B3 07mov Ы,07hмаска вывода символаxor bh, bh0014 32 FF18mov ex, kol0016 8B 4E 04kol в сх1920int 10П0019 CD 10вызов прерывания BIOS1 21POP BP001B 5D1 22001C C2 0008RET 0000811001F asmproc endp23конец процедуры24endконец программыТаковы стандартные способы вызова ассемблерных процедур из программ наPascal и лередачи им аргументов.
Эти способы будут работать всегда, но, совершенствуясь, компилятор может предоставлять и более удобные средства. Их мырассматривать не будем, так как, в конечном счете, они сводятся к рассмотреннойнами процедуре. Остались открытыми два вопроса.и Как быть с передачей данных остальных типов Pascal, ведь мы рассмотрели только данные размером в байт и слово?li Как возвратить значение в программу на Pascal?Что касается ответа на первый вопрос, то необходимо вспомнить, что в языкеPascal существуют два способа передачи аргументов в процедуру: по ссылке и позначению.Связь ассемблера с языками высокого уровня355Тип аргументов, передаваемых по ссылке, совпадает с типом ассемблера dwordи с типом pointer в Pascal. По сути, это указатель из четырех байтов на некоторыйобъект.
Структура указателя обычная: два младших байта — смещение, два старших байта — значение сегментной составляющей адреса. С помощью такого указателя в программу на ассемблере передаются адреса следующих объектов:Ш всех аргументов, объявленных при описании в программе на Pascal как var, независимо от их типа;аргументов pointer и longint;' строк string;множеств;массивов и записей, имеющих размер более четырех байтов.Аргументы по значению передаются следующим образом:для типов char и byte — как байт;для типа boolean — как байт со значением 0 или 1;для перечисляемых типов со значением 0...255 — как байт; более 255 — как двабайта;к для типов integer и word — как два байта (слово);» для типа real — как шесть байтов (три слова);» массивы и записи, длина которых не превышает четырех байтов, передаются«как есть».Заметим, что аргументы таких типов, как single, double, extended и comp, передаются через стек сопроцессора.Что касается ответа на второй вопрос, то мы выясним его на конкретном примере.
Напомню, что мы рассматриваем вызов из программы на Pascal внешнейпроцедуры на ассемблере. Понятно, что вызов ради вызова вряд ли нужен — вызываемая процедура должна иметь возможность вернуть данные в вызывающую программу. Поэтому такую вызываемую процедуру правильнее рассматривать какфункцию. В связке Pascal—ассемблер для того, чтобы возвратить результат, процедура на ассемблере должна поместить его значение в строго определенное место(табл. 15.2).Таблица 15.2. Возврат результата из процедуры на ассемблере в программу на PascalТип возвращаемого значенияМесто записи результатаБайтALСловоАХДвойное словоDX:AX (старшее слово:младшее слово)УказательDX:AX (сегментхмещение)В листинге 15.17 приведен текст вызывающего модуля на Pascal, а в листинге 15.18 — код вызываемого модуля на ассемблере.