При закрытии подписчики были переданы в рассылку "RFpro.ru: Ассемблер? Это просто! Учимся программировать" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
| Информационный Канал Subscribe.Ru |
Выпуск № 136
от 14.05.2005, 13:00
| Администратор: | Калашников О.А. |
| В номере: | Вопросов: 2, Ответов: 5 |
| Вопрос № 20577 |
|
Здравствуйте, помогите, пожалуйста, бедному студенту. Нужна помощь в написании программы по перехвату прерываний клавиатуры. В книжках ничего конкретного не почерпнул, копаться в рассылках не охото, нормальные статьи найти немогу, преподователь злой и не помогает - вот к Вам обращаюсь. Суть программы в том, что при нажатии на клавишу должен происходить перехват этого прерывания, и подмена выходных параметров. В частности, если нажата буква 'a' - на экране должна появиться буква 'b' и наоборот. Кое-что, конечно, препод подсказал - но все равно ничего не работает. Если раньше прога хоть вешала намертво комп, то сейчас вообще ничего не происходит. Помогите, пожалуйста. Расскажите, где основная ошибка и что надо откорректировать. Заранее списибо! Приложение: |
| Отправлен: 08.05.2005, 15:48 Вопрос задал: Сухоруков Юрий (статус: Посетитель) Всего ответов отправлено: 3 |
| Отвечает: Евгений Иванов Здравствуйте, raynor_y! сохраняй регистры в прерывании!!!! и не вызывай из своего обработчика то же самое прерывание. смотри файл Прикреплённый файл: Загрузить >> |
| Ответ отправил: Евгений Иванов (статус: Профессор) Отправлен: 08.05.2005, 23:47 |
| Отвечает: Ayl Здравствуйте, raynor_y! Хм... Ошибок много. Во-первых, у тебя не резидентная программа! Вот трассировка действий твоей программы: 1. Установить сегмент данных - ок. 2. Получить адрес старого обработчика 16-го прерывания - ок. 3. Сохранить адрес в переменных - ок. 4. Установить свой обработчик - ок. Обсуждение написания обработчика - дальше. 5. Установить ds:bx на адрес старого обработчика. Хм. А зачем? Непонятное действие. 6. Комментированные строки. Записать по адресу ds:chr_out значение регистра al. А куда указывает ds? правильно - на сегмент старого обработчика. Интересно, я бы, пожалуй, тоже обиделся на такую запись. 7. Вывести на экран строку, завершающуюся символом '$' и начинающуюся с адреса ds:chr_out. Ну, сегментный регистр по-прежнему указывает на сегмент старого обработчика, а вот будет ли там символ доллара - я не уверен. Кстати, прога вылетает, скорее всего, еще на шаге 6. 8. Завершить программу с выходом в ДОС. Итак, что ты имеешь: 1. Неправильная установка регистра ds 2. После возможного завершения программы ты теряешь адрес старого обработчика и при запуске следующей программы вызов 16-го прерывания все равно приведет к ошибке 3. Программа не резидентная, т.к. не остается в памяти после завершения. Теперь по поводу обработчика. Допустим, что его вызвали. Что о делает. А делает он то, что в первой же строке обращается к самому себе! Рекурсия, причем безусловная! Т.е. зацикливание. Очень быстро произойдет переполнение стека - и опаньки! Неправильный алгоритм. И последнее. Насколько я понял из задания, тебе нужно отлавливать нажатия на клавиши и подменять 'a' на 'b', а 'b' на 'a'. но все дело в том, что 16-е прерывание - программное! И работает только при прямом обращении. Т.е. если программа не будет вызывать 16-е прерывание, то и работать это не будет. В то же время любое нажатие или отпускание клавиши генерирует на аппаратном уровне прерывание IRQ1, которое соответствует вектору 9. Т.е. любое нажатие клавиши вызывает обработчик 9-го прерывания! Может, с ним лучше поиграть? И еще два вопроса. Зачем ты при написании резидента создаешь EXE-программу? Да, это не ошибка, но написание резидента в виде EXE-модуля гораздо сложнее написания такого же резидента, но в виде COM-программы. Второй вопрос - ты используешь 32-разрядные регистры или команды 386-го процессора? Если нет - зачем использовать .386? Достаточно .286, хотя твой код вполне компилируем и на 8088. Это, как ты понимаешь, не ошибка, но если бы я был твоим преподом, то в первую очередь задал бы этот вопрос, чтобы выяснить, а понимаешь ли ты вообще эту директиву. В общем, см. в приложении резидент на 16-е прерывание в виде COM-программы. Он очень простой, практически не делает никаких действий, только устанавливает новый обработчик прерывания и завершается резидентно. Теперь при любом получении нажатия клавиши через 16-е прерывание будет осуществляться проверка на скен-коды клавиш A и B и их подмена. Вывод на экран также будет формироваться внешней программой. От этого можешь отталкиваться. Приложение: |
| Ответ отправил: Ayl (статус: Профессор) Отправлен: 11.05.2005, 14:39 Оценка за ответ: 5 Комментарий оценки: Да, свои ошибки понял. БОЛЬШУЩЕЕ !!!спасибо!!! |
| Отвечает: Стас Здравствуйте, raynor_y! 1) накой тебе сдался PSP, Chr_out (который ты почему-то 9 функцией 21 прерывания пытаешься вывести)? 2) вызывая Int 16 из Int 16 ты намертво зацикливаешся. 3) mov ax,4C00h int 21h выгружает твою прогу из памяти ПОЛНОСТЬЮ, при этом Int16 yt восстанавливаешь. Тоже ерунда. 4) Вообще в данном случае перехват Int16 не лучший вариант, есть много других способов получить код нажатой клавиши минуя ah=0 int 16h. Тем не менее вот такой вариант: (COM файл) .model tiny 386 .code org 100h start: jmp begin ; ф-ция intproc: or ah,ah jnz loc1 pushf call dword ptr cs:oldint16 cmp ax,1e61h jnz loc2 mov ax,3062h loc2: iret loc1: jmp dword ptr cs:oldint16 oldint16: _off dw ? _seg dw ? ; ф-ция закончена begin: mov ax,3516h int 21h mov ax,es mov _seg,ax ;Запомнить старый Int16 mov _off,bx mov ax,cs mov ds,ax lea dx,intproc mov ax,2516h int 21h ;Установить новый lea dx,begin ;Оставить резидентом!!! int 27h end start А вот более приемлимый вариант перехватывающий INT9: .model tiny .386 .code org 100h start: jmp begin ; ф-ция intproc: pushf call dword ptr cs:oldint9 ;пусть отработает оригинальный и положит в буфер клавиатуры код push ds push bx push ax push 40h pop ds mov bx,ds:[1ch] ;какой последний код был положен в буффер cmp bx,1eh jnz loc1 add bx,20h; буффер круговой loc1: sub bx,2 mov ax,[bx] cmp ax,1e61h ;только маленькая 'a' !!!! большая будет:1e41 (c ctrl-a =1e01h) и т.д. jnz loc2 mov ax,3062h ;большая 3042h mov [bx],ax ;вот собственно и подмена loc2: pop ax pop bx pop ds iret oldint9: _off dw ? _seg dw ? ; ф-ция закончена begin: mov ax,3509h int 21h mov ax,es mov _seg,ax ;Запомнить старый Int09 mov _off,bx mov ax,cs mov ds,ax lea dx,intproc mov ax,2509h int 21h ;Установить новый lea dx,begin ;Оставить резидентом!!! int 27h end start Есть еще несколько вариантов решения той же проблемы. |
| Ответ отправил: Стас (статус: Практикант) Отправлен: 13.05.2005, 00:17 |
| Вопрос № 20582 |
|
Уважаемые эксперты..... Помогите найти в данных процедурах найти ошибку.... Всё всермя выбрасывает с недопустимой инструкцией...... Очень надо.... Int_1Ch_proc proc far pushf call dword ptr cs:[Int_1Ch_vect] ;вызов оригинального обработчика test cs:[MyFlags],bActivityFlag ;проверим флаг активизации резидента jz Not_active iret ;активирован выходим Not_active: test cs:[MyFlags],bCallFlag ;проверим флаг вызова резидента jnz callVideo or cs:[MyFlags],bActivityFlag ;установим флаг активации резидента mov al, 20h ;сбросим контроллер прерываний out 20h, al call MyResident ;вызываем резидентную процедуру and cs:[MyFlags], (not bActivityFlag) ; сбросим флаг активации iret ;выходим CallVideo: test cs:[MyFlags],b10hFlag ;проверим флаг вызова 10-ого прерывания jz Vid1 iret Vid1: or cs:[MyFlags],bActivityFlag ;установим флаг активации резидента mov al, 20h ;сбросим контроллер прерываний out 20h, al call Smena_Stranici ;вызываем резидентную процедуру and cs:[MyFlags], (not bCallFlag) ; сбросить флаг вызова and cs:[MyFlags], (not bActivityFlag) ; сбросим флаг активации iret ;выходим Int_1Ch_vect dd ? ;адрес оригинального абработчика Int_1Ch_proc endp Int_21h_proc proc far test cs:[MyFlags],bActivityFlag jnz Go_21h pushf or cs:[MyFlags],bActivityFlag cmp ax,9889h ;Проверка на повторную загрузку jne Goo_21h xchg ah,al ;Если мы уже в перехватывает прерывание, то popf and cs:[MyFlags], (not bActivityFlag) iret ;меняем регистры Goo_21h: popf and cs:[MyFlags], (not bActivityFlag) jmp dword ptr cs:[Int_21h_vect] ;передаем управление ;оригинальному обработчику 21h Go_21h: jmp dword ptr cs:[Int_21h_vect] ;передаем управление ;оригинальному обработчику 21h Int_21h_vect dd ? ;адрес оригинального абработчика Int_21h_proc endp |
| Отправлен: 08.05.2005, 19:51 Вопрос задал: edson (статус: Посетитель) Всего ответов отправлено: 2 |
| Отвечает: Евгений Иванов Здравствуйте, edson! отвечаю в жж http://www.livejournal.com/community/useful_faq/294819.html впредь будь внимателен |
| Ответ отправил: Евгений Иванов (статус: Профессор) Отправлен: 09.05.2005, 21:15 |
| Отвечает: Стас Здравствуйте, edson! Была бы прога полностью посмотрел, так не охота. Могу посоветовать как это сделал бы я: Отключал бы процедуры одна за другой, и смотрел когда перестает работать. Или наоборот отключил бы все, а потом постепенно подключал по модулю. |
| Ответ отправил: Стас (статус: Практикант) Отправлен: 13.05.2005, 00:24 |
© 2001-2005, RusFAQ.ru, Россия, Москва. Все права защищены.
Идея, дизайн, программирование, авторское право: Калашников О.А.
http://subscribe.ru/
http://subscribe.ru/feedback/Подписан адрес:
Код этой рассылки: comp.soft.prog.faqОтписаться
| В избранное | ||