Консультация № 192051
09.12.2017, 09:30
0.00 руб.
1 1 1
Здравствуйте, уважаемые эксперты! Прошу вас ответить на следующие вопросы:

Даю сначала код программы, а вопросы (под номерами) по ходу листинга, под комментариями. Прилагаю файл, с тем же кодом и вопросами, - выглядит более наглядно!

;1. вопрос. Как оформляется код в ассемблере, вот по этим параметрам: голова, тело и хвост (конец) программы, если можно на примере prog09.asm.? Нижний листинг.
(01) CSEG segment
(02) assume CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
(03) org 100h

(04) Begin:
; Открываем файл с помощью спецпроцедуры (см. ниже).
(05) mov dx, offset File_name
(06) call Open_file ; Открываем файл с именем Prog09.com
(07) jc Error_file ; Переход на метку Error_file при неудаче.
(08) mov bx, ax ; Сохраняем идентификатор файла.

; Чтение файла
(09) mov ah, 3Fh
; Загружаем длину нашей программы (количество читаемых байт) в регистр cx …
(10) mov cx, offset Finish-100h
(11) mov dx, offset Begin ; И читаем файл в память, начиная с метки Begin.
(12) int 21h ; читаем файл, начиная с метки Begin
(13) call Close_file ; Закрываем файл с помощью спецпроцедуры

; Выводим сообщение об удачном завершении
(14) mov ah, 9
(15) mov dx, offset Mess_ok
(16) int 21h
(17) ret
; Если файл с указанным именем не нашли (File_name db ‘Prog09.com’,0), то выдаем звуковой сигнал и выходим.
(18) Error_file:
(19) mov ah, 2
(20) mov dl, 7

(21) int 21h
(22) ret

; Процедуры
; Процедура открытия файла для чтения
; 2. вопрос. Дана процедура (любая), возьмем эту для примера. Выполняются ли все команды процедуры, перед возвратом из процедуры, следующие после оператора "ret", но стоящие перед закрытием процедуры, т.е. перед оператором "endp". По данной процедуре, будут ли выполнены, противоречащие друг другу команды "stc, ret" и "Handle dw 0FFFFh".
; 3. вопрос. Почему объявление переменной Handle – в коде программы, как объявляются переменные (или данные) в начале программы или в конце? Опять же про оформление (какой есть стандартный порядок) – голова, тело, хвост?
; 4. вопрос. Как применяется оператор "ret"? В Интернете, только и говорится – "в паре с командой call". Почему здесь оператор "ret" встречается в "свободном парении" (получается – куда захочу, туда и поставлю)? Есть ли еще, какие-то другие способы применения (может быть в паре с другими командами) оператора "ret"?
(23) Open_file proc
(24) cmp Handle, 0FFFFh ; Выясняем, отрыт ли файл
(25) jne Quit_open ; И если не открыт – открываем его;
(26) mov ax, 3D00h
(27) int 21h
28) mov Handle, ax
(29) ret
(30) Quit_open:
(31) stc ; Устанавливаем флаг переноса в 1, необходимый
; для подтверждения факта открытия файла (для jc).
; 5. вопрос. Может быть правильнее было бы сказать: "для подтверждения "не открытия" файла (для jc)"? Флаг переноса (CF), устанавливается в 1, в случае ошибки, правильно?
(32) ret


(33) Handle dw 0FFFFh
(34) Open_file endp
; Процедура закрытия файла
(35) Close_file proc

(36) mov ah, 3Eh
(37) mov bx, Handle
(38) int 21h
(39) ret
(40) Close_file endp

(41) File_name db ‘prog09.com’,0
; 0Ah, 0Dh – переход в начало следующей строки.
(42) Mess_ok db ‘Все нормально!’, 0Ah, 0Dh,’$’
(43) Finish equ $ ; Признак (адрес) конца кода программы.

(44) CSEG ends
(45) end Begin
Прикрепленные файлы:
95acad7f3d1ce96ac33a4c07f46e6a3848735a97.doc

Обсуждение

давно
Посетитель
7438
7205
11.12.2017, 17:33
общий
это ответ
Здравствуйте, kerenskyaf!
Как оформляется код в ассемблере, вот по этим параметрам: голова, тело и хвост (конец) программы, если можно на примере prog09.asm.?

