Assume CS:code, DS:data, SS:stk
; Простая программа сложения 32-разрядных чисел
data segment para public "data" ; Сегмент данных
Sum dd 0 ; Переменная для суммы
Data ends
stk segment para stack "stack" ; Сегмент стека
Db 256 dup (?) ; Буфер для стека
Stk ends
code segment para public "code" use16 ; Сегмент кода
begin:
Mov ax,data ; Адрес сегмента данных в регистр AX
Mov ds,ax ; Запись AX в DS
; Основной фрагмент программы
Mov eax,12345678h ; Первый 32-разрядный операнд
Add eax,87654321h ; Второй 32-разрадный операнд
Mov dword ptr sum,eax ; Запись результата в sum
; Завершение программы
Mov ax,4C00h ; Функция завершения программы
Int 21h ; Функция Dos
Code ends
END begin
Поскольку в данном примере обрабатываются 32-разрядные числа, в текст программы необходимо включить директиву .386, разрешающую использование команд 32-разрядных процессоров. Кроме того, при компоновке программы с помощью программы tlink.exe следует указать ключ /3 для разрешения 32-разрядных операций.
Если рассмотреть листинг этой программы, можно увидеть как команды МП 8086 для работы с 16-разрядными операндами, так и команды МП 386 для работы с 32-разрядными операндами. Для облегчения текста из протокола трансляции удалены строчные комментарии.
1 .386
Assume CS:code, DS:data, SS:stk
Простая программа сложения 32-разрядных чисел
5 00000000 data segment para public "data"
Sum dd 0
Data ends
9 00000000 stk segment para stack "stack"
10 00000000 0100*(??) db 256 dup (?)
Stk ends
13 0000 code segment para public "code" use16
14 0000 begin:
B8 0000s mov ax,data
E D8 mov ds,ax
Основной фрагмент программы
18 0005 66| B8 12345678 mov eax,12345678h
19 000B 66| 05 87654321 add eax,87654321h
20 0011 66| 67| A3 00000000r mov dword ptr sum,eax
Завершение программы
B8 4C00 mov ax,4C00h
B CD 21 int 21h
D code ends
END begin
В строках 15 и 16 листинга используется команда засылки операнда в аккумулятор (B8h). Однако в строке 18 наличие перед кодом этой команды префикса замены размера операнда (код 66h) определяет, что длина операнда равна 32 бита, и, следовательно, используется регистр ЕАХ. Префикс замены размера операнда включается в объектный модуль транслятором автоматически, если в программе указано мнемоническое обозначение 32-разрядного регистра, например, ЕАХ.
При отладке этой программы используется отладчик фирмы Borland (турбо дебаггер), использование которого для отладки программ подробно описывается в главе 4.
Для индикации содержимого 32-разрядных регистров требуется провести дополнительную настройку отладчика. Запустив отладчик, надо выбрать Основное меню®View®Registers. При этом откроется окно индикации содержимого регистров процессора. Затем необходимо вызвать локальное меню этого окна, нажав ALT-F10, выбрать в открывшемся меню пункт Registers 32 bit и нажать Enter. После этого стоявшее по умолчанию в этом пункте No сменится на Yes. Это обеспечит вывод на экран содержимого полных 32-разрядных регистров EAX...ESP взамен 16-разрядных регистров AX...SP. Окно отладчика с исходным состоянием программы и переменных показано на рисунке 1.6.
Рисунок 1.6 – Окно отладчика с исходным состоянием программы и переменных
Для иллюстрации выполнения 32-разрядного сложения надо выполнить программу до команды пересылки содержимого EAX в переменную sum включительно (строка программы 20). Для этого следует 5 раз нажать клавишу F7, которая вызывает покомандное выполнение программы. Результат такого выполнения показан на рисунке 1.7.
На рисунке 1.6 видно, что содержимое аккумулятора в окне просмотра регистров процессора и содержимое переменной sum в окне просмотре переменных нулевые. На рисунке 1.7 содержимое и аккумулятора и указанной переменной уже равно 99999999h (или 2576980377 десятичных), что является результатом сложения 12345678h и 87654321h.
Кроме значения рассматриваемой переменной в окне просмотра переменных указан еще тип переменной (dword) и ее адрес (6015:0000).
Рисунок 1.7 – Окно отладчика с результатом выполнения 32-разрядного сложения
В рассмотренном примере используются уже известные нам команды. Однако в систему команд современных процессоров включен ряд новых команд, выполнение которых не поддерживается процессором 8086. Некоторые из этих команд впервые появились в процессоре 80386, другие – в процессорах i486 или Pentium. Ниже приведен список этих команд.
Команды общего назначения
bound – проверка индекса массива относительно границ массива.
bsf/bsr – команды сканирования битов.
bt/btc/btr/bts – команды выполнения битовых операций.
bswap – изменение порядка байтов операнда.
cdq – преобразование двойного слова в четверное.
cmpsd – сравнение строк по двойным словам.
cmpxchg – сравнение и обмен операндов.
cmpxchg8b – сравнение и обмен 8-битовых операндов.
cpuid – идентификация процессора
cwde – преобразование слова в двойное слово с расширением.
enter – создание кадра стека для параметров процедур.
imul reg,imm – умножение операнда со знаком на непосредственное значение.
ins/outs – ввод/вывод из порта в строку.
iretd – возврат из прерывания в 32-разрядном режиме.
j(cc) – команды условного перехода, допускающие 32-битовое смещение.
leave – выход из процедуры с удалением кадра стека, созданного командой enter.
lss/lfs/lgs – команды загрузки сегментных регистров.
mov DRx,reg; reg,DRx
mov CRx,reg; reg,CRx
mov TRx,reg; reg,TRx– команды обмена данными со специальными регистрами. В качестве источника или приемника могут быть использованы регистры CR0...CR3, DR0...DR7, TR3...TR5.
movsx/movzx – знаковое/беззнаковое расширение до размера приемника и пересылка.
рора – извлечение из стека всех 16-разрядных регистров общего назначения (АХ, ВХ, СХ, DX, SP, ВР, SI, DI).
popad – извлечение из стека всех 32-разрядных регистров общего назначения (ЕАХ, ЕВХ, ЕСХ, EDX, ESP, EBP, ESI, EDI).
push imm – запись в стек непосредственного операнда размером байт, слово или двойное слово (например, push OFFFFFFFFh).
pusha – запись в стек всех 16-разрядных регистров общего назначения (АХ, ВХ, СХ, DX, SP, ВР, SI, DI).
pushad – запись в стек всех 32-разрядных регистров общего назначения (ЕАХ, ЕВХ, ЕСХ, EDX, ESP, EBP, ESI, EDI).
rcr/rcl/ror/rol reg/mem,imm – циклический сдвиг на непосредственное значение.
sar/sal/shr/shl reg/mem,imm – арифметический сдвиг на непосредственное значение.
scasd – сканирование строки двойных слов с целью сравнения.
set(cc) – установка байта по условию.
shrd/shld – логический сдвиг с двойной точностью.
stosd – запись двойного слова с строку.
xadd – обмен и сложение.
xlatb – табличная трансляция.
Команды защищенного режима
arpl – корректировка поля RPL селектора
clts – сброс флага переключения задач в регистре CR0.
lar – загрузка байта разрешения доступа.
lgdt – загрузка регистра таблицы глобальных дескрипторов.
lidt – загрузка регистра таблицы дескрипторов прерываний.
lldt – загрузка регистра таблицы локальных дескрипторов.
lmsw – загрузка слова состояния машины.
lsl – загрузка границы сегмента.
ltr – загрузка регистра задачи.
rdmsr – чтение особого регистра модели.
sgdt – сохранение регистра таблицы глобальных дескрипторов.
sidt – сохранение регистра таблицы дескрипторов прерываний.
sldt – сохранение регистра таблицы локальных дескрипторов.
smsw – сохранение слова состояния.
ssl – сохранение границы сегмента
str – сохранение регистра задачи.
verr – проверка доступности сегмента для чтения.
verw – проверка доступности сегмента для записи.
1.2 Первое знакомство с защищенным режимом
Как уже отмечалось, современные процессоры могут работать в трех режимах: реальном, защищенном и виртуального 86-го процессора. В реальном режиме процессоры функционируют фактически так же, как МП 8086 с повышенным быстродействием и расширенным набором команд. Многие весьма привлекательные возможности процессоров принципиально не реализуются в реальном режиме, который введен лишь для обеспечения совместимости с предыдущими моделями. Все программы, приведенные в предыдущих пособиях по системному программному обеспечению, относятся к реальному режиму и могут с равным успехом выполняться на любом из этих процессоров без каких-либо изменений. Характерной особенностью реального режима является ограничение объема адресуемой оперативной памяти величиной 1 Мбайт.
Только перевод микропроцессора в защищенный режим позволяет полностью реализовать все возможности, заложенные в его архитектуру и недоступные в реальном режиме. Сюда можно отнести:
- увеличение адресуемого пространства до 4 Гбайт;
- возможность работы в виртуальном адресном пространстве, превышающем максимально возможный объем физической памяти и достигающей огромной величины 64 Тбайт. Правда, для реализации виртуального режима необходимы, помимо дисков большой емкости, еще и соответствующая операционная система, которая хранит все сегменты выполняемых программ в большом дисковом пространстве, автоматически загружая в оперативную память те или иные сегменты по мере необходимости;
- организация многозадачного режима с параллельным выполнением нескольких программ (процессов). Собственно говоря, многозадачный режим организует многозадачная операционная система, однако микропроцессор предоставляет необходимый для этого режима мощный и надежный механизм защиты задач друг от друга с помощью четырехуровневой системы привилегий;
- страничная организация памяти, повышающая уровень защиты задач друг от друга и эффективность их выполнения.
При включении процессора в нем автоматически устанавливается реальный режим. Переход в защищенный режим осуществляется программно путем выполнения соответствующей последовательности команд. Поскольку многие детали функционирования процессора в реальном и защищенном режимах существенно различаются, программы, предназначенные для защищенного режима, должны быть написаны особым образом. Реальный и защищенный режимы не совместимы! Архитектура современного микропроцессора необычайно сложна. Столь же сложными оказываются и программы, использующие средства защищенного режима. К счастью, однако, отдельные архитектурные особенности защищенного режима оказываются в достаточной степени замкнутыми и не зависящими друг от друга. Так, при работе в однозадачном режиме отпадает необходимость в изучении многообразных и замысловатых методов взаимодействия задач. Во многих случаях можно отключить (или, точнее, не включать) механизм страничной организации памяти. Часто нет необходимости использовать уровни привилегий. Все эти ограничения существенно упрощают освоение защищенного режима
Начнем изучение защищенного режима с рассмотрения простейшей (но, к сожалению, все же весьма сложной) программы, которая, будучи запущена обычным образом под управлением MS-DOS, переключает процессор в защищенный режим, выводит на экран для контроля несколько символов, переходит назад в реальный режим и завершается стандартным для DOS образом [8]. Рассматривая эту программу, мы познакомимся с основополагающей особенностью защищенного режима – сегментной адресацией памяти, которая осуществляется совсем не так, как в реальном режиме.
Следует заметить, что для выполнения рассмотренной ниже программы необходимо, чтобы на компьютере была установлена система MS-DOS "в чистом виде" (не в виде сеанса DOS системы Windows). Перед запуском программ защищенного режима следует выгрузить как систему Windows, так и драйверы обслуживания расширенной памяти HIMEM.SYS и EMM386.EXE.
Листинг 1.1 – Программа, работающая в защищенном режиме
1 ;*********************************************
2 ; Программа, работающая в защищенном режиме *
3 ;*********************************************