@Bombus

Как найти соответствие адреса памяти коду программы загруженной программы для DOS?

Имеется довольно большой проект, который вылетает с ошибкой:
[Unknown code]CS:IP=C031:7AA1=006E SS:SP=09B4:06D4 DS=4441 ES=CD
С ассемблером пока разбираюсь, поэтому прошу совет опытных. Насколько я понял ошибка появилась, т.к. регист IP попал на ячейку со значением не соответствующем возможным машинным командам. Проект написан на C++ и компилируется без warning'ов, т.е нарушений памяти со стороны компилятора не обнаружено. Единственным объяснением вижу выход за пределы массива (или подобное) и как итог затирание участка кода записанными данными.
Только как найти соответствие CS:IP с кодом дизассемблированнной программы? Насколько я понял сегментные регистры меняют значение после загрузки программы с бинарника в память компьютера в соответствии с начальным адресом загрузки? Если так, то главный вопрос как найти это смещение?
Программа запускается на контроллере с процессором 80186 под операционкой MiniOS7 - клон MS DOS. Если смещение одинаковое, то возможно в произвольной функции вывести текущее значение CS и сравнить с CS для этой функции в дизассемблированной программе? А дальше уже смотреть какие данные соседствуют с данным участком и таким образом понять место нарушения памяти. Так правильно?
  • Вопрос задан
  • 747 просмотров
Пригласить эксперта
Ответы на вопрос 1
Преобразование 32 бит адреса "сегмент:смещение" в 20-битный линейный адрес по формуле "сегмент*16+смещение" и была придумана для того, чтобы можно было загружать фрагменты кода и данных практически в любые области памяти не теряя на фрагментации и при этом сохранять смещение равным тому, что было на этапе компиляции, а варьировать при загрузке только сегментный регистр. Так что смещение в принципе должно сохраняться.

Другое дело, что сам сегмент C031 весьма странный - в классической архитектуре он находится уже за пределами основного ОЗУ. Так что либо в MiniOS другая схема организации памяти, либо Ваша программа в результате нарушения логики либо искажения стека/кода совершила прыжок/вызов/возврат в непредназначенную для этого область памяти, например ПЗУ или видеобуфер, чем сразу же вызвала исключение. В этом случае сам адрес CS:IP ни о чем не говорит - нужно знать где была точка исполнения на один шаг раньше.

По поводу второго вопроса : честно не знаю есть ли возможность в С++ узнать текущие CS:IP, но в Ассемблере обычно делался ближний либо дальний вызов на адрес, расположенный непосредственно следующим кодом, а затем положенные этим вызовом в стек значения CS:IP считывались обычным POP :
call far x
x:
pop di
pop es
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы