СТАТЬИ > Низкоуровневое программирование для дZенствующих


DZebug: руководство юZверя

  Прога эта неимоверно крута и сильна! Она позволяет писать программы и вмешиваться в ход выполнения программ на самом низком, можно сказать "на самом дZенском" уровне! С помощью нее можно отображать и изменять значения регистров :), запускать и останавливать выполнение программы в любой момент :), вносить изменения в программу :), работать с винтом на физическом уровне :); работать с машинным кодом, ассемблировать и дизассемблировать его с той легкостью, которая присуща только продуктам корпорации Micro$oft...

Бредисловие

  ... В 945-ом году отправился князь Игорь к программистам за данью. Когда программисты узнали размеры дани, их лица сразу стали озабоченными, и они побили Игоря и его дружину. Тогда жена Игоря Ольга с огнем и мечом пошла на программистов. Отдавайте, говорит, законную дань, а не желаете, так поставьте на каждую тачку нашу новую навороченную ОСь. Обрадовались программисты, что могут отделаться малым, и их лица опять стали веселыми. А Ольга приказала в каждую ОСь зашить BUG. Программисты инсталлировали ОСь, и BUG уничтожил все их данные...
  И дело даже не в том, что жалко программистов, а в том, что история учит, какими б не казались крутыми ОСы, нужно уметь работать независимо от программного обеспечения. Ведь сила не в мегагерцах и не гигабайтах, и даже не в DZеньгах, сила - она в ньютонах...

Запуск dzebug'а

  Я знаю только два способа запуска DEBUG с файлом.

  1. С командной строкой:

debug имяфайла.тип [ENTER] 

  2. Без командной строки:

debug [ENTER]

  Тут вы получите приглашение DZEBUG в виде черточки "-".
  Далее следуют команды:

-n имяфайла.тип [ENTER] 
-l [ENTER]
  Ууупс! DZEBUG загрузил вашу программу и готов к работе :)))

Отображение и изменение значений регистров

  Первым делом мы просмотрим содержимое регистров, используя команду R. В качестве объекта извращения (Serrgio сегодня будет извращаться несколько иначе) - ваша же прога из #7 п. 4...
  Если вы ввели R без параметров, значения регистров будут выведены примерно так:

AX=0000 BX=0000 CX=0043 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 
DS=16BB ES=16BB SS=16BB CS=16BB IP=0100 NV UP DI PL NZ NA PO NC
15A3:0100 30C0 XOR AL,AL

  CX содержит длину файла (0043h или 67d). Если размер файла превышает 64К, то BX будет содержать старшую часть размера файла. Это очень важно знать при использовании команды Write - размер файла содержится именно в этих регистрах.
  Запомните: когда файл находится в памяти, DZebug не знает его размер. При записи данные о размере берутся из регистров CX и BX. Страшно даже подумать, что может произойти, если мы по ошибке введем команду Write, а в это время BX и CX будут содержать FFFF! Страшно, но приятно...
  Если мы хотим изменить значение одного из регистров, мы вводим R и имя регистра. Давайте поместим в AX слово *UCK (те, кто не знаком с английским, пусть спросят у своих умных друзей, что означает это слово).

-R AX

  Вывалится:

AX 0000 
:

  ":" - это приглашение ввести новое значение. Мы отвечаем *UCK

:*UCK

  Вывалится:

 ^Error 

  DZebug выдал сообщение об ошибке.
  Тут дело даже не в том, что DZебугу не понравилось слово, которое мы ввели. Ему, в сущности, глубоко наплевать, какое значение мы хотим занести в регистр, главное - чтобы цифры были HEX'овые. И если F является таковой, то U - нет. DZебуг заботливо указал нам на нее значком " ^ ".
  Ну и фиг с ним. Попробуем ввести что-нибудь более пристойное, например D3E0:

-R AX 
AX 0000
:D3E0

  Теперь, если мы просмотрим регистры, мы увидим следующее:

AX=D3E0 BX=0000 CX=0043 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000 
DS=16BB ES=16BB SS=16BB CS=16BB IP=0100 NV UP DI PL NZ NA PO NC
15A3:0100 30C0 XOR AL,AL

  Вы увидите, что ничего не изменилось кроме регистра AX. Ему присвоили новое значение, как мы помним.
  Еще один важный момент: команда Register может использоваться только для 16-битных регистров (AX, BX и т. д.). Она не может изменять значения 8-битных регистров (AH, AL, BH и т. д.). Например, чтобы изменить AH, вы должны ввести новое значение в регистр AX с новым AH и старым значением AL.

  Помедитируйте немного и поехали дальше...

Дамп памяти

  Если вы не очень хорошо умеете читать машинные команды процессора, команду Dump можно использовать для вывода на экран данных (тексты, флаги и т. д.). Для вывода кода лучше использовать команду Unassemble.
  Если мы теперь введем команду Dump, DZEBUG определит начало программы. Для этого он использует регистр DS, и, так как это COM-файл, начинает вывод с адреса DS:0100. Он выведет 80h (128d) байт данных (или то количество, которое вы сами определите)... Следующее употребление команды Dump отобразит следующие 80h байт и так далее.
  Например, первая команда Dump выведет 80h байт начиная с адреса DS:0100, вторая команда выведет 80h байт начиная с адреса DS:0180...
  Конечно, можно самому определять нужный вам сегмент и смещение при использовании Dump, только нужно использовать для определения только шестнадцатеричные цифры.
  Например, запись D DS:BX не верна. Загрузив нашу программу и введя команду Dump, мы увидим очень непонятные буквы и цифры.
  Вы наверное уже знаете, что эти буквы и цифры - не что иное как наша программа. Невероятно, но это так.
  Вы видите, что выводимые командой Dump данные разделены на три части.
  Самая левая содержит адрес первого байта в строчке. Ее формат - сегмент:смещение.
  Следующая колонка содержит шестнадцатеричные данные по указанному адресу. Каждая строчка содержит 16 байт данных.
  Третья колонка - это ASCII представление данных. Отображаются только стандартные символы ASCII. Специальные символы IBMPC не отображаются, вместо них выводятся точки ".". Это делает поиск простого текста более удобным.

  Dump не может выводить данные, выходящие за границы сегмента. Например, команда

   
-D 0100 L F000

  правильная (выводятся байты начиная с DS:0100 до DS:F0FF), а команда

-D 9000 L 8000 

  некорректна (8000h +9000h = 11000h - выходит за границу сегмента).

  Так как 64К - это 10000h то невозможно задать этот адрес четырьмя шестнадцатеричными цифрами, поэтому DEBUG использует 0000 для задания 10000h.
  Чтобы вывести на экран весь сегмент - введите

-D 0 L 0. 

  Помедитируйте немного и поехали дальше...

Поиск байтов

  Search служит для поиска заданного байта или последовательности байт в пределах сегмента. Параметры задания адреса точно такие, как для команды Dump, поэтому мы не будем здесь опять о них рассказывать.
  Еще мы должны задать данные, которые нужно искать. Они могут быть введены как в шестнадцатеричном, так и в символьном формате. Шестнадцатеричные данные вводятся как байты, через пробел или запятую. Символьные данные должны быть заключены в одинарные или двойные кавычки.
  Шестнадцатеричные и символьные данные могут чередоваться в любом порядке, например команда

-S 0 L 100 12 34 'abc' 56 [ENTER]

  - правильная, в результате произойдет поиск от DS:0000 до DS:00FF последовательности 12h 34h a b c 56h.
  Символы верхнего регистра отличаются от символов нижнего регистра. Например, 'ABC'- это не то же самое, что 'Abc' или 'abc' или другие комбинации верхних и нижних регистров. Однако, 'ABC' и "ABC" считаются одинаковыми, потому что кавычки - это всего лишь разделитель.
  Попробуем найти слово 'пИво'. У нас получится следующее:

-S 0 L 0 'пИво' [ENTER]
-

  Ну нет в этой программе пИва!
  Попробуем пИво поискать в другом месте, а в нашей программе лучше поищем слово B7 20 B5 06:

-S 0 L 0 B7 20 B5 06 [ENTER]
15A3:0110
-

  Итак, по адресу 15A3:0170 DZebug нашел слово B7 20 B5 06.
  Опять же: значение сегмента у вас может быть иным, но смещение должно быть такое же...
  Если мы выведем данные на экран, то по этому адресу мы найдем строку '. ......=...0..'. Мы можем попробовать найти строчку '_T¬ _:-.', или еще какую-нибудь нездоровую последовательность символов.
  Если мы захотим найти все места, где употребляется команда Int 10h (в машинном коде эта команда имеет вид CD 10), мы сделаем следующее:

-S 0 L 0 cd 10 [ENTER]

  и получим дли-и-инную простыню:

15A3:010E 
15A3:011A
15A3:0126
15A3:0132
15A3:013E
15A3:0AE6
15A3:0F23
-

  DZEBUG нашел последовательность CD 10 по этим адресам. Это не значит, что все CD 10 - это команды Int 10h. Просто по указанным адресам расположенны искомые данные. Это может быть (чаще всего) инструкция, но это также может быть и адрес, вторая часть инструкции JMP и т.д. Вы должны внимательно изучить код программы на данном участке памяти, чтобы быть уверенным, что это действительно INT 10.
  Вы ведь не думаете, что комп все сделает за вас? Конечно, компьютеры заменили человека во многих сферах деятельности, преимущественно там, где нужно работать нижними полушариями мозга, а там, где нужны еще и верхние полушария, без человека ну никак не обойтись! И это звучит гордо!

  Помедитируйте немного и поехали дальше...

Сравнение участков памяти

  Архиполезнейшая штука! Лично я долго над ней дZенствовал :).
  Команда сompare берет два заданных участка памяти и сравнивает их, байт за байтом. Если два адреса содержат разную информацию, они выводятся на экран вместе с их содержимым. Для примера мы сравним 2 байта DS:0100 с DS:0200 .

  
-С 0100 L 8 0200
15A3:0100 30 0E 15A3:0200
15A3:0101 C0 00 15A3:0201

  Все 2 байта различны, поэтому они все выведены на экран. Если какие-нибудь байты окажутся одинаковыми, то они не будут выводится на экран. Если две области окажутся полностью одинаковыми, DEBUG просто ответит новым приглашением. Это очень удобный способ сравнения данных из памяти с данными из файла или ROM-BIOS :)

ДиZассемблирование

  Unassemble - основная команда, которую вы будете использовать при отладке. Эта команда берет машинный код и преобразует его в инструкции ассемблера. Способ задания адреса такой же, как и в предыдущих командах, с одной лишь разницей: поскольку мы теперь будем работать с кодом (предыдущие команды в основном предназначены для работы с данными), регистр по умолчанию - CX. В .COM программах это делает небольшое отличие, если только вы сами не очистите DS. Однако в .EXE файлах это чревато некоторыми осложнениями, потому что изначально регистрам CS и DS присвоены разные значения.

-u 
15A3:0100 XOR AL,AL
15A3:0102 MOV BH,10
15A3:0104 MOV CH,05
15A3:0106 MOV CL,10
15A3:0108 MOV DH,10
15A3:010A MOV DL,3E
15A3:010C MOV AH,06
15A3:010E INT 10
15A3:0110 MOV BH,20
15A3:0112 MOV CH,06
15A3:0114 MOV CL,11
15A3:0116 MOV DH,0F
15A3:0118 MOV DL,3D
15A3:011A INT 10
15A3:011C MOV BH,30
15A3:011E MOV CH,07

  Мы видим уже знакомую нам программу. Если мы опять введем "u", то DZebug выдаст нам очередную порцию кода. В нашем случае все обошлось благополучно, но бывает и так, когда вы не знаете, что вы в данный момент дизассемблируете - действительно код программы, или же ее данные. DZebug сделает все, что вы ему прикажете. Если вы скажете дизассемблировать данные, он сделает это, ничего не заметив.

Размещение данных в памяти

  Команда Enter используется для размещения данных в памяти. Она имеет два режима: Display/Modify и Replace. Отличия между ними в расположении помещаемых данных - в самой команде Enter или после приглашения.
  Если вы ввели E <адрес>, вы будете находиться в режиме Display/Modify. DZEBUG предложит вам изменить значение байта, отображая его текущее значение. Вы можете ввести один или два шестнадцатеричных символа. Если вы нажмете пробел, DZEBUG не будет изменять текущий байт, а перейдет к следующему. Если вы зашли далеко, нажатие минуса "-" возвратит на один байт назад.

