Специальные средства отладчика 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Специальные средства отладчика



 

В операционной системе DOS версии 2.0 и старше можно использовать

DEBUG для ввода команд ассемблера так же, как и команд машинного языка. На

практике можно пользоваться обоими методами.

 

 

Команда A

-----------

Команда отладчика A (Assemble) переводит DEBUG в режим приема команд

ассемблера и перевода их в машинные коды. Установим начальный адрес

следующим образом:

 

A 100 [Return]

 

Отладчик выдаст значение адреса сегмента кодов и смещения в виде

хххх:0100. Теперь можно вводить каждую команду, завершая клавишей Return.

Когда вся программа будет введена, нажмите снова клавишу Return для выхода

из режима ассемблера. Введите следующую программу:

 

MOV AL,25 [Return]

MOV BL,32 [Return]

ADD AL,BL [Return]

RET [Return]

 

по завершению на экране будет следующая информация:

 

хххх:0100 MOV AL,25

хххх:0102 MOV BL,32

хххх:0104 ADD AL,BL

хххх:0106 RET

 

В этот момент отладчик готов к приему следующей команды. При нажатии

Return операция будет прекращена.

Можно видеть, что отладчик определил стартовые адреса каждой команды.

Прежде чем выполнить программу, проверим сгенерированные машинные коды.

 

 

Команда U

-----------

Команда отладчика U (Unassemble) показывает машинные коды для команд

ассемблера. Необходимо сообщить отладчику адреса первой и последней

команды, которые необходимо просмотреть (в данном cлучае 100 и 106).

Введите:

 

U 100,106 [и Return]

 

и на экране появится

 

хххх:0100 B025 MOV AL,25

хххх:0102 B332 MOV BL,32

хххх:0104 00D8 ADD AL,BL

хххх:0106 C3 RET

 

Теперь проведем трассировку выполнения программы, начиная с команды R для

вывода содержимого регистров и первой команды программы. С помощью команд

T выполним последовательно все команды программы.

Теперь вы знаете, как вводить программу в машинном коде или на языке

ассемблера. Обычно используется ввод на языке ассемблера, когда машинный

код неизвестен, а ввод в машинном коде - для изменения программы во время

выполнения. Однако в действительности программа DEBUG предназначена для

отладки программ и в следующих главах основное внимание будет уделено

использованию языка ассемблера.

 

 

Сохранение программы из отладчика

-----------------------------------

Можно использовать DEBUG для сохранения программ на диске в следующих

случаях:

 

1. После загрузки программы в память машины и ее модификации

необходимо сохранить измененный вариант. Для этого следует:

 

- загрузить программу по ее имени: DEBUG n:имя файла

[Return]

- просмотреть программу с помощью команды D и ввести

изменения по команде E,

- записать измененную программу: W [Return]

 

2. Необходимо с помощью DEBUG написать небольшую по объему

программу и сохранить ее на диске. Для этого следует:

 

- вызвать отладчик DEBUG,

- с помощью команд A (assemble) и E (enter) написать

программу,

- присвоить программе имя: N имя файла.COM [Return]. Тип

программы должен быть COM (см. гл.6 для пояснений по

COM-файлам),

- так как только программист знает, где действительно

кончается его программа, указать отладчику длину программы в

байтах. В последнем примере концом программы является команда

 

хххх:0106 C3 RET

 

Эта команда однобайтовая и поэтому размер программы будет равен

106 (конец) минус 100 (начало), т.е. 6.

- запросить регистр CX командой: R CX [Return]

- отладчик выдаст на этот запрос CX 0000 (нулевое значение)

- указать длину программы - 6,

- записать измененную программу: W [Return]

 

В обоих случаях DEBUG выдает сообщение "Writing nnnn bytes." (Запись

nnnn байтов). Если nnnn равно 0, то произошла ошибка при вводе длины

программы, и необходимо повторить запись cнова.

 

 

ОСНОВНЫЕ ПОЛОЖЕНИЯ НА ПАМЯТЬ

________________________________________________________________

 

Отладчик DOS DEBUG это достаточное мощное средство, полезное для

отладки ассемблерных программ. Однако следует быть осторожным с ее

использованием, особенно для команды E (ввод). Ввод данных в неправильные

адреса памяти или ввод некорректных данных могут привести к

непредсказуемым результатам. На экране в этом случае могут появиться

"странные" символы, клавиатура заблокирована или даже DOS прервет DEBUG и

