Dos7book
.pdfГлава 9: |
Примеры композиции исполняемых файлов |
|||
xor |
BX,BX |
|
; 113 |
Подготовим EBX=0 |
;********* Секция 2: проверка процессора |
||||
; 12F - адрес перехода со строки 125 |
||||
pushf |
|
|
; 115 |
Загрузим в стек 2 копии |
pushf |
|
|
; 116 |
исходного состояния флагов |
pop |
CX |
|
; 117 |
Выгрузим копию в CX |
xor |
CH,70 |
|
; 118 |
Инвертируем биты 0C, 0D, 0E |
push |
CX |
|
; 11B |
Перешлем измененные биты |
popf |
|
|
; 11C |
через стек в регистр |
pushf |
|
|
; 11D |
флагов, а потом снова |
pop |
AX |
|
; 11E |
через стек в AX |
popf |
|
|
; 11F |
Вернем исходные состояния |
xor |
AX,CX |
|
; 120 |
Установим несовпавшие биты |
test |
AH,40 |
|
; 122 |
Наш процессор 16-битовый? |
jz |
012F |
|
;*125 |
Если нет, проверим защиту |
mov |
AL,02 |
|
; 127 |
Если да, то переход на |
mov |
DX,03D6 |
|
;*129 |
выход с индикацией |
jmp |
02BF |
|
;*12C |
сообщения 03D6 |
test |
AH,30 |
|
;=12F |
Установлен защищенный режим? |
jz |
0163 |
|
;*132 |
Если нет, обойдем секцию 3 |
;********* Секция 3: проверки защищенного режима |
||||
; 14B - адрес перехода со строки 141 |
||||
mov word ptr |
[03D4],0483 |
;*134 |
Изменим адрес сообщения |
|
mov |
AX,1687 |
|
; 13A |
Вызов функции обнаружения |
int |
2F |
|
; 13D |
сервера DPMI |
or |
AX,AX |
|
; 13F |
Сервер DPMI загружен? |
jnz |
014B |
|
;*141 |
Если нет, перейдем дальше |
mov |
AL,08 |
|
; 143 |
Если да, то выход из |
mov |
DX,03FB |
|
;*145 |
программы с индикацией |
jmp |
02BF |
|
;*148 |
сообщения 03FB |
push |
DS |
|
;=14B |
Сохраним DS в стеке |
mov |
DS,BX |
|
; 14C |
Сегмент таблицы прерываний |
mov |
DS,[019E] |
; 14E |
Загрузим сегмент EMM |
|
cmp word ptr |
[0014],4249 |
; 152 |
Версия EMM от фирмы IBM ? |
|
pop |
DS |
|
; 158 |
Восстановим сегмент DS |
jz |
0163 |
|
;*159 |
Продолжим, если EMM от IBM |
mov |
AL,02 |
|
; 15B |
Если нет, то выход из |
mov |
DX,041E |
|
;*15D |
программы с индикацией |
jmp |
02BF |
|
;*160 |
сообщения 041E |
;********* Секция 4: получение линейного адреса
;163 - адрес перехода со строк 132, 159
;16A - адрес назначения цикла со строки 19C
;17B - адрес перехода со строки 175
;188 - адрес перехода со строки 17E
–561 –
|
Глава 9: |
Примеры композиции исполняемых файлов |
|
|
; 194 - адрес перехода со строк 16F, 179 |
||
mov |
CX,0004 |
;=163 |
Установим сдвиг 4 бита |
cld |
|
; 166 |
Счет SI на увеличение |
mov |
SI,005D |
; 167 |
Зададим стартовый адрес |
lodsb |
|
;=16A |
Загрузим один байт в AL |
sub |
AL,30 |
; 16B |
Преобразуем знак ASCII |
cmp |
AL,09 |
; 16D |
Если это десятичная цифра, |
jbe |
0194 |
;*16F |
то добавим ее к EBX |
sub |
AL,07 |
; 171 |
Преобразуем коды букв A-F |
cmp |
AL,0A |
; 173 |
Отсечем знаки до буквы A |
jb |
017B |
;*175 |
Перейдем выяснять причину |
cmp |
AL,0F |
; 177 |
Выберем буквы A-F и |
jbe |
0194 |
;*179 |
добавим к числу в EBX |
cmp |
SI,005E |
;=17B |
Это первая итерация? |
jnz |
0188 |
;*17E |
Если нет, посмотрим дальше |
mov |
AL,01 |
; 180 |
Если да, то выход из |
mov |
DX,04F1 |
;*182 |
программы с индикацией |
jmp |
02BF |
;*185 |
сообщения 04F1 |
cmp |
AL,E9 |
;=188 |
Последний знак - пробел 20h? |
jz |
019E |
;*18A |
Тогда все, больше знаков нет |
mov |
AL,01 |
; 18C |
Если знак - не пробел, то |
mov |
DX,04CB |
;*18E |
выход из программы с |
jmp |
02BF |
;*191 |
выводом сообщения 04CB |
|
|
;=194 |
Префикс 32-битового операнда |
db |
66 |
|
|
shl |
BX,CL |
; 195 |
Сдвиг EBX 4 бита влево |
or |
BL,AL |
; 197 |
Вставим знак в регистр BL |
cmp |
SI,0064 |
; 199 |
Достигнута ли 8-я итерация? |
jbe |
016A |
;*19Ñ |
Если нет, повторить цикл |
;********* Секция 5: активизация линии A20
;19E - адрес перехода со строки 18A
;1С3 - адрес перехода со строки 1AС
;1D3 - адрес перехода со строки 1A3
;1D8 - адрес перехода со строки 1C6
cmp byte ptr |
[006D],41 |
;=19E |
Имеется ли параметр "A"? |
|
jz |
01D3 |
;*1A3 |
Если да, оставим линию A20 |
|
mov |
AX,4300 |
; 1A5 |
Теперь посмотрим, |
|
int |
2F |
; 1A8 |
установлен ли |
|
cmp |
AL,80 |
; 1AA |
драйвер |
Himem.sys |
jnz |
01C3 |
;*1AC |
Åñëè íåò, òî |
переход |
push |
BX |
; 1AE |
Сохраним значение BX |
|
mov |
AX,4310 |
; 1AF |
Найдем адрес |
вызова |
int |
2F |
; 1B2 |
функций |
Himem.sys |
mov |
[03C0],BX |
;*1B4 |
Запомним адрес вызова |
|
|
|
|
– 562 – |
|
Глава 9: |
Примеры композиции исполняемых файлов |
|||
mov |
[03C2],ES |
;*1B8 |
функций Himem.sys |
|
mov |
AH,05 |
|
; 1BC |
Вызовем функцию |
call far |
[03C0] |
|
;*1BE |
активизации линии A20 |
pop |
BX |
|
; 1C2 |
Восстановим значение BX |
call |
02D3 |
|
;=1C3 |
Активна ли линия A20? |
jnz |
01D8 |
|
;*1C6 |
Если да, то переход |
mov word ptr |
[03C2],0001 |
;*1C8 |
Если нет, поставим метку |
|
mov |
AL,FF |
|
; 1CE |
Активизируем линию A20 |
call |
02EB |
|
;*1D0 |
подпрограммой 02EB |
call |
02D3 |
|
;=1D3 |
Активна ли линия A20? |
jz |
01DD |
|
;*1D6 |
Если да, дезактивируем |
mov byte ptr |
[0445],24 |
;=1D8 |
сообщение 0445 |
;******* Секция 6: индикация сегментного адреса GS
;1DD - адрес перехода со строки 1D6
;1E6 - адрес перехода со строки 1E2
cmp byte ptr |
[006D],52 |
;=1DD |
Параметр "R" указан? |
|
jz |
01E6 |
;*1E2 |
Если да, не считываем GS |
|
|
|
|
; 1E4 |
= MOV SI,GS |
db |
8C |
EE |
|
|
|
|
|
;=1E6 |
= MOV GS,SI |
db |
8E |
EE |
|
|
|
|
|
; 1E8 |
= PUSH GS |
db |
0F |
A8 |
|
|
pop |
[03D0] |
;*1EA |
Запомним GS в 3D0 |
|
call |
0339 |
;*1EE |
Пошлем 0Dh 20h в STDOUT |
|
call |
0349 |
;*1F1 |
Выведем 3D0 на экран |
|
mov |
DX,0445 |
;*1F4 |
Выведем на экран |
|
call |
0330 |
;*1F7 |
сообщение 0445 |
|
mov |
DX,045B |
;*1FA |
Выведем на экран |
|
call |
0330 |
;*1FD |
сообщение 045B |
|
;********* Секция 7: вычисление начала отсчета |
||||
db |
66 |
|
|
|
xchg |
SI,BX |
; 201 |
Переведем адрес в ESI |
|
mov |
BX,SI |
; 203 |
Вернем в BX только 2 байта |
|
and |
BX,000F |
; 205 |
Выберем самую правую цифру |
|
neg |
BL |
|
; 209 |
Получим начало отсчета |
and |
SI,FFF0 |
; 20B |
Теперь ESI - базовый адрес |
|
db |
66 |
|
|
|
mov |
DI,SI |
; 210 |
Скопируем ESI в EDI |
|
db |
66 |
|
|
|
xchg |
[03D0],DI |
;*213 |
Обменяем GS с EDI |
|
db |
66 |
|
|
|
shl |
DI,CL |
; 218 |
В EDI - линейный адрес GS |
|
mov |
DX,[03D4] |
;*21A |
Подготовим номер сообщения |
|
|
|
|
|
– 563 – |
|
Глава 9: |
Примеры композиции исполняемых файлов |
||
db |
66 |
|
|
|
sub |
SI,DI |
; 21F |
Вычислим смещение |
â ESI |
jnb |
0226 |
;*221 Если меньше нуля, |
сменим |
|
mov |
DX,0460 |
;*223 |
номер сообщения |
íà 0460 |
;********* Секция 8: замена флагов и указателей ; 226 - адрес перехода со строки 221
|
|
;=226 |
Префикс 32-битного операнда |
db |
66 |
|
|
pushf |
|
; 227 |
Затолкаем EFLAGS в стек |
mov |
BP,SP |
; 228 |
Указатель стека - в BP |
mov |
AL,[BP+02] |
; 22A |
Считаем и сохраним |
mov |
[03C4],AL |
;*22D |
третий байт флагов |
and byte ptr |
[BP+02],FE |
; 230 |
Сбросим флаг выравнивания |
db |
66 |
|
|
popf |
|
; 235 |
EFLAGS - обратно во флаги |
in |
AL,21 |
; 236 |
Считаем маску порта 21h |
mov |
[03C5],AL |
; 238 |
и запомним ее |
or |
AL,60 |
; 23B |
Установим биты 05 и 06 |
out |
21,AL |
; 23D |
Запретим IRQ5 и IRQ6 |
mov |
[03C8],DS |
;*23F |
Заполним сегменты в адресах |
mov |
[03CC],DS |
;*243 |
обработчиков прерываний |
push |
BX |
; 247 |
Сохраним BX в стеке |
mov |
AL,0D |
; 248 |
Заменим адреса обработчиков |
call |
03A0 |
;*24A |
прерывания INT 0D |
call |
03A0 |
;*24D |
и прерывания INT 0E |
pop |
BX |
; 250 |
Восстановим содержимое BX |
;********* Секция 9: пробное считывание |
|||
; 251 - адрес назначения цикла со строки 289 |
|||
mov |
[03CE],SI |
;=251 |
Сохраним SI для сравнения |
db |
65 67 |
|
|
lodsb |
|
; 257 |
Попытаемся считать байт |
cmp |
SI,[03CE] |
;*258 |
Изменилось ли значение SI? |
jnz |
0266 |
;*25C |
Если да - в основной цикл |
call |
0342 |
;*25E |
Индицируем линейный адрес |
call |
0321 |
;*261 |
Вычислим следующий адрес |
jmp |
0286 |
;*264 |
Переход к проверке адреса |
;********* Секция 10: основной цикл вывода строки
;266 - адрес перехода со строки 25C
;26E - адрес назначения цикла со строки 273
;278 - адрес назначения цикла со строки 27D
;286 - адрес перехода со строки 264
|
|
;=266 |
Префикс 32-битного |
операнда |
db |
66 |
|
|
|
dec |
SI |
; 267 |
Восстановим индекс |
â SI |
|
|
|
– 564 – |
|
Глава 9: |
Примеры композиции исполняемых файлов |
|||
call |
0349 |
|
;*268 |
Индицируем линейный адрес |
call |
0318 |
|
;*26B |
Промежуточная коррекция |
call |
0362 |
|
;=26E |
Индицируем байт из AL |
inc |
BL |
|
; 271 |
Увеличим счет байтов на 1 |
loop |
026E |
|
;*273 |
1-й цикл вывода строки |
call |
0309 |
|
;*275 |
Промежуточная коррекция |
call |
0379 |
|
;=278 |
Индицируем байт кодом ASCII |
inc |
BL |
|
; 27B |
Увеличим счет байтов на 1 |
loop |
0278 |
|
;*27D |
2-й цикл вывода строки |
call |
0339 |
|
;*27F |
Пошлем 0Dh 20h в STDOUT |
mov |
DX,[03D4] |
;*282 |
Заменим адрес сообщения |
|
cmp |
BL,80 |
|
;=286 |
Данная строка последняя? |
jb |
0251 |
|
;*289 |
Если нет - к следующей |
;********* Секция 11: возврат к исходному состоянию |
||||
; 2B4 - адрес перехода со строки 2AB |
||||
mov |
AL,0D |
|
; 28B |
Восстановим обработчики |
call |
03A0 |
|
;*28D |
прерывания INT 0D |
call |
03A0 |
|
;*290 |
и прерывания INT 0E |
mov |
AL,[03C5] |
;*293 |
Считаем прежнюю маску и |
|
out |
21,AL |
|
; 296 |
пошлем ее в порт 21h |
db |
66 |
|
|
|
pushf |
|
|
; 299 |
Считаем EFLAGS в стек |
mov |
BP,SP |
|
; 29A |
Указатель стека - в BP |
mov |
AL,[03C4] |
;*29C |
Считаем и восстановим |
|
mov |
[BP+02],AL |
; 29F |
прежний 3-й байт флагов |
|
db |
66 |
|
|
|
popf |
|
|
; 2A3 |
Восстановим EFLAGS |
cmp word ptr |
[03C2],0001 |
;*2A4 |
Проверим метку линии A20 |
|
jb |
02BA |
|
;*2A9 |
Если 0000, A20 не трогаем |
ja |
02B4 |
|
;*2AB |
К A20 - с помощью Himem.sys |
mov |
AL,FD |
|
; 2AD |
Восстановим A20 с помощью |
call |
02EB |
|
;*2AF |
подпрограммы 02EB |
jmp |
02BA |
|
;*2B2 |
Переход к завершению |
mov |
AL,06 |
|
;=2B4 |
Вызов функции закрытия A20 |
call far |
[03C0] |
|
;*2B6 |
драйвером Himem.sys |
;******** Секция 12: завершение программы
;2BA - адрес перехода со строк 2A9, 2B2
;2BF - выход со строк 12C, 148, 160, 185, 191
mov |
DX,0442 |
;=2BA |
Сообщение "конец строки" |
mov |
AL,00 |
; 2BD |
Код успешного завершения |
push |
AX |
;=2BF |
Сохраним код ошибки |
mov |
AH,09 |
; 2C0 |
Вывод завершающего |
int |
21 |
; 2C2 |
сообщения на экран |
pop |
AX |
; 2C4 |
Восстановим код ошибки |
|
|
|
– 565 – |
|
Глава 9: |
Примеры композиции исполняемых файлов |
||
mov |
AH,4C |
; |
2C5 |
Вызов функции завершения |
int |
21 |
; |
2C7 |
и возврат в DOS |
|
;******* Секция 13: обработчики исключений 0D и 0E |
;2C9 - должен быть указан в ячейке 3CA
;2CC - должен быть указан в ячейке 3C6
mov |
DX,04A5 |
;=2C9 |
Адрес вызова Int 0E |
mov |
BP,SP |
;=2CC |
Адрес вызова Int 0D |
add word ptr |
[BP+00],+03 |
; 2CE |
Корректируем адрес |
iret |
|
; 2D2 |
возврата и возвращаемся |
;******** Секция 14: проверка состояния линии A20 |
|||
; 2D3 - адрес вызова из строк 1C3, 1D3 |
|||
push |
DS |
;=2D3 |
Сохраним состояния |
push |
CX |
; 2D4 |
регистров DS и CX |
db |
66 |
|
|
xor |
SI,SI |
; 2D6 |
Обнулим регистр ESI |
push |
SI |
; 2D8 |
Сохраним в стеке SI=0 |
mov |
DS,SI |
; 2D9 |
Теперь DS:SI=0000:0000 |
mov |
DI,F0F1 |
; 2DB |
Установим ES:DI=F0F1:F0F0 |
mov |
ES,DI |
; 2DE |
чтобы получить адрес |
dec |
DI |
; 2E0 |
F0F10h + F0F0h = 100000h |
cld |
|
; 2E1 |
Зададим счет на увеличение |
mov |
CX,0010 |
; 2E2 |
Предел счета - 16 байт |
repz |
|
; 2E5 |
Повторяем до несовпадения |
cmpsb |
|
; 2E6 |
Адреса "свернуты" ? |
pop |
SI |
; 2E7 |
Восстановим содержимое |
pop |
CX |
; 2E8 |
регистров и возвращаемся, |
pop |
DS |
; 2E9 |
сохраняя результат в |
ret |
|
; 2EA |
состоянии флага ZF |
|
;***** Секция 15: подпрограмма управления линией A20 |
|||
|
; 2EB - адрес вызова из строк 1D0, 2AF |
|
||
push |
AX |
;=2EB |
Сохраним команду в стеке |
|
call |
02FD |
;*2EC |
Ждем готовности |
|
mov |
AL,D1 |
; 2EF |
1-й байт команды |
|
out |
64,AL |
; 2F1 |
посылаем в |
ïîðò 64h |
call |
02FD |
;*2F3 |
Ждем готовности |
|
pop |
AX |
; 2F6 |
2-й байт команды из AX |
|
out |
60,AL |
; 2F7 |
посылаем в |
ïîðò 60h |
call |
02FD |
;*2F9 |
Ждем пока контроллер |
|
ret |
|
; 2FC |
сработает и |
возвращаемся |
|
;********* Секция 16: ожидание готовности контроллера |
;2FD - адрес вызова из строк 2EC, 2F3, 2F9
;301 - адрес циклического возврата со строки 305
push |
CX |
;=2FD |
Сохраним CX в стеке |
mov |
CX,FFFF |
; 2FE |
Запишем в CX число циклов |
|
|
|
– 566 – |
|
Глава 9: |
Примеры композиции исполняемых файлов |
|
in |
AL,64 |
;=301 Считаем состояние порта 64h |
|
test |
AL,02 |
; 303 |
Проверим бит готовности |
loopnz |
0301 |
;*305 Если порт не готов, повторим |
|
pop |
CX |
; 307 |
Восстановим CX и вернемся |
ret |
|
; 308 |
в вызывающую программу |
;********* Секция 17: промежуточная коррекция
|
; 309 - адрес вызова из строки 275 |
||
|
; 318 - адрес вызова из строки 26B |
||
sub |
BL,10 |
;=309 |
Вернем счет на строку назад |
push |
BX |
; 30C |
Сохраним BX в стеке |
mov |
BL,10 |
; 30D |
10h = величина приращения |
db |
66 |
|
|
add |
[03D0],BX |
;*310 |
Корректируем линейный адрес |
db |
66 |
|
|
sub |
SI,BX |
; 315 |
Скорректируем смещение |
pop |
BX |
; 317 |
Восстановим BX |
call |
0393 |
;=318 |
Дважды пошлем знак |
call |
0393 |
;*31B |
пробела в STDOUT |
mov |
CL,10 |
; 31E |
Предустановим счет байтов |
ret |
|
; 320 |
Возврат из подпрограммы |
;********* Секция 18: перевод строки дампа
;321 - адрес вызова из строки 261
;330 - адрес вызова из строк 1F7, 1FD
;339 - адрес вызова из строк 1EE, 27F
add |
BL,10 |
;=321 |
Увеличим счет байтов на 16 |
push |
BX |
; 324 |
Сохраним BX в стеке |
mov |
BL,10 |
; 325 |
Зададим приращение на 16 |
db |
66 |
|
|
add |
[03D0],BX |
;*328 |
Коррекция линейного адреса |
db |
66 |
|
|
add |
SI,BX |
; 32D |
Коррекция смещения |
pop |
BX |
; 32F |
Восстановим содержимое BX |
mov |
DI,DX |
;=330 |
Скопируем адрес в DI |
mov |
AH,09 |
; 332 |
Функция вывода |
int |
21 |
; 334 |
сообщения в STDOUT |
mov byte ptr |
[DI],24 |
; 336 |
Дезактивируем сообщение |
mov |
AL,0D |
;=339 |
Пошлем команду возврата к |
call |
0395 |
;*33B |
началу строки в STDOUT |
call |
0393 |
;*33E |
Пошлем пробел в STDOUT |
ret |
|
; 341 |
Возврат из подпрограммы |
;********* Секция 19: индикация числа из ячейки 3D0
;342 - адрес вызова из строки 25E
;349 - адрес вызова из строк 1F1, 268
;354 - адрес перехода со строки 35E
–567 –
Глава 9: |
Примеры композиции исполняемых файлов |
||
; 361 - адрес перехода со строки 347 |
|||
mov |
DI,DX |
;=342 |
Дезактивировано ли |
cmp byte ptr |
[DI],24 |
; 344 |
запрошенное сообщение? |
jz |
0361 |
;*347 |
Если да, не выводим его |
mov |
AL,0A |
;=349 |
Пошлем команду перевода |
call |
0395 |
;*34B |
строки в STDOUT |
push |
BX |
; 34E |
Сохраним содержимое BX |
xor |
BL,BL |
; 34F |
Отключим проверку предела |
mov |
DI,03D3 |
; 351 |
В DI - адрес старшего байта |
mov |
AL,[DI] |
;=354 |
Выведем байт в AL |
call |
0368 |
;*356 |
Вызовем трансляцию байта AL |
dec |
DI |
; 359 |
Перейдем к следующему байту |
cmp |
DI,03D0 |
;*35A |
Это последний байт? |
jnb |
0354 |
;*35E |
Если нет, повторим цикл |
pop |
BX |
; 360 |
Восстановим содержимое BX |
ret |
|
;=361 |
Возврат из подпрограммы |
;********* Секция 20: подпрограмма трансляции AL
|
; 362 - адрес вызова из строки 26E |
||
|
; 368 - адрес вызова из строки 356 |
||
call |
0393 |
;=362 |
Воспроизведем пробел |
db |
67 65 |
|
|
lodsb |
|
; 367 |
GS:[32-битовый адрес] |
push |
CX |
;=368 |
Сохраним содержимое CX |
mov |
CL,04 |
; 369 |
Сдвиг 4 бита зададим в CL |
shl |
AH,CL |
; 36B |
Очистим младшие 4 бита AH |
shl |
AX,CL |
; 36D |
Разделим полубайты из AL |
shr |
AL,CL |
; 36F |
Очистим старшие 4 бита AL |
pop |
CX |
; 371 |
Восстановим содержимое CX |
call |
0384 |
;*372 |
Вызов индикации AH |
call |
0384 |
;*375 |
Вызов индикации AL |
ret |
|
; 378 |
Возврат из подпрограммы |
;********* Секция 21: индикация одного знака
;379 - адрес вызова из строки 278
;384 - адрес вызова из строк 372, 375
;38E - адрес перехода со строк 37E, 382, 38A
;393 - адрес вызова из строк 318, 31B, 33E, 362
;395 - адрес вызова из 33B, 34B, переход от 391
|
|
;=379 |
Считаем в AL один знак из |
db |
67 65 |
|
|
lodsb |
|
; 37B |
GS:[32-битный адрес] |
cmp |
AL,20 |
; 37C |
Значение до 20h или больше? |
ja |
038E |
;*37E |
Значения AL < 20h заменим |
mov |
AL,2E |
; 380 |
точками и перейдем к |
jmp |
038E |
;*382 |
проверке границ |
|
|
|
– 568 – |