Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Уроки ассемблеру. Быстро и просто. Урок 14


А давайте, друзья, попробуем массово поизменять какие-нибудь файлы, лежащие в текущем каталоге.
Для этого нам понадобятся функции 1Ah (установка PSP), 4Eh (поиск первого файла), 4Fh (поиск следующего файла) прерывания 33 (т.е. 21h).

Возьмём за основу код из 8-го урока и изменим его:

;Всё, что следует за значком ";" - это комментарий.

.286 ;Разрешает ассемблирование непривилегированных инструкций
;процессора 80286 (реальный режим) и инструкций арифметического
;сопроцессора 80287.

CSEG segment ;Даём имя сегменту, а точнее определяем абсолютный
;сегмент в памяти программ по определённому адресу.
;Имя нашего сегмента будет CSEG.

assume cs:CSEG, ds:CSEG, es:CSEG, ss:CSEG ;Задаём сегментные регистры, которые будем использовать для
;вычисления действующего адреса для всех меток и переменных, опре-
;делённых для сегмента или группы сегментов с указанным именем.
;У нас их четыре, - CS, DS, ES, SS и они будут указывать на наш
;единственный сегмент (мы его назвали CSEG).

org 100h ;Устанавливаем счётчик инструкций в текущем сегменте в соот-
;ветствии с адресом, задаваемым "выражением".
;Сейчас этот счётчик равен 100h - используется для всех программ
;типа .com

begin: ;Метка начала программы.

mov ah,1Ah ;Установим PSP в конец файла.
mov dx,offset Finish
int 21h

call Find_first ;Ищем первый файл.
jc Error_file_metka ;Нет txt-файлов - на выход.

goto_cikl: ;Начало цикла.

mov ax,3D02h ;Загружаем в регистр ah число 3Dh (функция открытия
;файла с записью), а в al число 02h (пишем в конец).
;Можно было записать и так - mov ah,3Dh
;mov al,02h