перезагрузит себя с диска. Какие-либо серьезные повреждения вряд ли

произойдут, но возможны некоторые неожиданности, а также потеря данных,

которые вводились при работе с отладчиком.

Если данные, введенные в сегмент данных или сегмент кодов, оказались

некорректными, следует, вновь используя команду E, исправить их. Однако,

можно не заметить ошибки и начать трассиpовку программы. Но и здесь

возможно еще использовать команду E для изменений. Если необходимо начать

выполнение с первой команды, то следует установить в регистре командного

указателя (IP) значение 0100. Введите команду R (register) и требуемый

регистр в следующем виде:

 

R IP [Return]

 

Отладчик выдаст на экран содержимое регистра IP и перейдет в ожидание

ввода. Здесь следует ввести значение 0100 и нажать для проверки результата

команду R (без IP). 0тладчик выдаст содержимое регистров, флагов и первую

выполняемую команду. Теперь можно, используя команду T, вновь выполнить

трассировку программы.

Если ваша программа выполняет какие-либо подсчеты, то возможно

потребуется очистка некоторых областей памяти и регистров. Но yбедитесь в

сохранении содержимого регистров CS, DS, SP и SS, которые имеют

специфическое назначение.

Прочитайте в руководстве по DOS главу о программе DEBUG. В настоящий

момент рекомендуется: вводный материал и следующие команды oтладчика: дамп

(D), ввод (E), шестнадцатиричный (H), имя (N), выход (Q), регистры (R),

трассировка (T) и запись (W). Можно oзнакомиться также и с другими

командами и проверить как они работают.

 

Машинная адресация

Для доступа к машинной команде процессор определяет ее адрес из

содержимого регистра CS плюс смещение в регистре IP. Например,

предположим, что регистр CS содержит шест.04AF (действительный адрес

04AF0), а регистр IP содержит шест. 0023:

 

CS: 04AF0

IP: 0023

-----

Адрес команды: 04B13

 

Если, например, по адресу 04B13 находится команда:

 

A11200 MOV AX,[0012]

|

Адрес 04B13

 

то в памяти по адресу 04B13 содержится первый байт команды. Процессор

получает доступ к этому байту и по коду команды (A1) oпределяет длину

команды - 3 байта.

Для доступа к данным по смещению [0012] процессор определяет aдрес,

исходя из содержимого регистра DS (как правило) плюс cмещение в операнде

команды. Если DS содержит шест.04B1 (реальный адрес 04B10), то

результирующий адрес данных определяется cледующим образом:

 

DS: 04B10

Смещение: 0012

-----

Адрес данных: 04B22

 

Предположим, что по адресам 04B22 и 04B23 содержатся следующие

данные:

 

Содержимое: 24 01

| |

Адрес: 04B22 04B23

 

Процессор выбирает значение 24 из ячейки по адресу 04B22 и помещает

его в регистр AL, и значение 01 по адресу 04B23 - в регистр AH. Регистр AX

будет содержать в результате 0124. В процессе выборки каждого байта

команды процессор увеличивает значение регистра IP на единицу, так что к

началу выполнения следующей команды в нашем примере IP будет содержать

смещение 0026. Таким обpазом процессор теперь готов для выполнения

следующей команды, которую он получает по адресу из регистра CS (04AF0)

плюс текущее смещение в регистре IP (0026), т.е. 04B16.

 

 

Четная адресация

------------------

Процессор 8086, 80286 и 80386 действуют более эффективно, eсли в

программе обеспечиваются доступ к словам, расположенным по четным адресам.

В предыдущем примере процессор может сделать oдну выборку слова по адресу

4B22 для загрузки его непосредственно в регистр. Но если слово начинается

на нечетном адресе, процессор выполняет двойную выборку. Предположим,

например, что команда должна выполнить выборку слова, начинающегося по

адреcу 04B23 и загрузить его в регистр AX:

 

Содержимое памяти: |хх|24|01|хх|

|

Адрес: 04B23

 

Сначала процессор получает доступ к байтам по адресам 4B22 и 4B23 и

пересылает байт из ячейки 4B23 в регистр AL. Затем он получает доступ к

байтам по адресам 4B24 и 4B25 и пересылает байт из ячейки 4B23 в регистр

AH. В результате регистр AX будет содержать 0124.

Нет необходимости в каких-либо специальных методах программирования

для получения четной или нечетной адресации, не обязательно также знать

является адрес четным или нет. Важно знать, что, во-первых, команды

