Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

гос / sp-lect (1)

.pdf
Скачиваний:
18
Добавлен:
16.02.2016
Размер:
2.59 Mб
Скачать

Змінна унікальне у межах підпрограми символьне імя локальної змінної підпрограми, а тип змінної будь який простий тип або попередньо визначений структурований тип.

При великій кількості локальних змінних для перенесення переліку змінних на наступний рядок використовується символ «\» після коми або декілька директив LOCAL.

Використання розширених можливостей синтаксичного опису підпрограми забезпечує автоматичне дотримання конвенцій виклику та іменування, що, зокрема, забезпечується генерацією асемблером «прихованого» коду прологу та епілогу підпрограми.

Наприклад, для підпрограми визначеної як

FunctonName PROC STDCALL PUBLIC USES esi edi ebx p1:DWORD, p2:DWORD LOCAL v1:BYTE, v2:WORD, v3:DWORD

LOCAL v4[20]:BYTE mov eax,p1 mov ebx,p2 mov v1,1 mov v2,2 mov v3,3

ret FunctonName ENDP

Асемблер генерує наступний код

; Пролог підпрограми (наступні 3 команди еквівалентні команді ENTER 28,0)

push ebp

; Зафіксувати стан кадру стеку для

mov ebp, esp

; подальшого доступу до параметрів

sub esp, 28

; Зарезервувати місце для локальних

; змінних визначених директивами LOCAL (27 байт і вирівнювання стеку)

push esi

push edi ; USES esi edi ebx

push ebx

; Код підпрограми

STDCALL (так само для C і SYSCALL,

mov eax, ss:[ebp+8]

mov ebx, ss:[ebp+12] однак для PASCAL по іншому як?)

mov byte ptr ss:[ebp-1],1

; Локальні змінні

mov word ptr ss:[ebp-4],2

; розміщуються

mov dword ptr ss:[ebp-8],3

; в стеку

; Епілог підпрограми

 

pop ebx

 

 

 

pop edi

 

 

 

pop esi

 

 

 

mov esp, ebp

Команда

 

pop ebp

 

LEAVE

 

ret 8

; STDCALL (так само для PASCAL,

;однак для С по іншому як?)

Зрозширеного синтаксичного опису підпрограми видно, що MASM, безпосередньо не підтримує, як це не дивно, найбільш «асемблерну» з усіх конвенцій виклику FASTCALL. Однак, зовсім не обовязково використовувати повні можливості розширеного синтаксису опису підпрограми, і на асемблері можна «під лаштуватися» під будь яку конвенцію виклику, сформувавши за необхідності потрібний код прологу та епілогу «вручну» – те, що неможливо

написати на асемблері, не можливо написати взагалі!

Певні перешкоди створюють не підтримувані безпосередньо конвенції іменування, але тут на допомогу приходить підтримувана MASM конвенція виклику і іменування SYSCALL, яка не передбачає модифікації визначеного в описі підпрограми імені функції при формуванні її внутрішнього імені. Це дозволяє при описі підпрограм призначати їм імена, що співпадають з внутрішніми іменами, які хоче бачити С-компілятор.

Наприклад, функцію з прототипом int __fastcall FunctionName(int x, int y) компілятор Microsoft Visual C++буде шукати за іменем @FunctionName@8.

Тоді опис відповідної підпрограми на асемблері буде виглядати наступним чином:

@FunctionName@8

PROC SYSCALL PUBLIC USES esi edi ebx

; В регістрі ecx параметр x, в edx – параметр y <код підпрограми>

ret

@FunctionName@8 ENDP

В цьому прикладі кількість параметрів не передбачає використання стеку, однак слід зазначити, що і в цьому випадку при формування внутрішнього імені використовується декорація пост суфіксом @8. При більшій кількості параметрів їх опис потрібно розпочинати з третього, імя функції завершити пост суфіксом @N, де N дорівнює загальному розміру усіх параметрів функції.

Порядок параметрів в стеку для SYSCALL співпадає з порядком прийнятим для __fastcall (і __cdecl), асемблер для SYSCALL побудує коректний стековий кадр для звертання до параметрів за іменами зазначеними в описі. Завершити підпрограму доведеться трохи порушивши SYSCALL командою RET K, де K дорівнює загальному розміру параметрів функції в стеку.

7.5 Статичні бібліотеки

7.5.1 Структура вихідного коду статичних бібліотек

