· Начало · Отвђтить · Статистика · Поиск · FAQ · Правила · Установки · Язык · Выход · WASM.RU · Noir.Ru ·

 WASM Phorum —› WASM.HELHEIM —› Проблема с ret в модульной программе

Посл.отвђт Сообщенiе


Дата: Май 25, 2004 02:31:59

Доброго времени суток!

Я начинающий в программировании на ассемблере. У меня такая задача: нужно прабочую программу на ассемблере разбить на несколько частей: поместить их в разные asm файлы. Используется компилятор masm 6.11 и tasm в составе [Turbo Assembler 3.0 Turbo Link 4.0]

Основная программа lab.asm выглядит так:
.model small
.stack 100h

.code

extrn InputData:proc
extrn Solution:proc

 main proc far
  push ds
  xor ax,ax
  push ax
;  begin of main program
  call InputData
  call Solution
;  end of main program
  ret
 main endp

end main


а "вспомогательный" модуль modul1.asm так:
.model small
.data
  n=7

  xc dw 10,8,12,15,12,7,5         ; X coordinate of circle
  yc dw 7,9,11,7,3,3,6         ; Y coordinate of circle
  rc dw 3,3,3,3,3,3,3         ; radius of circle

  x dw ?
  y dw ?

  k=3
  field dw 1000100b,1110000b,100001b        ; the lowest bit -> the last circle

 ;messages
  msg1 db "Введите, пожалуйста, координату x $"
  msg2 db "Введите, пожалуйста, координату y $"
  err_msg db "Вы, видимо, ошиблись в вводе. Повторите пожалуйста.",0Dh,0Ah,"$"
  posmsg db "Данная точка входит в закрашенную область",0Dh,0Ah,"$"
  negmsg db "Данная точка не входит в закрашенную область",0Dh,0Ah,"$"
  clrf db 0Dh,0Ah,"$"

  buffer db 10, 10 dup (?)

 ;
   tvar dw ?

.code