обращения к памяти меняют слово при загрузке его в регистр так, что

получается правильная последовательность байт и, во-вторых, если программа

имеет частый доступ к памяти, то для повышения эффективности можно

определить данные так, чтобы они начинались по четным адресам.

Например, поскольку начало сегмента должно всегда находиться по

четному адресу, первое поле данных начинается также по четному адресу и

пока следующие поля определены как слова, имеющие четную длину, они все

будут начинаться на четных адресах. В большинстве случаев, однако,

невозможно заметить ускорения работы при четной адресации из-за очень

высокой скорости работы процессоров.

Ассемблер имеет директиву EVEN, которая вызывает выравнивание данных

и команд на четные адреса памяти.

 

 

ПРИМЕР МАШИННЫХ КОДОВ: ОПРЕДЕЛЕНИЕ РАЗМЕРА ПАМЯТИ

________________________________________________________________

 

В первом упражнении в данной главе проводилась проверка размера

памяти (RAM), которую имеет компьютер. BIOS (базовая система ввода/вывода)

в ROM имеет подпрограмму, которая определяет pазмер памяти. Можно

обратиться в BIOS по команде INT, в данном cлучае по прерыванию 12H. В

результате BIOS возвращает в регистр AX размер памяти в килобайтах.

Загрузите в память DEBUG и введите для INT 12H и RET следующие машинные

коды:

 

E CS:100 CD 12 CB

 

Нажмите R (и Return) для отображения содержимого регистров и первой

команды. Регистр IP содержит 0100, при этом высвечивается команда INT 12H.

Теперь нажмите T (и Return) несколько раз и просмотрите выполняемые

команды BIOS (отладчик показывает мнемокоды, хотя в действительности

выполняются машинные коды):

 

STI

PUSH DS

MOV AX,0040

MOV DS,AX

MOV AX,[0013]

POP DS

IRET

 

В этот момент регистр AX содержит размер памяти в шестнадцатиpичном

формате. Теперь введите еще раз команду T для выхода из BIOS и возврата в

вашу программу. На экране появится команда RET для машинного кода CB,

который был введен вами.

Требования языка ассемблера

Язык ассе́мблера — машинно-ориентированный язык низкого уровня с командами, обычно соответствующими командам машины, который может обеспечить дополнительные возможности вроде макрокоманд[1]; автокод, расширенный конструкциями языков программирования высокого уровня, такими как выражения, макрокоманды, средства обеспечения модульности программ. Команды языка ассемблера один к одному соответствуют командам процессора. Фактически, они и представляют собой более удобную для человека символьную форму записи — мнемокоды — команд и их аргументов. При этом одной команде языка ассемблера может соответствовать несколько вариантов команд процессора.[4]

 

Кроме того, язык ассемблера позволяет использовать символические метки вместо адресов ячеек памяти, которые при ассемблировании заменяются на вычисляемые ассемблером или компоновщиком абсолютные или относительные адреса, а также так называемые директивы (команды ассемблера, не переводимые в машинные команды процессора, а выполняемые самим ассемблером).

Директивы ассемблера позволяют, в частности, включать блоки данных, задать ассемблирование фрагмента программы по условию, задать значения меток, использовать макрокоманды с параметрами.

Каждая модель (или семейство) процессоров имеет свой набор — систему — команд и соответствующий ему язык ассемблера. Наиболее популярные синтаксисы языков ассемблера — Intel-синтаксис и AT&T-синтаксис.

Существуют компьютеры, реализующие в качестве машинного язык программирования высокого уровня (Форт, Лисп, Эль-76). Фактически, в таких компьютерах они выполняют роль языков ассемблера.

(Использование комментариев в программе улучшает ее

ясность, oсобенно там, где назначение набора команд

непонятно. Комментаpий всегда начинаются на любой строке

исходного модуля с символа точка с запятой (;) и ассемблер

полагает в этом случае, что все символы, находящиеся справа

от; являются комментарием. Комментарий может содержать

любые печатные символы, включая пробел.

Комментарий может занимать всю строку или следовать за

командой на той же строке, Основной формат кодирования команд ассемблера имеет

следующий вид:

 

[метка] команда [операнд(ы)]

 

Метка (если имеется), команда и операнд (если имеется)

pазделяются по крайней мере одним пробелом или символом

табуляции. Максимальная длина строки - 132 символа. Первым символом в метке должна быть буква или спецсимвол.

Ассемблер не делает различия между заглавными и строчными

буквами. Максимальная длина метки - 31 символ. Примеры

меток: COUNT, PAGE25, $E10. Рекомендуется использовать

описательные и смысловые метки. Имена регистров, например,

AX, DI или AL являются зарезервированными и используются

только для указания соответствующих регистров.)

