Воробьёвы

(-:

№10.2. DZebug: руководство юZверя, часть 2

ПРИВЕТСТВУЮ ВАС, 4009 ШТ. ДZЕНСТВУЮЩИХ БРАТЬЕВ И СЕСТЕР!

Прошлый выпуск "лабал" NYRON. Дело было перед Новым Годом и он спешил. Теперь он горько жалеет об этом. И дело вовсе не в том, что он допустил кучу ляпов в #10, а в том, что он напился-таки и, нарядившись Дедом Морозом... короче: наш малолетний "мегахакер" получил по морде :(.

В общем, милениум он встретил валяясь на потертом линолеуме.

За окном шел снег. Солист русской-народной группы Sepultura выхаркивал очередную вариацию на тему кровавых корней человечества... По телику показывали высокопарную новогоднюю дрянь... Соседи за стенкой орали пошлую песню...

Но взошло солнце и было утро. Была минералка и крепкий чай. Была горячая вода и куча поздравительных е-мэйлов...

И было это НОВОЕ ТЫСЯЧЕЛЕТИЕ, день Первый! Ик...

СПИСОК ЛЯПОВ, СДЕЛАННЫХ NYRON'ОМ В ПРОШЛОМ НОМЕРЕ

ПОИСК БАЙТОВ:

- написано: "Итак, по адресу 15A3:0170 DZebug нашел слово B7 20 B5 06."

- должно быть: 15A3:0110.

СРАВНИВАНИЕ УЧАСТКОВ ПАМЯТИ

- написано: "-С 0100 L 8 0200"

- должно быть: -C 0100 L 2 0200.

ДИZАССЕМБЛИРОВАНИЕ:

- написано: "...регистр по умолчанию - CX"

- должно быть: регистр по умолчанию - CS.

РАЗМЕЩЕНИЕ ДАННЫХ В ПАМЯТИ:

- написано: "По адресу 104 байт 10 нас вполне удовлетворяет, "

- должно быть: По адресу 103...

РАЗМЕЩЕНИЕ ДАННЫХ В ПАМЯТИ:

- написано: "После ввода 40 в позиции 105 мы обнаружили, "

- должно быть: в позиции 106.

Ляпы найдены by ДZЕНСТВУЮЩИЙ Sashok,

за что ему публичный сенькс (уважаем!!)

ПИСЬМО ЧИТАТЕЛЯ (И ЭТО ПРАВИЛЬНО!)

"Захотелось черкануть пару строк по поводу оптимизации исходного кода (№8).

Общеизвестно, что

      XOR AX,AX
      INC AX

работает быстрее, чем

      MOV AX,0001.

Аналогично и с командами

      ADD AX,0001

и

      INC AX

(к тому же ADD AX,0001 не согласуется с провозглашенным принципом байтом меньше (№7).

Так что старайтесь по мере возможностей сразу использовать красивый оптимизированный код."

Sergey Kondratenko

ПРЕДЫДУЩИЕ ВЫПУСКИ РАССЫЛКИ

По идее, ну не то, чтобы повторение - мать учения... просто не проштудировав материал прыдыдущих номеров, вам будет весьма затруднительно "въехать" в номер текущий...

Выпуск 2 - про систему счисления.

Выпуск 3 - про порядок загрузки компьютера.

Выпуск 4 - про регистры.

Выпуск 5 - про программу в памяти.

Выпуск 6 - про прерывания.

Выпуск 7 - программируем и отлаживаем.

Выпуск 8 - "ломаем" игры, разборки со стеком, циклами, оптимизацией.

Выпуск 9 - разборки с процедурами и CX = 10000h.

Выпуск 10 - DZebug: руководство юзверя, часть 1.

Кстати, у кого проблемы с интернетом... хм... это только ваши проблемы и к нам по этому поводу обращаться не стОит... не стоИт...

(C) Serrgio (из NYRON'овского выпуска скопировано правильно)

КРАТКОЕ СОДЕРЖАНИЕ ПРЕДЫДУЩЕЙ ЧАСТИ

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

Итак, поехали дальше... NYRON представляет:

DZEBUG: полное руководство юзверя, часть вторая.

ПЕРЕМЕЩЕНИЕ ДАННЫХ

Команда MOVE перемещает данные "внутри компьютера". Она берет данные, расположенные по одному адресу, и копирует их "в другой" адрес.

Если вы хотите выполнить эту команду во время трассировки, это может нарушить ход ее выполнения и получится очень здорово ;) - данные и инструкции, расположенные после "вставки", будут теперь расположены в са-а-авсем другом месте...

Команда MOVE может быть использована для сохранения части программы в свободной памяти, пока вы будете вносить в нее изменения. (Завернул??) Тогда программу можно будет восстановить в любой момент...

Вы можете вносить изменения "в BIOS" не утруждая себя программированием ROM:

     - M 100 L 200 ES:100

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

     - M ES:100 L 200 100

что скопирует данные туда, где они должны быть. Если мы не изменяли данные в памяти по адресу 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. Они изменяют ход выполнения программы, поэтому может случиться так, что выполнение начнется с середины какой-нибудь инструкции, что приведет к крайне нежелательным результатам.

Как говорили монашка, натягивая презерватив на свечу: "Береженого бог бережет"...

Предо... (тьфу) ... помедитируйте с часок и поехали дальше...

ИМЯ, СЕСТRА, ИМЯ

Команда 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 не может быть прервана нажатием Cntl-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.

Медитируем...

НИРВАНА!!!

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

Если чего не так, то DZ Sashok подправит, а DZ Serrgio в следующем номере за меня извинится. На то он и босс, чтоб за мои ляпы задним местом своей головы отвечать. Гы... опять ему на голову кирпич свалится, скажи, Sashok? ;)