|
Ассемблер в примерах - Свободные кластеры логического диска "А"
- Вопрос:
- Разработать ассемблер-программу,выводящую в файл номера свободных кластеров логического диска "А". Для вывода использовать handle-ориентированные системные функции обработки файлов. Формат вывода - символьно-шестнадцатеричный. Пояснить назначение выводимых объектов и их отдельных полей.
Для поиска объектов использовать только прерывания 13h.
- Ответ:
- Программа в приложении.
Единственно, что еще следовало бы добавить - обработку ошибок типа "не читается диск".
.model tiny ;буддем создавать com-файл
.186 ;чтобы можно было было использовать команды shr ax,4
BOOT_STRUCTURE struc ;структура данных бутовой записи
Jmp_Command db 3 dup (?) ;jmp
Company_Name db 8 dup (?) ;производитель
Sector_Size dw ? ;размер сектора в байтах
Cluster_Size db ? ;размер кластера в секторах
Reserved_Sectors dw ? ;количество резервных секторов (после бутовой записи и до FAT-а)
FAT_Count db ? ;количество FAT-ов
Root_Size dw ? ;размер корневого каталога в 32-байтных записях (в секторе 16 штук)
Total_Sectors dw ? ;общее число секторов
Media db ? ;тип носителя
FAT_Size dw ? ;размер одного FAT-а в секторах
Track_Sectors dw ? ;количество секторов на дорожке
Heads_Count dw ? ;количество головок
Hidden_Sectors dw ? ;невидимые сектора (на флоппи их нет)
BOOT_STRUCTURE ends
.data
output_name db 'free.dat',0 ;имя файла
first_string db 'Номера свободных кластеров диска A:',0dh,0ah ;заголовок в файле
len_first_string equ $-first_string ;длина заголовка
.data?
boot db 512 dup (?) ;буфер для приема бутовой записи (и для вывода в файл)
fat label byte ;начиная с этого адреса запишем все сектора FAT-а
.code
.startup
lea bx, boot ;прочитаем бутовую запись
mov cx, 1 ;0 дорожка, 1-й сектор
mov dx, 0 ;0 головка, первый флоп
mov ax, 0201h ;читаем один сектор
int 13h
mov si, bx ;будем адресовать бутовую запись через si
;число секторов одного FAT-а
mov cx, [BOOT_STRUCTURE ptr si].FAT_size
;адрес буфера для FAT-а
lea bx, fat
;определим первый сектор первого FAT-а
;будем хранить в di номер считываемого сектора + дорожка (в формате регистра cx)
mov di, 2 ;1-й - boot, ищем, начиная со 2-го
;а вдруг есть невидимые (на флоппи их обычно нет)
add di, [BOOT_STRUCTURE ptr si].Hidden_Sectors
xor dx, dx ;0 головка, первый флоп
sectors_loop:
push cx
mov cx,di ;зададим сектор+дорожку
mov ax,0201h;читаем один сектор
int 13h
inc di ;инкремент номера сектора
;проверим, дошли ли до края дорожки?
cmp di, [BOOT_STRUCTURE ptr si].Track_Sectors
jbe next ;все ок, на следующий сектор
;переходим на другую головку
mov di, 1 ;с первого сектора
inc dh ;увеличиваем номер головки
;проверим, прошли ли все головки?
cmp dh, byte ptr [BOOT_STRUCTURE ptr si].Heads_Count
jb next
;переходим на следующий цилиндр (дорожку)
mov dh, 0 ;с 0-й дорожки
add di, 100h;инкремент цилиндра
next:
add bx, 200h;адрес буфера для следующего сектора
pop cx
loop sectors_loop ;по всем секторам
;Определим, сколько у нас есть кластеров
;Сначала посчитаем, сколько секторов использовано
mov di, 2 ;начинаем со второго (первый - Boot)
add di, [BOOT_STRUCTURE ptr si].Hidden_Sectors ;невидимые
xor ax, ax
mov al, [BOOT_STRUCTURE ptr si].FAT_Count ;количество FAT-ов
mul [BOOT_STRUCTURE ptr si].FAT_size ;размер всех FAT-ов
add di, ax ;накапливаем
mov ax, [BOOT_STRUCTURE ptr si].Root_Size ;размер Root-а в записях
shr ax, 4 ;всего в одном секторе 16 записей - делим на 16
add di, ax ;накапливаем
mov ax, [BOOT_STRUCTURE ptr si].Total_Sectors;общее число секторов
sub ax, di ;отнимем использованные
mov cl, [BOOT_STRUCTURE ptr si].Cluster_Size;число секторов в кластере
dec cl
shr ax, cl ;ax = числу кластеров
dec ax ;отнимем 1, т.к. первого нет, счет идет с 2
;просмотрим считанную FAT и найдем все свободные кластера
mov cx, ax ;счетчик кластеров
mov bp, bx ;где закончили писать сектора FAT-а - буфер для номеров
; свободных кластеров
xor di, di ;индекс в буфере свободных кластеров
mov si, 2 ;в si - номер очередного кластера
lea bx, fat+3 ;пропустим первые 3 байта
search_free_loop:
mov ax, [bx] ;"четный" номер
and ax, 0fffh ;выделяем его
jnz next_odd ;не 0 - занят
mov [bp+di], si ;0 - свободен - сохраняем его номер
add di, 2 ;для следующего
next_odd:
inc si ;номер следующего кластера
loop cmp_odd ;циклим по cx
jmp output_data ;если пройдем по всем, то на формирование файла
cmp_odd:
mov ax, [bx+1] ;"нечетный" номер
shr ax, 4 ;выделяем его
jnz next_both ;не 0 - занят
mov [bp+di], si ;0 - свободен - сохраняем его номер
add di, 2
next_both:
inc si
add bx, 3 ;на следующую пару
loop search_free_loop
output_data: ;сформируем файл с информацией
lea dx, output_name ;создадим файл
mov ah, 3ch
mov cx, 0
int 21h
mov bx, ax ;handle файла
lea dx, first_string ;выведем заголовок
mov cx, len_first_string
mov ah, 40h
int 21h
mov si, bp ;адрес буфера номеров
mov cx, di ;конечный использованный адрес
shr cx, 1 ;число слов
new_row:
xor bp, bp ;будем выводить по 16 значений в строке,
; bp - счетчик в строке
lea di, boot ;адрес буфера для формирования очередной строки
row_loop:
push cx
lodsw ;читаем очередное слово
call PrintWordHex ;сформируем в буфере hex-строку
inc bp ;считаем число величин в строке
cmp bp, 16 ;16 - максимум
jb output_next ;меньше - добавим запятую и пробел
mov ax, 0a0dh ;иначе - добавим перевод строки
stosw
mov cx, di ;адрес, куда дописали
lea dx, boot ;адрес буфера
sub cx, dx ;длина
mov ah, 40h ;и выведем
int 21h
pop cx
loop new_row ;на новую строку
jmp close_file ;попадем сюда, если будут ровно по 16
output_next:
mov ax, ' ,' ;разделим величины
stosw
pop cx
loop row_loop ;на следующее значение
cmp di, offset boot ;проверим, если есть незаконченная строка
jne close_file
mov word ptr [di-2],0a0dh ;закроем ее
mov cx, di ;и выведем
lea dx, boot
sub cx, dx
mov ah, 40h
int 21h
close_file:
mov ah, 3eh ;закроем файл
int 21h
.exit 0 ;выход в ДОС
PrintWordHex proc ;слово в hex
push ax ;сохраним al в стеке
mov al,ah ;выведем старший байт
call PrintByteHex
pop ax ;восстановим младший
PrintByteHex proc ;выводим байт в hex
push ax ;сохраним младшую тетраду
shr al,4 ;старшая тетрада 00-0f
call PrintHexDigit ;выводим hex цифру
pop ax ;восстановим младшую тетраду
and al,0fh ;выделим
PrintHexDigit proc ;выводим hex цифру
add al,90h ;последующие 4 команды преобразовывают
daa ;число 00-0f в символы '0'-'9','A'-'F'
adc al,040h
daa
stosb
ret
PrintHexDigit endp
PrintByteHex endp
PrintWordHex endp
ret
end
| |