Welcome, guest. You can be a Login или register
« Previous 1 2 3 Next » | All
Author
Topic title
UAC
Offline
Бывший UAC и Sodomizer
833 posts
Karma 27
Недавно сдавал домашку по рекурсии (на ассемблере) и препод чего-то там возмутился насчёт моего стиля, а толком, как надо сделать объяснить не смог или не захотел... разговор весь начался с инструкции Ret 6 в главной процедуре...

Может подскажете, чего он завёлся? Хотя домашку он всё-таки принял.


_DATA segment
_Print db 100 dup (?)
_N db (?)
_DATA ends

_STK segment stack
dw 100 dup (?)
_STK ends

_CODE segment
assume cs:_CODE, ds:_DATA, ss:_STK
_main proc far
push ds
mov ax, 0
push ax
mov ax, _DATA
mov ds, ax

mov bx, offset _Print
push bx
mov di, 0
push di
mov ch, _N
mov cl, 1
push cx
call _PrintNumber
ret 6
_main endp

_PrintNumber proc near
mov bp, sp
mov bx, [bp+6]
mov di, [bp+4]
mov cx, [bp+2]

cmp cl, ch
jg @1 ; while (counter <= N) do

mov [bx+di], cl
inc di
inc cl
push bx
push di
push cx

call _PrintNumber

pop cx
pop di
pop bx

dec cl
cmp cl, 0 ; do (counter >= 1 ) while
jle @1
cmp cl, ch
je @2

mov [bx+di], cl
inc di

@2:
mov bp, sp
mov [bp+2], cx
mov [bp+4], di



@1: ret

_PrintNumber endp

_CODE ends
end _main
willow
Offline
Сражён шальной гранатой
570 posts
Karma 56
Ну, стиль это дело такое, личное.

Но насчёт
ret 6
препод прав, нехорошо это. Программа DOS так завершаться не должна, могут быть проблемы после передачи управления command.com. а может и не command.com, это ведь не единственная оболочка, кроме того могут быть перехватчики прерываний, которые отслеживают завершение программы - я сам отслеживал, когда писал файловый менеджер с графическим интерфейсом, например.

Много лишнего делаешь. Не говорю, что плохо, просто лишнее и всё.

типа связок
mov BX, xxx
push BX

это есть не что иное как
push word ptr xxx

