Консультация № 188037
19.09.2015, 13:44
0.00 руб.
30.09.2015, 13:21
0 1 1
Разбираю код программы из учебника, программа формирует log-файл(report.txt) действий пользователя. В самом log-файле будут записи, такого формата: "Launch file ---> C:\AFDPRO\RESID19.COM".
Все понятно, кроме одного: откуда в регистре DX в строке

Move_string proc
...
mov si,dx
...
Move_string endp

берется смещение имени файла "C:\AFDPRO\RESID19.COM"

Вот сам код:

[code h=200]; RESID19.ASM - программа к Главе № 19

; (С) Авторские права на файлы-приложения принадлежат автору книги
; "Ассемблер? Это просто! Учимся программировать под MS-DOS"
; Автор: Калашников Олег Александрович (e-mail: Assembler@Kalashnikoff.ru)
; http://www.Kalashnikoff.ru

; --- Ассемблирование (получение *.com файла) ---
;При использовании MASM 6.11 - 6.13:
;ML.EXE resid19.asm /AT

;При использовании TASM:
;TASM.EXE resid19.asm
;TLINK.EXE resid19.obj /t/x


; === Начало программы: ===
.286
CSEG segment
assume cs:CSEG, ds:CSEG, ss:CSEG, es:CSEG
org 100h

Begin:
jmp Init ;На метку инициализации 

; === Обработчик 21h-ого прерывания ===
Int_21h_proc proc
cmp ax,9889h
jne Next_step

xchg ah,al
iret

Next_step:
pusha ;Сохраним регистры...
push ds
push es

mov bx,ds ;BX=DS

push cs ;Настроим сегментные регистры
push cs
pop es
pop ds

;cmp ax, 0998h ; MY CODE!!! - wrong way!
;je Start_f

cmp ax,4B00h ;Это запуск файла на выполнение?
je Start_f

cmp ah,39h ;Это создание каталога?
je Create_dir

cmp ah,3Ah ;Это удаление каталога?
je Delete_dir

cmp ah,3Bh ;Это смена каталога?
je Change_dir

cmp ah,3Ch ;Это создание файла?
je Create_file

cmp ax,3D02h ;Это открытие файла для чтения/записи?
je Open_fl

cmp ah,41h ;Это удаление файла?
je Delete_file

jmp short Go_21h ;Если другое, то передадим управление 21h-ому... 

Start_f:
mov si,offset Start_filemess ;Строка для записи в наш log-файл.
call Move_string ;Готовим строку и записываем ее в файл...
jmp short Go_21h ;Передадим управление 21h-ому прерыванию...

Create_dir:
mov si,offset Create_dirmess
call Move_string
jmp short Go_21h

Delete_dir:
mov si,offset Delete_dirmess
call Move_string
jmp short Go_21h

Change_dir:
mov si,offset Change_dirmess
call Move_string
jmp short Go_21h

Create_file:
mov si,offset Create_filemess
call Move_string
jmp short Go_21h

Open_fl:
mov si,offset Open_filemess
call Move_string
jmp short Go_21h

Delete_file:
mov si,offset Delete_filemess
call Move_string


Go_21h:
pop es ;Восстановим регистры...
pop ds
popa

jmp dword ptr cs:[0FCh] ;Передаем управление прежнему 21h-ому
Int_21h_proc endp

;=== Переносим строку и пишем информацию в файл ===
Move_string proc
mov di,2 ;DS:SI указывают на строку
;ES:DI - на место в памяти, где будет формироваться строка...
lodsw ;Получим длину строки (первый байт строки)
mov cx,ax ;Длину строки в CX
rep movsb ;Переместили строку по адресу ES:DI (Текущий сегмент:0002h)

push ds
mov ds,bx ;DS указывает на сегмент, где находится имя файла
mov si,dx ;SI - на смещение

Next_char:
lodsb ;Получаем очередной символ
or al,al ;Это конец строки с именем файла? Проверка на 0...
jz Zero_found
stosb ;Если еще не конец - заносим его в нашу формирующуюся строку
jmp short Next_char ;Следующий символ...

Zero_found:
pop ds ;Имя файла перенесли! Восстановим DS.

mov ax,0A0Dh ;Добавим возврат каретки/перевод строки.
stosw

dec di
dec di
mov word ptr cs:[0],di ;Занесем по 0-ому смещению длину готовой строки

call Save_file ;Запишем готовую строку в наш log-файл...

ret
Move_string endp


;=== Пишем в файл ===
Save_file proc
call Check_file ;Проверим, существует ли наш log-файл или нет...

mov al,02h ;Открываем файл для чтения/записи
call Open_file

mov ax,4202h ;Устанавливаем указатель на конец файла
xor cx,cx
xor dx,dx
int 3

mov ah,40h ;Функция записи в файл
mov cx,cs:[0] ;Количество записываемых байт
mov dx,2 ;Откуда будем писать (DS:DX)
int 3

call Close_file ;Закрываем файл...

ret
Save_file endp

