До сих пор мы баловались с вами, друзья, изменением текстовых файлов.
Давайте побалуемся модификацией com-файлов. А именно - будем дописывать в
начало нашего знаменитого файла hello.com
некоторое количество байт - например, ничего не делающих операторов
NOP. Только чур - изменённая программа hello.com должна работать, как и
раньше!
За основу возьмём программу из 11-го урока.
;Всё, что следует за значком ";" - это комментарий.
CSEG segment ;Даём имя сегменту, а точнее определяем абсолютный ;сегмент в памяти программ по
определённому адресу. ;Имя нашего сегмента будет CSEG.
assume cs:CSEG, ds:CSEG, es:CSEG, ss:CSEG ;Задаём сегментные регистры, которые будем использовать для ;вычисления действующего адреса для всех меток и переменных, опре- ;делённых для сегмента или группы сегментов с указанным именем. ;У нас их четыре, - CS, DS, ES, SS и они будут указывать на наш ;единственный сегмент (мы его назвали CSEG).
org 100h
;Устанавливаем счётчик инструкций в текущем сегменте в соот- ;ветствии с адресом, задаваемым "выражением". ;Сейчас этот счётчик равен 100h - используется для всех программ ;типа .com
begin: ;Метка начала программы.
;Данная программа будет обновлять файл ;hello.com.
mov ax,3D02h ;Первоначально откроем файл для чтения-записи. mov dx,offset File_name int 21h jc
Message_bad
mov Handle,ax ;Если файл существует, сохраняем номер файла. mov bx,ax
mov ah,3Fh ;Чтение в память. mov cx,19h ;Определяем количество читаемых байт (напр.25 - больше нам пока не нужно). mov dx,offset Finish ;по адресу памяти за нашей программой. add dx,16 ;Добавляем х байт (наши nop и изменение DS). int
21h ;В стеке - число реально прочитанных байт. push ax
mov si,offset Add_nop ;Переносим х байт c адреса смещения Add_nop mov di,offset Finish ;в конец нашей программы, но перед загруженной нами. mov cx,16 ;Перемещаем 16 байт. rep movsb
mov dx,0h ;Устанавливаем указатель с начала файла +0h. mov cx,0h
;+0h мы указали потому, что будем mov ax,4200h ;перезаписывать файл hello.com с первого байта. int 21h ;
mov ah,40h ;Записываем программу (в т.ч.$) из смещения Finish mov dx,offset Finish ;по адресу, указанному выше. pop cx ;В cx - длина считанной нами программы. add cx,16
;Увеличиваем до длины, установленной нами. int 21h
Message_ok: ;Подпрограмма успешного вывода строки и выхода. mov bx,Handle ;Сначала сохраним файл, восстановив bx. mov ah,3Eh ;Закроем файл. int 21h
mov ah,9 ;Выводим строку. mov dx,offset Mess_ok int 21h int 20h
Message_bad: ;Подпрограмма вывода сообщения об ошибке и выхода. mov
ah,9 mov dx,offset Mess_bad int 21h int 20h
Add_nop: ;Приписываемые байты (16 - посчитайте отладчиком). NOP NOP NOP NOP NOP NOP NOP NOP mov ax,ds ;Изменяем ds в новой программе. Прямые операции с ds запрещены! add ax,1 ;Внимание - вопрос! Почему изменяем ds на 1? mov ds,ax
NOP ;Контрольный NOP. Проще смотреть в отладчике.
File_name db 'hello.com',0,'!$' ;Имя файла.
Mess_ok db 'Файл обновлён. Всем спасибо.$' ;Успешное сообщение и сообщение об ошибке (ниже).
Mess_bad db 'Файл не найден. Поместите hello.com в каталог с программой.$'
Handle dw 0FFFFh ;Определяем переменную (для идентификатора
файла).
Finish equ $ ;Метка конца нашей программы!
CSEG ends end begin И конечно же, ml test.asm /AT (не забывая при этом устанавливать в текстовом файле кодировку 866). Не забываем помещать файл hello.com в каталог с нашей программой.
На что следует обратить внимание? Нижеследующий текст и есть то, что мы приписываем в начало нашего файла hello.com:
Add_nop: NOP NOP NOP NOP NOP NOP NOP NOP mov ax,ds add ax,1 mov ds,ax NOP На NOP'ы мы внимания не обращаем, а вот модификация регистра DS уже в программе hello.com
должна нас заинтересовать. Как мы помним, текст выводимой строки
"Hello, world" располагается по адресу DS:DX... Но почему мы увеличиваем
DS всего лишь на единицу? Продолжим изучение материала в следующем уроке.