Директивы

Ассемблер имеет ряд операторов, которые позволяют упpавлять процессом

ассемблирования и формирования листинга. Эти операторы называются

псевдокомандами или директивами. Они действуют только в процессе

ассемблирования программы и не генерируют машинных кодов. Большинство

директив показаны в следующих разделах. В гл.24 подробно описаны все

директивы ассемблера и приведено более чем достаточно соответствующей

информации. Гл.24 можно использовать в качестве справочника.

 

 

Директивы управления листингом: PAGE и TITLE

----------------------------------------------

Ассемблер содержит ряд директив, управляющих форматом печати (или

листинга). Обе директивы PAGE и TITLE можно использовать в любой

программе.

 

 

Д и р е к т и в а PAGE. В начале программы можно указать количество

строк, распечатываемых на одной странице, и максимальное количество

символов на одной строке. Для этой цели cлужит директива PAGE. Следующей

директивой устанавливается 60 строк на страницу и 132 символа в строке:

 

PAGE 60,132

 

Количество строк на странице может быть в пределах от 10 до 255, а

символов в строке - от 60 до 132. По умолчанию в ассемблере установлено

PAGE 66,80.

Предположим, что счетчик строк установлен на 60. В этом случае

ассемблер, распечатав 60 строк, выполняет прогон листа на начало следующей

страницы и увеличивает номер страницы на eдиницу. Кроме того можно

заставить ассемблер сделать прогон листа на конкретной строке, например, в

конце сегмента. Для этого необходимо записать директиву PAGE без

операндов. Ассемблер автоматически делает прогон листа при обработке

диpективы PAGE.

 

 

Д и р е к т и в а TITLE. Для того, чтобы вверху каждой страницы

листинга печатался заголовок (титул) программы, используется диpектива

TITLE в следующем формате:

 

TITLE текст

 

Рекомендуется в качестве текста использовать имя программы, под

которым она находится в каталоге на диске. Например, если программа

называется ASMSORT, то можно использовать это имя и описательный

комментарий общей длиной до 60 символов:

 

TITLE ASMSORT - Ассемблерная программа сортировки имен

 

В ассемблере также имеется директива подзаголовка SUBTTL, которая

может оказаться полезной для очень больших программ, содержащих много

подпрограмм.

 

 

Директива SEGMENT

-------------------

Любые ассемблерные программы содержат по крайней мере один сегмент -

сегмент кода. В некоторых программах используется сегмент для стековой

памяти и сегмент данных для определения данных. Асcемблерная директива для

описания сегмента SEGMENT имеет следующий формат:

 

Имя Директива Операнд

имя SEGMENT [параметры]

.

.

.

имя ENDS

 

Имя сегмента должно обязательно присутствовать, быть уникальным и

соответствовать соглашениям для имен в ассемблере. Директива ENDS

обозначает конец сегмента. Обе директивы SEGMENT и ENDS должны иметь

одинаковые имена. Директива SEGMENT может содержать три типа параметров,

определяющих выравнивание, объединение и класс.

 

1. В ы р а в н и в а н и е. Данный параметр определяет границу

начала сегмента. Обычным значением является PARA, по которому сегмент

устанавливается на границу параграфа. В этом случае начальный адрес

делится на 16 без остатка, т.е. имеет шест. адрес nnn0. В случае

отсутствия этого операнда ассемблер принимает по умолчанию PARA.

2. О б ъ е д и н е н и е. Этот элемент определяет объединяется

ли данный сегмент с другими сегментами в процессе компановки после