Деление достаточно условное. Можно считать, что
[code lang=asm] CSEG segment
assume CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
org 100h
[/code]это голова. Сюда, при другом способе записи, еще пишут тип процессора, модель памяти.[code lang=asm]CSEG ends
end Begin
[/code]Это, понятное дело, хвост. Закрывается сегмент, код с указанием точки старта.
Все остальное - тело.
Дана процедура (любая). Выполняются ли все команды процедуры, перед возвратом из процедуры, следующие после оператора "ret", но стоящие перед закрытием процедуры, т.е. перед оператором "endp". По данной процедуре, будут ли выполнены, противоречащие друг другу команды "stc, ret" и "Handle dw 0FFFFh".
Тут надо уяснить следующее: в ассемблерном тексте есть команды, которые превращаются в реальные команды в коде, а есть операторы, которые являются просто подсказкой для компилятора. Оператор endp является указанием компилятору, что программист закончил на этом месте подпрограмму. Для компилятора важно, чтобы proc и endp были парными, не более того. Реально, из подпрограммы можно легко сделать переход дальше endp. В принципе, можно вообще не использовать proc/endp.
Реально будет работать только код, полученный из команд первого типа. А как они будут оформлены - дело десятое. Оформление важно для человека, который будет читать этот код. Исключительно человеку важно видеть, где начало, а где конец подпрограммы...
Теперь по поводу того, какие команды будут отработаны... В каждый момент времени выполняется команда по текущему адресу. Этот адрес может меняться как последовательно от команды к команде, так и резким переходом на другую команды при помощи соответствующих команд. К последним относятся вызов подпрограмм и выход из них. Что происходим при вызове подпрограммы с помощью команды call? В стек заносится адрес следующей команды, в регистр текущего адреса заносится указанный адрес и происходит переход. Команда ret извлекает из вершины стека адрес и передает туда управление. Я говорю сейчас для случая короткого вызова, т.е. вызова в пределах одного сегмента кода. Т.о., после отработки команды ret управление вернется на следующий адрес после вызова подпрограммы. Поэтому переменная handle за командой ret никоим образом не будет использована, как код. Если только не будет туда явный переход!
Почему объявление переменной Handle – в коде программы, как объявляются переменные (или данные) в начале программы или в конце? Опять же про оформление (какой есть стандартный порядок) – голова, тело, хвост?
Данная программа написана под ДОС, для модели памяти TINY (и код, и данные, и стек - в одном сегменте)
Поэтому абсолютно неважно, где записать данные. Разумеется, можно оформить отдельным сегментом данных. В других моделях памяти обычно так и делают, но можно писать и в сегменте кода. Это можно делать потому, что под ДОС-ом можно читать/писать откуда/куда угодно, из любого сегмента.
Вот если будете писать под систему Windows/Linux, вот там уже такие фокусы просто так не пройдут. Там, если сегмент кода, то ОС не даст туда писать данные! А команду из сегмента данных нельзя будет выполнить! Можно, но необходимо будет принимать дополнительные меры... :)
Теперь о порядке сегментов. Да пишите, как угодно, хоть в начале код, потом - данные, стек. Хоть в любом другом порядке. Это абсолютно не важно! Как кому нравится! Главное, чтобы данные не интерпретировались, как код. И то (под ДОС-ом!) можно сформировать последовательность команд, как байты данных и их отработать! :)
Как применяется оператор "ret"? В Интернете, только и говорится – "в паре с командой call". Почему здесь оператор "ret" встречается в "свободном парении" (получается – куда захочу, туда и поставлю)? Есть ли еще, какие-то другие способы применения (может быть в паре с другими командами) оператора "ret"
Во-первых, как я уже объяснил, команда ret передает управление по адресу, который находится в вершине стека. Во-вторых, при старте программы выделяется сегмент в памяти, в начало которого записывается 100h некоторой информации (называется программный префикс PSP), первыми байтами записана команда int 20h. Далее, файл программы загружается, начиная с адреса 100h, а в стек заносится величина 0. И вот эта команда ret извлекает из стека этот нуль и передает туда управление, а там, что? int 20h. Тем самым происходит выход из программы! Ничего просто так и само не делается! Если выполнить просто так ret, то можно легко "улететь" неизвестно куда!
В-третьих, да, чаще всего ret используется в паре с call. Одно заносит в стек адрес возврата, второе извлекает его оттуда. Но занести в стек некий адрес можно разными способами! Например:[code lang=asm]
lea ax, next
push ax
ret
;
next:
[/code]После команды ret мы попадем на адрес next :)
Кстати, возможны и такие конструкции:[code lang=asm]
call prg
dw 0
prg: pop bx
mov word ptr[bx], 1234h
;...
[/code]Или такие:[code lang=asm]
call prg
;...
prg: pop ax
;...
jmp ax
[/code]Или такие:[code lang=asm]
table dw prg1,prg2,prg3,prg4
;...
mov bx, 2
call prg
;...
prg: jmp [bx+table]
;...
prg1: ret
prg2: ret
prg3: ret
prg4: ret
[/code]Что, по-Вашему, произойдет?
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Форма ответа