Консультация № 191241
24.07.2017, 13:03
0.00 руб.
0 20 1
Здравствуйте, уважаемые эксперты! Прошу вас ответить на следующий вопрос:
Как правильно прочитать и понять команды:
1.[code lang=asm]jmp dword ptr cs:[Int_21h_vect][/code]
2.[code lang=asm]Int_21h_vect dd ?[/code]
3. [code lang=asm]mov word ptr Int_21h_vect, bx
mov word ptr Int_21h_vect+2, es[/code]

Обсуждение

давно
Старший Модератор
31795
6196
24.07.2017, 13:45
общий
24.07.2017, 19:06
Адресаты:
Начнем с п.2.
Запись
[code lang=asm]Int_21h_vect dd ?[/code]
равносильна записи
[code lang=asm]Int_21h_vect dw ?;bx
dw ?;es[/code]
в комментариях я написал, что куда будет записано в п.3

п.3
директива word ptr указывает компилятору, что код нужно создавать как будто переменная Int_21h_vect, не двойное слово, а слово. Если убрать эту директиву, компилятор выдаст ошибку "не соответствие типов(type mismatch)".

п.1.
Директива компилятору генерировать в коде длинный(far) переход, т.е. переход по адресу сегмент : смещение, которые хранятся в переменной Int_21h_vect. Или другими словами передать управление старому обработчику прерывания считанного перед этим, функцией 0х21/0х35
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Посетитель
7438
7205
24.07.2017, 13:54
общий
это ответ
Здравствуйте, Caesar!
1)Вектора, т.е. подпрограммы отработки прерывания в ДОСе представляют собой
длинные указатели, состоящие из смещения и сегмента. Все они записаны в начале памяти,
начиная с 0 адреса, на каждый адрес отводится по 4 байта.
2)В системе может быть несколько программ, которые "висят" на каком-то векторе.
Это может быть, как сама система, так и резиденты, плюс текущая программа.
Поэтому необходимо при установке собственного обработчика прерывания
позаботиться о сохранении адреса предыдущего обработчика вектора.
и отдаче туда управления, после того, как отработали свою функцию или вообще увидели, что
пришедшую функцию нам отрабатывать не надо.
Т.о., мы встраиваемся в цепочку обработчиков текущего вектора.
После выхода из программы (если, конечно, программа - не резидент) необходимо позаботиться о
восстановлении вектора прерывания на предыдущий обработчик.
3) Как это делается?
Пред установкой своего обработчика прерывания читаем адрес текущего при помощи[code lang=asm]mov ah=35h ;функция
mov al=21h ;интересующий номер прерывания
int 21h
[/code]получаем в bx смещение и в es - сегмент старого обработчика прерывания
И сохраняем в двойном слове[code lang=asm]Int_21h_vect dd ?[/code] при помощи команд[code lang=asm]mov word ptr Int_21h_vect, bx
mov word ptr Int_21h_vect+2, es[/code]Далее, в том месте, где надо отдать управление старому обработчику делаем длинный переход[code lang=asm]jmp dword ptr cs:[Int_21h_vect][/code]который поменяет и смещение и сегмент, т.о. управление передастся предыдущему обработчику

Как читать? Да так и читать:
1) длинный переход по длинному адресу, хранящемуся в Int_21h_vect в сегменте cs
2) двойное слово Int_21h_vect, в котором хранится длинный адрес предыдущего обработчика вектора 21h
3) сохранение смещения и сегмента в длинном указателе Int_21h_vect
Обратите внимание, что сама переменная описана, как dword, поэтому, чтобы записать туда слова, надо добавлять word ptr
5
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
24.07.2017, 14:25
общий
Адресаты:
Все понятно?
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
401251
75
24.07.2017, 14:48
общий
24.07.2017, 14:50
В принципе понятно все, но нет уверенности в понимании!
Или не могу понять, что именно непонятно, т.е. сформулировать вопрос!
Как то так)))

1. После 1-го запуска программы, в переменной Int_21h_vect будет хранится адрес предыдущего обработчика (даже если это обработчик другой программы, значения не имеет)?
2. Если не будет происходить вызова нужного нам прерывания (т.е. на которое отреагирует программа) предыдущие обработчики будут меняться, это как-то отразиться в переменной или адрес измениться только при перехвате прерывания?
2. Каким образом попадет в эту переменную адрес следующего предыдущего обработчика при перехвате прерывания, если тот участок кода уже отработал и не был записан как резидент?
3.
[code lang=asm]mov ax,2521h
mov dx, offset Int_21h_proc
int 21h

; теперь если какая нибудь прога вызовет 21 то сработает наш обработчик осталось завершить программу,
; оставив ее резидентной в памяти (чтоб никто не затер наш обработчик) Иначе комп зависнет[/code]

Как это работает?

