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

гос / sp-lect (1)

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

Всі призначені для використання поза межами DLL (експортовані) функції динамічної бібліотеки повинні визначатися з атрибутом видимості EXPORT. Також керувати створенням таблиці експорту можна за допомогою параметрів командного рядка лінкера, однак найбільше можливостей щодо керування експортом при побудові бібліотек DLL надають файли визначення модуля.

7.6.3.2 Файли визначення модуля

Файли визначення модуля являють собою звичайні текстові файли з розширенням *.def, які надають лінкеру додаткову інформацію, щодо особливостей компонування модуля. Типова структура def-файлу DLL має наступний вигляд:

LIBRARY [library] [BASE=address]

NAME [application]

EXPORTS

entryname[=internalname] [@ordinal [NONAME]] [PRIVATE] [DATA]

entryname – це ім'я функції або змінної, за яким вона буде експортуватися. Це ім'я функції або змінної може бути не визначене DLL. Можна експортувати за іменем, що відрізняється від імені функції або змінної в DLL виконавши зіставлення entryname зі справжнім визначеним в DLL іменем internalname.

@ordinal дозволяє вказати номер, за яким експортується імя entryname. Цей номер потрапить у таблицю експорту DLL, що дозволить використовувати як ім'я функції так і номер при пізньому звязуванні. Звязування за номером відбувається швидше.

Додаткове ключове слово NONAME дозволяє експортувати тільки порядковий номер і скоротити таким чином розмір таблиці експорту DLL. Додаткове ключове слово PRIVATE не допускає присутності entryname у бібліотеці імпорту, тобто entryname буде не експортоване і не доступне для додатків та інших модулів. Додаткове ключове слово DATA указує на те, що експортуються дані, а не код.

Оператори, ключові слова атрибутів і визначені розробником ідентифікатори є чутливими до регістру символів. Оператори NAME і LIBRARY повинні передувати будь-яким іншим операторам. Оператори EXPORTS можуть використовуватися в def-файлі більше одного разу. Коментарі в def-файлі позначаються крапкою з комою на початку кожного рядка. Коментар не може перебувати в тому самому рядку, що й оператор, однак він може перебувати між специфікаціями в багаторядкових операторах. (EXPORTS є багаторядковим оператором). Числові аргументи вказуються в десятковій або шістнадцятковій системі числення.

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

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

Подальше отримання програмного файлу DLL виконується за допомогою спеціального параметра командного рядка лінкера /DLL. При використанні файлу визначення модуля він зазначається за допомогою параметру командного рядка /DEF:імя.def.

LINK.EXE /NOLOGO /SUBSYSTEM:WINDOWS /RELEASE /DLL /DEF:імя.def

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

В результаті компонування створюються два файли: програмний файл імя.dll і файл бібліотеки імпорту імя.lib, який використовується для раннього звязування додатку з DLL.

Приклад 7.4 Динамічна бібліотека dlldemo.dll абсолютно ідентична за своїми функціональними можливостями раніше розглянутій статичній бібліотеці ssldemo.lib (див. Приклад 7.1)

; Файл dlldemo.inc

include windows.inc ; HINSTANCE, LPVOID, TRUE

; Файл dlldemo.asm

.486

.model flat,stdcall

include dlldemo.inc

.code

DllMain proc hinstDLL:HINSTANCE, fdwReason:DWORD, lpvReserved:LPVOID

mov eax, TRUE

 

ret

 

DllMain Endp

 

StringLength

proc uses ecx edi

mov ecx,-1

 

xor al,al

 

repnz scasb neg ecx

lea eax,[ecx-2] ret

StringLength endp

astrlen proc STDCALL EXPORT uses edi lpstr:DWORD

mov edi,lpstr call StringLength ret

astrlen endp

memcpy proc C uses esi edi ebx lpdst:DWORD, lpsrc:DWORD, n:DWORD

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

memcpy endp

strcpy proc C uses esi edi lpdst:DWORD, lpsrc:DWORD

mov edi,lpsrc call StringLength

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

rep movsd

lea ecx,[eax+1]

and ecx,3

 

rep movsb

 

ret

 

strcpy endp

 

@fcstrcpy@8

proc SYSCALL EXPORT uses esi edi

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

memset proc C uses edi ebx lpdest:DWORD, chr:BYTE, count:DWORD 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

memset

endp

fmemset

proc SYSCALL uses edi ebx count:DWORD

 

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

fmemset

endp

strcat

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

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 strcat endp End DllMain

; Файл dlldemo.def

LIBRARY dlldemo

EXPORTS

;Функція astrlen і __fastcall-варіант strcpy експортуються

;за допомогою директиви EXPORT, зазначеної в описі функції

