Преобразование 32 бит адреса "сегмент:смещение" в 20-битный линейный адрес по формуле "сегмент*16+смещение" и была придумана для того, чтобы можно было загружать фрагменты кода и данных практически в любые области памяти не теряя на фрагментации и при этом сохранять смещение равным тому, что было на этапе компиляции, а варьировать при загрузке только сегментный регистр. Так что смещение в принципе должно сохраняться.
Другое дело, что сам сегмент C031 весьма странный - в классической архитектуре он находится уже за пределами основного ОЗУ. Так что либо в MiniOS другая схема организации памяти, либо Ваша программа в результате нарушения логики либо искажения стека/кода совершила прыжок/вызов/возврат в непредназначенную для этого область памяти, например ПЗУ или видеобуфер, чем сразу же вызвала исключение. В этом случае сам адрес CS:IP ни о чем не говорит - нужно знать где была точка исполнения на один шаг раньше.
По поводу второго вопроса : честно не знаю есть ли возможность в С++ узнать текущие CS:IP, но в Ассемблере обычно делался ближний либо дальний вызов на адрес, расположенный непосредственно следующим кодом, а затем положенные этим вызовом в стек значения CS:IP считывались обычным POP :
call far x
x:
pop di
pop es