| [Назад] [Далее] | ![]() |
Кроме обычных приложений в Windows появился специальный тип файла — динамические библиотеки (DLL). DLL — это файл, содержащий процедуры и данные, которые доступны программам, обращающимся к нему. Например, все системные функции Windows, которыми мы пользовались, на самом деле были процедурами, входящими в состав таких библиотек, — kernel32.dll, user32.dll, comdlg32.dll и т.д. Динамические библиотеки позволяют уменьшить использование памяти и размер исполнимых файлов для тех случаев, когда несколько программ (или даже несколько копий одной и той же программы) используют одну и ту же процедуру. Можно считать, что DLL — это аналог пассивной резидентной программы, с тем лишь отличием, что DLL не находится в памяти, если ни одна программа, его использующая, не загружена.
С точки зрения программирования на ассемблере DLL — это самый обычный исполнимый файл формата РЕ, отличающийся только тем, что при входе в него в стеке находятся три параметра (идентификатор DLL-модуля, причина вызова процедуры и зарезервированный параметр), которые надо удалить, например командой ret 12. Кроме этой процедуры в DLL входят и другие, часть которых можно вызывать из других программ. Список этих экспортируемых процедур должен быть задан во время компиляции DLL, и поэтому команды для компиляции нашего следующего примера будут отличаться от обычных.
Компиляция MASM:
ml /с /coff /Cp /D_MASM_ dllrus.asm link dllrus.obj @dllrus.lnk
Содержимое файла dllrus.lnk:
/DLL /entry:start /subsystem:windows /export:koi2win_asm /export:koi2win /export:koi2wins_asm /export:koi2wins
Компиляция TASM:
tasm /m /x /ml /D_TASM_ dllrus.asm tlink32 -Tpd -c dllrus.obj,,,,dllrus.def
Содержимое файла dllrus.def:
EXPORTS koi2win_asm koi2win koi2wins koi2wins_asm
Компиляция WASM:
wasm dllrus.asm wlink @dllrus.dir
Содержимое dllrus.dir:
file dllrus.obj
form windows nt DLL
exp koi2win_asm,koi2win,koi2wins_asm,koi2wins
; dllrus.asm
; DLL для Win32 - перекодировщик из koi8 в ср1251
.386
.model flat
; функции, определяемые в этом DLL
ifdef _MASM_
public _koi2win_asm@0 ; koi2win_asm - перекодирует символ в AL
public _koi2win@4 ; CHAR WINAPI koi2win(CHAR symbol)
public _koi2wins_asm@0 ; koi2wins_asm - перекодирует строку в [ЕАХ]
public _koi2wins@4 ; VOID WINAPI koi2win(CHAR * string)
else
public koi2win_asm ; те же функции для TASM и WASM
public koi2win
public koi2wins_asm
public koi2wins
endif
.const
; таблица для перевода символа из кодировки KOI8-r (RFC1489)
; в кодировку Windows (cp1251),
; таблица только для символов 80h - FFh
; (то есть надо будет вычесть 80h из символа, преобразовать его командой xlat
; и снова добавить 80h)
k2w_tbl db 16 dup(0) ; символы, не существующие в ср1251,
db 16 dup(0) ; перекодируются в 80h
db 00h, 00h, 00h, 38h, 00h, 00h, 00h, 00h
db 00h, 00h, 00h, 00h, 00h, 00h, 00h, 00h
db 00h, 00h, 00h, 28h, 00h, 00h, 00h, 00h
db 00h, 00h, 00h, 00h, 00h, 00h, 00h, 00h
db 7Eh, 60h, 61h, 76h, 64h, 65h, 74h, 63h
db 75h, 68h, 69h, 6Ah, 6Bh, 6Ch, 6Dh, 6Eh
db 6Fh, 7Fh, 70h, 71h, 72h, 73h, 66h, 62h
db 7Ch, 7Bh, 67h, 78h, 7Dh, 79h, 77h, 7Ah
db 5Eh, 40h, 41h, 56h, 44h, 45h, 54h, 43h
db 55h, 48h, 49h, 4Ah, 4Bh, 4Ch, 4Dh, 4Eh
db 4Fh, 5Fh, 50h, 51h, 52h, 53h, 46h, 42h
db 5Ch, 5Bh, 47h, 58h, 5Dh, 59h, 57h, 5Ah
.code
; процедура DLLEntry. Получает три параметра - идентификатор, причину вызова
; и зарезервированный параметр. Нам не нужен ни один из них
_start@12:
mov al,1 ; надо вернуть ненулевое число в ЕАХ
ret 12
; процедура BYTE WINAPI koi2win (BYTE symbol) -
; точка входа для вызова из С
ifdef _MASM_
_koi2win@4 proc
else
koi2win proc
endif
pop ecx ; обратный адрес в ЕСХ
pop eax ; параметр в ЕСХ (теперь стек очищен
; от параметров!)
push ecx ; обратный адрес вернуть в стек для RET
; здесь нет команды RET - управление передается следующей процедуре
ifdef _MASM_
_koi2win@4 endp
else
koi2win endp
endif
; процедура koi2win_asm
; точка входа для вызова из ассемблерных программ:
; ввод: AL - код символа в KOI
; вывод: AL - код этого же символа в WIN
ifdef _MASM_
_koi2win_asm@0 proc
else
koi2win_asm proc
endif
test al,80h ; если символ меньше 80h (старший бит 0),
jz dont_decode ; не перекодировать,
push ebx ; иначе -
mov ebx,offset k2w_tbl
sub al,80h ; вычесть 80h,
xlat ; перекодировать
add al,80h ; и прибавить 80h
pop ebx
dont_decode:
ret ; выйти
ifdef _MASM_
_koi2win_asm@0 endp
else
koi2win_asm endp
endif
; VOID koi2wins(BYTE * koistring) -
; точка входа для вызова из С
ifdef _MASM_
_koi2wins@4 proc
else
koi2wins proc
endif
pop ecx ; адрес возврата из стека
pop eax ; параметр в ЕАХ
push ecx ; адрес возврата в стек
ifdef _MASM_
_koi2wins@4 endp
else
koi2wins endp
endif
; точка входа для вызова из ассемблера:
; ввод: ЕАХ - адрес строки, которую надо преобразовать из KOI в WIN
ifdef _MASM_
_koi2wins_asm@0 proc
else
koi2wins_asm proc
endif
push esi ; сохранить регистры, которые
; нельзя изменять
push edi
push ebx
mov esi,eax ; приемник строк
mov edi,eax ; и источник совпадают
mov ebx,offset k2w_tbl
decode_string:
lodsb ; прочитать байт,
test al,80h ; если старший бит 0,
jz dont_decode2 ; не перекодировать,
sub al,80h ; иначе - вычесть 80h,
xlat ; перекодировать
add al,80h ; и добавить 80h
dont_decode2:
stosb ; вернуть байт на место,
test al,al ; если байт - не ноль,
jnz decode_string ; продолжить
pop ebx
pop edi
pop esi
ret
ifdef _MASM_
_koi2wins_asm@0 endp
else
koi2wins_asm endp
endif
end _start@l2
Как видно из примера, нам пришлось назвать все процедуры по-разному для различных ассемблеров. В случае MASM понятно, что все функции должны иметь имена типа _start@12, а иначе программам, использующим их, придется обращаться к функциям с именами типа _Jmp_start, то есть такой DLL нельзя будет использовать из программы, написанной на Microsoft С. В случае TASM и WASM процедуры могут иметь неискаженные имена (и более того, wlink.exe не позволяет экспортировать имя переменной, содержащее символ @), так как их компиляторы берут имена процедур не из библиотечного файла, а прямо из DLL при помощи соответствующей программы — implib или wlib.
Итак, чтобы воспользоваться полученным DLL, напишем простую программу, которая перекодирует одну строку из КОI-8r в Windows ср1251.
; dlldemo.asm
; Графическое приложение для Win32, демонстрирующее работу с dllrus.dll,
; выводит строку в KOI8 и затем в ср1251, перекодированную функцией koi2wins
include def32.inc
include user32.inc
include kernel32.inc
includelib dllrus.lib
ifndef _MASM_
extrn koi2win__asm:near ; определения для функций из DLL для
extrn koi2win:near ; TASM и WASM
extrn koi2wins_asm:near ; (хотя для WASM было бы эффективнее
extrn koi2wins:near ; использовать __imp__koi2win, выделив
else ; его в отдельный условный блок),
extrn __imp__koi2win_asm@0:dword ; а это для MASM
extrn __imp__koi2win@4:dword
extrn __imp__koi2wins_asm@0:dword
extrn __imp__koi2wins@4: dword
koi2win_asm equ __imp__koi2win_asm@0
koi2win equ __imp__koi2win@4
koi2wins_asm equ __imp__koi2wins_asm@0
koi2wins equ __imp__koi2wins@4
endif
.386
.model flat
.const
title_string1 db "koi2win demo: string in KOI8",0
title_string2 db "koi2win demo: string in cp1251",0
.data
koi_string db 0F3h,0D4h,0D2h,0CFh,0CBh,0C1h,20h,0CEh,0C1h
db 20h,0EBh,0EFh,0E9h,2Dh,28h,0
.code
_start:
push MB_OK
push offset title_string1 ; заголовок окна MessageBox
push offset koi_string ; строка на KOI
push 0
call MessageBox
mov eax,offset koi_string
push eax
call koi2wins
push MB_OK
push offset title_string2
push offset koi_string
push 0
call MessageBox
push 0 ; код выхода
call ExitProcess ; конец программы
end _start
Этот небольшой DLL может оказаться очень полезным для расшифровки текстов, приходящих из сети Internet или других систем, в которых используется кодировка KOI8. Воспользовавшись таблицами из приложения 1, вы можете расширить набор функций dllrus.dll, вплоть до перекодировки из любого варианта в какой угодно.