StringLength

PRIVATE

 

amemcpy

= memcpy

@101

astrcpy

= strcpy

@102

amemset

= memset

@103

@fcmemset@12

= fmemset

@104

astrcat

= strcat

@105

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

7.6.4.1 Раннє звязування

Зовнішньо раннє звязування проекту Microsoft Macro Assembler із динамічною бібліотекою нічим не відрізняється від звязування із статичною бібліотекою (див. розділ 7.5.2). Для раннього звязування програмний файл DLL (з розширенням dll) не потрібен і використовується тільки файл бібліотеки імпорту з розширенням lib, який автоматично створюється в результаті компонування DLL.

Приклад 7.5 Додаток на асемблері dllstaticlink.exe, що демонструє використання динамічної бібліотеки dlldemo.dll (див. Приклад 7.4) шляхом раннього звязування.

; Файл dllstaticlink.inc

include windows.inc include user32.inc include kernel32.inc include masm32.inc

include C:\MASM32\MACROS\strings.mac

includelib

user32.lib

includelib

kernel32.lib

includelib

masm32.lib

includelib dlldemo.lib

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

BYTE "First string",0

str2

BYTE "+second string",0

str3

BYTE "+third string",0

.data?

 

buffer

BYTE 80 dup (?)

; Файл dllstaticlink.asm

.386

.model flat, stdcall

option casemap:none

include dllstaticlink.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' push 10

call @fcmemset@12

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

invoke astrlen,esi inc eax

invoke amemcpy,edi,esi,eax

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

invoke astrlen,esi mov ebx,eax

invoke astrcpy,edi,$CTA0("\nstrlen:\t\tLength of string '") invoke astrcat,2,edi,esi,$CTA0("' equal ")

invoke astrlen,edi lea esi,[edi+eax] invoke dwtoa,ebx,esi invoke StdOut,edi mov ecx,edi

lea edx,str1

call @fcstrcpy@8

invoke StdOut,$CTA0("\nfcstrcpy:\t")

invoke StdOut,edi

invoke StdIn,edi,lengthof buffer

invoke ExitProcess,0

end start

7.6.4.2 Пізнє звязування

При пізньому звязуванні завантаження DLL і визначення адреси потрібної функції виконується самим додатком в процесі його роботи за допомогою функцій Win API LoadLibrary (або LoadLibraryEx) і GetProcAddress.

Функція HMODULE WINAPI LoadLibrary(__in LPCTSTR lpFileName)

відображає модуль з імям зазначеним у рядку символів за адресою lpFileName

вадресний простір поточного процесу. Імя може зазначатися із завданням шляху і без розширення файлу, яке може бути .dll або .exe. У разі успіху функція повертає ідентифікатор модуля, інакше – NULL. Ідентифікатор модуля

вподальшому використовується як один з параметрів функції

FARPROC WINAPI GetProcAddress(__in HMODULE hModule,

__in LPCSTR lpProcName)

яка у разі успіху повертає адресу функції або змінної з іменем (рядок символів, що завершується нулем) за адресою lpProcName або номером (ордіналом) зазначеним у параметрі lpProcName у модулі з ідентифікатором, зазначеним у параметрі hModule. При помилці функція повертає NULL.

Функції LoadLibrary (або LoadLibraryEx) і GetProcAddress перебувають в бібліотеці kernel32.dll, з якою попередньо потрібно виконати статичне (раннє) звязування.

Приклад 7.6 Додаток на асемблері dlldynamiclink.exe, що демонструє використання динамічної бібліотеки dlldemo.dll (див. Приклад 7.4) шляхом пізнього звязування.

; Файл dlldynamiclink.inc

include windows.inc

include user32.inc

include kernel32.inc

include masm32.inc

include C:\MASM32\MACROS\strings.mac

includelib

user32.lib

includelib

kernel32.lib

includelib

masm32.lib

.data

 

 

str1

BYTE "First string",0

str2

BYTE "+second string",0

str3

BYTE "+third string",0

.data?

 

 

hDll

HANDLE ?

 

astrlen

PVOID ?

 

fcstrcpy

PVOID ?

 

amemcpy

PVOID ?

;@101

astrcpy

PVOID ?

;@102

amemset

PVOID ?

;@103

fcmemset

PVOID ?

;@104

astrcat

PVOID ?

;@105

buffer

BYTE 80 dup (?)

; Файл dlldynamiclink.asm

.386

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

.code

start: invoke LoadLibrary,$CTA0("dlldemo.dll") or eax,eax

jz exit

mov hDll,eax

invoke GetProcAddress,hDll,$CTA0("_astrlen@4") or eax,eax

jz exit

mov astrlen,eax

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