ассемблирования (пояснения см. в следующем разделе "Компановка

программы"). Возможны следующие типы объединений: STACK, COMMON,

PUBLIC, AT выражение и MEMORY. Сегмент стека определяется следующим

образом:

имя SEGMENT PARA STACK

 

Когда отдельно ассемблированные программы должны объединяться

компановщиком, то можно использовать типы: PUBLIC, COMMON и MEMORY. В

случае, если программа не должна объединяться с другими программами,

то данная опция может быть опущена.

3. К л а с с. Данный элемент, заключенный в апострофы,

используется для группирования относительных сегментов при

компановке:

 

имя SEGMENT PARA STACK 'Stack'

 

Фрагмент программы на рис.3.1. в следующем разделе иллюстрирует

директиву SEGMENT и ее различные опции.

 

 

Директива PROC

----------------

Сегмент кода содержит выполняемые команды программы. Кроме того этот

сегмент также включает в себя одну или несколько процедур, определенных

директивой PROC. Сегмент, содержащий только одну процедуру имеет следующий

вид:

имя-сегмента SEGMENT PARA

имя-процедуры PROC FAR Сегмент

. кода

. с

. одной

RET процедурой

имя-процедуры ENDP

имя-сегмента ENDS

 

Имя процедуры должно обязательно присутствовать, быть уникальным и

удовлетворять соглашениям по именам в ассемблере. Операнд FAR указывает

загрузчику DOS, что начало данной процедуры является точкой входа для

выполнения программы.

Директива ENDP определяет конец процедуры и имеет имя, аналогичное

имени в директиве PROC. Команда RET завершает выполнение программы и в

данном случае возвращает управление в DOS.

Сегмент может содержать несколько процедур (см. гл.7).

 

 

Директива ASSUME

------------------

Процессор использует регистр SS для адресации стека, регистр DS для

адресации сегмента данных и регистр CS для адресации cегмента кода.

Ассемблеру необходимо сообщить назначение каждого сегмента. Для этой цели

служит директива ASSUME, кодируемая в сегменте кода следующим образом:

 

Директива Операнд

ASSUME SS:имя_стека,DS:имя_с_данных,CS:имя_с_кода

 

Например, SS:имя_стека указывает, что ассемблер должен ассоциировать

имя сегмента стека с регистром SS. Операнды могут записываться в любой

последовательности. Регистр ES также может присутствовать в числе

операндов. Если программа не использует регистр ES, то его можно опустить

или указать ES:NOTHING.

 

 

Директива END

---------------

Как уже показано, директива ENDS завершает сегмент, а директива ENDP

завершает процедуру. Директива END в свою очередь полностью завершает всю

программу:

 

Директива Операнд

END [имя_процедуры]

 

Операнд может быть опущен, если программа не предназначена для

выполнения, например, если ассемблируются только определения данных, или

эта программа должна быть скомпанована с другим (главным) модулем. Для

обычной программы с одним модулем oперанд содержит имя, указанное в

директиве PROC, которое было oбозначено как FAR.

 

 

Инициализация программы

DOS имеет четыре требования для инициализации ассемблерной

EXE-программы: 1) указать ассемблеру, какие cегментные регистры должны

соответствовать сегментам, 2) сохранить в стеке адрес, находящийся в

регистре DS, когда программа начнет выполнение, 3) записать в стек нулевой

адрес и 4) загрузить в регистр DS адрес сегмента данных.

Выход из программы и возврат в DOS сводится к использованию команды

RET.

1. ASSUME – это ассемблерная директива, которая устанавливает

 

для ассемблера соответствие между конкретными сегментами и

 

сегментными регистрами

Ассоциируя сегменты с сегментными регистрами, ассемблер сможет

определить смещения к отдельным областям в каждом сегменте. Например,

каждая команда в сегменте кодов имеет определенную длину: первая

команда имеет смещение 0, и если это двухбайтовая команда, то вторая

команда будет иметь смещение 2 и т.д.

2. Загрузочному модулю в памяти непосредственно предшествует

256-байтовая (шест.100) область, называемая префиксом программного

сегмента PSP. Программа загрузчика использует регистр DS для

установки адреса начальной точки PSP. Пользовательская программа

должна сохранить этот адрес, поместив его в стек. Позже, команда RET

использует этот адрес для возврата в DOS.

3. В системе требуется, чтобы следующее значение в стеке

являлось нулевым адресом (точнее, смещением). Для этого команда SUB

очищает регистр AX, вычитая его из этого же регистра AX, а команда

PUSH заносит это значение в стек.

4. Загрузчик DOS устанавливает правильные адреса стека в

регистре SS и сегмента кодов в регистре CS. Поскольку программа

загрузчика использует регистр DS для других целей, необходимо

инициализировать регистр DS двумя командами MOV

5. Команда RET обеспечивает выход из пользовательской программы

и возврат в DOS, используя для этого адрес, записанный в стек в

начале программы командой PUSH DS. Другим обычно используемым выходом

является команда INT 20H.



Поделиться:


Последнее изменение этой страницы: 2016-08-15; просмотров: 391; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.117.153.38 (0.196 с.)