Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Сборка Часть2 / АВМиС / Лекции / Исследование работы IA

.doc
Скачиваний:
37
Добавлен:
15.09.2014
Размер:
72.19 Кб
Скачать

Исследование работы 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), можно использовать различные системные средства для перехода в защищенный режим. Наиболее предпочтительны следующие средства (в порядке уменьшения предпочтительности):

  1. DPMI - DOS Protected Mode Interface (реализован в DOS/4G, Quarterdeck DPMI, Borland DOS Extender, а также во всех версиях Windows).

  2. VCPI - Virtual Control Program Interface (реализуется драйвером EMS).

  3. 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.