-E 100 [Enter]
15A3:0100 30.41 C0.42 B7.43 10. B5.45
15A3:0105 05.46 B1.40 10.-
15A3:0106 40.47 10.

  В нашем примере мы ввели E 100. Dzebug ответил адресом и значением байта по этому адресу (30). Мы ввели 41, и DZebug автоматически перешел к следующему байту данных (C0). Опять, мы вводим 42, и DEBUG переходит к следующему байту (B7). Мы изменили его на 43. По адресу 104 байт 10 нас вполне удовлетворяет, поэтому мы нажали пробел. DEBUG не изменил его значение и перешел к следующему байту.
  После ввода 40 в позиции 105 мы обнаружили, что ввели неправильное значение. Нажимаем минус, и DEBUG возвращается на одну позицию назад, отображая адрес и содержимое. Обратите внимание, что оно отличается от первоначального (B5) и имеет значение, которое мы ввели (40). Мы вводим правильное значение и завершаем работу нажатием ENTER.
  Как вы видите, это утомительная работа, особенно когда вы работаете с большими объемами данных или с ASCII-текстом - вы должны знать шестнадцатеричное значение каждого символа. В этом случае можно воспользоваться режимом Replace.
  Режим Display/Modify предназначен для изменения значения небольшого количества байтов по различным смещениям. Replace предназначен для изменения любого количества идущих подряд байтов.
  Данные можно вводить как в символьном, так и в шестнадцатеричном формате, и все байты можно ввести за один раз, не ожидая приглашения отладчика. Если вы хотите разместить строку 'Wind0yZ must Die', заканчивающуюся на 0, по адресу 100, то вы должны ввести : E 100 'Wind0yZ must Die' 0
  Люди!!! То, что вы сейчас сделали, подобно самоубийству!!! Вместо МАТРИЦЫ вы только что поимели свою собственную программу. Вы отредактировали ее КОД!!! Причем самым извращенным образом!!!
  Если теперь вы введет команду U, то увидите ЭТО:

15A3:0100 57      PUSH DI 
15A3:0101 69 DB 69
15A3:0102 6E DB 6E
15A3:0103 64 DB 64
15A3:0104 30795A XOR [BX+DI+5A],BH
15A3:0107 206D75 AND [DI+75],CH
15A3:010A 7374 JNB 0180
15A3:010C 204469 AND [SI+69],AL

  А если вам, не дай бог, взбредет в голову ввести команду G, то... Ну, в общем, сами увидите. Как и в команде Search, данные в символьном и HEX формате могут чередоваться в любом порядке. Это наиболее удобный способ размещения больших объемов данных в память.

Размещение данных одинакового значения

  Команда Fill удобна для размещения данных одинакового значения. Она отличается от команды Enter тем, что завершает свою работу только тогда, когда будет полностью заполнен заданный участок памяти. Как и Enter, она работает и с символьными данными, и с шестнадцатеричными значениями. В отличие от Enter, с помощью этой команды можно заполнять большой объем памяти за один раз, без определения значения каждого символа.
  Например, чтобы очистить 32К (8000h) памяти, вы всего лишь должны ввести команду:

-F 0 L 8000 0 [Enter]

  В итоге все байты памяти начиная с DS:0000 и до DS:8000 будут обнулены. Если бы вместо нуля мы ввели '1234' , то память была бы заполнена повторяющейся последовательностью '123412341234', и так далее. Обычно, для задания небольших объемов данных лучше использовать команду Enter, потому что ошибка в длине при вызове команды Fill может наделать много бед. Команда Enter изменяет значения только тех байт, которые вы непосредственно укажете, что позволяет минимизировать вероятность ошибки.

  Помедитируйте немного и поехали дальше...

