Консультация № 186450
17.07.2012, 10:40
0.00 руб.
0 19 1
1. Чем отличаются первая редакция книги Калашникова от 2006 и вторая от 2011(2) ??

2. У меня при изучении ассемблера по книге Калашникова возникли мысли и хотелось бы понять насколько они верные.

Почему в этой программе избыточный код
http://www.kalashnikoff.ru/Assembler/issues/encl/009/PROG09.asm.htm
???
а именно
Процедура

Open_file proc
cmp Handle,0FFFFh ; Вот эта проверка будет всегда пройдена поскольку мы сами ниже определяем значение Handle а второй раз этот код отрабатывать не будет и в итоге вообще непонятна целесообразность Handle
jne Quit_open
mov ax,3D00h
int 21h
mov Handle,ax <------ Здесь идентификатор переносится в переменную, хотя еще не была произведена проверка флага переноса. иначе вхолостую можно потерять время если файл не открыт.
ret
Quit_open:
stc
ret
Handle dw 0FFFFh
Open_file endp

то есть мы могли бы написать....
mov dx,offset File_name
mov ax,3D00h
int 21h
jc Error_file

Но Олег усложнил код по какой то причине мне непонятной.... Очень любопытно !!!

Чисто теоретически файл мог бы быть открыт второй раз.... но!!!
если бы мы спрашивали ОС открыт ли файл, то это было бы верно, но там с потолка (???) идёт присвоение переменной идентификатора значения FFFFh

Допустим запустили раз эту программу и второй раз (что для DOSа нереально ибо он однозадачен), но даже если запустили под win98 то в каждой программе будет своё адресное пространство и своя переменная Handle и даже если файл уже открыт, другая копия программы об этом не узнает. Возможно более лучший выход файлы семафоры.

Обсуждение

давно
Старший Модератор
31795
6196
17.07.2012, 11:28
общий
Вы несколько не туда смотрите:
1)с каким файлом работает код?
2)куда он читается?
3)после чтения, какая версия файла будет выполнятся?
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Посетитель
7438
7205
17.07.2012, 11:46
общий
это ответ
Здравствуйте, Роман И.!
Давайте по-порядку...
1) cmp Handle,0FFFFh ; Вот эта проверка будет всегда пройдена поскольку мы сами ниже определяем значение Handle а второй раз этот код отрабатывать не будет и в итоге вообще непонятна целесообразность Handle
Да, Вы правы, проверка будет пройдена. И можно было ее не делать.
Но то, что сделано, ничего страшного. Дело в том, описатель файла надо было сохранить, чтобы потом файл закрыть.
Хотя опять же, можно было обойтись и регистром bx.
То, что, некая переменная, в нашем случае, handle изначально равна 0ffffh, часто используется, к примеру, в проверке, надо ли
закрывать файл. Здесь этого нет, но идея такая.

2)mov Handle,ax <------ Здесь идентификатор переносится в переменную, хотя еще не была произведена проверка флага переноса. иначе вхолостую можно потерять время если файл не открыт.
Вы опять правы. Сохранять описатель следует после проверки корректности открытия...

3) то есть мы могли бы написать....
mov dx,offset File_name
mov ax,3D00h
int 21h
jc Error_file
Можно было... Но handle желательно сохранять, можно, конечно, хранить и в bx...

4) Но Олег усложнил код по какой то причине мне непонятной.... Очень любопытно !!!
Я уже объяснил, что при чтении, записи, закрытии надо проверять корректность операций, что можно сделать проверкой handle на равенство 0ffffh. В простейших случаях, можно этого не делать. Но в более сложных программах без этого не обойтись. В данной программе просто заложен, но не реализован, механизм проверки.

5) с потолка (???) идёт присвоение переменной идентификатора значения FFFFh
Сделано присвоение заранее определенным значением, чтобы иметь возможность проверки на корректность

6) Допустим запустили раз эту программу и второй раз (что для DOSа нереально ибо он однозадачен), но даже если запустили под win98 то в каждой программе будет своё адресное пространство и своя переменная Handle и даже если файл уже открыт, другая копия программы об этом не узнает. Возможно более лучший выход файлы семафоры.
Под ДОС-ом программы не знают о существовании друг друга... А семафоры - это уже из программирования под другие ОС

