вторник, 12 мая 2009 г.

Здравствуйте, я ваша тётя!

Продолжение сериала с программой hello.asm :)
Сперва медитативная часть. Вспоминаем, что один и тот же физический байт памяти может иметь различные логические адреса, определяемые разными, но при этом эквивалентными парами сегмент-смещение. Скриншот для медитации:

Замечаем, что в выводе команды d cs:0, наши данные располагаются по адресу 144B:0020, а в выводе команды d ds:0, наши данные располагаются по адресу 144D:0000. Дам был сделан после исполнения двух первых команд программы. Медитируем и просветляемся :).
Далее практическая часть.
Справедливости ради, оттранслируем hello.asm при помощи MASM с ключами генерации листинга и карты. Запускаем m.bat и даем команду ml /Fl /Fm hello.asm. Замечаем что для MASM надо указывать расширение – .asm. В результате работы ассемблера получаем четыре файла: hello.obj, hello.lst, hello.map и hello.exe.

Посмотрим содержимое файла hello.lst.

Сгенерированный MASM-ом листинг очень похож на тот, что создал TASM. Есть лишь не большие различия. В листинге MASM отсутствуют номера строк программы. Так же, немного различается, вывод команд по смещениям 0000 и 0007, хотя суть одна и та же.
Теперь начнем эксперименты с выравниваниями сегментов. Изменим немного программу hello.asm добавив атрибут выравнивания byte к командам описаниям сегментов. Cохраним текст программы, как hello1.asm, ассемблируем с генерацией листинга, и посмотрим, что получилось.
Из последнего скриншота видно, что пропали пустые промежутки между сегментом кода и сегментом данных, и сегментом данных и сегментом стека. Значит программа hello1.exe, по идее, должна стать на 27 байт меньше, то есть 805 байт. Так оно и есть.

Если внимательно посмотреть, то немного изменились и заголовки программ. Но с форматом заголовков буду разбираться попозже. Щас играемся с сегментами.
Теперь опять медитация. Будем созерцать под отладчиком обе программы: hello.exe и hello1.exe.
Для вывода дизассемблированного кода программы используется команда – u (unassemble), параметрами которой является диапазон смещений в сегменте. Наша программа имеет размер 11h байт. То есть наши 11h байт располагаются в адресном пространстве с 0h по 10h. Чтобы вывести дизассемблированный листинг этого пространства даем команду u cs:0 10.
Как видно из дампов памяти отладчиков, в программе hello.exe присутствуют пустые промежутки (отмечены зеленым), в программе hello1.exe их нет, так как использовался атрибут выравнивания byte в директивах segment. В результате этого произошло смещение сегмента данных, что отразилось на команде mov dx,offset msg, которая в программе hello.exe имеет вид mov dx,0000, а в программе hello1.exemov dx,0001.
Еще один интересный момент это то, что команда mov ax,data в обеих программах имеет одинаковый машинный код mov ax,144D, не смотря на то, что в программе hello1.exe мы применили выравнивание параграфа. К чему бы это? И почему бы это? Вспоминаем, что сегментная часть адреса всегда кратна 16 или 10h. Наша программа занимает больше одного параграфа на 1 байт. Поэтому ассемблер, видя, что сегмент кода занимает больше одного параграфа, но меньше двух, определил сегментную часть адреса сегмента данных на 20h байт (2 параграфа) отстоящую от начала сегмента кода. Соответственно в программе hello.exe сегмент данных начинается на границе параграфа, то есть имеет смещение 0, а в программе hello1.exe, сегмент данных, из-за атрибута выравнивания, имеет смещение в 1 байт (в данном случае), от начала параграфа. Что мы и видим в коде команды mov dx,offset msg.

Теперь поперемещаем сегменты и посмотрим, как это отразится на листинге программы и ее коде. Создадим «новую» программку – hello2.asm. Определим в ней данные перед сегментом кода.

От сюда видно, что сегменты располагаются в том порядке, как они были объявлены в программе. Теперь помедитируем – посмотрим прогу под дебагером :)

Из дебагера видно, что данных не видно :) … ну при текущем расположении сегментов в программе…. Если внимательно смотрели предыдущие дампы, то данные сразу можно было видеть в выводе команды d cs:0. Теперь их не видно, так как данные располагаются выше в адресном пространстве, чем данные. Но все же при помощи хитрого хака, их можно увидеть еще до инициализации сегментного регистра DS сегментным адресом данных. Для этого поменяем значение сегментного регистра ES (так как его наша программа не использует), на сегментный адрес 144C (от куда взялся этот адрес? … это предмет медитации ;) ). И так даем команду r es и жмем Enter, потом вводим 144C и жмем Enter, потом вводим d es:0 и жмем Enter и видим наши данные.

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

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

Комментариев нет: