Жанр: Учеба
Ассемблер и программирование для IBM PC
...=13C6 CS=13C6 IP=0103 NV UP EI PL NZ NA PO NC
13C6:0103 03060200 ADD AX,[0002] DS:0002=0025
-T
AX=0148 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=13C6 ES=13C6 SS=13C6 CS=13C6 IP=0107 NV UP EI PL NZ NA PE NC
13C6:0107 A30400 MOV [0004],AX DS:0004=9A00
-T
AX=0148 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=13C6 ES=13C6 SS=13C6 CS=13C6 IP=0108 NV UP EI PL NZ NA PO NC
13C6:010A CB RETF
-D DS:0
13C6:0000 23 01 25 00 00 9A 2A 2A-2A F0 F5 02 2C 10 2E 03 #.%...***...,...
13C6:0010 2C 10 BD 02 2C 10 B1 0D-01 03 01 00 02 FF FF FF ,...,...........
13C6:0020 FF FF FF FF FF FF FF FF-FF FF FF FF EF 0F 64 00 ..............d.
13C6:0030 61 13 14 00 18 00 C7 13-FF FF FF FF 00 00 00 00 a...............
13C6:0040 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
13C6:0050 CD 21 CB 00 00 00 00 00-00 00 00 00 00 20 20 20 .!...........
13C6:0060 20 20 20 20 20 20 20 20 00 00 00 00 00 20 20 20 .....
13C6:0070 20 20 20 20 20 20 20 20-00 00 00 00 00 00 00 00 ........
-Q
__________________________________________________________________________
Рис.2.3. Трассировка машинных команд.
Теперь введите R для просмотра содержимого регистров и флагов и для
отображения первой команды. Регистры содержат те же значения, как при
старте первого примера. Команда отобразится в виде:
13C6:0100 A10000 MOV AX,[0000]
Так, как регистр CS содержит 13C6, то CS:100 содержит первую команду
A10000. Отладчик интерпретирует эту команду как MOV и определяет ссылку к
первому адресу [0000] в сегменте данных. Квадратные скобки необходимы для
указания ссылки к адресу памяти, а не к непосредственным данным.
Если бы квадратных скобок не было, то команда
MOV AX,0000
обнулила бы регистр AX непосредственным значением 0000.
Теперь введем команду T. Команда MOV AX,[0000] перешлет содержимое
слова, находящегося по нулевому смещению в сегменте данных, в регистр AX.
Содержимое 2301 преобразуется командой в 0123 и помещается в регистр AX.
Следующую команду ADD можно выполнить, введя еще раз команду T. В
результате содержимое слова в DS по смещению 0002 прибавится в регистр AX.
Теперь регистр AX будет содержать сумму 0123 и 0025, т.е. 0148.
Следующая команда MOV [0004],AX выполняется опять по вводу T. Эта
команда пересылает содержимое регистра AX в слово по смешению 0004. Для
просмотра изменений содержимого сегмента данных введите D DS:00. Первые
девять байт будут следующими:
значение в сегменте данных: 23 01 25 00 48 01 2A 2A 2A
величина смещения: 00 01 02 03 04 05 06 07 08
Значение 0148, которое было занесено из регистра AX в сегмент данных по
смещению 04 и 05, имеет обратное представление 4801. Заметьте что эти
шест. значения представлены в правой части экрана их символами в коде
ASCII. Например, шест.23 генерируется в символ #, а шест.25 - в символ %.
Три байта с шест. значениями 2A высвечиваются в виде трех звездочек (***).
Левая часть дампа показывает действительные машинные коды, которые
находятся в памяти. Правая часть дампа только помогает проще локализовать
символьные (срочные) данные.
Для просмотра содержимого сегмента кодов введите D DS:100 так, как
показано на рис.2.3. В заключении введите Q для завершения работы с
программой.
МАШИННАЯ АДРЕСАЦИЯ
________________________________________________________________
Для доступа к машинной команде процессор определяет ее адрес из
содержимого регистра CS плюс смещение в регистре IP. Например,
предположим, что регистр CS содержит шест.04AF (действительный адрес
04AF0), а регистр IP содержит шест. 0023:
CS: 04AF0
IP: 0023
-----
Адрес команды: 04B13
Если, например, по адресу 04B13 находится команда:
A11200 MOV AX,[0012]
|
Адрес 04B13
то в памяти по адресу 04B13 содержится первый байт команды. Процессор
получает доступ к этому байту и по коду команды (A1) определяет длину
команды - 3 байта.
Для доступа к данным по смещению [0012] процессор определяет адрес,
исходя из содержимого регистра DS (как правило) плюс смещение в операнде
команды. Если DS содержит шест.04B1 (реальный адрес 04B10), то
результирующий адрес данных определяется следующим образом:
DS: 04B10
Смещение: 0012
-----
Адрес данных: 04B22
Предположим, что по адресам 04B22 и 04B23 содержатся следующие
данные:
Содержимое: 24 01
| |
Адрес: 04B22 04B23
Процессор выбирает значение 24 из ячейки по адресу 04B22 и помещает
его в регистр AL, и значение 01 по адресу 04B23 - в регистр AH. Регистр AX
будет содержать в результате 0124. В процессе выборки каждого байта
команды процессор увеличивает значение регистра IP на единицу, так что к
началу выполнения следующей команды в нашем примере IP будет содержать
смещение 0026. Таким образом процессор теперь готов для выполнения
следующей команды, которую он получает по адресу из регистра CS (04AF0)
плюс текущее смещение в регистре IP (0026), т.е. 04B16.
Четная адресация
------------------
Процессор 8086, 80286 и 80386 действуют более эффективно, если в
программе обеспечиваются доступ к словам, расположенным по четным адресам.
В предыдущем примере процессор может сделать одну выборку слова по адресу
4B22 для загрузки его непосредственно в регистр. Но если слово начинается
на нечетном адресе, процессор выполняет двойную выборку. Предположим,
например, что команда должна выполнить выборку слова, начинающегося по
адресу 04B23 и загрузить его в регистр AX:
Содержимое памяти: |хх|24|01|хх|
|
Адрес: 04B23
Сначала процессор получает доступ к байтам по адресам 4B22 и 4B23 и
пересылает байт из ячейки 4B23 в регистр AL. Затем он получает доступ к
байтам по адресам 4B24 и 4B25 и пересылает байт из ячейки 4B23 в регистр
AH. В результате регистр AX будет содержать 0124.
Нет необходимости в каких-либо специальных методах программирования
для получения четной или нечетной адресации, не обязательно также знать
является адрес четным или нет. Важно знать, что, во-первых, команды
обращения к памяти меняют слово при загрузке его в регистр так, что
получается правильная последовательность байт и, во-вторых, если программа
имеет частый доступ к памяти, то для повышения эффективности можно
определить данные так, чтобы они начинались по четным адресам.
Например, поскольку начало сегмента должно всегда находиться по
четному адресу, первое поле данных начинается также по четному адресу и
пока следующие поля определены как слова, имеющие четную длину, они все
будут начинаться на четных адресах. В большинстве случаев, однако,
невозможно заметить ускорения работы при четной адресации из-за очень
высокой скорости работы процессоров.
Ассемблер имеет директиву EVEN, которая вызывает выравнивание данных
и команд на четные адреса памяти.
ПРИМЕР МАШИННЫХ КОДОВ: ОПРЕДЕЛЕНИЕ РАЗМЕРА ПАМЯТИ
________________________________________________________________
В первом упражнении в данной главе проводилась проверка размера
памяти (RAM), которую имеет компьютер. BIOS (базовая система ввода/вывода)
в ROM имеет подпрограмму, которая определяет размер памяти. Можно
обратиться в BIOS по команде INT, в данном случае по прерыванию 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 содержит размер памяти в шестнадцатиричном
формате. Теперь введите еще раз команду T для выхода из BIOS и возврата в
вашу программу. На экране появится команда RET для машинного кода CB,
который был введен вами.
СПЕЦИАЛЬНЫЕ СРЕДСТВА ОТЛАДЧИКА
________________________________________________________________
В операционной системе 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) показывает машинные коды для команд
ассемблера. Необходимо сообщить отладчику адреса первой и последней
команды, которые необходимо просмотреть (в данном случае 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, то произошла ошибка при вводе длины
программы, и необходимо повторить запись снова.
ОСНОВНЫЕ ПОЛОЖЕНИЯ НА ПАМЯТЬ
________________________________________________________________
Отладчик DOS DEBUG это достаточное мощное средство, полезное для
отладки ассемблерных программ. Однако следует быть осторожным с ее
использованием, особенно для команды E (ввод). Ввод данных в неправильные
адреса памяти или ввод некорректных данных могут привести к
непредсказуемым результатам. На экране в этом случае могут появиться
"странные" символы, клавиатура заблокирована или даже DOS прервет DEBUG и
перезагрузит себя с диска. Какие-либо серьезные повреждения вряд ли
произойдут, но возможны некоторые неожиданности, а также потеря данных,
которые вводились при работе с отладчиком.
Если данные, введенные в сегмент данных или сегмент кодов, оказались
некорректными, следует, вновь используя команду E, исправить их. Однако,
можно не заметить ошибки и начать трассировку программы. Но и здесь
возможно еще использовать команду E для изменений. Если необходимо начать
выполнение с первой команды, то следует установить в регистре командного
указателя (IP) значение 0100. Введите команду R (register) и требуемый
регистр в следующем виде:
R IP [Return]
Отладчик выдаст на экран содержимое регистра IP и перейдет в ожидание
ввода. Здесь следует ввести значение 0100 и нажать для проверки результата
команду R (без IP). 0тладчик выдаст содержимое регистров, флагов и первую
выполняемую команду. Теперь можно, используя команду T, вновь выполнить
трассировку программы.
Если ваша программа выполняет какие-либо подсчеты, то возможно
потребуется очистка некоторых областей памяти и регистров. Но убедитесь в
сохранении содержимого регистров CS, DS, SP и SS, которые имеют
специфическое назначение.
Прочитайте в руководстве по DOS главу о программе DEBUG. В настоящий
момент рекомендуется: вводный материал и следующие команды отладчика: дамп
(D), ввод (E), шестнадцатиричный (H), имя (N), выход (Q), регистры (R),
трассировка (T) и запись (W). Можно ознакомиться также и с другими
командами и проверить как они работают.
ВОПРОСЫ ДЛЯ САМОПРОВЕРКИ
________________________________________________________________
2.1. Напишите машинные команды для
а) пересылки шест. значения 4629 в регистр AX;
б) сложения шест. 036A с содержимым регистра AX.
2.2. Предположим, что была введена следующая е команда:
E CS:100 B8 45 01 05 25 00
Вместо шест. значения 45 предполагалось 54. Напишите команду E для
корректировки только одного неправильно введенного байта, т.е.
непосредственно замените 45 на 54.
2.3. Предположим, что введена следующая е команда:
E CS:100 B8 04 30 05 00 30 CB
а) Что представляют собой эти команды? (Сравните с первой
программой в этой главе).
б) После выполнения этой программы в регистре AX должно быть
значение 0460, но в действительности оказалось 6004. В чем ошибка и
как ее исправить?
в) После исправления команд необходимо снова выполнить программу
с первой команды. Какие две команды отладчика потребуются?
2.4. Имеется следующая программа в машинных кодах:
B0 25 D0 E0 B3 15 F6 E3 CB
Программа выполняет следующее:
- пересылает шест. значение 25 в регистр AL;
- сдвигает содержимое регистра AL на один бит влево (в
результате в AL будет 4A);
- пересылает шест. значение 15 в регистр BL;
- умножает содержимое регистра AL на содержимое регистра BL.
Используйте отладчик для ввода (E) этой программы по адресу CS:100. Не
забывайте, что все значения представлены в шестнадцатиричном виде. После
ввода программы наберите D CS:100 для просмотра сегмента кода. Затем
введите команду R и необходимое число команд T для пошагового выполнения
программы до команды RET. Какое значение будет в регистре AX в результате
выполнения программы?
2.5. Используйте отладчик для ввода (E) следующей программы в
машинных кодах:
Данные: 25 15 00 00
Машинный код: A0 00 00 D0 E0 F6 26 01 00 A3 02 00 CB
Программа выполняет следующее:
- пересылает содержимое одного байта по адресу DS:00 (25) в
регистр AL;
- сдвигает содержимое регистра AL влево на один бит (получая в
результате 4A);
- умножает AL на содержимое одного байта по адресу DS:01 (15);
- пересылает результат из AX в слово, начинающееся по адресу
DS:02.
После ввода программы используйте команды D для просмотра сегмента
данных и сегмента кода. Затем введите команду R и необходимое число команд
T для достижения конца программы (RET). В этот момент регистр AX должен
содержать результат 0612. Еще раз используйте команду D DS:00 и заметьте,
что по адресу DS:02 значение записано как 1206.
2.6. Для предыдущего задания (2.5) постройте команды для записи
программы на диск под именем TRIAL.COM.
2.7. Используя команду A отладчика, введите следующую про грамму:
MOV BX,25
ADD BX,30
SHL BX,01
SUB BX,22
NOP
RET
сделайте ассемблирование и трассировку выполнения этой программы до
команды NOP.
ГЛАВА 3 Требования языка ассемблер
__________________________________________________________________________
Ц е л ь: показать основные требования к программам на языке
ассемблера и этапы ассемблирования, компановки и выполнения программы.
ВВЕДЕНИЕ
________________________________________________________________
В гл.2 было показано как ввести и выполнить программу на машинном
языке. Несомненно при этом ощутима трудность расшифровки машинного кода
даже для очень небольшой программы. Сомнительно, чтобы кто-либо серьезно
кодировал программы на машинном языке, за исключением разных "заплат"
(корректировок) в программе на языках высокого уровня и прикладные
программы. Более высоким уровнем кодирования является уровень ассемблера,
на котором программист пользуется символическими мнемокодами вместо
машинных команд и описательными именами для полей данных и адресов памяти.
Программа написанная символическими мнемокодами, которые используются
в языке ассемблера, представляет собой исходный модуль. Для формирования
исходного модуля применяют программу DOS EDLIN или любой другой подходящий
экранный редактор. Затем с помощью программы ассемблерного транслятора
исходный текст транслируется в машинный код, известный как объектная
программа. И наконец, программа DOS LINK определяет все адресные ссылки
для объектной программы, генерируя загрузочный модуль.
В данной главе объясняются требования для простой программы на
ассемблере и показаны этапы ассемблирования, компановки и выполнения.
КОММЕНТАРИИ В ПРОГРАММАХ НА АССЕМБЛЕРЕ
________________________________________________________________
Использование комментариев в программе улучшает ее ясность, особенно
там, где назначение набора команд непонятно. Комментарий всегда начинаются
на любой строке исходного модуля с символа точка с запятой (;) и ассемблер
полагает в этом случае, что все символы, находящиеся справа от ; являются
комментарием. Комментарий может содержать любые печатные символы, включая
пробел.
Комментарий может занимать всю строку или следовать за командой на
той же строке, как это показано в двух следующих примерах:
1. ;Эта строка полностью является комментарием
2. ADD AX,BX ;Комментарий на одной строке с командой
Комментарии появляются только в листингах ассемблирования исходного
модуля и не приводят к генерации машинных кодов, поэтому можно включать
любое количество комментариев, не оказывая влияния на эффективность
выполнения программы. В данной книге команды ассемблера представлены
заглавными буквами, а комментарии - строчными (только для
удобочитаемости).
ФОРМАТ КОДИРОВАНИЯ
________________________________________________________________
Основной формат кодирования команд ассемблера имеет следующий вид:
[метка] команда [операнд(ы)]
Метка (если имеется), команда и операнд (если имеется) разделяются по
крайней мере одним пробелом или символом табуляции. Максимальная длина
строки - 132 символа, однако, большинство предпочитают работать со
строками в 80 символов (соответственно ширине экрана). Примеры
кодирования:
Метка Команда Операнд
COUNT DB 1 ;Имя, команда, один операнд
MOV AX,0 ;Команда, два операнда
Метки
-------
Метка в языке ассемблера может содержать следующие символы:
Буквы: от A до Z и от a до z
Цифры: от 0 до 9
Спецсимволы: знак вопроса (?)
точка (.) (только первый символ)
знак "коммерческое эт" (@)
подчеркивание (-)
доллар ($)
Первым символом в метке должна быть буква или спецсимвол. Ассемблер
не делает различия между заглавными и строчными буквами. Максимальная
длина метки - 31 символ. Примеры меток: COUNT, PAGE25, $E10. Рекомендуется
использовать описательные и смысловые метки. Имена регистров, например,
AX, DI или AL являются зарезервированными и используются только для
указания соответствующих регистров. Например, в команде
ADD AX,BX
ассемблер "знает", что AX и BX относится к регистрам. Однако, в команде
MOV REGSAVE,AX
ассемблер воспримет имя REGSAVE только в том случае, если оно будет
определено в сегменте данных. В прил.3 приведен список всех
зарезервированных слов ассемблера.
Команда
---------
Мнемоническая команда указывает ассемблеру какое действие должен
выполнить данный оператор. В сегменте данных команда (или директива)
определяет поле, рабочую область или константу. В сегменте кода команда
определяет действие, например, пересылка (MOV) или сложение (ADD).
Операнд
---------
Если команда специфицирует выполняемое действие, то операнд
определяет а) начальное значение данных или б) элементы, над которыми
выполняется действие по команде. В следующем примере байт COUNTER
определен в сегменте данных и имеет нулевое значение:
Метка Команда Операнд
COUNTER DB 0 ;Определить байт (DB) с нулевым значением
Команда может иметь один или два операнда, или вообще быть без
операндов. Рассмотрим следующие три примера:
Команда Операнд Комментарий
Нет операндов RET ;Вернуться
Один операнд INC CX ;Увеличить CX
Два операнда ADD AX,12 ;Прибавить 12 к AX
Метка, команда и операнд не обязательно должны начинаться с
какой-либо определенной позиции в строке. Однако, рекомендуется записывать
их в колонку для большей удобочитаемости программы. Для этого, например,
редактор DOS EDLIN обеспечивает табуляцию через каждые восемь позиций.
ДИРЕКТИВЫ
________________________________________________________________
Ассемблер имеет ряд операторов, которые позволяют управлять процессом
ассемблирования и формирования листинга. Эти операторы называются
псевдокомандами или директивами. Они действуют только в процессе
ассемблирования программы и не генерируют машинных кодов. Большинство
директив показаны в следующих разделах. В гл.24 подробно описаны все
директивы ассемблера и приведено более чем достаточно соответствующей
информации. Гл.24 можно использовать в качестве справочника.
Директивы управления листингом: PAGE и TITLE
----------------------------------------------
Ассемблер содержит ряд директив, управляющих форматом печати (или
листинга). Обе директивы PAGE и TITLE можно использовать в любой
программе.
Д и р е к т и в а PAGE. В начале программы можно указать количество
строк, распечатываемых на одной странице, и максимальное количество
символов на одной строке. Для этой цели служит директива PAGE. Следующей
директивой устанавливается 60 строк на страницу и 132 символа в строке:
PAGE 60,132
Количество строк на странице может быть в пределах от 10 до 255, а
символов в строке - от 60 до 132. По умолчанию в ассемблере установлено
PAGE 66,80.
Предположим, что счетчик строк установлен на 60. В этом случае
ассемблер, распечатав 60 строк, выполняет прогон листа на начало следующей
страницы и увеличивает номер страницы на единицу. Кроме того можно
...Закладка в соц.сетях