После внимательного анализа программы, после замечания Зенченко Константина Николаевича,
выяснилась любопытная деталь, связанная с работой данной программы:
1) После открытия файла описатель файла сохраняется в переменной handle
2) После чтения файла, а это наша же программа на ее же место, переменная handle опять станет равной 0ffffh!
3) Последующее закрытие будет уже оперировать с handle = 0ffffh, что является ошибкой!
Выходов, как минимум два:
1) Хранить handle в другом месте (в bx, стеке, в другой памяти)
2) Читать не весь файл, например только сегмент кода (переделав слегка код)
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
17.07.2012, 13:46
общий
17.07.2012, 14:21
Благодарю за ответы, я их еще перечитаю, а пока отвечу на вопросы и кое что добавлю.
Может я и вправду не туда смотрю...

1) Код работает с исполняемым файлом самого себя.
2) Код файла читается в память прямо поверх самого себя же в памяти. В примере ниже имя файла l.com
3) После чтения будет выполняться то же что и было...

Чтобы понять, что и как я попробовал убрать эту переменную. Программа теперь работает и без неё.

Отладчик не работает после чтения (может быть SOftICe бы работал, но не получается в виртуальной машине с win98 его запустить, если подскажете как буду благодарен).

Поскольку отладчик не срабатывает, я воспольвался простой печатью строки после каждой операции, чтобы проверить до какой строки программа отрабатывает код.
Код программа приведенной ниже печатает строки
"File read"
"File closed"
"Всё нормально!"
и без handle...

Код:
cseg segment
assume cs:cseg,ds:cseg,es:cseg,ss:cseg
org 100h
start:
mov dx,offset file_name
mov ax,3D00h
int 21h
jc error_file

mov bx,ax
mov ah,3Fh
mov cx,offset finish-100h
mov dx,offset start
int 21h

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

mov ah,3Eh
int 21h

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

mov dx,offset message_ok
mov ah,9
int 21h
jmp end_

error_file:
mov dx,offset error
mov ah,9
int 21h
end_:
ret

;ДАННЫЕ
file_name db 'l.com',0
error db 'Error open file',0Ah,0Dh,'$'
readf db 'File read',0Ah,0Dh,'$'
closef db 'File closed',0Ah,0Dh,'$'
message_ok db 'Все нормально!',0Ah,0Dh,'$'
finish equ $
cseg ends
end start


Неизвестный
17.07.2012, 14:14
общий
17.07.2012, 14:20
1) надо проверять корректность операций, что можно сделать проверкой handle на равенство 0ffffh.
Вот это остается непонятным как можно сделать операцию некорректной если делать проверку на флаг переноса ?
может есть какие примеры ?

2) "Под ДОС-ом программы не знают о существовании друг друга... А семафоры - это уже из программирования под другие ОС"
Семафоры или файлы блокировки... просто можно создать файл именем lock и делать проверку через него.
Кстати такие программы как ThunderBird, FireFox это используют чтобы узнать запущен ли другой процесс.
А нашем случае это тоже можно использовать если запускается несколько копий программы.
Верно ?

3) "После чтения файла, а это наша же программа на ее же место, переменная handle опять станет равной 0ffffh!"
Да, если файл будет записан поверх себя же в памяти, то значение handle затрётся начальным.
Выходит оно тут бесполезно .... а чтобы избежать этого надо перенести инициализацию идентификатора в блок данных и просто передвинуть метку
finish equ $
до инициализации этой переменной, то есть перетираться будет только исплоняемый код, а значение переменной тогда сохранится.

................
message_ok db 'Все нормально!',0Ah,0Dh,'$'
finish equ $
Handle dw 0FFFFh
...................

Верно я мыслю ?
давно
Старший Модератор
31795
6196
17.07.2012, 14:25
общий
Цитата: 394180
3) После чтения будет выполняться то же что и было...

Будет выполнятся то, что было прочитано, а это иногда не одно и тоже.


