Ассемблер Это просто! Учимся программировать

       

Немного теории


Я получил много писем с таким вопросом:

TASM выдает ошибку: Near jump or call to different CS.

Я предложил вставить строку assume cs:CSEG. Что же происходит?

Дело в том, что эта строка указывает Ассемблеру на привязку сегментного регистра CS к нашему сегменту (CSEG). MASM ассемблирует прекрасно и без этой строки. Если оператор assume отсутствует, то MASM как бы по умолчанию вставляет ее автоматически.

Другое дело TASM. Он, встретив в программе строки вида:

loop Label_1 jmp Label_2 call Procedure

не может "понять" к какому сегменту следует обратиться (CS, DS, ES) и выдает сообщение об ошибке.

Как уже говорилось, мы пишем com-файлы в которых всего один сегмент (мы обзываем его CSEG). Если вы создадите еще один (например, DSEG), то компоновщик (link.exe), при попытке создать com-файл, выдаст ошибку.

Чтобы полностью закрыть данную тему, привожу полный вид разбираемой нами строки:

assume cs:CSEG, ds:CSEG, es:CSEG, ss:CSEG

Этим мы указываем Ассемблеру на то, что сегментные регистры CS, DS, ES, SS будут указывать на наш единственный сегмент.


Допустим, в текущем каталоге файла "file" не было найдено. Тогда, функция 3Dh устанавливает в единицу флаг переноса (помните схожую ситуацию с флагом нуля из прошлых глав?). Если же файл все-таки найден и успешно открыт, то флаг переноса устанавливается в нуль.

Для проверки состояния флага переноса используется оператор JC (Jump if Carry - переход, если установлен флаг переноса) и JNC (Jump if Not Carry - переход, если флаг переноса не установлен): ... int 21h jc Error Ok: .... Error: ...

или так: ... int 21h jnc Ok Error: ... Ok: ...

Естественно, вместо меток Ok и Error (ошибка) можно задавать любые другие имена.

Вы уже можете сделать вывод, что JC и JNC - команды условного перехода.

Все функции устанавливают в единицу флаг переноса, если произошла ошибка и сбрасывают его, если ошибки не было.

Вот полный пример открытия файла: ... mov ax,3D00h mov dx,offset File_name int 21h jc Bad_file mov dx,offset Mess1 Quit_prog: mov ah,9 int 21h int 20h Bad_file: mov dx,offset Mess2 jmp Quit_prog

Далее. При успешном открытии файла в AX возвращается уникальный идентификационный номер файла. В дальнейшем, при обращении к данному файлу, будет указываться не его имя, а этот номер. После вызова функции 3Dh сохраните номер файла!

После того, как мы закончили работу с файлом (записали или прочитали что-нибудь), его необходимо закрыть функцией 3Eh :

Функция 3Eh прерывания 21h - закрытие файла:

Вход: AH = 3Eh
BX - номер файла Выход: ничего Все данные, которые мы записывали в файл, на самом деле не записываются сразу на диск. Они хранятся в памяти до тех пор, пока файл не будет закрыт. Только после этого сбрасываются все дисковые буферы, и файл сохраняется на диске. Это не совсем так, но принцип такой.

Не забывайте закрывать файл! mov ah,3Eh mov bx,Handle int 21h

Файл закрыт.

Обратите внимание на запись mov bx,Handle. Здесь Handle - это переменная, в которую необходимо будет занести номер файла после открытия. Переменные мы подробно рассмотрим в следующих выпусках, а сейчас коснемся только того, как создать переменную Handle. Вот пример: Handle dw 0

Здесь мы резервируем два байта для хранения каких-нибудь данных. В данном случае - для хранения номера файла. Таким образом, рассмотрим фрагмент программы, которая открывает файл для чтения, сохраняет номер файла в переменную, а затем закрывает файл: ... mov ax,3D00h mov dx,offset File_name int 21h jc Error mov Handle,ax ; файл открыт успешно... mov ah,3Eh mov bx, Handle int 21h ;файл закрыт Error: int 20h ... Handle dw 0 ...

Для чтения информации из файла используется функция 3Fh, а для записи в файл - 40h. При этом BX должен содержать тот самый номер файла (Handle), CX - количество читаемых или записываемых байт, DS:DX - адрес буфера для чтения / записи.


Содержание раздела