Data Options Uindov Help
BEADY |
Ё File Edit Uieu Bun Breakpoints -tiJ-flodiile: p File: p.asn 4 ~ -™
;0пиием сегмент конанд
assune CS:codes ,DS:data
;Откроен сегмент команд ;Настроим DS :на сегмент данных |
codes segnent
' begin: nou AX,data
*ou DS.AX
;Выведем на экран строку текста
;Функция DOS вывода на экран;Адрес выводимой строки;Вызов DOS ;Функция DOS завершения программы ;Битов DOS ;Закроем сегмент команд |
пои AH,G9h
пои DX,offset nsg
Int 21h
:Завершим программу
пои flX,4CeOh
Int 21h
codes ends
:0пинем сегмент данных
data segment.'Откроен сегиент данных
nsg db 'Программа работает!$'
data ends;Закроем сегиент данных
Fl-4telp F2-Bkpt ГЗ-Nod F4-Here FS-Zoon Fo-Next F7-Trace F8-Step FS-Run Fie-Henu |
рис. 2.3. Начальный кадр отладчика с текстом отлаживаемой программы. |
;0пишем сегмент стека
Глава 2
Основы программирования
В процессе отладки программы на экран приходится выводить много дополнительных окон; они перекрываются и часто скрывают друг друга. Чтобы увидеть их все одновременно, размер окон приходится уменьшать, а сами окна перемещать по экрану. Режим изменения размеров и положения окна включается командой <Ctrl>+<F5>, после чего клавиши со стрелками перемешают окно по экрану, а те же клавиши при нажатой клавише <Shift> позволяют изменять его размер. Выход из режима настройки окна осуществляется нажатием клавиши <Enter>.
Начальное окно отладчика даст слишком мало информации для отладки программы. В нем можно выполнять программу по частям до местоположения курсора (клавиша <F4>) и команда за командой (клавиша <F8>); можно также с помощью окна Watches наблюдать изменения заданных полей данных. Однако для отладки программы на уровне языка ассемблера необходимо контролировать все регистры процессора, включая регистр флагов, а также, во многих случаях, поля данных вне программы (например, векторы прерываний или системные таблицы). Гораздо более информативным является «окно процессора», которое вызывается с помощью пункта View>CPU верхнего меню или командой <AK>+<V>+<C> (рис. 2.1).
Ё File Ш ------- Module:; Опишем се assume codes ^ begin: * : Выведен н * | •r U leu Run Breakpoints Data Options Uindou | Help ~ — —Z^l] | R | EftDV 13=n сМЭ z=0 s=0 o=0 p=0 a=0 i=l | |
ttpRbegin a cs:OOQGKB8071Z *begin: now AX, data:Hact cs:8003 8ED8 мои DS.ftX:ма сегнемт 1 cs:Q005 B409 мои ЙН.ОЭЬ; Функция DOi cs:0007 BftOOOO мои OX, offset nsg:Ащ>| cs:OOOA CDZ1 int Zlh: Вызов DOS | cs:00QC B8Q04C мои AX,4COOh; Функция 1 cs:OOOF CB21 int Zlh; Визой DOS I > cs:0011 0000 add [Ьх+sll.al I cs:0013 0000 add Ebx+sil.&l 1 cs:001S 0000 add Ebx*sU,al i cs:0017 0000 add Cbx*siJ,al | cs:OQ19 0000 add Ebx+si],al -» ds:OOQO CD 20 7D 9D 00 9ft FO FE - >3 ЪБ1 | ax 0000 bx 0000 ex 0000 dx 0000 si 0000 di 0000 bp 0000 sp 0100 ds 11F5 | ||||
Оию исяоакогэ текста | Т | ||||
ss 1209 cs 1205 | Окно [тагов | ||||
ip 0000 | |||||
Окно регистров | |||||
Окно дал па памяти | _. ds:0008 ID FO 3Z OB B9 OF 6B 07 *E2fifl*R. ds:0010 H OD 28 08 14 OD 9Z OB WCQflTTff ds:0018 01 01 01 00 02 06 FF FF 933 B» | ss:G10Z 04 ss: 01001-52 --------------- 1 | 03 FB | ||
Fl-Help FZ-Bkpt F3-Hod F4-Here F5-2oon F6-Hext F?-Trace F8-Step F9-Run FlG-dem
Рис. 2.4. Окно процессора с внутренними окнами.
Окно процессора состоит, в свою очередь, из 5 внутренних окон для наблюдения текста программы на языке ассемблера и в машинных кодах, регистров процессора, флагов, стека и содержимого памяти. С помощью этих окон можно полностью контролировать ход выполнения отлаживае-
мой программы. Для того чтобы можно было работать с конкретным окном, например, прокручивать его содержимое, надо сделать его активным, щелкнув по нему мышью. Перейти из окна в окно можно также с помощью клавиатуры, нажимая клавишу Tab. Посмотрим, какие сведения можно изшгечь из содержимого окна процессора.
Содержимое сегментных регистров DS и ES одинаково и составляет llF5h. Эта значит, что программа загружена в память, начиная с физического адреса 11F50, т.е. приблизительно с 70-го килобайта. Чем заняты первые 70 Кбайт памяти' Обычно компьютер конфигурируется так, что в обычной памяти размещается только малая часть DOS (около 16 Кбайт), драйверы обслуживания расширенной памяти и резидентная часть COMMAND.COM. Основная часть DOS, остальные драйверы и необходимые резидентные программы (например, русификатор) переносятся в расширенную память. В этом случае системные области в начале памяти занимают всего 20 — 25 Кбайт. Тем не менее наша программа начинается не с 25-го, а с 70-го килобайта. Произошло это из-за того, что программа запущена под управлением отладчика, который сначала загружается в память сам, и лишь затем загружает отлаживаемую программу. Но отсюда следует, что если бы мы запустили программу без отладчика, она попшга бы на другое место в памяти, гораздо ближе к ее началу. В большинстве случаев это обстоятельство не имеет особого значения, так как любая программа должна одинаково успешно выполняться в любом месте памяти, однако необходимо отдавать себе отчет, что отладчик изменяет операционную среду программы (в частности, переносит ее на другое место в памяти). Строго говоря, программа под управлением отладчика выполняется не совсем так, как она выполнялась бы непосредственно в DOS.
Еще один пример «самодеятельности» отладчика можно увидеть в том же окне регистров процессора. Содержимое всех регистров общего назначения (АХ, BX, CX, DX, SI, DI и ВР) равно 0. Отсюда можно сделать вывод, что DOS, загружая программу в память, очищает регистры процессора. Однако на самом деле это совсем не так! Регистры очищает не DOS, а отладчик. При обычном запуске программы исходное содержимое регистров практически непредсказуемо, и ни в косм случае нельзя рассчитывать, что в них будут нули. Иногда можно столкнуться и с более тонким влиянием отладчика на ход выполнения программы, вплоть до того, что некоторые виды программ, например, управляющие подключенной к компьютеру аппаратурой, в отладчике будут выполняться просто неверно.
Итак, после загрузки программы в память содержимое регистров DS и ES оказалось одинаковым. Это вполне естественно, если вспомнить, что перед выполнением оба регистра указывают на префикс программы (см. рис. 1.9). Вслед за префиксом располагается сегмент команд и поскольку префикс всегда занимает точно lOOli байт (т.е. 10h параграфов по 16 байт), то содержимое CS в нашем случае должно быть равно llF5h + 10h = 1205U. Так оно и есть (см. рис. 2.4).
Глава 2
Основы программирования
В нашем примере программа должна начать выполняться с метки begin, поскольку именно эту метку мы указали в качестве операнда завершающей директивы end. Эта метка относится к самой первой команде сегмента команд и ее значение (или, что то же самое, смещение первой команды программы) должно быть равно 0. Поэтому исходное значение указателя команд, как это видно из рис. 2.4, тоже равно 0. В дальнейшем, по мере выполнения команд, значение IP будет возрастать. Выполним две первые команды программы, дважды нажав клавишу <F8>. Состояние программы после этой операции показано на рис. 2.5.
Ё File Edit Uieu Run Breakpoints Data Options Uindou Help HEADY | |||
f — — — Mrvlii 1^ • rt Filp' n Л4?и V— --------------------- — 1 — ---- ------ " ------ ъ IHJUUtl^' p [11C* p.tlirl • i l | |||
^ boo ЙН.ОЭп | |||
• пои DX, offset nsg | | |||
c=0 | |||
; Завершим • | IpRbeg in * ax 1207 cs:QOOQ B80712 «begin: nov AX, data;Haci cs:0063 8ED8 * nou DS.AX;на сегмент cs:0065HH09 * паи AH.OSh; Функция ВО | bx 0000 ex 0600 dx 0060 | z=0 s=0 o=0 |
codes | cs:6Q07 ВАЭО60 * пои DXjoffset nsg;Адр cs:060A CD21 * int Zlh; Вызов DOS cs:OQ6C B8064C * поч ftX,4CQOh; Функция cs:60QF CD21 + int Zlh; Вы зов DOS cs;0011 0060 add [bx^sil.al | si 0006 di 0000 bp 0060 sp 6106 ds 1207 es 11F5 | p=0 а-Л |
а-U i=i d=o | |||
cs:0013 0000 add U>x+si],al cs:0015 0000 add Cbx+sibal cs:0017 6000 add Ibx+sU.al cs:0619 0000 add [bx*sil,al | ss 1НОЭ cs 1205 ' ip 0005 | ||
es:60Q6 CD 26 7D 3D 06 9ft FO ГЕ - >3 ЪЁ| | |||
es:0008 ID FO 32 OB B9 OF 6B 07 -EZdfl+k* es:0010 И 6D ZQ 08 14 6D 92 OB VtQlTId es:601B 01 01 61 60 62 06 FF FF 030 B» | ss:0162 0463 ss:6100>-52FB |
Fl-Help FZ-Bkpt F3-t1od F4-Here F5-Zoon F6-Hext F7-Trftce F8-Step F9-Bun FlO-fleiu
Рис. 2.5. Состояние программы после выполнения двух первых команд.
Видно, что указатель команд получил значение 5 и показывает на очередную (еще не выполнявшуюся) команду mov AH,09h, относительный адрес которой равен 5. Сегментный регистр DS получил значение 1207И, что должно соответствовать сегментному адресу сегмента данных. Вспомним, что сегмент команд у нас занимает llh байт и требует в памяти 2 параграфа. Сегмент команд имеет сегментный адрес 1205h, следовательно, сегментный адрес сегмента данных должен быть равен 1207U, что
мы и получили.
Обратим внимание на самую правую колонку в окне процессора, в которой индицируются состояния флагов процессора. Как уже говорилось, состояния флагов заново устанавливаются процессором после выполнения каждой команды, и по ним можно в определенной степени судить о результате команды. С самого начала у нас был устаноачен только флаг IF (i в окне отладчика), что свидетельствует о включенном механизме аппарат-
ных прерываний; остальные флаги сброшены. После выполнения двух первых команд состояние регистра флагов не изменилось. Произошло это потому, что команда пересылки mov не изменяет состояния флагов. Поскольку в нашей программе нет никаких команд, кроме mov и hit, а команда int тоже состояния флагов обычно не изменяет, то наблюдать с помощью нашего примера функционирование регистра флагов не удастся.
Рассмотрим теперь стек. Сегмент данных имеет у нас размер 14h байт, и под него в памяти надлежит выделить 2 параграфа. Это объясняет содержимое сегментного регистра стека SS — 12091г. Под стек отведено 256 байт, поэтому исходное положение SP (под дном стека) соответствует смещению lOOh.
Наконец, стоит еще обратить внимание на нижнюю половину окна команд, заполненную странными командами add [bx+si],al. Таких команд, да еще в таком количестве, в нашей программе нет, их «придумал» отладчик, пытаясь деассемблировать промежуток между сегментом команд и сегментом данных, заполненный нулями. Код OOOOh соответствует команде add [bx+si],al, которую и изобразил отладчик.
Таким образом, рассмотрев информацию, предоставленную отладчиком, мы подтвердили все предыдущие рассуждения о расположении в памяти сегментов программы и об инициализации регистров процессора при загрузке программы в память.
Обратимся теперь к окну дампа. При запуске отладчика в окно дампа выводится содержимое памяти, начиная с адреса DS:OOOOh, т.е. начало префикса программы (см. рис. 2.4 и 2.5). Для того, чтобы вывести на экран что-либо иное, надо воспользоваться командой <Alt>+<F10>, которая для каждого внутреннего окна процессора открывает дополнительное меню. Вид этого меню зависит от того, какое окне было активным в момент ввода команды. На рис. 2.6 показано дополнительное меню окна дампа.