Зацикленая программа

Низкоуровневое программирование портов, микроконтроллеров и т.д.

Модератор: Andy

ррррррроман
Сообщения: 10
Зарегистрирован: 18 апр 2009, 15:59

написал лабу на 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
    ;ïå÷àòü (ìèíóñà &#232 ;) öèôð
    pon2:
      mov ah, 2; ôóíêöèÿ 02 ïðåðûâàíèÿ 21h
      ;dec si
      mov dl, [bp - si]
      int 21h; âûâîä (çíàê&#224 ;) öèôðû íà ýêðàí
      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
Аватара пользователя
somewhere
Сообщения: 1858
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

1) Не хватает RET в конце процедуры
2) Программа не завершается и не выходит в ОС. см. Int 21h функ 4C
Удивительная процедура печати чисел из книги, которая использует метод прямого редактирования стека для хранения остатков от деления на 10 исходного числа. Но видать автор книги не учел или не знал, что недопустимо использовать [bp - si] так как такой интерпретации нет и компилятор оставит вариант [bp + si] и в этом контексте программа затирает адрес возврата и затем попадает в совсем другое место при выходе.
Если есть желание исправить то SI должен инициализироваться FFFF и расти вниз. Во втором цикле наоборот расти вверх. И если нет желания напишите свою или используйте более простую функцию и понятную - сразу видно поиск вы не юзали.
It's a long way to the top if you wanna rock'n'roll
airyashov
Сообщения: 441
Зарегистрирован: 02 ноя 2007, 10:31

неплохо было бы инициализировать сегмент данных и определить сегмент стека
;dec si нужно раскомментить иначе бесконечный цикл
Аватара пользователя
somewhere
Сообщения: 1858
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

Там много исправлять нужно, даже если раскоментить не будет работать
It's a long way to the top if you wanna rock'n'roll
airyashov
Сообщения: 441
Зарегистрирован: 02 ноя 2007, 10:31

согласен :-)
ррррррроман
Сообщения: 10
Зарегистрирован: 18 апр 2009, 15:59

спасибо вам большое за замечания, они очень мне помогли, особенно я прояснил для себя некоторые вещи. вот написал еще одну версию проги, а точнее функции.
Так вот, при использовании функции, прога просто вылетает(это я определил по прописанной в конце листинга операции ввода символа, что-то вроде просмотра результатов выполнения проги, пока символ не введешь, можно смотреть на результат. такое ощущение, что ассемблер просто не доходит до нее, фиксирует ошибку и вылетает), а если эту процедуру закоментить, все проходит нормально. Хотя компиляция проходит без ошибок. Компилирую 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; ìåíÿåì çíàê íà ïðîòèâîïîëîæíûé (â äàííîì êîíòåêñòå íå ðàáîòàå&#242 ;)
    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 
airyashov
Сообщения: 441
Зарегистрирован: 02 ноя 2007, 10:31

при делении на слово 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; íàëè÷èå öèôð â ÷èñëå
и код завершения программы не забудте
ррррррроман
Сообщения: 10
Зарегистрирован: 18 апр 2009, 15:59

спасибо, я исправил, прога перестала вылетать. Но она конечнай результат выдает неверный. Например я еще в начале программы пробовал выводить значение 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; ìåíÿåì çíàê íà ïðîòèâîïîëîæíûé (â äàííîì êîíòåêñòå íå ðàáîòàå&#242 ;)
    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 
Аватара пользователя
somewhere
Сообщения: 1858
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

В начале кода

Код: Выделить всё

  mov ax, date
  mov ds, ax
ten dw 10 вынести из начала процедуры за ret, т.к. ее расположение находится в исполняемом коде
It's a long way to the top if you wanna rock'n'roll
ррррррроман
Сообщения: 10
Зарегистрирован: 18 апр 2009, 15:59

Заработало!!!!
somewhere вам respect. Спасибо всем, что приняли участие в исправлении моих ошибок.
Но немного непонятными для меня остались две вещи.
1)
ten dw 10 вынести из начала процедуры за ret, т.к. ее расположение находится в исполняемом коде.
я вкоде процедуры явно указывал регистр данных (div cs:ten; ax:= (dx, ax) div 10, dx:= (dx, ax) mod 10)

2)
В начале кода

Код: Выделить всё

  mov ax, date
  mov ds, ax
почему указатель в регистр данных нужно заносить таким образом.
Ведь я делал это с помощью директивы assume в начале проги
(code segment
assume ss:s, ds:date, cs:code)
Ответить