;=== Проверяем: существует ли нужный файл ===
Check_file proc
xor al,al ;Пробуем открыть наш log-файл
call Open_file
jnc File_exists ;Если файл существует, то на метку File_exists

; === Атрибуты файла ===
;00001 - только чтение
;00010 - спрятанный
;00100 - системный
;01000 - метка тома
;010000 - подкаталог
;100000 - архивный
mov ah,3Ch ;Если файл не существует, то создадим его.
mov cx,100010b ;Атрибут: архивный, спрятанный
mov dx,offset File_name ;DS:DX указывают на имя файла
int 3
jc Error_create ;Ошибка?.. 
mov Handle,ax ;Если успешно создали, то запомним номер файла

File_exists:
call Close_file ;Закрываем файл...

Error_create:
ret

File_name db 'C:\report.txt',0 ;Наш log-файл
Check_file endp

;=== Открытие файла ===
Open_file proc
mov dx,offset File_name
mov ah,3Dh
int 3
jc Error_open

mov bx,ax
mov Handle,ax

Error_open:
ret
Handle dw 0FFFFh
Open_file endp

;=== Закрытие файла ===
Close_file proc
pusha
pushf
cmp Handle,0FFFFh ;Нечего закрывать?.. 
je No_close

mov ah,3Eh
mov bx,Handle
int 3
mov Handle,0FFFFh ;Закрываем и отмечаем, что нет открытых файлов...

No_close:
popa
popf
ret
Close_file endp

;--- Сообщения резидента ---
Start_filemess dw Start_filemessl
db 'Launch file ---> ' ;db 'Запуск файла ---> '
Start_filemessl equ $-Start_filemess-2

Create_dirmess dw Create_dirmessl
db 'Create folder ---> ' ;db 'Создание каталога ---> '
Create_dirmessl equ $-Create_dirmess-2

Delete_dirmess dw Delete_dirmessl
db 'Delete folder ---> ' ;db 'Удаление каталога ---> '
Delete_dirmessl equ $-Delete_dirmess-2

Change_dirmess dw Change_dirmessl
db 'Change folder to ---> ' ;db 'Смена каталога на ---> '
Change_dirmessl equ $-Change_dirmess-2

Create_filemess dw Create_filemessl
db 'Create file ---> ' ;db 'Создание файла ---> '
Create_filemessl equ $-Create_filemess-2

Open_filemess dw Open_filemessl
db 'Open file for read/write ---> ' ;db 'Открытие файла для чтения/записи ---> '
Open_filemessl equ $-Open_filemess-2

Delete_filemess dw Delete_filemessl
db 'Deleta file ---> ' ;db 'Удаление файла ---> '
Delete_filemessl equ $-Delete_filemess-2




; === Инициализация (подготовка и настройка резидента) ===
Init:
mov ax,9889h ;Проверим, в памяти ли мы уже или еще нет
int 21h
cmp ax,8998h
jne Set_resident

mov ah,9 ;Если в памяти, то выведем соответствующее сообщение
mov dx,offset In_memory
int 21h

ret ;...И вернемся в DOS

Set_resident: ;Если нас в памяти нет, то установим резидент
; 21h-ое...
mov ax,3521h
int 21h ;Получим и сохраним адрес (вектор) 21h прерывания
mov word ptr cs:[0FCh],bx
mov word ptr cs:[0FEh],es

mov ax,es ;Установим старый вектор 21h-прерывания на 3...
push 0 ;(вырубим отладчик)
pop es
mov es:[3*4],bx
mov es:[3*4+2],ax

mov ax,2521h
mov dx,offset Int_21h_proc
int 3 ;"Повесим" нашу процедуру на 21h прерывание

call Check_file ;А есть ли наш log-файл?

mov ah,9
mov dx,offset Mess_hello
int 21h

mov dx,offset Init
int 27h ;Оставим программу резидентной в памяти.

In_memory db 'Программа уже загружена в память!!!',0Ah,0Dh,0Ah

Mess_hello db 'Резидент к книге "Ассемблер? Это просто! Учимся программировать", Глава № 19.',0Ah,0Dh,0Ah
db 'Автор: Калашников Олег Александрович (Assembler@Kalashnikoff.ru),',0Ah,0Dh
db 'http://www.Kalashnikoff.ru, Россия, Москва, 2000 год.',0Ah,0Dh,'$'

CSEG ends
end Begin
[/code]

Обсуждение

давно
Старший Модератор
312929
1973
20.09.2015, 15:28
общий
это ответ
Здравствуйте, Посетитель - 398958!

Для тех функций прерывания 21h, которые используют имя файла (39h, 3Ah, 3Bh, 3Ch, 3Dh, 41h, 43h, 4Bh, 4Eh, 56h и некоторые другие) адрес строки с именем файла передаётся через DS:DX. В данном обработчике DS сразу сохраняется в BX, а DX не изменяется, после чего для всех перехватываемых функций вызывается процедура Move_string, которая использует пару регистров BX и DX для получения сегмента и смещения строки с именем файла. Для функции 4Bh это будет имя запускаемой программы, для функций 39h, 3Ah, 3Bh - имя каталога, для остальных - имя файла.
Форма ответа