UAC
833 постов
Карма: 27
#1 08 мая 2009 в 14:31
Недавно сдавал домашку по рекурсии (на ассемблере) и препод чего-то там возмутился насчёт моего стиля, а толком, как надо сделать объяснить не смог или не захотел... разговор весь начался с инструкции Ret 6 в главной процедуре... <br /><br />Может подскажете, чего он завёлся? Хотя домашку он всё-таки принял. <br /><br /><br />_DATA segment <br /> _Print db 100 dup (?)<br /> _N db (?)<br />_DATA ends<br /><br />_STK segment stack<br /> dw 100 dup (?)<br />_STK ends<br /><br />_CODE segment<br /> assume cs:_CODE, ds:_DATA, ss:_STK<br />_main proc far<br /> push ds<br /> mov ax, 0<br /> push ax<br /> mov ax, _DATA<br /> mov ds, ax<br /> <br /> mov bx, offset _Print<br /> push bx<br />&nbsp; mov di, 0<br /> push di<br /> mov ch, _N<br /> mov cl, 1<br /> push cx<br /> call _PrintNumber<br /> ret 6<br />_main endp<br /><br />_PrintNumber proc near<br /> mov bp, sp<br /> mov bx, [bp+6]<br /> mov di, [bp+4]<br /> mov cx, [bp+2]<br /><br /> cmp cl, ch<br /> jg @1 ; while (counter &lt;= N) do<br /> <br /> mov [bx+di], cl<br /> inc di<br /> inc cl<br /> push bx<br /> push di<br /> push cx<br /><br /> call _PrintNumber<br /><br /> pop cx<br /> pop di<br /> pop bx<br /><br /> dec cl <br /> cmp cl, 0 ; do (counter &gt;= 1 ) while<br /> jle @1<br /> cmp cl, ch<br /> je @2<br /><br /> mov [bx+di], cl<br /> inc di<br /><br />@2:<br /> mov bp, sp<br /> mov [bp+2], cx<br /> mov [bp+4], di<br /><br /><br /><br />@1: ret<br /><br />_PrintNumber endp<br /><br />_CODE ends<br />end _main<br />
willow
570 постов
Карма: 56
#2 08 мая 2009 в 16:05
Ну, стиль это дело такое, личное.<br /><br />Но насчёт<br /> ret 6<br />препод прав, нехорошо это. Программа DOS так завершаться не должна, могут быть проблемы после передачи управления command.com. а может и не command.com, это ведь не единственная оболочка, кроме того могут быть перехватчики прерываний, которые отслеживают завершение программы - я сам отслеживал, когда писал файловый менеджер с графическим интерфейсом, например.<br /><br />Много лишнего делаешь. Не говорю, что плохо, просто лишнее и всё.<br /><br />типа связок<br />mov&nbsp; BX, xxx<br />push BX<br /><br />это есть не что иное как<br />push word ptr xxx<br /><br />P.S. ... Всё, не могу больше печатать, форма глючит и курсор по строчкам сам бегает&nbsp; :(
UAC
833 постов
Карма: 27
#3 08 мая 2009 в 16:19
Условие было такое, использовать стэк для передачи параметров. <br />Следовательно, в _мэйн() пихаем, а возвращаем в рекурсии() ? <br /><br />Беда, ведь рекурсия не меняется и первый прогон от последущих ничем не должен отличаться в плане передачи параметров... <br /><br />То-есть, надо было вместо Ret 6 в _main() сделать 3 раза POP? <br /><br />P.S.: &gt;&gt;&gt;Всё, не могу больше печатать, форма глючит и курсор по строчкам сам бегает<br />Что пил?&nbsp; :o
willow
570 постов
Карма: 56
#4 08 мая 2009 в 19:25
То-есть, надо было вместо Ret 6 в _main() сделать 3 раза POP?
<br />Нет, почему же, ret 6 это вполне правильная очистка стека.<br />Но вот выход в ДОС по ret - уже неправильно.<br /> Используй<br />mov AH,4Ch ;команда DOS - завершение программы<br />mov AL,0 ;код возврата<br />int&nbsp; 21h ;Вызов DOS<br />Оптимизировать надо с умом, не жертвуй совместимостью!<br /><br />Вот, что некрасиво, так это твои блоки типа<br />mov BX,0<br />push BX<br />когда на самом деле это всего лишь<br />push word ptr 0<br /><br />или<br /><br />dec cl <br />cmp cl, 0 ; do (counter &gt;= 1 ) while<br />jle @1<br /><br />Это есть не что иное как<br /><br />dec cl ; do (counter &gt;= 1 ) while<br />jle @1<br /><br />или<br /><br />mov BP,SP<br /><br />Это совершенно лишнее, SP справился бы со своей работой ничуть не хуже BP<br /><br />И ещё, мне страшно трассировать в уме твою программу, она делает жуткие вещи, пишет за пределами выделяемой памяти и мозг уходит в ребут! Ассемблерщик не просто читает твою программу, но и прогоняет её в уме! Так что прочитать процедуру печати я не смог, завис.<br />Когда работаешь со стеком, будь ласка, работай с переменными не так:<br /><br />mov BX,[SP]<br /><br />а так:<br /><br />mov BX,SS:[SP]<br /><br /><br />Ты заставляешь выглядеть ассемблер сложнее чем он есть на самом деле<br />В реальности хорошую программу читать на ассемблере не сложнее чем сишную<br />Так шо незачёт, многа лишних буковиц!<br /><br /><br />
Что пил?&nbsp; :o
<br />Процитировал текст твоей программы и после этого текстовый курсор стал произвольно в начало предыдущих строк убегать. Что странно, я всё удалил а эффект сохранился. Там какие-то управляющие символы использовались а форумный редактор их, очевидно, не переваривает.<br /><br />Мл1! Опять прыгает, скотинка! Наверное, это из-за восьмого IE, недавно установил.<br />
UAC
833 постов
Карма: 27
#5 08 мая 2009 в 20:04
willow<br />Это аццкий сотона форум съел!&nbsp; ;D <br />Спасибо за советы, не поверишь, но я всё запомню и со следущей же домашки активно начну использовать. <br />Действительно, много лишнего понаписанно... просто нам такие шаблоны на лекциях дают, а у нас мозгов не хватает пересилить. <br /><br />Программа тупорылая в частности от того, что рекурсия здесь не очень уместна имхо, всё что она должна делать это - по получении числа N заполнить массив таким макаром: <br /><br />1, 2,... N-1, N, N-1, ... 2, 1<br />типа полиндрома как функция от N
Берсеркер
2326 постов
Карма: 217
#6 09 мая 2009 в 10:59
Маленькое дополнение:<br />первоначальный код в первом посту содержал чистые 8086 команды, именно на этот CPU ориентируется компилятор, если не задать опцию типа .386<br />Поэтому допустимы куски:<br />mov ax, нумбер<br />push ax<br />и<br />mov bp,sp<br />mov bx,[bp+6]<br />Это стандартный стиль программирования для 8086.<br />К тому же, при адресации с помощью BP не требуется оверрайд сегментного регистра, т.е.<br />mov bx,[bp+6]<br />и<br />mov bx,ss:[bp+6]<br />абсолютно равноправные куски кода (правда, второй длиннее первого на 1 лишний байт: префикс SS:)<br />Но в настоящее время даже на 386 процессор неразумно ориентироваться, потому следует указать опцию как минимум .386 или лучше .586 и пользоваться прямыми командами:<br />push word ptr нумбер<br />и<br />mov bx,[sp+6]&nbsp; ; правда тут не помню какой сегментный регистр юзается, припиши SS:<br />Без опций .386/.586 компилер не поймет вышеуказанный код.
Машина несла меня через неведомые районы Галактики сквозь пространство математической реальности быстрее скорости света. (C) Фред Саберхаген.
Берсеркер
2326 постов
Карма: 217
#7 09 мая 2009 в 11:19
В реальности хорошую программу читать на ассемблере не сложнее чем сишную
<br /><br />На современных CPU можно пользовать любые регистры в любых целях (за исключением группы комплексных команд: умножение, деление, строковые команды (movs*, lods*, scas*, etc), устаревший loop и т.п.), но для улучшения понимания кода существует правило:<br /><br />AX - для задания и получения результатов Арифметики<br />BX - для задания адреса памяти для обычного применения (не потоковый/строковой доступ)<br />CX - от слова Counter (Счётчик)<br />DX - регистр Данных, как правило является старшим дополнением регистра AX.<br /><br />SI - Source, источник. Задаёт адрес памяти, откуда берутся данные.<br />DI - Destination, приёмник, задает память, куда пишут данные.<br />BP - Base Point, служит как базовый указатель в памяти, обычно для доступа к стеку.<br />SP - Stack Point. Не рекомендуется юзать его, хотя и не запрещено. Служебный регистр для организации стека. Вместо него рекомендуется использовать BP.<br /><br />Сегментные регистры:<br />CS - Code Segment - сегмент где находится исполняемый код.<br />DS - Data Segment - сегмент данных. По умолчанию используется при адресации, а также в потоковых/строковых командах при чтении<br />ES - Extra Segment - дополнительный сегмент данных. Используется в потоковых/строковых командах при записи<br />SS - Stack Segment - сегмент стека. Используется при работе со стеком, а также при адресации с участием регистра BP.<br /><br />Комплексные команды (loop, movsb, mul, idiv и т.п.) используют регистры в соответствии с вышеуказанными правилами.<br /><br />
Машина несла меня через неведомые районы Галактики сквозь пространство математической реальности быстрее скорости света. (C) Фред Саберхаген.
UAC
833 постов
Карма: 27
#8 09 мая 2009 в 11:52
Берсеркер<br />Спасибо! <br /><br />А что насчёт того что willow написал? <br />Надо после Ret 6 добавить Mov ax, 4c00h ; int 21h ?
Берсеркер
2326 постов
Карма: 217
#9 09 мая 2009 в 12:01
А что насчёт того что willow написал? <br />Надо после Ret 6 добавить Mov ax, 4c00h ; int 21h ?
<br />Именно так и надо завершать EXE программу.<br />Кста, встречал в bat/cmd-скриптах системную переменную errorlevel?<br />Если хочешь чтоб прога твоя сообщала при выходе некий код (в errorlevel), то в AL пиши этот код.<br />MOV AH, 4Ch<br />MOV AL, errorlevel code<br />INT 21h
Машина несла меня через неведомые районы Галактики сквозь пространство математической реальности быстрее скорости света. (C) Фред Саберхаген.
UAC
833 постов
Карма: 27
#10 09 мая 2009 в 12:05
Берсеркер<br />Ух-ты, не знал. Переменную вроде встречал.