assembler. Учебник для вузов_Юров В.И_2003 -637с (862834), страница 80
Текст из файла (страница 80)
Программа на Pascal инициализирует две переменные, valuel и valueZ, после чего вызывает функцию на ассемблере AddAsm для их сложения. Результат возвращается в программу на Pascalи присваивается переменной rez.356Глава 15. Модульное программированиеЛистинг 15.17.
Вызывающая программа на Pascal{prgl5_17.pas}program prg!4101;{внешние объявления}functionAddAsmtword; external;{$L prg!5_18.obj}varvaluelrword;{здесь как внешние}value2:word;rez:word;beginvaluel:=2;value2:=3;{вызов функции}rez:=AddAsm;wri1е1п("Результат: " , r e z ) ;end.Листинг 15.18. Вызываемая процедура на ассемблере;prg!5_18.asmMASHMODELsmalldatasegment word public ;сегмент данных;объявление внешних переменныхextrn valuel:WORDextrn value2:WORDdataends;KOHeu сегмента данных.codeassume ds:data;привязка ds к сегменту-.данных программы на Pascalmain:AddAsm procnearPUBLIC AddAsm ;внешняяmov c x . d s : valuel;valuelB exmov dx.ds:value2; value2B dxadd cx.dx;сложениеmov a x , e x;результат в ах, так как - словоret;возврат из функцииAddAsm endp;конец функцииend main;конец программыВ последней программе следует обратить внимание еще на одну возможностьдоступа к разделяемым данным — с помощью сегментов типа PUBLIC (см.
главу 5).Совместное использование сегментов данных стало возможным благодаря тому,что компилятор Pascal создает внутреннее представление программы в виде сегментов, как и положено программе, выполняющейся в архитектруре IA-32 напроцессоре Intel. Сегмент данных в этом представлении тоже имеет названиеdata, и директива SEGMENT для него со всеми вытекающими последствиямивыглядит так:data segment word p u b l i cКоманды ENTER и LEAVEУчитывая важность проблемы организации межмодульных связей, в систему команд процессора были введены специальные команды ENTER и LEAVE. Их использование позволяет облегчить написание кода пролога и эпилога в процедурах ассемблера, например:Связь ассемблера с языками высокого уровня357;старый код пролога:pushbpmov bp.sp;новый код пролога:enter 0,0;старый код эпилога:mov sp.bppop bp;новый код эпилога:leaveТранслятор ассемблера предоставляет средства в виде директив, которые ещебольше упрощают работу программиста по формированию кодов пролога и эпилога.
Одной из них является директива ARG. Применение этой и других директивобсудим на конкретном примере. В главе 16 рассматриваются довольно сложныепрограммы, в которых, в частности, используются обсуждаемые здесь директивы.В листинге 16.7 производится обращение к процедуре WindowProc. При этом ей в стеке передается ряд параметров. Кроме того, в процедуре имеются локальные переменные. Заголовок и конец процедуры выглядят следующим образом:;Wi ndowProcWindowProcprocarg@@hwnd:DWORD, @@mes:DWORD, @@wparam:DWORD, @@lparam:DWORDuses ebx.edi,esi,еЬх;эти регистры обязательно должны сохранятьсяlocal@@hdc:DWORD,@@hbrush:DWORD,@@hbit:DWORDexit_wndproc:retWindowProc endpВ этом фрагменте новыми средствами ассемблера для нас являются директивыUSES и LOCAL.Директива USES содержит список регистров (см.
рис. 10.3 в главе 10). Ее использование заставляет транслятор генерировать код для сохранения в стеке этих регистров при входе в процедуру и их восстановления при выходе из нее.Директива LOCAL (см. рис. 10.3) позволяет задействовать в процедуре локальные переменные. Эти переменные должны быть перечислены в списке аргументоввместе с их типами. Информацию о количестве и типах переменных трансляториспользует для формирования соответствующего программного кода.Оттранслируем исходный текст программы из листинга 16.7 и откроем для просмотра файл prg!6_7.lst. Посмотрим на результат применения этих директив:.WindowProc0000012DWindowProc procarg @@hwnd:DWORD, @@mes:DWORD, @@wparam:DWORD, @@1param:DWORDusesebx.edi,esilocal @@hdc:DWORD,@@hbrush:DWORD,@@hbit:DWORD0000012D C8 000C 00 ENTERD 0000Ch,000000131 53PUSH ebx00000132 57PUSH edi00000133 56PUSH esi00000134 83 7D 0C 02crop @@mes,WM_DESTROY000002CFexit_wndproc:000002CF 5E POP esi000002D0 5F POP edi000002D1 5B POP ebx000002D2 C9 LEAVED358Глава 15.
Модульное программирование000002D3 С20010 RET 00010hQ0Q002D6WindowProc endpВидно, что транслятор хорошо «поработал» над кодами входа в процедуру и выхода из нее. Директива USES ebx, edi, esi заставляет транслятор генерировать Команды PUSH и POP для сохранения-восстановления регистров EBX, EDI и ESI. А какоевлияние на формирование кода входа в процедуру и выхода из нее оказывают директивы ARG и LOCAL? Чтобы разобраться с этим, выполним трансляцию трехвариантов программы из листинга 16.7 (глава 16), в каждом из которых закомментируем определенные строки:в Закомментируем строку с директивой ARG.
Фрагмент листинга будет выглядеть следующим образом:;Wi ndowProc.0000012DWindowProc proc:arg@@hwnd:DWORD, @@mes:DWORD, @@wparam:DWORD. @@lpa ram:DWORDuses ebx,edi,esi;эти регистры обязательно должны сохранятьсяlocal@@hdc:DWORD,@@hbrush:DWORD,@@hbit:DWORD0000012D C8 000C 00 ENTERD 0000Ch,000000131 53 PUSH ebx00000132 57 PUSH edi00000133 56 PUSH esi00000134 83 3D 00000000 02 cmp @@mes,WM_DESTROY000002F9exi t_wndproc:000002F9 5EPOP esi000002FA 5FPOP edi000002FB 5BPOP ebx000002FC C9LEAVED000002FD C3RET 00000h000002FEWindowProc endpЗакомментируем строки с директивами LOCAL и USES. Фрагмент листинга будетвыглядеть так:;Wi ndowProc0000012DW1ndowProc procarg @@hwnd:DWORD, @@mes:DWORD, @@wparam:DWORD, @@lparam:DWORD;uses ebx,edi,esi ;эти регистры обязательно должны сохраняться;local @@hdc:DWORD,@@hbrush:DWORD,@@hbit:DWORD0000012D C8 0000 00 ENTERD 00000h,000000131 83 7D0C 02 cmp@@mes,WM_DESTROY000002E6exi t_wndproc:000002E6 C9LEAVED000002E7 C2 0010 RET 00010П000002EAWindowProc endp« Наконец, закомментируем строки с директивами LOCAL и ARG.
Фрагмент листинга:-WindowProc0000012DWindowProc proc;arg @@hwnd:DWORD, @@mes -.DWORD, @@wparam: DWORD, @@l pa ram: DWORDuses ebx,edi,esi ;эти регистры обязательно должны сохраняться;local @@hdc:DWORD,@@hbrush:DWORD,@@hbit:DWORD0000012D 53PUSH ebx0000012E 7PUSH edi0000012F 56PUSH esi00000130 83 3D 00000000 02 cmp @@mes,WM_DESTROY**Error** prg!6_3.asm(209) PROCBEG(4) Undefinedsymbol:@@mes•Warning* prg!6_3.asra(209) PROCBEG(4) Argument needs type overrideСвязь ассемблера с языками высокого уровня359GQ00030Fexit_wndproc:0000030F 5ЕPOP esi00000310 5FPOP edi00000311 5BPOP ebx00000312 C3RET 00000h00000313WindowProc endpПроанализируем эти фрагменты.Применение директив ARG и LOCAL приводит к генерации команд ENTER и LEAVEпри входе и выходе из процедуры.
Поочередное комментирование этих директивпоказывает, что они влияют только на формирование операнда команды ENTER.При использовании директивы LOCAL он равен числу байтов, необходимых для размещения в стеке локальных переменных. Это так называемый кадр стека. Еслистроку с директивой LOCAL закомментировать, то команда ENTER все равно формируется, но с нулевым значением первого операнда. Это говорит о том, что прологпроцедуры создается в любом случае, но директива LOCAL позволяет еще и сформировать кадр стека для хранения локальных переменных процедуры. Соответственно, во всех вариантах генерации команды ENTER в конце процедуры формируется команда LEAVE.Теперь посмотрим на то, какое влияние оказывает директива ARG на формирование команды RET в процедуре WindowProc. Из анализа четырех приведенных ранее вариантов фрагмента листинга видно, что в некоторых из них транслятор вычисляет суммарный размер аргументов, передаваемых в процедуру, и делает этозначение операндом команды RET.
Это производится в тех случаях, когда директива ARG не закомментирована. Отсюда следует вывод о прямом влиянии директивыARG на операнд команды RET. Ненулевое значение операнда команды RET приводитк изменению значения регистра SP\ESP — в нашем случае это означает очистку стека от аргументов, переданных в процедуру.Отметим, что эти средства можно использовать не только для связи Pascalассемблер, но и для организации других межъязыковых связей, в том числе ассемблер—ассемблер.С и ассемблерОбщие принципы организации связи С—ассемблер напоминают только что рассмотренное соединение Pascal и ассемблера.
Поэтому мы коротко обсудим различия на примере конкретных программ. Но прежде отметим, что хотя язык C++предоставляет дополнительные возможности связи программы с ассемблером, одновременно в нем продолжает поддерживаться традиционная организация связи.Поэтому мы рассмотрим связь с ассемблером в стиле С как стандартную. При необходимости читатель, зная основы подобной связи, без труда разберется с нюансами дополнительных возможностей связи в стиле C++.Нас по-прежнему интересуют три вопроса: как передать аргументы в процедуру на ассемблере, как к ним обратиться в процедуре на ассемблере и как возвратить результат?Вначале отметим, что всегда нужно сохранять (и перед выходом из процедурывосстанавливать) содержимое регистров ВР, SP, CS, DS и SS.