Каркасний код статичної бібліотеки має наступний вигляд

.386

.model flat [,<конвенція>]

option casemap:none

.code

<визначення підпрограми>

………………….

end

Всі призначені для використання поза межами модуля (експортовані) функції статичної бібліотеки повинні визначатися з атрибутом видимості PUBLIC або за допомогою окремої однойменної директиви: PUBLIC імя_функції.

Трансляція вихідного тексту майбутньої бібліотеки виконується звичайним способом

ML.EXE /c /coff /Cp /nologo /I"C:\MASM32\INCLUDE" імя.asm

Подальше отримання бібліотечного lib-файлу виконується за допомогою спеціального параметра лінкера /LIB

LINK.EXE /LIB /LIBPATH:"C:\MASM32\LIB" імя.obj

або з використанням спеціальної утиліти Microsoft Library Manager LIB.EXE /LIBPATH:"C:\MASM32\LIB" імя.obj

Приклад 7.1 Статична бібліотека slldemo.lib в якій реалізовано альтернативні і розширені варіанти стандартних функцій С для обробки рядків. Зокрема, стандартна С-функція strcat вміє обєднувати тільки два рядки, а її розширений бібліотечний аналог astrcat – довільну кількість. Деякі функції мають як __cdecl так і __fastcall реалізації, а аналог функції strlen реалізовано згідно з конвенцією __stdcall.

; Файл slldemo.asm

.486

.model flat

option casemap:none

.code

StringLength

proc PRIVATE uses ecx edi

;Внутрішня функція для визначення довжини ASCIIZ-рядка

;Передавання параметрів регістрове.

; Вхід: EDI – адреса рядка, Вихід: EAX – довжина

; Внутрішня функція зберігає ВСІ регістри, які використовує

mov ecx,-1

xor al,al

repnz scasb

neg ecx

lea eax,[ecx-2]

ret

StringLength endp

astrlen proc STDCALL PUBLIC uses edi lpstr:DWORD

;size_t strlen(const char* String)

mov edi,lpstr call StringLength ret

astrlen endp

amemcpy proc C PUBLIC uses esi edi ebx lpdst:DWORD,\ lpsrc:DWORD, n:DWORD

;void *memcpy(void *dst, const void *src, size_t n)

mov edi,lpdst mov esi,lpsrc mov ecx,n mov ebx,ecx shr ecx,2 rep movsd mov ecx,ebx and ecx,3 rep movsb ret

amemcpy endp

astrcpy proc C PUBLIC uses esi edi lpdst:DWORD, lpsrc:DWORD mov edi,lpsrc

call StringLength

lea ecx,[eax+1] ; 0 для завершення рядка

mov esi,edi mov edi,lpdst shr ecx,2 rep movsd

lea ecx,[eax+1] and ecx,3

rep movsb ret

astrcpy endp

@fcstrcpy@8

proc SYSCALL PUBLIC uses esi edi

; __fastcall-варіант astrcpy.

mov edi,edx

call StringLength mov esi,edi

mov edi,ecx lea ecx,[eax+1] shr ecx,2

rep movsd

lea ecx,[eax+1] and ecx,3

rep movsb ret

@fcstrcpy@8 endp

amemset proc C PUBLIC uses edi ebx lpdest:DWORD, chr:BYTE,\ count:DWORD

;void *memset( void *dest, int c, size_t count );

mov edi,lpdest mov al,chr mov ecx,count mov ah,al mov bx,ax bswap eax mov ax,bx mov ebx,ecx shr ecx,2

rep stosd mov ecx,ebx and ecx,3 rep stosb ret

amemset endp

@fcmemset@12 proc SYSCALL PUBLIC uses edi ebx count:DWORD

;void *memset( void *dest, int c, size_t count );

;lpdest=ECX, chr=DL (EDX),

mov edi,ecx mov al,dl mov ecx,count mov ah,al mov bx,ax bswap eax mov ax,bx mov ebx,ecx shr ecx,2

 

rep stosd

 

mov ecx,ebx

 

and ecx,3

 

rep stosb

 

ret 4

@fcmemset@12 endp

astrcat

proc C PUBLIC uses esi edi ebx strcount:DWORD, lpstrlist:VARARG

;Виконує конкатенацію декількох ASCIIZ-рядків, приєднуючи їх до першого

