Страница 1 из 2
Зацикленая программа
Добавлено: 22 апр 2009, 01:16
ррррррроман
написал лабу на assembler. тема лабы - вывод чисел со знаком на экран, придумал процедуру(точнее переделал ее из книги под свои нужды)
при использовании ее, прога зацикливается, при этом ничего не выводится.
ошибка фатальная, очень долго ее искал, пока найти не удалось. если кто подскажет где она проявляется, буду очень благодарен
вот листинг(прога написана в кодировке досовской кодировке, поэтому здесь проблемы с коментариями)
Код: Выделить всё
s segment stack; ñåãìåíò ñòåêà
db 256 dup(?)
s ends
date segment; ñåãìåíò äàííûõ
a dw 23
b dw -30
c dw 42
d dw 21
date ends
code segment
assume ss:s, ds:date, cs:code
print proc near; ïðîöåäóðà âûâîäà ÷èñëà íà ýêðàí âûâîäèò ñîäåðæèìîå ðåãèñòðà ax
push bp
mov bp, sp
push ax
push dx
push cx
push si
sub sp, 6; îòâîäèì 6 áàéòîâ â ñòåêå ïîä ÷èñëî
mov dh, 1; ïî óìîë÷àíèþ ÷èñëî >= 0
mov cx, 10; îñíîâàíèå ñèñòåìû ñ÷èñëåíèÿ
cmp ax, 0;
jge pon0; åñëè ÷èñëî >= 0
mov dh, 2; åñëè ax < 0
neg ax; òî dh:= 2, ax:= abs(ax)
pon0:
push dx; ñïàñàåì çíàê
;çàïèñü öèôð ÷èñëà â ñòåê â îáðàòíîì ïîðÿäêå
xor si, si; îáíóëåíèå ñ÷åò÷èêà êîëè÷åñòâà ÷èñåë â ÷èñëå
pon1:
mov dx, 0; ax:= (dx, ax)
idiv cs:ten; ax:= (bx, ax) div 10, bx:= (bx, ax) mod 10
add dl, '0'; ïåðåâîäèì ÷èñëî â ñèìâîë
mov [bp - si], dl; ðàçìåùåíèå öèôðû â ñòåêå
inc si;
or ax, ax;
jnz pon1; åùå íå 0, ò.å. åùå íå çàêîí÷èëèñü öèôðû â ÷èñëå
;çàïèñü ìèíóñà åñëè åñòüâ ñòåê
pop dx;
cmp dh, 2
jne pon2; åñëè íåò çíàêà
mov byte ptr [bp - si], '-'; åñëè çíàê åñòü
inc si
;ïå÷àòü (ìèíóñà è ;) öèôð
pon2:
mov ah, 2; ôóíêöèÿ 02 ïðåðûâàíèÿ 21h
;dec si
mov dl, [bp - si]
int 21h; âûâîä (çíàêà ;) öèôðû íà ýêðàí
or si, si; ïðîâåðêà íà íàëè÷èå â ñòåêå öèôð
jnz pon2; åñëè åñòü, òî ïîâòîðíûé âûâîä
;âûõîä èç ïðîöåäóðû
add sp, 6
pop si
pop cx
pop dx
pop ax
pop bp
ten dw 10
print endp
begin:
mov ax, 4; ax:=4 êàê ñëîâî
imul d; (dx, ax)= 4*d= 84 dx:= 0FFFFh ax:= 0FF54h
mov d, ax; ñîõðàíåíèå 4*d
mov ax, c; ax:= c êàê ñëîâî
mov dx, 0; dx:= 0000h
idiv b; ax:= (dx, ax) div d; dx:= (dx, ax) mod d
sub d, ax; d:= 4d - (c div b) êàê ñëîâî
mov ax, a
imul ax; (dx, ax):= ax*ax
add ax, d; ax:= a*a - (c div b) + 4*d
call print
code ends
end begin
Re: Зацикленая программа
Добавлено: 22 апр 2009, 09:54
somewhere
1) Не хватает RET в конце процедуры
2) Программа не завершается и не выходит в ОС. см. Int 21h функ 4C
Удивительная процедура печати чисел из книги, которая использует метод прямого редактирования стека для хранения остатков от деления на 10 исходного числа. Но видать автор книги не учел или не знал, что недопустимо использовать [bp - si] так как такой интерпретации нет и компилятор оставит вариант [bp + si] и в этом контексте программа затирает адрес возврата и затем попадает в совсем другое место при выходе.
Если есть желание исправить то SI должен инициализироваться FFFF и расти вниз. Во втором цикле наоборот расти вверх. И если нет желания напишите свою или используйте более простую функцию и понятную - сразу видно поиск вы не юзали.
Re: Зацикленая программа
Добавлено: 22 апр 2009, 11:58
airyashov
неплохо было бы инициализировать сегмент данных и определить сегмент стека
;dec si нужно раскомментить иначе бесконечный цикл
Re: Зацикленая программа
Добавлено: 22 апр 2009, 12:03
somewhere
Там много исправлять нужно, даже если раскоментить не будет работать
Re: Зацикленая программа
Добавлено: 22 апр 2009, 12:58
airyashov
согласен :-)
Re: Зацикленая программа
Добавлено: 22 апр 2009, 21:16
ррррррроман
спасибо вам большое за замечания, они очень мне помогли, особенно я прояснил для себя некоторые вещи. вот написал еще одну версию проги, а точнее функции.
Так вот, при использовании функции, прога просто вылетает(это я определил по прописанной в конце листинга операции ввода символа, что-то вроде просмотра результатов выполнения проги, пока символ не введешь, можно смотреть на результат. такое ощущение, что ассемблер просто не доходит до нее, фиксирует ошибку и вылетает), а если эту процедуру закоментить, все проходит нормально. Хотя компиляция проходит без ошибок. Компилирую TASM 16bit. Если вам нетрудно, то посмотрите, в чем я на этот раз накосячил
Код: Выделить всё
s segment stack; ñåãìåíò ñòåêà
db 256 dup(?)
s ends
date segment; ñåãìåíò äàííûõ
a dw 23
b dw -30
c dw 42
d dw 21
buf db 10,?,10 dup(' '); áóôåð ââîäà
date ends
code segment
assume ss:s, ds:date, cs:code
print proc near; ïðîöåäóðà âûâîäà ÷èñëà íà ýêðàí âûâîäèò ñîäåðæèìîå ðåãèñòðà ax
ten dw 10; îñíîâàíèå ñèñòåìû ñ÷èñëåíèÿ
push ax
push cx
push dx
xor cx, cx; îáíóëåíèå ñ÷åò÷èêà êîëè÷åñòâà öèôð â ÷èñëå
cmp ax, 0;
jge pon0; åñëè ÷èñëî >= 0
push ax; åñëè ax < 0, çàïèñü â ñòåê
mov ah, 2; ôóíêöèÿ 02 ïðåðûâàíèÿ 21h
mov dl, '-'
int 21h; âûâîä ìèíóñà íà ýêðàí
pop ax; èçâëå÷åíèå èç ñòåêà
;neg ax; ìåíÿåì çíàê íà ïðîòèâîïîëîæíûé (â äàííîì êîíòåêñòå íå ðàáîòàåò ;)
mov cx, -1; âû÷èñëåíèå ìîäóëÿ ax
xor dx, dx; ax:= (dx, ax)
imul cx
xor cx, cx; îáíóëåíèå ñ÷åò÷èêà êîëè÷åñòâà öèôð â ÷èñëå
pon0:
div cs:ten; ax:= (dx, ax) div 10, dx:= (dx, ax) mod 10
push dx; {çàïèñü â ñòåê}
inc cx
or ax, ax
jnz pon0; íàëè÷èå öèôð â ÷èñëå
mov ah, 2; {ôóíêöèÿ âûâîäà ñèìâîëà ïðåðûâàíèÿ 21h}
pon1:
pop dx; {èçâëå÷åíèå ÷èñëà èç ñòåêà}
add dl, '0'; {ïåðåâîä öèôðû ÷èñëà â ñèìâîë}
int 21h; {âûâîä öèôðû íà ýêðàí}
loop pon1
mov dl, ' '
int 21h; {âûâîä ïðîáåëà ïîñëå ÷èñëà}
;âûõîä èç ïðîöåäóðû
pop dx
pop cx
pop ax
ret; ïåðåäà÷à óïðàâëåíèÿ
print endp
begin:
mov ax, 4; ax:=4 êàê ñëîâî
xor dx, dx; ax:= (dx, ax)
imul d; (dx, ax)= 4*d= 84 dx:= 0FFFFh ax:= 0FF54h
mov d, ax; ñîõðàíåíèå 4*d
mov ax, c; ax:= c êàê ñëîâî
mov dx, 0; dx:= 0000h
idiv b; ax:= (dx, ax) div d; dx:= (dx, ax) mod d
sub d, ax; d:= 4d - (c div b) êàê ñëîâî
mov ax, a
xor dx, dx
imul ax; (dx, ax):= ax*ax
add ax, d; ax:= a*a - (c div b) + 4*d
;mov ax, -23892
call print
lea dx, buf; âû÷èñëåíèå àäðåñà áóôåðà ââîäà
mov ah, 0ah
int 21h
code ends
end begin
Re: Зацикленая программа
Добавлено: 22 апр 2009, 23:04
airyashov
при делении на слово dx:ax/10
dx-нужно чистить от отстатка
Код: Выделить всё
pon0:
[B] xor dx,dx[/B]
div cs:ten; ax:= (dx, ax) div 10, dx:= (dx, ax) mod 10
push dx; {çàïèñü â ñòåê}
inc cx
or ax, ax
jnz pon0; íàëè÷èå öèôð â ÷èñëå
и код завершения программы не забудте
Re: Зацикленая программа
Добавлено: 23 апр 2009, 01:32
ррррррроман
спасибо, я исправил, прога перестала вылетать. Но она конечнай результат выдает неверный. Например я еще в начале программы пробовал выводить значение d(оно в сегменте данных инициализировалось как dw 21), то там значение отнюдь не 21 а другое, может такое быть, что сегмент команд сместился из-за большого количества команд в нем(ведь размер сегмента не должен превышать 128)?
То в этом случае мне придется описывать процедуру в отдельном сегменте, а затем например assume es:<сегмент где описана процедура>. Пока описать процедуру в отдельном сегменте не удалось. Буду дальше читать литературу. Еще сделал в конце проги возвращение результата выполнения программы
Код: Выделить всё
mov al, 0; 0-удачное завершение
mov ah, 4ch
int 21h
так с этим возвратом процессор обнаруживает ошибку
http://s59.radikal.ru/i165/0904/00/db02ad029a5f.jpg
вот крупнее
http://s59.radikal.ru/i163/0904/53/46d5b77951ff.jpg
Код: Выделить всё
s segment stack; ñåãìåíò ñòåêà
db 256 dup(?)
s ends
date segment; ñåãìåíò äàííûõ
a dw 23
b dw -30
c dw 42
d dw 21
buf db 10,?,10 dup(' '); áóôåð ââîäà
date ends
code segment
assume ss:s, ds:date, cs:code
print proc near; ïðîöåäóðà âûâîäà ÷èñëà íà ýêðàí âûâîäèò ñîäåðæèìîå ðåãèñòðà ax
ten dw 10; îñíîâàíèå ñèñòåìû ñ÷èñëåíèÿ
push ax
push cx
push dx
xor cx, cx; îáíóëåíèå ñ÷åò÷èêà êîëè÷åñòâà öèôð â ÷èñëå
cmp ax, 0;
jge pon0; åñëè ÷èñëî >= 0
push ax; åñëè ax < 0, çàïèñü â ñòåê
mov ah, 2; ôóíêöèÿ 02 ïðåðûâàíèÿ 21h
mov dl, '-'
int 21h; âûâîä ìèíóñà íà ýêðàí
pop ax; èçâëå÷åíèå èç ñòåêà
;neg ax; ìåíÿåì çíàê íà ïðîòèâîïîëîæíûé (â äàííîì êîíòåêñòå íå ðàáîòàåò ;)
mov cx, -1; âû÷èñëåíèå ìîäóëÿ ax
xor dx, dx; ax:= (dx, ax)
imul cx
xor cx, cx; îáíóëåíèå ñ÷åò÷èêà êîëè÷åñòâà öèôð â ÷èñëå
pon0:
xor dx, dx
div cs:ten; ax:= (dx, ax) div 10, dx:= (dx, ax) mod 10
push dx; {çàïèñü â ñòåê}
inc cx
or ax, ax
jnz pon0; íàëè÷èå öèôð â ÷èñëå
mov ah, 2; {ôóíêöèÿ âûâîäà ñèìâîëà ïðåðûâàíèÿ 21h}
pon1:
pop dx; {èçâëå÷åíèå ÷èñëà èç ñòåêà}
add dl, '0'; {ïåðåâîä öèôðû ÷èñëà â ñèìâîë}
int 21h; {âûâîä öèôðû íà ýêðàí}
loop pon1
mov dl, ' '
int 21h; {âûâîä ïðîáåëà ïîñëå ÷èñëà}
;âûõîä èç ïðîöåäóðû
pop dx
pop cx
pop ax
ret; ïåðåäà÷à óïðàâëåíèÿ
print endp
begin:
mov ax, 4; ax:=4 êàê ñëîâî
xor dx, dx; ax:= (dx, ax)
imul d; (dx, ax)= 4*d= 84 dx:= 0FFFFh ax:= 0FF54h
;mov d, ax; ñîõðàíåíèå 4*d
;mov ax, c; ax:= c êàê ñëîâî
;mov dx, 0; dx:= 0000h
;idiv b; ax:= (dx, ax) div d; dx:= (dx, ax) mod d
;sub d, ax; d:= 4d - (c div b) êàê ñëîâî
;mov ax, a
;xor dx, dx
;imul ax; (dx, ax):= ax*ax
;add ax, d; ax:= a*a - (c div b) + 4*d
;mov ax, -23892
mov ax, d
call print
lea dx, buf; âû÷èñëåíèå àäðåñà áóôåðà ââîäà
mov ah, 0ah
int 21h
mov al, 0; 0-óäà÷íîå çàâåðøåíèå
mov ah, 4ch
int 21h
code ends
end begin
Re: Зацикленая программа
Добавлено: 23 апр 2009, 10:03
somewhere
В начале кода
ten dw 10 вынести из начала процедуры за ret, т.к. ее расположение находится в исполняемом коде
Re: Зацикленая программа
Добавлено: 23 апр 2009, 10:49
ррррррроман
Заработало!!!!
somewhere вам respect. Спасибо всем, что приняли участие в исправлении моих ошибок.
Но немного непонятными для меня остались две вещи.
1)
ten dw 10 вынести из начала процедуры за ret, т.к. ее расположение находится в исполняемом коде.
я вкоде процедуры явно указывал регистр данных (div cs:ten; ax:= (dx, ax) div 10, dx:= (dx, ax) mod 10)
2)
почему указатель в регистр данных нужно заносить таким образом.
Ведь я делал это с помощью директивы assume в начале проги
(code segment
assume ss:s, ds:date, cs:code)