Перемещение данных

  Команда MOVE перемещает данные "внутри компьютера". Она берет данные, расположенные по одному адресу, и копирует их "в другой" адрес.
  Если вы хотите выполнить эту команду во время трассировки, это может нарушить ход ее выполнения и получится очень здорово ;) - данные и инструкции, расположенные после "вставки", будут теперь расположены в са-а-авсем другом месте...
  Команда MOVE может быть использована для сохранения части программы в свободной памяти, пока вы будете вносить в нее изменения. (Завернул??) Тогда программу можно будет восстановить в любой момент...
  Вы можете вносить изменения "в BIOS" не утруждая себя программированием ROM:

- M 100 L 200 ES:100 [Enter]

  Мы копируем данные с адреса DS:0100 до DS:02FF (длина - 200) в область памяти, которая начинается с ES:100. Позднее мы можем их восстановить. Нужно только ввести:

- M ES:100 L 200 100 [Enter],

 , что скопирует данные туда, где они должны быть. Если мы не изменяли данные в памяти по адресу ES:0100, то эта команда восстановит первоначальное состояние памяти DS:0100 - DS:02FF.
  Вроде правильно написал, а? А если неправильно, то все равно ведь ничего страшного. ДZЕНСТВУЮЩИЙ Sashok подправит, если что не так... верно?
  Помедитируйте с часок и поехали дальше...

Ассемблирование

  А вот теперь начинается самое интересное!
  Команда ASSEMBLE запрашивает мнемоники (то бишь команды микроассемблера) и преобразует их в машинный код.
  Есть некоторые операции, которая она не может проделать (в отличие от MASM/TASM/NASM): ссылка на метки, использование макроса или чего-нибудь еще, что не может СРАЗУ транслироваться в машинный код.
  Обращение к данным должно происходить по их физическому адресу в памяти, сегментные регистры, если они отличаются от установленного значения, должны быть определены, и при использовании команды RET должен быть указан тип возврата (NEAR или FAR).
  А еще, если инструкция обращается к данным, а не к регистрам (например, MOV [278], 5), то нужно указывать их длину - Byte ptr или Word ptr. Чтобы указать DZebug различие между пересылкой 1234h в AX и пересылкой слова по адресу 1234 в регистр AX, используют квадратные скобки - последнее будет иметь вид MOV AX, [1234].
  Всяческие разновидности инструкции JMP автоматически ассемблируются в Short, Near или Far переходы.
  А теперь мы... гы... напишем еще одно "окошко" :). Только оно будет не очень красивое :). Размеры его будут максимально возможными, а атрибут - стандартный досовский. Работать эта программа будет по образу и подобию команды CLS (очистка экрана).

     
-A 100
15A3:0100 mov ax,600
15A3:0103 mov cx,0
15A3:0106 mov dx,184f
15A3:0109 mov bh,07
15A3:010B int 10
15A3:010D int 20
15A3:010F
-

  Мы использовали прерывание BIOS 10h, которое предназначено для работы с экраном. Мы обращаемся к BIOS с AX=600, BH=7, CX=0, and DX=184Fh. Сначала необходимо установить регистры, что мы и сделали, введя первые четыре инструкции. Команда по адресу 15A3:010B - команда обращения к BIOS. INT 20 (по адресу 010D) служит для безопасности. Нам эта команда практически не нужна, но когда она есть, программа остановится автоматически. Без INT 20, и если мы сами не остановим программу, DEBUG продолжит выполнение программы (от 010F и дальше). А так как после 010D начинается неопределенная область, то, скорее всего, система зависнет. Теперь поможет только ctrl-alt-del (может быть) или же выключение и включение питания. Будьте осторожны и дважды проверяйте, прежде чем что-нибудь делать. А еще лучше - трижды...
  Теперь мы должны запустить программу. Чтобы это сделать, введите команду G и нажмите Enter. Если вы правильно ввели свою программу, экран должен очиститься и должно появиться сообщение "Program terminated normally". Более подробно команда Go будет рассмотрена ниже.
  Опять же, я не могу выразить всей важности правильного введения инструкций при использовании Assemble. Особенно нужно быть осторожным с инструкциями типа JMP и CALL. Они изменяют ход выполнения программы, поэтому может случиться так, что выполнение начнется с середины какой-нибудь инструкции, что приведет к крайне нежелательным результатам.
  Как говорили монашки, натягивая презервативы на свечи: "Береженого бог бережет"...
  Предо... (тьфу) ... помедитируйте с часок и поехали дальше...