P.S. ... Всё, не могу больше печатать, форма глючит и курсор по строчкам сам бегает :(
UAC
Offline
Бывший UAC и Sodomizer
833 posts
Karma 27
Условие было такое, использовать стэк для передачи параметров.
Следовательно, в _мэйн() пихаем, а возвращаем в рекурсии() ?

Беда, ведь рекурсия не меняется и первый прогон от последущих ничем не должен отличаться в плане передачи параметров...

То-есть, надо было вместо Ret 6 в _main() сделать 3 раза POP?

P.S.: >>>Всё, не могу больше печатать, форма глючит и курсор по строчкам сам бегает
Что пил? :o
willow
Offline
Сражён шальной гранатой
570 posts
Karma 56
То-есть, надо было вместо Ret 6 в _main() сделать 3 раза POP?

Нет, почему же, ret 6 это вполне правильная очистка стека.
Но вот выход в ДОС по ret - уже неправильно.
Используй
mov AH,4Ch ;команда DOS - завершение программы
mov AL,0 ;код возврата
int 21h ;Вызов DOS

Оптимизировать надо с умом, не жертвуй совместимостью!

Вот, что некрасиво, так это твои блоки типа
mov BX,0
push BX
когда на самом деле это всего лишь
push word ptr 0

или

dec cl
cmp cl, 0 ; do (counter >= 1 ) while
jle @1

Это есть не что иное как

dec cl ; do (counter >= 1 ) while
jle @1

или

mov BP,SP

Это совершенно лишнее, SP справился бы со своей работой ничуть не хуже BP

И ещё, мне страшно трассировать в уме твою программу, она делает жуткие вещи, пишет за пределами выделяемой памяти и мозг уходит в ребут! Ассемблерщик не просто читает твою программу, но и прогоняет её в уме! Так что прочитать процедуру печати я не смог, завис.
Когда работаешь со стеком, будь ласка, работай с переменными не так:

mov BX,[SP]

а так:

mov BX,SS:[SP]


Ты заставляешь выглядеть ассемблер сложнее чем он есть на самом деле
В реальности хорошую программу читать на ассемблере не сложнее чем сишную
Так шо незачёт, многа лишних буковиц!


Что пил? :o

Процитировал текст твоей программы и после этого текстовый курсор стал произвольно в начало предыдущих строк убегать. Что странно, я всё удалил а эффект сохранился. Там какие-то управляющие символы использовались а форумный редактор их, очевидно, не переваривает.

Мл1! Опять прыгает, скотинка! Наверное, это из-за восьмого IE, недавно установил.
UAC
Offline
Бывший UAC и Sodomizer
833 posts
Karma 27
willow
Это аццкий сотона форум съел! ;D
Спасибо за советы, не поверишь, но я всё запомню и со следущей же домашки активно начну использовать.
Действительно, много лишнего понаписанно... просто нам такие шаблоны на лекциях дают, а у нас мозгов не хватает пересилить.

Программа тупорылая в частности от того, что рекурсия здесь не очень уместна имхо, всё что она должна делать это - по получении числа N заполнить массив таким макаром:

1, 2,... N-1, N, N-1, ... 2, 1
типа полиндрома как функция от N
Берсеркер
Offline
Суровый челябинский программист
2281 posts
Karma 204
Маленькое дополнение:
первоначальный код в первом посту содержал чистые 8086 команды, именно на этот CPU ориентируется компилятор, если не задать опцию типа .386
Поэтому допустимы куски:
mov ax, нумбер
push ax

и
mov bp,sp
mov bx,[bp+6]

Это стандартный стиль программирования для 8086.
К тому же, при адресации с помощью BP не требуется оверрайд сегментного регистра, т.е.
mov bx,[bp+6]
и
mov bx,ss:[bp+6]
абсолютно равноправные куски кода (правда, второй длиннее первого на 1 лишний байт: префикс SS:)
Но в настоящее время даже на 386 процессор неразумно ориентироваться, потому следует указать опцию как минимум .386 или лучше .586 и пользоваться прямыми командами:
push word ptr нумбер
и
mov bx,[sp+6] ; правда тут не помню какой сегментный регистр юзается, припиши SS:
Без опций .386/.586 компилер не поймет вышеуказанный код.
Машина несла меня через неведомые районы Галактики сквозь пространство математической реальности быстрее скорости света. (C) Фред Саберхаген.
Берсеркер
Offline
Суровый челябинский программист
2281 posts
Karma 204
В реальности хорошую программу читать на ассемблере не сложнее чем сишную


На современных CPU можно пользовать любые регистры в любых целях (за исключением группы комплексных команд: умножение, деление, строковые команды (movs*, lods*, scas*, etc), устаревший loop и т.п.), но для улучшения понимания кода существует правило:

AX - для задания и получения результатов Арифметики
BX - для задания адреса памяти для обычного применения (не потоковый/строковой доступ)
CX - от слова Counter (Счётчик)
DX - регистр Данных, как правило является старшим дополнением регистра AX.

SI - Source, источник. Задаёт адрес памяти, откуда берутся данные.
DI - Destination, приёмник, задает память, куда пишут данные.
BP - Base Point, служит как базовый указатель в памяти, обычно для доступа к стеку.
SP - Stack Point. Не рекомендуется юзать его, хотя и не запрещено. Служебный регистр для организации стека. Вместо него рекомендуется использовать BP.

Сегментные регистры:
CS - Code Segment - сегмент где находится исполняемый код.
DS - Data Segment - сегмент данных. По умолчанию используется при адресации, а также в потоковых/строковых командах при чтении
ES - Extra Segment - дополнительный сегмент данных. Используется в потоковых/строковых командах при записи
SS - Stack Segment - сегмент стека. Используется при работе со стеком, а также при адресации с участием регистра BP.

Комплексные команды (loop, movsb, mul, idiv и т.п.) используют регистры в соответствии с вышеуказанными правилами.

Машина несла меня через неведомые районы Галактики сквозь пространство математической реальности быстрее скорости света. (C) Фред Саберхаген.
UAC
Offline
Бывший UAC и Sodomizer
833 posts
Karma 27
Берсеркер
Спасибо!

А что насчёт того что willow написал?
Надо после Ret 6 добавить Mov ax, 4c00h ; int 21h ?
Берсеркер
Offline
Суровый челябинский программист
2281 posts
Karma 204
А что насчёт того что willow написал?
Надо после Ret 6 добавить Mov ax, 4c00h ; int 21h ?

Именно так и надо завершать EXE программу.
Кста, встречал в bat/cmd-скриптах системную переменную errorlevel?
Если хочешь чтоб прога твоя сообщала при выходе некий код (в errorlevel), то в AL пиши этот код.
MOV AH, 4Ch
MOV AL, errorlevel code
INT 21h
Машина несла меня через неведомые районы Галактики сквозь пространство математической реальности быстрее скорости света. (C) Фред Саберхаген.
UAC
Offline
Бывший UAC и Sodomizer
833 posts
Karma 27
Берсеркер
Ух-ты, не знал. Переменную вроде встречал.
« Previous 1 2 3 Next » | All