public InputData
public Solution

 OutputPositiveResult proc far
  mov ax,@data
  mov ds,ax
  mov dx,offset posmsg
  mov ah,9
  int 21h

  ret
 OutputPositiveResult endp

 OutputNegativeResult proc far
  mov ax,@data
  mov ds,ax
  mov dx,offset negmsg
  mov ah,9
  int 21h

  ret
 OutputNegativeResult endp
 
 str2num proc far
  mov ax,@data
  mov ds,ax

  mov cl,buffer[1]  ; load to cx count of incoming symbols
  xor ch,ch
  mov di,2
  xor ax,ax
  xor bx,bx
  mov tvar,10  ; use tvar as temp variable
  slp_1:
   mov bl,buffer[di]
   sub bl,'0'
   jb s2n_err
   cmp bl,9
   ja s2n_err

   imul tvar
   add ax,bx

   inc di
  loop slp_1
  jmp es2n
  s2n_err:
  mov ax,-1
  es2n:
  ret
 str2num endp

 InputData proc far

  mov ax,@data
  mov ds,ax

  sidp:  ;start input data procedure

  mov dx,offset msg1
  mov ah,9
  int 21h

  mov dx,offset buffer
  mov ah,0Ah
  int 21h

  mov dx,offset clrf
  mov ah,9
  int 21h

  call str2num
  cmp ax,0
  jl symb_err
  mov x,ax

  mov dx,offset msg2
  mov ah,9
  int 21h

  mov dx,offset buffer
  mov ah,0Ah
  int 21h

  mov dx,offset clrf
  mov ah,9
  int 21h

  call str2num
  cmp ax,0
  jl symb_err
  mov y,ax

  ret              ; ВОТ ТУТ ОШИБКА :(
  symb_err:
  mov ah,9
  mov dx,offset err_msg
  int 21h
  jmp sidp
 InputData endp

 Solution proc far

  mov ax,@data
  mov ds,ax

  xor di,di
  xor bx,bx
  mov cx,n
  lp_1:
    ; distance from point to center of circle
   mov ax,xc[di]
   sub ax,x
   imul ax
   mov tvar,ax
   mov ax,yc[di]
   sub ax,y
   imul ax
   add ax,tvar

   mov tvar,ax
   mov ax,rc[di]
   imul ax

   shl bx,1
   cmp tvar,ax    ; r^2(ax) <= x^2+y^2(tvar)
   jg sk_1

   or bx,1 

   sk_1:
   inc di
   inc di
  loop lp_1

  xor di,di
  xor ax,ax
  mov cx,k
  lp_2:
   cmp field[di],bx
   jne sk_2

   call OutputPositiveResult
   mov ax,1
   mov cx,1

   sk_2:
   inc di
   inc di
  loop lp_2

  cmp ax,1
  je sk_3

  call OutputNegativeResult

  sk_3:
  
  ret
 Solution endp

end


При этом для компиляции использую:

для tasm:
@echo off
rem for TASM

E:\languages\asm\tasm /zi /l modul1.asm
E:\languages\asm\tasm /zi /l lab.asm

E:\languages\asm\tlink /v LAB.OBJ MODUL1.OBJ


для masm:
@echo off
rem for MASM
E:\languages\MASM611\BIN\ml.exe /Zm /Fm /Fl modul1.asm
E:\languages\MASM611\BIN\ml.exe /Zm /Fm /Fl lab.asm

E:\languages\MASM611\BINR\link.exe /co /f lab.obj modul1.obj


Ошибка вылезает при попытки выполнить команду ret находясь в процедуре InputData в файле modul1.asm, то есть при попытке выйти из процедуры одного файла (?сегмента?) в другой. Ведь "внутренний"(в одном файле(?сегменте?)) ret, в процедуре str2num, нормально выполняется.

Кинте пожалуйста линк, где об этом можно более-менее доступно почитать или, если не сложно, объясните где глюк.

Заранее спасибо.

P.S. Извиняюсь, что сообщение получилось такое длинное - я просто не знаю чем можно в данном случае пожертвовать для сокращения :(


Дата: Май 25, 2004 03:06:15 · Поправил: Anonimka

Гым. А что за ошибка-то? И, пагдон, откуда уверенность, что ошибка именно там? А то вон у тебя в lab.asm стек не сбалансирован перед завершением main... Да и выходить из программы с моделью памяти small командой ret, а не ah=4Ch/int 21h, по-моему нэкоррэктно..

--Update--
Прошу прощения, товарищ, что не разобравшись, я имел налгость дать пару неверных советов. В общем, все в порядке, стек сбалансирован, и программа корректно завершается, только палками нужно бамбуковыми бить того, кто такие задания дает, потому что модель памяти small - полная архаика.
Теперь по делу: я переделал lab.asm так:
.model small
.stack 100h

.code

extrn InputData:proc
extrn Solution:proc

 main proc far
  push ds
  xor ax,ax
  push ax
;  begin of main program
	push cs
  call InputData
	push cs
  call Solution
;  end of main program
  ret
 main endp

end main

и у меня все получилось.


Дата: Май 25, 2004 03:20:35

Ошибка: Процессор NTVDM обнаружил недопустимую инструкцию.
CS:0000 IP:0077 OP:f0 37 05 12 02

Уверенность от того, что Debugger'ом прошелся... Turbo, который....

А насчет несбалансированости стека - это подготовка к заключительному ret (так, по крайней мере надо для tasm'а, когда не использую .code .data и т.п. а прописую ручками cseg segment assume ds:dseg,cs:cseg .... cseg ends)

Насчет ah=4Ch/int 21h - это ведь для завершения программы... туда ОНО вообще не доходит :( если я так сделаю при выходе из процедуры - я вообще вывалюсь из программы... кстати: а почему это не коректно?


Дата: Май 25, 2004 03:26:50

tasman
Читай апдейт к предыдущему посту :-)


Дата: Май 25, 2004 03:34:37

Спасибо большое!

Я даже понял в чем проблема - компилятор не сгенерировал код для загона регистра cs в стек - для возврата из процедуры (вызов то дальний). Поправь если я не прав. Но - автоматически возникают вопросы:
1. Почему компилятор (тем более их 2) этого не сделали (может версия - все они достаточно старые). Или они и не должны были это делать? Может это МОЯ работа? Или виновата модель памяти?(понял из постаAnonimka)
2. Как сделать так что-бы писать нормально и все работало ;) (вопрос риторический)
3. И, наконец, самое главное: где об этом всем можно почитать: так как я понимаю - отвечать на это все не есть хорошо...


Дата: Май 25, 2004 03:52:54

tasman
Я даже понял в чем проблема - компилятор не сгенерировал код для загона регистра cs в стек - для возврата из процедуры (вызов то дальний). Поправь если я не прав.
Ну, я того же мнения, а история нас поправит, если что =).

1. Почему компилятор (тем более их 2) этого не сделали (может версия - все они достаточно старые). Или они и не должны были это делать? Может это МОЯ работа? Или виновата модель памяти?(
Да черт их знает.. Может быть, дело в том, что компилятор "не видит", какой вызов требуют процедуры другого модуля - far или near, и по умолчанию вставляют код для near-вызова..

2. Как сделать так что-бы писать нормально и все работало ;)
Риторическим вопросом на риторический вопрос - что мешает писать 32-битный код (для win32 или dos-extender'а)?

3. где об этом всем можно почитать
Наверное, лучше об этом не читать.. Небогоугодное это дело (да и неблагодарное) - изучать модель, исключительной целью введения которой был обход лимита на 64Кб кода/данных, в то время когда современные форматы устанавливают "предел" в 4Гб.


Дата: Май 25, 2004 04:00:14

Еще раз большое спасибо Anonimka! Теперь все работает... Буду изучать ассемблер дальше ;)


Дата: Май 25, 2004 04:19:07

tasman
Я даже понял в чем проблема - компилятор не сгенерировал код ...
Ни чего ты не понял, а Anonimka только добавил тумана. Ни ты, ни он понятия не имеете о моделях памяти.

Модель памяти small подразумевает единый сегмент кода, следовательно, компилятор справедливо не генерирует сохранение регистра cs в стеке. Чтобы убедиться в этом измени модель на large и посмотри на инструкцию вызова подпрограмм.

Ошибка твоя в том, что ты силой обявил процедуры с атрибутом far, а этого делать не следует (кроме специфических случаев), т.к. используется директива model. В случае с подпрограммой main, far помогает избежать ошибки при возврате из нее. Хотя и тут far не нужен, а надо воспользоваться инструкцией retf.

Anonimka
стек не сбалансирован ... выходить из программы с моделью памяти small командой ret ... нэкоррэктно
Инструкции ret нет. Она заменяется в зависимости от атрибута дальности подпрограммы на retf или retn. В начале работы программы регистр ds указывает на psp, по адресу psp:0000h, который в начале main помещается в стек, находится код CD 20 - int 20h, что является документированной функцией завершения программы.


Дата: Май 25, 2004 04:26:56

q_q
Понятно... То есть ошибка моя была в неверном выборе модели памяти? А как тогда можно сделать в модели памяти small такую программу (такую - значит модульную)? Как в ней постороить вызовы процедур?

А вообще надо проводить эту "преподготовку" - т.е. заганять в стек значения ds и 0 ? И зачем это вообще все (особенно 0). (Пользуясь случаем спрошу ;)

Заранее спасибо.


Дата: Май 25, 2004 05:51:10

tasman
То есть ошибка моя была в неверном выборе модели памяти?
Нет. В установке атрибута far, конфликтующего с выбранной моделью памяти.

тогда можно сделать в модели памяти small такую программу
Модульность не имеет отношения к модели памяти.
Если используешь директиву model, то доверяй ей (хотя смотреть листинг, для проверки/оптимизации, тоже надо).

Как в ней постороить вызовы процедур?
Убери все far'ы, и замени ret а main на retf.

А вообще надо проводить эту "преподготовку" ...
Не обязательно, если завершать программу через int 20h или int 21h Ah=4Ch.

И зачем это вообще все (особенно 0)
Я объяснил это, ответив Anonimk'е.


Дата: Май 25, 2004 09:20:29

q_q
Ни чего ты не понял, а Anonimka только добавил тумана. Ни ты, ни он понятия не имеете о моделях памяти.
Знаешь, товарисч Ку-ку, я бы постеснялся так опрометчиво говорить о людях, которых я не знаю. В конце концов, я дал правильное решение. Ну да Господь с тобой.

Модель памяти small подразумевает единый сегмент кода, следовательно, компилятор справедливо не генерирует сохранение регистра cs в стеке. Чтобы убедиться в этом измени модель на large и посмотри на инструкцию вызова подпрограмм.
Мой ответ твоему не противоречит. Да и твой у меня отторжения не вызывает.

Anonimka
стек не сбалансирован ... выходить из программы с моделью памяти small командой ret ... нэкоррэктно

Не стоило это цитировать. Перед автором треда я уже извинился за эти поспешные строки.

Инструкции ret нет. Она заменяется ... программы.
Это ликбез, причем для автора треда, но коль скоро это в ответе на мой пост, то имею полное моральное право отнести это и на свой счет. Так вот - спасибо за информацию, но я об этом уже догадался, о чем ты мог бы узнать, дочитав пост до конца.

tasman
Я не изменяю своего мнения: 64Кб-сегментная модель памяти - это гав-гав, и нужно от этого избавляться.


Дата: Май 25, 2004 10:24:55 · Поправил: q_q

Anonimka
я бы постеснялся так опрометчиво говорить
Давай, восстановим твой и tasman'а диалог (без воды) + мои комментарии.

1) tasman > Ошибка вылезает при попытки выполнить команду ret ...
Anonimka > А что за ошибка-то? ... стек не сбалансирован ... выходить из программы ... командой ret ... нэкоррэктно
q_q > Ответ человека, который не удосужился собрать и выполнить предложенный код. Причем ответ уводит от проблемы. Это я назвал "добавил тумана".