Пройдите в отладчике код и обратите внимание на ту самую переменную handle, до и после чтения файла.
- Проверка cmp Handle,0FFFFh не нужна, т.к. всегда там будет -1, даже если зациклить программу.
- Запись переменной mov Handle,ax не нужна, т.к. после этого используется регистровая пересылка(для функции чтения - mov bx,ax), а само значение теряется после чтения.
- После чтения из файла будет востановлено первоначальное значение handle, т.е. -1. Следующая п/программа Close_file будет закрывать неоткрытый файл с значением дискриптора -1.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Старший Модератор
31795
6196
17.07.2012, 14:58
общий
17.07.2012, 15:06
Цитата: 394180
Семафоры или файлы блокировки... просто можно создать файл именем lock и делать проверку через него.


Обратимся к самому полному первоисточнику:
Цитата: Ralf Brown Interrupt List
DOS 2+ - OPEN - OPEN EXISTING FILE
AH = 3Dh
AL = access and sharing modes (see #01402)
DS:DX -> ASCIZ filename
CL = attribute mask of files to look for (server call only)

Return:
CF clear if successful
AX = file handle
CF set on error
AX = error code (01h,02h,03h,04h,05h,0Ch,56h) (see #01680 at AH=59h)


В регистре AL указываются атрибуты доступа и разделения. Взависимости от их значения система ДОС даст ошибку при повторном открытии.

Цитата: 394180
надо проверять корректность операций, что можно сделать проверкой handle на равенство 0ffffh.

Эта проверка взята из такой темы как перхват прерывания и резидентные программы.
Если кратко, при запуске резидента он устанавливает вместо системных обработчиков прерываний свои. При возникновении прерывания анализирует входные значения. Примеру такой код:
Код:
new_int29:	cmp ah,al
jnz @@01
inc al
iret
@@01: jmp oldInt29

Вполне может быть использован резидентом для проверки самого себя в памяти.
При запуске резитента обычно идет инициализация, т.е. установка своих обработчиков, сохранение старых и т.д.
Перед началом инициализации с помощью:
Код:
mov ax,2020h
int 29h

Если после вызова будет ax=2021h, то резидент уже установлен, т.е. можно исключить повторную загрузку в память самого себя и завершить текущее приложение.
Что проверять и как - это только ограничивается фантазией программиста.

3)да.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Руководитель
2
547
17.07.2012, 15:16
общий
Роман, второе издание дополнено новой информацией, исправлены ошибки и неточности. Также на компакт-диске присутствуют адаптированные к Win Vista и 7 файлы-приложения...
Неизвестный
17.07.2012, 15:36
общий
17.07.2012, 15:43
Адресаты:
К сожалению отладчик бухается после чтения файла и не могу отследить handle, а я б с удовольствием.
Неизвестный
17.07.2012, 15:53
общий
Адресаты:
а какой новой можно где то почитать ?
давно
Посетитель
7438
7205
17.07.2012, 16:00
общий
1) надо проверять корректность операций, что можно сделать проверкой handle на равенство 0ffffh.
Вот это остается непонятным как можно сделать операцию некорректной если делать проверку на флаг переноса ?
Проверка на флаг С делается после операции, а проверка на handle == 0ffffh - до операции. Например, у нас есть достаточно большая программа, которая что-то там открывает, читает, пишет, закрывает. И все эти операции разнесены по времени... Так вот, в таких случаях, полезно перед операцией проверять, а корректен ли handle. Можно, конечно, обойтись и без этого, но бывает удобно написать, например, функцию закрытия, которая, если надо - закроет файл, не надо - не будет этого делать...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
17.07.2012, 16:19
общий
К сожалению отладчик бухается после чтения файла
Мой AFD просто переходит на начало и говорит, что программа завершена... Кто мешает подойти к нужному месту и начать с команды после чтения файла?
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Руководитель
2
547
17.07.2012, 16:23
общий
Цитата: 394180
а какой новой можно где то почитать ?

Нет, такой информации нет. Если Вы читали первое издание, то второе брать нет особого смысла.
давно
Старший Модератор
31795
6196
17.07.2012, 16:28
общий
17.07.2012, 16:30
Раз дебугер падает, то посмотим по другому
Добавьте такой код:

Код:
saveFile:
mov ax,3ch
xor cx,cx
int 21h
push ax
mov bx,ax
mov cx,offset finish-100h
mov dx,100h
mov ah,40h
int 21h
pop bx
mov ah,3eh
int 21h
ret