;Вхід: strcount – кількість рядків, що буде приєднуватися до першого,

;тобто при виклику з N параметрами strcount=N-1

; lpstrlist – перелік адрес рядків, перший елемент адреса рядка-приймача

; Вихід: немає (EAX==0)

lea edx,lpstrlist mov edi,[edx] call StringLength lea edi,[edi+eax] mov ebx,strcount jmp zero

next: lea edx,[edx+4] mov esi,[edx]

@@: lodsb

stosb or al,al jnz @B dec edi dec ebx

zero: or ebx,ebx jnz next stosb

ret astrcat endp End

7.5.2 Звязування MASM із статичними бібліотеками

Для звязування проекту Microsoft Macro Assembler із статичною бібліотекою потрібно додати імя файлу бібліотеки в командний рядок лінкера або скористатися директивою INCLUDELIB. При лінкуванні проекту файл бібліотеки повинен розміщуватися в каталозі проекту, або в стандартних каталогах, в яких лінкер виконує пошук бібліотек, або зазначатися за повним імям.

Після цього потрібно виконати опис прототипів використовуваних функцій бібліотеки у вихідному тексті асемблерної програми у вигляді:

ім’я PROTO [<конвенція>] <тип_параметрів>

<тип_параметрів> являє собою розділений комою список записів виду :тип, де тип співпадає з типом параметрів функції. Символьні імена параметрів зазначати не обовязково.

Після визначення прототипів виклик функцій виконується за допомогою директиви з синтаксисом високого рівня INVOKE. Ця директива генерує послідовність з команд PUSH для розміщення параметрів в стеку, команди CALL для виклику підпрограми і команди для вирівнювання стеку, якщо це передбачається конвенцією виклику. Наприклад, для функцій з прототипами

FuctionName1 PROTO C :DWORD, :DWORD

FuctionName2 PROTO STDCALL :DWORD, :DWORD

FuctionName3 PROTO PASCAL :DWORD, :DWORD

Виклики з використанням директиви INVOKE

invoke FuctionName1,x,y

invoke FuctionName2,x,y

invoke FuctionName3,x,y

перетворюються трансляторм, відповідно на

push y push x

call _ FuctionName1 add esp,8

push y push x

call _FuctionName2@8

push x push y

call FUCTIONNAME3

Для конвенцій, що безпосередньо не підтримуються MASM, прототипи функцій визначити не можливо і замість прототипів використовуються директиви EXTRNDEF або EXTRN. При цьому виклик функції за допомогою

INVOKE стає не можливим і потрібно вручну сформувати код виклику згідно з з конвенцією виклику.

Приклад 7.2 Додаток на асемблері slldemocall.exe, що демонструє використання бібліотеки slldemo.lib (див. Приклад 7.1).

; Файл slldemocall.inc

include kernel32.inc

include masm32.inc

include c:\masm32\Macros\Strings.mac

includelib

kernel32.lib

; ExitProcess і потрібна для masm32.lib

includelib

masm32.lib

; StdOut,StdIn,dwtoa

includelib

slldemo.lib

 

BYTE "First string",0 BYTE "+second string",0 BYTE "+third string",0
BYTE 80 dup (?)

astrlen

PROTO STDCALL lpstr:DWORD

amemcpy

PROTO C lpdst:DWORD, lpsrc:DWORD, n:DWORD

; імена параметрів в прототипі необов'язкові

astrcpy

PROTO C :DWORD, :DWORD

amemset

PROTO C lpdest:DWORD, chr:BYTE, count:DWORD

astrcat

PROTO C strcount:DWORD, lpstrlist:VARARG

externdef syscall @fcstrcpy@8:proc externdef syscall @fcmemset@12:proc

.data

str1

str2

str3

.data? buffer

; Файл slldemocall.asm

.386

.model flat, stdcall option casemap:none include slldemocall.inc

.code

start: lea edi,buffer lea esi,str1

invoke astrcpy,edi,esi

invoke StdOut,$CTA0("\nstrcpy:\t\t") invoke StdOut,edi

invoke astrcat,2,edi,addr str2,addr str3 invoke StdOut,$CTA0("\nstrcat:\t\t") invoke StdOut,edi

invoke amemset,edi,'x',15

invoke StdOut,$CTA0("\nmemset:\t\t") invoke StdOut,edi

mov ecx,edi mov dl,'y'

Соседние файлы в папке гос