2) Anonimka > Прошу прощения ...
q_q > Программу прокрутил в уме (или собрал exe'шник) однако ответа нет.

3) Anonimka > ... палками нужно бамбуковыми бить того, кто такие задания дает
q_q > Разве автор вопроса хочет это обсуждать?

4) tasman > А насчет несбалансированости стека - это подготовка к заключительному ret (так, по крайней мере надо ...
q_q > Т.е. код списан без понимания его работы.

5) tasman > Насчет ah=4Ch/int 21h ... туда ОНО вообще не доходит
Anonimka > Читай апдейт к предыдущему посту
q_q > В нем только извинения, а ответа нет.

6) tasman > Я даже понял в чем проблема ... Почему компилятор (тем более их 2) этого не сделали ... Как сделать ...
Anonimka > Ну, я того же мнения ... Да черт их знает.. Может быть, дело в том, что компилятор "не видит" ... Наверное, лучше об этом не читать ...
q_q > Вот это "Я даже не понял" и "Да черт их знает.. Может быть" я и назвал "Ни ты, ни он понятия не имеете о моделях памяти."

Итого: Зачем отвечать, если не готов? Подумай, проверь на практике, а потом отвечай.

PS Конструктивная критика не нравится? Если нужен елей в уши, то это не ко мне.

64Кб-сегментная модель памяти - это гав-гав, и нужно от этого избавляться
Опять. Разве у автора есть выбор. Хочешь это обсудить - создай свою тему.


Дата: Май 25, 2004 16:24:32

q_q
Я предложил конкретное решение; ты сказал, о чем проблема. Остановимся на этом. Меньше всего мне хочется гав-гав-гав.


Дата: Май 26, 2004 02:09:31

Anonimka
q_q
Большое всем спасибо за помощь! Я даже понял кое-что для себя новое, так что респект. И, пожалуйста, не сортесь ;)


Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.100