
Сборка Часть2 / АВМиС / Лекции / Исследование работы IA
.docИсследование работы IA-32 в защищенном режиме
Цель работы: Познакомится с особенностями написания программы для защищенного режима. На примере конкретной программы пронаблюдать механизмы формирования линейного адреса в различных режимах работы процессора.
Теоретическая часть
Основным режимом работы 32-битных процессоров семейства IA-32 является защищенный. В реальном режиме происходит лишь инициализация системы, иногда он используется для выполнения старых приложений для процессоров 8086/88 и 80286. Механизмы защиты, многозадачность, страничное преобразование, полноценное выполнение 32-битного кода и многие другие возможности 32-битных процессоров доступны лишь в защищенном режиме.
Прежде, чем перевести процессор в защищенный режим, следует подготовить дескрипторные таблицы (глобальную и для прерываний), а также таблицы, необходимые для страничного преобразования (если система собирается его использовать). Переход в защищенный режим происходит после выставления младшего бита в регистре CR0 (MSW), затем следует выполнить далекий межсегментный переход (FAR JUMP) для очистки кэша команд:
MOV EAX,1
MOV CR0,EAX
JMP DWORD PTR [PMEntry]
При использовании 32-битной операционной системы для защищенного режима пользовательским программам нет необходимости в таких действиях. Среду для защищенного режима подготавливает сама операционная система. Прикладная программа может считать, что уже работает в линейном 4Гбайтном пространстве.
Пример для Windows (tasm32) |
Пример для Linux (nasm) |
.386 ; "плоская" модель - для защищенного режима MODEL FLAT
.DATA ; сегмент данных Msg DB "Hello, world",0
.CODE ; сегмент кода Entry: ; точка входа в программу SUB EBX,EBX
PUSH EBX ; флаги (0=MB_OK) PUSH EBX ; адрес текста заголовка PUSH OFFSET Msg ; адрес контента PUSH EBX ; дескриптор окна ; вызов WinAPI MessageBox(NULL,Msg,NULL,MB_OK) CALL MessageBoxA
PUSH EBX ; код возврата ; вызов WinAPI ExitProcess(0) CALL ExitProcess
END Entry |
section .data ; сегмент данных Msg: DB "Hello, world",10
section .code ; сегмент кода global _start _start: ; точка входа в программу MOV ECX,Msg ; адрес буфера MOV EDX,13 ; длина сообщения l1: MOV EBX,1 ; дескриптор файла (stdout) ; вызов write(1,Msg,13) MOV EAX,4 INT 80h CMP EAX,-4096 JA skip ; в EAX кол-во выведенных байт ADD ECX,EAX SUB EDX,EAX JNZ l1 ; при необходимости выводим остаток skip: SUB EBX,EBX ; код возврата ; вызов exit(0) MOV EAX,1 INT 80h HLT
|
Если операционная система не предназначена для работы в защищенном режиме (например, DOS), можно использовать различные системные средства для перехода в защищенный режим. Наиболее предпочтительны следующие средства (в порядке уменьшения предпочтительности):
-
DPMI - DOS Protected Mode Interface (реализован в DOS/4G, Quarterdeck DPMI, Borland DOS Extender, а также во всех версиях Windows).
-
VCPI - Virtual Control Program Interface (реализуется драйвером EMS).
-
INT 15h (реализуется BIOS).
DPMI обеспечивает программам для DOS доступ к памяти выше 1Мб, предоставляя программный интерфейс к некоторым функциям BIOS и DOS в защищенном режиме. Этот интерфейс содержит функции, позволяющие программам в защищенном режиме резервировать память, дескрипторы, вызывать код в режиме V86.
Прежде, чем воспользоваться сервисами DPMI, программа должна переключиться в защищенный режим с помощью предназначенной для этого функции. Для перехода в защищенный режим программа должна сделать межсегментный вызов (FAR CALL) по адресу, возвращаемому функцией:
MOV AX,1687h
INT 2Fh
Если DPMI присутствует, и вызов прошел успешно, AX=0, DX содержит версию DPMI, SI содержит количество параграфов, необходимых для служебных данных DPMI, а ES:DI - адрес процедуры переключения в защищенный режим. В случае ошибки AX - не ноль. Перед тем, как вызвать процедуру переключения, программа резервирует память указанного размера и помещает в ES соответствующий сегментный адрес.
TEST AX,AX
JNZ Error
MOV [PM_Entry+2],ES
MOV [PM_Entry],DI
MOV BX,SI
MOV AH,48h
INT 21h ; резервируем память под служебные данные DPMI
; перед использованием функции 48h
; программа должна вернуть DOS неиспользуемую память
; при помощи функции 4Ah
MOV ES,AX
Кроме этого, процедура переключения рассматривает младший бит в регистре AX как признак 32-битного режима. Если бит выставлен, то после переключения программа будет выполняться в 32-битном сегменте кода.
SUB AX,AX
CALL DWORD PTR [PM_Entry]
JC Error
Если переключение прошло успешно, флаг переноса (CF) равен 0. Программа работает в защищенном режиме. Сегментные регистры содержат селекторы дескрипторов сегментов с соответствующими базовыми адресами и пределами в 64К (ES содержит селектор сегмента с PSP, его предел - 256 байт). В дальнейшем доступны сервисы DPMI, которые вызываются при помощи программного прерывания INT 31h. Завершение программы защищенного режима возможно при помощи функции AH=4Ch прерывания INT 21h. Спецификация DPMI декларирует доступность лишь этой функции DOS. Однако многие реализации, например, DPMI в Microsoft Windows, обеспечивают функционирование и других функций DOS (01h-0Ch - ввод с клавиатуры, вывод на экран; 39h-43h - работа с файлами и каталогами и некоторые другие).
Вот некоторые сервисы DPMI INT 31h (подробнее см. Tech! Help v.6.0):
Номер функции (значение AX) |
Назначение |
0000h |
Зарезервировать дескриптор в LDT |
0001h |
Освободить дескриптор в LDT |
0002h |
Конвертировать сегмент реального режима в дескриптор |
0006h |
Получить базовый адрес сегмента |
0007h |
Установить базовый адрес сегмента |
0008h |
Установить предел сегмента |
0009h |
Установить права доступа дескриптора |
000Bh |
Получить дескриптор |
000Ch |
Установить дескриптор |
0100h |
Зарезервировать память в DOS |
0101h |
Освободить память в DOS |
0102h |
Изменить размер памяти, зарезервированной в DOS |
02xxh |
Получение и установка прерываний и исключений для реального и защищенного режима |
0300h |
Вызов программного прерывания в реальном режиме |
0301h - 0302h |
Вызов процедуры в реальном режиме |
0303h |
Зарезервировать новый шлюз переключения из реального в защищенный режим |
0304h |
Освободить шлюз переключения из реального в защищенный режим |
0306h |
Получить шлюзы переключения между режимами |
0400h |
Получить версию DPMI |
0500h |
Получить информацию о свободной памяти |
0501h |
Зарезервировать блок памяти |
0502h |
Освободить блок памяти |
0503h |
Изменить размер зарезервированного блока памяти |
06xxh |
Управление подкачкой |
и др. |
Задание:
1) Напишите программу для Windows или для Linux, выводящую значения сегментных регистров. По этим значениям выясните уровень привилегий, с которым запущена ваша программа, а также в какой дескрипторной таблице содержатся дескрипторы, соответствующие селекторам.
Для того, чтобы использовать в программе вызовы Windows API, в тексте программы следует определить соответствующие символы как внешние, с помощью следующих директив ассемблера:
INCLUDELIB import32.lib
EXTRN MessageBoxA:NEAR
EXTRN ExitProcess:NEAR
При компиляции программы, используйте опцию /ml для того, чтобы в объектный файл эти символы были включены с учетом регистра. Компоновщику TLINK32 следует указать опцию /Tpe, отвечающую за генерацию исполняемого файла для Win32. При необходимости также укажите при помощи /L путь к библиотеке import32.lib (например, D:ASMLIB).
Стандартной для Linux ассемблерной семантикой является семантика AT&T, которая существенно отличается от принятой Intel (например, TASM/MASM для DOS и Windows). Однако существуют и средства для использования семантики Intel: as86 или nasm. В данной работе приведены примеры для использования nasm. Чтобы транслировать исходный текст test32.asm в исполняемый файл, необходимы следующие команды:
nasm -f elf test32.asm
ld test32.o -o test32
Опция -f в команде nasm указывает формат выходного файла - ELF (executable linux format). В результате работы ассемблера nasm получается объектный файл test32.o, который необходимо обработать редактором связей ld. Опция -o в команде ld задает имя выходного файла. Если ее не указывать, исполняемый файл будет записан в a.out.