Имя, сестрa, имя

  Команда NAME служит только для одной цели - определить имя файла, который DZEBUG должен загрузить или сохранить. Она не изменяет память и не выполняет программу, она только формирует "блок контроля" для файла, с которым будет работать DZEBUG. Если вы хотите загрузить программу, то можете указать это в этой же строчке параметры, как при работе с ДОС. Единственное отличие - должно быть задано расширение.
  Расширений по умолчанию не существует. DEBUG загрузит или запишет на диск любой файл, если указано его полное имя.

   
-n format.com c:/s

  Мы приготовили DZEBUG к загрузке программы FORMAT.COM с заданным ключом. Когда мы введем команду Load (см. ниже), DZEBUG загрузит программу format.com с параметрами c:/s.
  Ну, тут и ежу все понятно, можно не медитировать....

Грузить

  Команда LOAD имеет два формата. Первый загружает программу, которая была определена командой NAME, устанавливает все регистры, готовит все необходимое для исполнения. Все заданные параметры программы будут помещены в PSP, и программа "приготовится" к выполнению.
  Если файл в формате HEX, он должен содержать правильные шестнадцатеричные символы, которые определяют размер памяти. Загруженные файлы выполняются с адреса CS:0100 или с адреса, указанного в команде. Для файлов .COM., .HEX and .EXE регистры содержат адрес первой инструкции программы. Для других типов файлов регистры не определены. Сегментные регистры имеют значение, указанное в PSP (100h байт перед кодом программы), в BX и CX содержится размер файла. Остальные регистры не определены.

  
-n format.com
-l

  Эта последовательность команд загрузит format.com в память, поместит в IP точку входа - 0100, а CX будет содержать HEX-размер файла. Программа теперь готова к работе :)
  Другой формат команды LOAD не использует команду NAME. Он предназначен для чтения секторов с диска (гибкого или жесткого) в память.
  За один раз можно прочитать 80h (128d) секторов. При использовании этой команды вы должны указать начальный адрес, диск (0=А, 1=В и т. д.), начальный сектор и количество читаемых секторов.
  Например

-l 100 0 10 20

  указывает DZEBUG загрузить в память с DS:0100 20h секторов с диска А начиная с сектора 10h.
  Таким образом, DZEBUG можно иногда использовать для восстановления части информации в поврежденном секторе. Но это уже изврат!
  Вот. Кратко и лаконично. Медитируйте...

Писать (ударение на "а")

  Команда WRITE очень похожа на команду LOAD. Обе имеют два режима работы, и обе могут работать как с файлами, так и с физическими секторами. Как вы наверное уже поняли, WRITE производит запись на диск. Поскольку все параметры такие же, как и в LOADе, мы не будем их опять описывать.
  Отметим только одну вещь - при использовании этой команды размер записываемых данных определен в BX и CX, где BX содержит старшую часть размера файла. Начальный адрес должен быть определен по умолчанию - CS:0100. Файлы с расширением .EXE или .HEX не могут быть записаны (появится сообщение об ошибке). Если вы хотите изменить .EXE или .HEX файл, просто переименуйте его, загрузите, сделайте необходимые изменения, сохраните его и дайте ему прежнее имя.
  Медитируйте...

Чтение данных из порта

  Команда INPUT предназначена для чтения данных из любого I/O порта PC. Адрес порта может быть как однобайтовым, так и двухбайтовым. DZEBUG произведет чтение из порта и отобразит на экране его содержимое.

-i 3fd 7D 

  Этой командой мы прочитали данные из "входного" порта "первого асинхронного адаптера". Результат, который вы получите, может отличаться от приведенного :) - все зависит от текущего состояния порта. У меня в момент чтения регистр порта имел значение 7Dh.
  Естественно, чтение из разных портов может привести к различным результатам.
  Медитируйте...

Запись данных в порт

  Вы можете использовать команду OUTPUT для того, чтобы послать один байт или последовательность данных в порт. Помните, что запись в некоторые порты может привести к непредсказуемым последствиям. Будьте осторожны при работе с этой командой!

    