4. Как работает iret и в каких случаях ее применять
давно
Посетитель
7438
7205
24.07.2017, 15:13
общий
Адресаты:
1. После 1-го запуска программы, в переменной Int_21h_vect будет хранится адрес предыдущего обработчика (даже если это обработчик другой программы, значения не имеет)?
Сам он там не появится. Его надо туда записать. Еще раз посмотрите мой ответ, как его туда записать
2. Если не будет происходить вызова нужного нам прерывания (т.е. на которое отреагирует программа) предыдущие обработчики будут меняться, это как-то отразиться в переменной или адрес измениться только при перехвате прерывания?
Адреса предыдущего прерывания записывает в своем теле сама программа при перехвате прерывания. В принципе, конечно, вполне возможно, пробежаться по цепочке отработок и поменять тело чужой программы Но так никто не делает... Каждая программа отвечает только за свой код.
3. Каким образом попадет в эту переменную адрес следующего предыдущего обработчика при перехвате прерывания, если тот участок кода уже отработал и не был записан как резидент?
Если программа перехватила отработку какого-то вектора и не является резидентов, то она обязана восстановить предыдущие вектора. Иначе, при последующем запуске какой-либо программы, отработка вектора скорее всего вызовет вылет, т.к. код, куда ссылается вектор уже неактуален.
[code lang=asm]mov ax,2521h
mov dx, offset Int_21h_proc
int 21h[/code]данный код устанавливает свой обработчик прерывания. В комментарии сказано примерно то же, что и я чуть выше.
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
401251
75
24.07.2017, 15:18
общий
Цитата: Лысков Игорь Витальевич
Сам он там не появится. Его надо туда записать. Еще раз посмотрите мой ответ, как его туда записать
я это и имел в виду))

Спасибо, помогли разобраться.
давно
Старший Модератор
31795
6196
24.07.2017, 15:30
общий
Адресаты:
Все несколько не так.
Представьте, что в памяти есть таблица векторов 0х0000 : 0х0400, всего 256 прерываний, на каждое прерывание 4-е байта. Когда программа ставит свой обработчик, она должна прочитать адрес старого обработчика, запомнить его и в таблицу прерываний записать сегмент : смещение своего обработчика.
Судя по вопросу Вы медленно подходите к гл.10, если уже не там.
В этой главе рассматриваются резиденты. Смысл их - программа запустилась, отработала, поставив свой обработчик, завершилась, оставшись резидентной. После этого запускается другая программа и к примеру пытается вывести строку, функцией 9, прерывания 21. Наш резидентный обработчик, получает управление, т.к. его сегмент : смещение записаны в таблице векторов и именно ему система передаст управление, когда будет вызвано прерывание 21, проверив содержимое регистра АН, если там нужное нам значение(9), мы как бы перехватываем этот вызов, делаем, что нам нужно и все, если значение не совпадает, то просто передает управление обработчику, который был до нашего резидента и так будет продолжатся, пока по всей цепочке не спустимся в недра ОСи и не будет вызван системный обработчик прерывания.

iret аналогичен retf, но он еще восстанавливает и регистр флагов. Это связано с тем, что механизм прерываний аналогичен как для программных, так и для аппаратных. С той лишь разницей, что аппаратные прерывания могут наступить в любой момент и прервать любую программу и если он нарушит, какой либо флаг, то прерванная программа может не правильно работать.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Посетитель
401251
75
24.07.2017, 15:33
общий
Цитата: Зенченко Константин Николаевич
Судя по вопросу Вы медленно подходите к гл.10, если уже не там.
вот я ее закончил, теперь пора вопросов))
давно
Старший Модератор
31795
6196
24.07.2017, 15:37
общий
Адресаты:
Цитата: Caesar
теперь пора вопросов


И где они?
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Посетитель
7438
7205
24.07.2017, 15:39
общий
24.07.2017, 15:45
Не заметил
4. Как работает iret и в каких случаях ее применять

Есть два способа вызова подпрограмм: с помощью call и с помощью int
Call, в свою очередь, может быть коротким и длинным

Короткий call - это вызов в текущем сегменте,
в стек заносится смещение следующей команды за call
текущим адресом становится смещение подпрограммы
После завершении подпрограммы при помощи ret из стека извлекается адрес следующей
команды и заносится в текущий адрес.

Длинный call усложняется тем, что в стек заносится длинный указатель, т.е. сегмент:смещение
Передается управление в новые сегмент:смещение, которые берутся из кода команды
Т.е. вызывается подпрограмма из другого сегмента.
После завершении подпрограммы при помощи retf из стека извлекается длинный указатель следующей
команды и мы оказываемся за командой call.

Прерывания бывают двух типов: аппаратные и программные. Аппаратные, например, клавиатуры или таймер,
вызываются автоматически по соответствующему событию. Программные, например, int 21h вызываются явно.
И те, и те, работают одинаково. В принципе, и аппаратное прерывание можно вызвать явно, но, обычно,
это не имеет смысла. Из-за того, что прерывания, особенно аппаратные, вызываются в любой момент времени,
необходимо еще сохранять флажки, регистр FLAGS. Команда int это делает автоматически. Сам вызов отработчика похож на дальний вызов.

Т.о., перед вызовом прерывания (любым способом) в стек заносятся флажки, сегмент, смещение.
Выход из прерывания осуществляется командой iret, которая извлекает из стека эти три слова,
восстанавливает флажки и делает длинный переход.