mov dx,offset Finish ;Указываем адрес файла в DTA (по умолчанию он 80h от начала PSP,
add dx,1Eh ;+1Eh - наше имя файла.
int 21h ;Выполняем функцию.

mov Handle,ax ;При открытии файлу будет присвоен номер, его и
;сохраняем для дальнейших действий,
mov bx,ax ;а заодно и сохраняем его в bx.

mov ax,4202h ;Используем функцию установки указателя.
;al=02h - устанавливаем в конец.
mov cx,0 ;Нам надо записать прямо в конец файла, поэтому
mov dx,0 ;обнулим cx и dx (иначе будет писать далее на
;значение (CX * 65536) + DX
int 21h ;Выполняем функцию.

mov ah,40h ;Используем функцию записи в файл.
mov dx,offset one ;В dx занесём адрес смещения к записываемому
;тексту.
mov cx,1 ;Число записываемых байт - 1.
int 21h ;Выполняем функцию.

mov ah,3Eh ;Используем функцию закрытия файла.
mov bx,Handle ;Для закрытия обязательно "вспоминаем" его номер,
;номер у нас был сохранён в Handle.
int 21h ;Выполняем функцию.

call Find_next ;Ищем следующий файл.
jnc goto_cikl ;Нашли ещё один файл; прыгаем на метку.

mov ah,9 ;Загружаем в регистр ah число 9 (указываем функцию).
mov dx,offset Vse_ok ;Указываем, что за фразу мы будем выводить.
int 21h ;Выводим фразу.

mov ah,4Ch ;Используем для выхода из программы.
int 21h

Error_file_metka: ;Вывод сообщения об ошибке.

mov ah,9 ;Загружаем в регистр ah число 9 (указываем функцию).
mov dx,offset Error_file ;Указываем, что за фразу мы будем выводить.
int 21h ;Выводим фразу.

mov ah,4Ch ;Используем для выхода из программы.
int 21h

Find_first proc ;Подпрограмма поиска первого файла.
mov ah,4Eh ;Ищем первый файл по маске (функция 4Eh).
xor cx,cx ;Атрибуты обычные. Смотрим, что в CX.
mov dx,offset File_name ;Адрес маски в DS:DX
int 21h ;В DTA заносится имя найденного файла.
ret
Find_first endp
;Подпрограмма поиска следующего файла.
Find_next proc
mov dx,offset Finish ;DS:DX указывают на DTA.
xor cx,cx ;CX=0.
mov ah,4Fh ;4Fh - поиск следующего файла.
int 21h ;В DTA заносится имя найденного файла.
ret
Find_next endp

File_name db '*.txt',0 ;Маска файла.

Handle dw 0FFFFh ;Определяем переменную Handle, которую используем для
;хранения номера файла. По умолчанию она равна 0FFFFh.

one db '1' ;Определяем переменную one, содержащую символ "1",
;которую мы будем приписывать в конец файла.
Vse_ok db 'Файлы найдены и обновлены. Всем спасибо.$'

Error_file db 'Файлы не найдены. Поместите файлы *.txt в каталог с программой.$'

Finish equ $ ;Метка конца программы.

CSEG ends
end begin

Разберём, по традиции, наши функции.

HELP.EXE -> Указатель функций DOS/BIOS -> Функции DOS -> 1aH Set DTA

Вход: AH — 1aH
DS:DX: адрес для DTA
Описание: Устанавливает адрес DTA.
∙ Все FCB-ориентированные операции работают с DTA.
∙ DOS не позволяет операциям в/в пересекать границу сегмента.
∙ Функции поиска: 11H 12H 4eH и 4fH помещают данные в DTA.
∙ DTA глобальна, поэтому будьте осторожны, назначая ее в рекурсивной или реентерабельной процедуре.
∙ При запуске программы ее DTA устанавливается по смещению 80H относительно PSP.

Зачем же нам устанавливать PSP (и DTA) в другое место? PSP — Program Segment Prefix - префикс программного сегмента, а DTA — Data Transfer Area — область переноса данных. DTA находится по умолчанию по адресу 80h. Так вот, проблема в том, что по этому адресу (80h) располагается изначально командная строка DOS. Как только мы найдём первый файл, мы затрём командную строку, а как только будем осуществлять вывод информационных сообщений, программа зависнет. Мы используем самый простой способ — переустановка адреса PSP (и DTA вместе с ним). Можно временно перенести PSP, а потом восстановить перед началом соответствующей команды. Куда переносить — это уже следующий вопрос.

HELP.EXE -> Указатель функций DOS/BIOS -> Функции DOS -> 4eH Fnd1stFile

Вход: AH — 4fH
DS:DX: адрес строки ASCIIZ с именем файла (допускаются ? и *)
CX: атрибут файла для сравнения
Выход: AX — код ошибки, если CF установлен
DTA: заполнена данными (если не было ошибки)
Описание: DS:DX указывает на строку ASCIIZ в форме: "d:\путь\имяфайла",0.
Если диск и/или путь опущены, они подразумеваются по умолчанию.
Обобщённые символы * и ? допускаются в имени файла и расширении.

DOS находит имя первого файла в оглавлении, которое совпадает с заданным именем и атрибутом, и помещает найденное имя и другую информацию в DTA.

HELP.EXE -> Указатель функций DOS/BIOS -> Функции DOS -> 4fH FndNxtFile

Вход: AH — 4fH
DS:DX: адрес данных, возвращенных предыдущей 4eH Найти 1-й Файл
Выход: AX — код ошибки если CF установлен
DTA: заполнена данными
Описание: DS:DX указывает на 2bH-байтовый буфер с информацией, возвращённой функцией 4eH Найти 1-й (либо DTA, либо буфер, скопированный из DTA).

Используйте эту функцию после вызова 4eH. Следующее имя файла, совпадающее по обобщённому имени и атрибуту файла, копируется в буфер по адресу DS:DX вместе с другой информацией (см. функцию 4eH о структуре файловой информации в буфере, заполняемом DOS).

Дальше всё просто. ml test.asm /AT. Перед этим, правда, необходимо отключить антивирус, так как мой ESET NOD32 показал следующее:

 


В избранное