и вызов

Код:
lea	dx,dbFile1
call saveFile
;
;
mov bx,handle;тут указываем handle
mov ah,3Fh
mov cx,offset Finish-100h
mov dx,offset Begin
int 21h
;
;
lea dx,dbFile2
call saveFile

Имена файлов на Ваше усмотрение. Это так извращение с файлами, которое потом нужно HIEW'ом просматривать.
На самом деле для нас важно знать состояние переменной handle, тогда можно и такой код использовать:
Код:
show:	push	ax
push bx
push cx
push dx
mov ax,hanlde
mov bx,10
xor cx,cx
s1: xor dx,dx
div bx
push dx
inc cx
or ax,ax
jnz s1
s2: inc cx
cmp cx,8
jnz s2
s3: pop ax
or al,30h
int 29h
loop s3
pop dx
pop cx
pop bx
pop ax
ret

а внужном месте ставить call show
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
17.07.2012, 22:42
общий
17.07.2012, 23:25
Адресаты:
Спасибо за пояснения... да стало понятно, что "handle and etc" это некий метод для больших программ где нужна проверка перед на предмет, а нужно ли вообще открывать(закрывать, читать), но в данной программе он и не целесообразен и еще и не будет работать.

1. У меня тоже самое, в момент чтения AFD говорит, что программа окончила работу.
Я не совсем понял, что значит кто мешает подойти ?
вот я на 112 жму F2 и всё Program terninated OK quit

Если вы о содержимом памяти по адресу переменной handle, то до чтения оно выглядит как
0500
после
FFFF

Разве имеет смысл смотреть в память если отладчик пишет, что программа завершена? если программа завершена, то там может быть всё что угодно или не так ?

Если имеет тогда получается, что да после чтения всё зануляется и в handle смысла нет.


2. в момент сравнения
cmp handle,0FFFFh

в отладчике видно, что там где handle
0125 833E3701FF CMP [0137],FFFF
смотрю ниже что там в 137 строке
а там
0137 FF DB FF
<---- ВОт это меня смутило... там же должно быть FFFFh
смутно понимаю, что в тексте dw, а тут db
непонятно куда делась вторая часть ... почему то отладчик AFD отнёс второй байт переменной к следующей команде.
Глюк отладчика ?

3. После команды mov [0137],ax
в памяти стало видно что в 137ой байт легло значение 05, а в 138 - 00
выглядит как 0500, хотя в ax лежало значение 0005
то есть в памяти всё наоборот что ли ?
Неизвестный
17.07.2012, 22:48
общий
Адресаты:
Книгу первой редакции прочёл частично.
Сейчас возобновил занятия, но вот вышла вторая и встал вопрос, а не новее ли там данные и нет ли ответов на мои вопросы...
Неизвестный
17.07.2012, 23:12
общий
17.07.2012, 23:14
Адресаты:
ПОпробую ваш код, только мне его изучить надо вначале...

вот тут вопрос возник:
saveFile:
mov ax,3Сh<====я так понимаю это равносильно mov al,3Ch ?? просто не могу найти такой функции у 21 прерывания в справочнике.
xor cx,cx
int 21h
давно
Старший Модератор
31795
6196
18.07.2012, 10:26
общий

Вот старый болван.

Там должно быть MOV AH,3Ch
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Старший Модератор
31795
6196
18.07.2012, 10:51
общий
Цитата: 394180
то есть в памяти всё наоборот что ли ?

Это интеловская организация памяти: младший байт по младшему адресу, т.е. читать значения слова или двойного слова нужно как арабам - справой стороны.

Цитата: 394180
Разве имеет смысл смотреть в память если отладчик пишет, что программа завершена? если программа завершена, то там может быть всё что угодно или не так ?

Имеет смысл всегда, т.к. там остаются следы действий программы.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Посетитель
7438
7205
18.07.2012, 13:26
общий
И еще об этом:
0137 FF DB FF
В программе handle размещено вперемежку с кодом.
И когда Вы смотрите в отладчике код, то отладчик пытается интерпретировать данные, как код.
А понять не может, вот и пишет db ff, т.е. имеем один байт,
Следующий находим в следующей строке
Т.о., имеем два байта 0ffffh
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Форма ответа