Если известен адрес вектора, то можно вызвать отработчик прерывания и длинным вызовом call, но перед вызовом call
необходимо дать команду pushf (сымитировать вызов по int), чтобы iret корректно завершило отработку обработчика прерывания.

Если сказать проще: прерывания должны заканчиваться iret, обычные подпрограммы ret или retf, в зависимости от способа вызова.
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
401251
75
24.07.2017, 15:45
общий
несколько уже были))
Цитата: Caesar
В принципе понятно все, но нет уверенности в понимании!
Или не могу понять, что именно непонятно, т.е. сформулировать вопрос!
Как то так)))



Кроме аппаратных, программных есть еще и системные прерывания?

Я понял! В таблице векторов прерываний мы осуществляем подмену адреса прерывания
[code lang=asm]mov ax,2521h
mov dx, offset Int_21h_proc
int 21h[/code]
на свой адрес и "дорабатываем" или не дорабатываем прерывание.

Я не пойму того как адрес предыдущего обработчика, попадает в переменную Int_21h_vect, когда программа уже висит в памяти,
ведь участок кода, который отвечал за загрузку адреса в эту переменную
[code lang=asm]mov ah, 35h
mov al,21h
int 21h

mov word ptr Int_21h_vect, bx
mov word ptr Int_21h_vect+2, es[/code]
уже отработал, при первом запуске, а в участок программы, который стал резидентом он не попадает?
давно
Посетитель
7438
7205
24.07.2017, 15:56
общий
Адресаты:
Так код отработал. Получил адрес вектора и записал в длинном указателе, который находится в участке кода,
который остается резидентным. А больше этот код не нужен. Адрес предыдущего обработчика мы получаем только один раз, при запуске программы.

В своем обработчике делаем длинный переход по адресу, хранящемуся в длинном указателе, когда надо и никаких проблем.
Единственно, когда обработчик получит управление, достоверно будет только содержимое сегментного регистра CS,
поэтому перед именем указателя пишем CS:
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
24.07.2017, 15:59
общий
Адресаты:
Кроме аппаратных, программных есть еще и системные прерывания?
Есть только аппаратные и программные прерывания.
Система пользуется теми же самыми прерываниями.
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Старший Модератор
31795
6196
24.07.2017, 16:22
общий
Адресаты:
Цитата: Caesar
Я не пойму того как адрес предыдущего обработчика, попадает в переменную Int_21h_vect, когда программа уже висит в памяти, ведь участок кода, который отвечал за загрузку адреса в эту переменную уже отработал


При написании резидентов, есть код настройки и код резидента. После выполнения прерывания 27 с параметром Init:, все что ниже этой метки будет отброшено(т.е. код настройки), а память будет помечена как свободная.
Переменная Int_21h_vect, с записанными значениями адреса старого обработчика, расположена в резидентной части и отброшена не будет, так и останется в памяти. Именно от туда и будет читаться адрес старого обработчика.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Посетитель
401251
75
24.07.2017, 19:53
общий
Так как я практически ничего не знаю о таблице векторов прерываний, то накидал как смог (Приложение)?
Прикрепленные файлы:
ff0b730554133d0b007639c64b8950ca.png
давно
Посетитель
401251
75
25.07.2017, 07:02
общий
Цитата: Зенченко Константин Николаевич
адрес старого обработчика.
т.е. оригинального?
давно
Старший Модератор
31795
6196
25.07.2017, 09:41
общий
Адресаты:
Последовательность расположения обработчиков в памяти будет иметь такой вид:


При запуске системы, ОСь поставит свой обработчик. Каждый раз, при установке нового обработчика, в таблице векторов будет записан новый адрес обработчика и запомнен адрес старого.

Как уже Вам сказали:
Цитата: Лысков Игорь Витальевич
В принципе, конечно, вполне возможно, пробежаться по цепочке отработок

в поисках оп.кодов команд CALL FAR или JMP FAR, после которых будет находится адрес предыдущего обработчика и спустится в саму ОСь. Но это только в теории, и только в ручном режиме. Правила написания резидентов как бы есть, но им не всегда следуют отдельные "клоуны".
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Посетитель
7438
7205
25.07.2017, 10:33
общий
Адресаты:
в поисках оп.кодов команд CALL FAR или JMP FAR
Более надежно прошагать до сегмента ОС.
Когда-то развлекался подобным...
Т.к. код вполне можно построить динамически, т.е. сформировать команду перехода по ходу дела...
На "правильный" код не стоит рассчитывать...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Старший Модератор
31795
6196
25.07.2017, 11:12
общий
Адресаты:
Цитата: Лысков Игорь Витальевич
На "правильный" код не стоит рассчитывать.


Я как раз и говорил, сам вопрос спуска в ОСь скорее теоретический, и только в ручном режиме.
Цитата: Лысков Игорь Витальевич
Более надежно прошагать до сегмента ОС

Сегмент ОСи, можно из PSP выловить, там как раз есть альтернативный обработчик 0х21.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Посетитель
7438
7205
25.07.2017, 12:54
общий
Адресаты:
Да возможностей определить сегмент ОС масса.
Например, можно найти список сегментов.
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Форма ответа