-o 3fc 1

  Порт 3FCh - это "регистр контроля модема" для "первого асинхронного порта". Запись в него 01h устанавливает бит DTR. 00h сбрасывает все биты. Если у вас есть модем, который отображает состояния этих бит, вы сможете увидеть вспышку лампочки, когда будете устанавливать и сбрасывать этот бит.
  Медитируйте...

Go! Go! Go! Але-але-але...

  Команда GO начинает выполнение программы. Она позволяет запускать программу с любой точки и останавливать ее в любой из десяти брекпоинтов программы. Если брекпоинты не установлены (или не выполнены), выполнение программы будет продолжаться до конца, после чего будет выведено сообщение "Program terminated normally". (Именно последнее, кстати и является "але-але-але" ).
  Если выполнение программы дошло до брекпоинта, программа будет остановлена, отобразится содержимое регистров и появится обычное приглашение DZEBUG. Теперь можно вводить любые команды DZEBUG, включая и команду Go для продолжения выполнения программы.
  Команда Go не может быть прервана нажатием Ctrl-break. Это одна из тех немногих команд, которые не могут быть прерваны во время исполнения.

-g =100 

  Команда GО без брекпоинтов начинает выполнение программы с адреса, указанного в параметре.
  Кстати, перед адресом должен стоять знак "равно" - без этого знака адрес воспринимается как брекпоинт...
  Если не указан стартовый адрес, выполнение программы начинается с CS:IP.
  Что еще тут сказать? Пример если только привести...

-g 176 47d 537 647

  Данной командой мы запускаем программу и устанавливаем брекпоинты по адресам CS:176, CS:47D, CS:537 и CS:647.
  Несколько слов о бряках теперь...
  Работа проги останавливается непосредственно ПЕРЕД брекпоинтами. Установка их на текущую инструкцию приведет к тому, что программа не будет выполняться. DZEBUG сначала устанавливает брекпоинт, и только потом пытается выполнить программу. Бряки (разновидность бяк) используют INT 3 для остановки выполнения. DZEBUG вызывает прерывание 3 для остановки программы и отображает содержание регистров.
  Брекпоинты не сохраняются между двумя вызовами команды GO. Все брекпоинты вы должны указывать при КАЖДОМ обращении к этой замечательной команде :)
  С зеленым чаем в "точках останова"... медитируем...

"Трррассиррровка" - сказал пулеметчик

  Команда TRACE имеет сходство с командой GO. Различие между ними заключается в том, что GO выполняет целый блок кода за один раз, а TRACE выполняет инструкции по одной, каждый раз отображая содержимое регистров.
  Как и в GO, выполнение можно начинать с любой точки. Перед стартовым адресом должен стоять знак "равно". При вызове команды можно указать количество инструкций, которые нужно выполнить.

-t =100 5 

  Эта команда начнет работу с адреса CS:100 и выполнит пять инструкций. Без указания адреса, выполнение начнется с CS:IP. Команда Т без параметров выполнит только одну инструкцию. При использовании TRACE желательно обходить обращения к DOS и другие прерывания. DOS нельзя трассировать - это может привести к плохим последствиям. Можно трассировать программу до инструкции прерывания, затем командой GO выполнить прерывание и продолжать трассировку дальше.
  Медитируем-с... скоро нирвана...

Плюс-минус

  С помощью команды с завернутым названием HEXARITHMETIC можно складывать (+) и вычитать (-) шестнадцатеричные числа. Она имеет два параметра: два числа, которые нужно сложить или вычесть. Числа должны иметь длину не более четырех шестнадцатеричных цифр. Сложение и вычитание беззнаковое, не учитывается переполнение старшего разряда.

-h 5 6 
000B FFFF

-h 5678 1234
68AC 4444

  В первом примере мы хотели сложили 0005 и 0006. Их сумма - 000B, а разность -1. Однако, т.к. числа беззнаковые, мы получили FFFF.
  Во втором примере сумма 5678 и 1234 - 68AC, а разность - 4444.
  Медитируем...

Нирвана!

  Имею счастие заявить: я кончил.

  [C] Nyron / HI-TECH

· Комментарии читателей (7)




© 2002-2005 wasm.ru - all rights reserved and reversed