mov word ptr old_08+2,ES
;Установим наш обработчик >>
mov AX,2508h
mov DX,oflset new_08
int 21h
;Прочитаем системное время, прибавим требуемый интервал;и сохраним в двухсловной ячейке памяти
mov AX,40h;Настройка ES на
усмиренные возможности современных микропроцессоров
mov ES.AX;область данных BIOS
mov EAX,ES:6Ch;Получаем системное время add EAX,time_int;Прибавить интервал mov time_end,EAX;Сохраним в памяти;Имитация рабочего цикла программы с опросом флага
again: test jiiz mov mov int jmp mov mov int |
flag.OFFh ok AH,02h DL.V 21h again AH,09h DX,offset msg |
ok: |
;Проверка флага готовности;Если установлен, на ОК;В ожидании окончания;временного интервала;выводим на экран точки;И снова на проверку флага;Интервал завершен.;Выполним, что хотели
21h;3авсршим программу, восстановив сначала исходный вектор
Ids DX,old_08
mov AX,2508h
int 21h
mov AX,4COOh
int 21h main endp
;Наш обработчик прерываний от системного таймера new_08 proc
pushf call CS:old_08 push EAX ES AX,40h ES,AX EAX,ES:6Ch |
push mov mov mov cmp jb inc |
;3апишем флаги в стек;и вызовем системный обработчик;Сохраним используемые; регистры; Настроим ES;на область данных BIOS;Прочитаем текущее время EAX,CS:time_end;CpaBHHM с вычисленным
ex CS:flag AL,20h 20h,AL ES EAX endp |
ех: |
;Если меньше, на выход;Интервал истек, установим;флаг
mov out pop pop iret new 08 |
;Команда конца прерывания;в контроллер прерываний;Восстановим;сохраненные регистры;Выход из обработчика
;Поля данных программы old_08 dd О time_int dd 18*2 time_end ddO Hag db 0 |
;Для хранения исходного вектора;Требуемый интервач (~2с);Момент истечения интервала;Флаг истечения интервала
msg db "Время истекло!$" Информационное сообщение
code ends
end main
168________________________________________________________________ £лава_4
Организация программного комплекса с обработчиком прерываний от системного таймера уже рассматривалась в примере 3-3 в гл. 3. Установка обработчика в рассматриваемом примере выполняется немного проще, так как нет необходимости настраивать регистр DS на сегмент данных
— он и так уже настроен на единственный сегмент программы. Установив
обработчик, программа настраивает регистр ES на область данных BIOS и
считывает из ячейки с адресом 46Ch текущее системное время. Командой
add к нему прибавляется заданный в ячейке time_int интервал (в примере
— приблизительно 2 с), и результат сохраняется в ячейке time_end.
Действия по установке обработчика закончены, и программа может приступить к выполнению запланированных для нее действий. В данном примере программа в цикле вызывает функцию DOS 02h вывода на экран символа точки; в действительности она может, например, выполнять обработку и вывод на экран некоторых данных. В каждом шаге цикла происходит тестирование флага окончания временного интервала flag, который должен быть установлен обработчиком прерываний по истечении заданного временного интервала. Пока флаг сброшен, цикл продолжается. Как только флаг окажется установлен, программа приступает к выполнению действий по отработке этого события. В рассматриваемом примере выполняется вывод на экран информационного сообщения и завершение программы с обязательным восстановлением исходного содержимого вектора 8.
Обработчик прерываний new_08 прежде всего выполняет вызов исходного обработчика, адрес которого мы сохранили в ячейке old_08. Методика сцепления обработчиков прерываний рассматривалась в гл.З (см. пример 3-4). В данном случае сцепление обработчиков необходимо, так как подключение к вектору 8 нашего обработчика не должно нарушить ход системных часов.
После возврата из системного обработчика выполняется сохранение используемых регистров, настройка регистра ES на область данных BIOS, чтение текущего времени и сравнение его с записанным в ячейке time_end. Пока текущее время меньше заданного, обработчик просто завершается командой irct, послав предварительно в контроллер прерываний команду конца прерывания EOI и восстановив сохраненные ранее регистры. Если же заданный временной интервал истек, и текущее время оказывается равным (или большим) значению в ячейке time_end, обработчик перед своим завершением устанавливает флаг flag, инициируя в основной программе запланированные для этого события действия. Если такими действиями должно быть, например, включение или выключение аппаратуры, подключенной к компьютеру, это можно сделать в самом обработчике прерываний. В этом случае флаг flag не нужен, и действия основной программы и обработчика прерываний протекают паршшельно и независимо.
Рассмотренную программ}' нетрудно модифицировать так, чтобы флаг flag устанавливался не после истечения заданного интервала, а в заданный момент календарного времени. Эта задача позволит нам проиллюстрировать приемы выполнения арифметических операций с 32-разрядными операндами.
Расширенные возможности современных микропроцессоров
Пример 4-2 отличается от предыдущего только изменением алгоритма вычисления времени и служебными полями данных. Процедуры установки обработчика прерываний, цикла ожидания установки флага и самого обработчика прерываний полностью совпадают с примером 4-1.
Для получения требуемого значения времени в тех же единицах, которые используются системой при работе с ячейкой 46Ch, надо сначала вычислить время в секундах от начала суток, а затем для получения времени в тактах таймера умножить эту величину на 18,2065 (см. раздел 3.5). Для того, чтобы не привлекать арифметический сопроцессор и оставаться в рамках целых 32-битовых чисел, умножение числа секунд на 18.2065 выполняется по следующей формуле:
Такты = t*18 + t/5 + t/154
Отлаживая на машине пример 4-2, надо следить за тем, чтобы заданное время было больше текущего по машинным часам, иначе программа будет вечно ожидать установки флага. Попытка завершить ее нажатием комбинации <Ctrl>/<C> приведет к зависанию системы, так как в этом случае не будут выполнены строки восстановления исходного содержимого перехваченного программой вектора. По-настоящему в программах, содержащих обработчики каких-либо прерываний, используемых системой, необходимо предусматривать собственные средства обработки нажатия <Ctrl>/<C>, чтобы аварийное завершение программы выполнялось так же корректно, как и штатное, с предварительным с восстановлением векторов.
;Пример 4-2. Ожидание заданного момента времени
;по прерываниям от таймера
.586
assume CS:code,DS:code
code segment usel6
org lOOh main proc;Сохраним исходный вектор
Преобразуем требуемое;интервалов по 55 мс mov EAX,hour mov EBX,3600 mul EBX mov temp.EAX mov EAX,min mov EBX,60 mul EBX add temp,EAX mov EAX,sec add temp,EAX |
;Установим наш обработчик
календарное время в количество
;Возьмем часы
;Коэффициент преобразования в секунды
Преобразуем часы в секунды в EDX:EAX
;Сохраним часы в temp
;Возьмем минуты
;Коэффициент преобразования в секунды
;Преобразусм минуты в секунды в EDX:EAX
; Прибавим минуты в temp
;Возьмем секунды
;Прибавим секунды в temp
Глава '4
mov mov mul mov xor mov mov div add xor mov mov div add; Имитация
EAX.temp
EBX,18
EBX
time, E AX
EDX,EDX
EAX,temp
EBX, 5
EBX
time.EAX
EDX.EDX
EAX,temp
EBX, 154
EBX
time,EAX
рабочего цикла
;Число секунд;Будем умножать на 18;Умножим на 18;Сохраним в time;Подготовимся к делению;Будем делить число секунд;Будем делить на 5; Поделим;Прибавим к time Подготовимся к делению;Будем делить число секунд;Будем делить на 154; Поделим;Прибавим к time программы с опросом флага
;3авершим программу, восстановив сначала исходный вектор
main endp new_08 proc
endp dd |
new_08 old_08 hour dd min dd sec time temp dd nag db msg code end |
;Часы
; Минуты
dd dd |
; Секунды
вычисленное время в тактах таймера
;Ячейка для промежуточного результата
;Флаг наступления заданного времени
db "Время наступило!$"
ends
main
Рассмотрим некоторые детали приведенного примера.
Три ячейки для хранения заданного времени (часов, минут и секунд) объявлены оператором dd, как двойные слова для упрощения программы и ускорения загрузки этих значений в расширенный регистр ЕАХ. Если бы мы, экономя память, отводимую по данные, объявили бы эти ячейки как байты, то загрузка, например, числа часов в регистр ЕАХ выглядела бы следующим образом:
xor mov
ЕАХ, ЕАХ
AL,hour
Для преобразования часов в секунды мы должны число часов умножить на 3600. Оба сомножителя (3600 и максимум 23) представляют собой небольшие числа, которые поместились бы в 16-разрядный регистр. Одна-
Расширенные возможности современных микропроцессоров
ко результат может достигнуть величины 82800, которая в регистр АХ уже не поместится. Если бы мы выполнили умножение двух 16-разрядных регистров, например, АХ на ВХ, то результат (по правилам выполнения команды mul) оказался бы в паре регистров DX:AX, и нам пришлось бы эти два числа объединять в одно несколькими операциями переноса и сдвига:
push AX;Сохраняем на время АХ
mov AX,DX;Старшая половина произведения
sal ЕАХ,16;Сдвигаем в старшую половину ЕАХ
pop AX;Младшая половина произведения
Выполняя умножение с использованием 32-разрядных регистров, мы получаем результат опять же в паре регистров EDX:EAX, но поскольку в нашем случае произведение никогда не превысит 64 К, все оно целиком будет находиться в одном регистре ЕАХ, и мы избавляемся от приведенной выше процедуры. Результат умножения сохраняется во вспомогательной ячейке temp.
Аналогичным образом выполняется перевод числа минут в секунды; полученный результат прибавляется к содержимому ячейки temp.
Число секунд преобразовывать не надо, оно просто прибавляется к содержимому temp.
Полученное число секунд умножается на 18, и результат помещается в ячейку time, которая затем будет опрашиваться в обработчике прерываний.
К полученному числу тактов таймера надо прибавить еще две корректирующих величины — результаты деления числа секунд на 5 и на 154. При использовании в операции деления 32-разрядных регистров делимое помещается в пару регистров EDXrEAX. В.нашем случае делимое целиком помещается в ЕАХ, и регистр EDX необходимо обнулить. Для этого можно было выполнить команду
mov ЕАХ,О 1ч
но более эффективна операция хог ЕАХ,ЕАХ
которая при любом содержимом ЕАХ оставляет в нем 0.
При делении EDX:EAX на ЕВХ частное помещается в ЕАХ, остаток в EDX. Остаток нас не интересует, а частное (первая корректирующая величина) прибашыется к содержимому ячейки temp.
Аналогичным образом то же число секунд из ячейки tmp делится на 154, и результат прибавляется к содержимому time. Преобразование закончено.
В заключение рассмотрим пример упорядочивания массива 32-разрядных чисел в убывающем порядке методом пузырьковой сортировки. В приведенном алгоритме используются расширенные возможности адресации 32-разрядных процессоров.
Глава 4
;Пример 4-3. Пузырьковая сортировка .586 assume CS:code,DS:data code segment use!6 main proc AX,data DS,AX ESI.offset list ЕСХДООО EDX,0 EDX,ECX stop |
; Настроим DS;на сегмент данных;ESI-> начало массива; ;Число элементов в массиве;Индекс сравниваемой пары;Индекс пары дошел до;индекса массива' К следующей паре ЕАХ,[Е51-ЬЕОХ*4+4];Второй элемент пары [ESI-f-EDX*4],EAX;Сравним с предыдущим noswap;Если первый больше, то хорошо [ESI+EDX*4],EAX;Первый меньше. Обменять [Е51+ЕОХ*4+4],ЕАХ;первый на второй |
mov
mov
mov
mov
start: mov sort: cmp
jge
mov
cmp
jge
xchg
;Увеличим индекс пары ;И на сравнение ;Цикл по всем элементам |
mov noswap: inc EDX
jmp sort stop: loop start
mov AX,4COOh
;Имя тестового массива;3аполним массив на этапе;трансляции числами от О;до 990;через 10 |
hit 21h
main endp
code ends
data segment
list label
nmb=0
rept 1000
dd nmb
nmb=nmb+10
endm
data ends
stk segment stack;.
dw 128 dup (0) С
stk ends II
end main
Алгоритм пузырьковой сортировки предусматривает выполнение двух вложенных циклов. Во внутреннем цикле сравниваются пары элементов. Первый элемент берется по адресу [ESI + EDX * 4], второй — по следующему адресу [ESI + EDX * 4 + 4]. Если второй элемент больше первого, происходит обмен значений этих элементов, и элемент с меньшим значением «всплывает» на одно место выше (т.е. перемещается по большему адресу). После этого увеличивается индекс пары и выполняется сравнение второго элемента со следующим. Если оказывается, что следующий элемент больше предыдущего, они меняются местами. В результате элемент с самым маленьким значением всплывает на самый верх списка.
Расширенные возможности современных микропроцессоров
Внутренний цикл, пройдясь по всем парам, повторяется сначала, обеспечивая всплывание следующего по величине элемента. Каждый следующий проход внутреннего цикла требует на 1 меньше шагов, чем предыдущий. После завершения упорядочивания элементы выстраиваются по возрастающим адресам в порядке уменьшения их значений.
В примере 4-3 тестовый массив данных образован из возрастающих (на 10) чисел от 0 до 990. В результате упорядочивания они должны расположиться в обратном порядке, от больших к меньшим. В примере не предусмотрены средства вывода на экран элементов массива, поэтому его изучение следует проводить в отладчике, наблюдая всплывание каждого элемента
Как уже отмечалось, в 32-разрядных процессорах увеличено до 4 число сегментных регистров данных. Это дает возможность совместной работы с четырьмя сегментами данных (общим объемом до 256 Кбайт) без перенастройки сегментных регистров. Структура такого рода программы может выглядеть следующим образом:
.586
datal segment use!6
; Массив 56 Кбайт |
first dw 7000U dup(')
datal ends
data2 segment use 16
;Массив 56.Кбайт |
second dw 7000U dup (')
datal ends
data3 segment use 16
;Массив 56 Кбайт |
third dw 7000h dup (')
data3 ends
data4 segment use 16
;Массив 56 Кбайт |
forth dw 7000h dup (')
data4 ends
code segment
use!6
assume DS:datal,ES:data2,FS:data3,GS:data4 main proc
;Настроим все 4 сегментных регистра на базовые адреса соответствующих сегментов
mov AX.datal
mov DS,AX;DS->datal
mov AX,data2
mov ES,AX;ES->data2 • ' I
mov AX,data3
mov FS,AX;FS->data3
mov AX,data4
mov GS,AX;GS->data4
;Теперь можем обращаться к полям данных сегментов
mov BX,7000h*2-2;BX->последнее слово массива
mov word р1г[ВХ],111111;Обращение через DS по умолчанию;Обращение к разным сегментам с явным указанием ^требуемого сегментного регистра (замена сегмента)
Глава 4
mov word ptr ES:[BX],2222h
mov word ptr FS:[BX],3333h
mov word ptr GS:[BX],4444h
;Обращение по именам полей данных разных сегментов;с учетом действия директивы assume
mov first, 1;3апись в сегмент datal
mov second,2;3апись в сегмент data2
mov third,3;3апись в сегмент data3
mov fourth,4;3апись в сегмент data4
;Перенос данных из сегмента в сегмент
push first
pop sccoud+2
push third
pop fourth+2
main endp code ends
В программе объявлены 4 сегмента данных с именами datal, data2, data3 и data4, содержащие массивы 16-разрядных данных с именами first, second, third и fourth. Длина каждого массива составляет 56 Кбайт, и, таким образом, общий объем данных, доступных программе в любой момент, составляет более 200 Кбайт. Сегменты данных описаны до сегмента команд, что в данном случае имеет значение. В сегменте команд с помощью директивы assume указано соответствие каждом}' из сегментов своего сегментного регистра (DS, ES, FS и GS). Это даст нам возможность обращаться по именам полей сегментов без явного указания соответствующих этим сегментам сегментных регистров.
Программа начинается с обычной практически для всех программ
процедуры настройки всех сегментных регистров. Стоит еще раз повто
рить, что директива assume лишь обеспечивает правильную трансляцию
программы, но не инициализирует сегментные регистры. «Правильная
трансляция» в данном случае заключается в том, что при обработке ко
манд, в которых упоминаются имена данных того или иного сегмента,
ассемблер автоматически предваряет эти команды префиксом замены сег
мента, выбирая для замены сегментный регистр, указанный в директиве
assume для данного сегмента. Так, команда;.
mov first,!)';
преобразуется в последовательность кодов (по листингу трансляции) С7 06 ООООг 0001
где С7 06 — это код команды mov в случае прямой адресации памяти и использования непосредственного операнда, ООООг — смещение адресуемой ячейки, а 0001 — непосредственный операнд (все числа, разумеется, шсстнадцатеричныс). Здесь нет префикса замены сегмента, потому что адресуется сегмент, которому соответствует регистр DS, используемый
Г
'дсишренные возможности современных микропроцессоров____________________ 175
процессором по умолчанию. Однако команды с обращением к другим сегментам транслируются с включением в их коды соответствующих префиксов, несмотря на то, что в исходных предложениях не указаны сегментные регистры, а содержатся только ссылки на (уникальные) имена ячеек тех или иных сегментов:
mov second,2;Код команды 26: С7 06 ООООг 0002
mov third,3;Код команды 64: С7 06 ООООг 0003
mov fourth,4;Код команды 65: С7 06 ООООг 0004
Настроив сегментные регистры, мы можем обращаться к полям данных всех четырех сегментов с использованием любых способов адресации. В приведенном фрагменте в регистр ВХ помещается смещение последней ячейки любого из массивов, после чего с помощью косвенной базовой адресации в последние слова всех четырех массивов записываются произвольные числа llllh, 2222h, 3333h и 4444h. Во всех случаях требуется описатель word ptr, так как по виду команды ассемблер не может определить, хотим ли мы занести в память байт, слово или двойное слово. При обращении к сегментам, адресуемых не через DS, необходимо явное указание сегментного регистра (которое будет преобразовано в код префикса замены сегмента), потому что по виду команды с адресацией через регистры транслятор не может определить, к какому сегменту происходит обращение.
Проще обстоит дело, если в команде указаны имена ячеек сегментов. В этом случае, как уже говорилось выше, транслятор автоматически включает в код команды требуемый префикс замены сегмента.
Наконец, в конце программы приведены строки пересылки данных из сегмента в сегмент через стек. Они убедительны в том отношении, что в четырех последовательных командах производится обращение к четырем различным сегментам программы без перенастройки сегментных регистров, которую пришлось бы выполнить, если бы мы ограничились возможностями МП 86.
4.4. Основы защищенного режима
Микропроцессоры Pentium, так же, как и его предшественники (начиная с 80268), могут работать в двух режимах: реального адреса и виртуального защищенного адреса. Обычно эти режимы называют просто реальным и защищенным. В реальном режиме 32-разрядные микропроцессоры функционируют фактически так же, как МП 86 с повышенным быстродействием и расширенным набором команд. Многие весьма привлекательные возможности микропроцессоров принципиально не реализуются в реальном режиме, который введен лишь для обеспечения совместимости с предыдущими моделями процессоров. Характерной особенностью реального режима является ограничение объема адресуемой оперативной памяти величиной 1 Мбайт.
Только перевод микропроцессора в защищенный режим позволяет полностью реализовать все возможности, заложенные в его архитектуру и недоступные в реальном режиме. Сюда можно отнести:
Глава -t
— увеличение адресуемого пространства до 4 Гбайт;
— возможность работать в виртуальном адресном пространстве, превы
шающем максимально возможный объем физической памяти и со
ставляющем огромную величину 64 Тбайт;
— организация многозадачного режима с параллельным выполнением
нескольких программ (процессов). Собственно говоря, многозадачный
режим организует многозадачная операционная система, однако мик
ропроцессор предосташшет необходимый для этого режима мощный
и надежный механизм защиты задач друг от друга с помощью четыре
хуровневой системы привилегий;
— страничная организация памяти, повышающая уровень защиты задач
друг от друга и эффективность их выполнения.
При включении микропроцессора в нем автоматически устанавливается режим реального адреса. Переход в защищенный режим осуществляется программно путем выполнения соответствующей последовательности команд. Поскольку многие детали функционирования микропроцессора в реальном и защищенном режимах существенно различаются, программы, предназначенные для защищенного режима, должны быть написаны особым образом. При этом различия реачьного и защищенного режимов настолько велики, что программы реального режима не могут выполняться в защищенном режиме и наоборот. Другими словами, реальный и защищенный режимы не совместимы.
Архитектура современного микропроцессора необычайно сложна. Столь же сложными оказываются и средства защищенного режима, а также программы, использующие эти средства. С другой стороны, при решении многих прикладных задач (например, при отладке приложений Windows, работающих, естественно, в защищенном режиме), нет необходимости в понимании всех деталей функционирования защищенного режима; достаточно иметь знакомство с его основными понятиями. В настоящем разделе дается краткое описание основ защищенного режима и его наиболее важных структур и алгоритмов функционирования.
Пожалуй, наиболее важным отличием защищенного режима от ре-ального является иной принцип формирования физического адреса. Вспомним, что в реальном режиме физический адрес адресуемой ячейки памяти состоит из двух компонентов — сегментного адреса и смещения. Оба компонента имеют размер 16 бит, и процессор, обращаясь к памяти, пользуется следующим правилом вычисления физического адреса:
Физический адрес = сегментный адрес * 16 4- смещение
И сегментный адрес, и смещение не могут быть больше FFFFh, откуда следуют два важнейших ограничения реального режима: объем адресного пространства состаатяет всего 1 Мбайт, а сегменты не могут иметь размер, превышающий 64 Кбайт.
В защищенном режиме программа по-прежнему состоит из сегментов, адресуемых с помощью 16-разрядных сегментных регистров, однако местоположение сегментов в физической памяти определяется другим способом.
Расширенные возможности современных микропроцессоров
В сегментные регистры в защищенном режиме записываются не сегментные адреса, а так называемые селекторы, биты 3...15 которых рассматриваются, как номера (индексы) ячеек специальной таблицы, содержащей дескрипторы сегментов программы. Таблица дескрипторов обычно создается операционной системой защищенного режиме (например, системой Windows) и, как правило, недоступна программе. Каждый дескриптор таблицы дескрипторов имеет размер 8 байт, и в нем хранятся все характеристики, необходимые процессору для обслуживания этого сегмента. Среди этих характеристик необходимо выделить в первую очередь две: адрес сегмента и его длину (рис. 4.4).
Таблица дескрипторов сегментов
Первый пустой дескриптор
Адрес = О Длина = 1 Мбайт
Адрес = 1 Мбайт Длина = 100 Кбайт
.Адрес =8,5 Мбайт Длина = 256 байт
Рис. 4.4. Дескрипторы сегментов и их селекторы.
Под адрес сегмента в дескрипторе выделяется 32 бит, и, таким обра-ром, сегмент может начинаться в любой точке адресного пространства Зъемом 232 = 4 Гбайт. Это адресное пространство носит название линей-[ного. В простейшем случае, когда выключено страничное преобразование, котором речь будет идти позже, линейные адреса отвечают физическим. Таким образом, процессор может работать с оперативной памятью объемом до 4 Гбайт.
Как и в реальном режиме, адрес адресуемой ячейки вычисляется процессором, как сумма базового адреса сегмента и смещения:
Линейный адрес = базовый адрес сегмента + смещение
В 32-разрядных процессорах смещение имеет размер 32 бит, поэтому максимальная длина сегмента составляет 2м = 4 Гбайт.
На рис. 4.4 приведен гипотетический пример программы, состоящей из трех сегментов, первый из которых имеет длину 1 Мбайт и расположен в начале адресного пространства, второй, размером 100 Кбайт, вплотную примыкает к первом)', а третий, имеющий размер всего 256 байт, расположен в середине девятого по счету мегабайта.
Адреса, используемые программой для обращения к ячейкам памяти, и состоящие всегда из двух компонентов — селектора и смещения — иногда называются виртуальными. Система сегментной адресации преобразует
Глава 4
виртуальные адреса в линейные. Поскольку таблица дескрипторов, с помощью которой осуществляется это преобразование, обычно недоступна программе, программа может не знать, в каких именно участках логического адресного пространства находятся ее компоненты. Фактически это сводится к тому, что, загружая программу в память, вы не знаете, в каких местах памяти будут находиться ее сегменты, и каков будет порядок их размещения. Программисту доступны только виртуальные адреса, преобразование же их в линейные и затем в физические берет на себя операционная система.
Каков объем виртуального адресного пространства' Программа указывает номер нужного ей дескриптора с помощью селектора, в котором для индекса дескриптора отведено 13 бит. Отсюда следует, что в дескрипторной таблице может быть до 2й = 8 К дескрипторов. Однако в действительности их в два раза больше, так как программа может работать не с одной, а с двумя дсскрипторными таблицами — одной глобальной, разделяемой всеми выполняемыми задачами, и одной локальной, принадлежащей конкретной задаче. В селекторе предусмотрен специачьный бит (бит 2), состояние которого говорит о типе требуемой программе дескрипторной таблицы. Таким образом, всего программе могут быть доступны 214 = 16 К дескрипторов, т.е. 16 К сегментов. Поскольку размер каждого сегмента, определяемый максимальной величиной смещения, может достигать 2}- = 4 Гбайт, объем виртуального адресного пространства оказывается равным 16 К * 4 Кбайт = = 64 Тбайт.
Реально, однако, оперативная память компьютера с 32-разрядной адресной шиной не может быть больше 4 Гбайт, т.е. при сделанных выше предположениях (16 К сегментов размером 4 Гбайт каждый) в памяти может поместиться максимум один сегмент из более чем 16 тысяч. Где же будут находиться все остальные?
Полный объем виртуального пространства может быть реализован только с помощью многозадачной операционной системы, которая хранит все неиспользуемые в настоящий момент сегменты на диске, загружая их в память по мере необходимости. Разумеется, если мы хотим полностью реализовать возможности, заложенные в современные процессоры, нам потребуется диск довольно большого объема — 64 Тбайт. Однако и при нынешних более скромных технических средствах (память до 100 Мбайт, жесткий диск до 10 Гбайт) принцип виртуальной памяти используется всеми многозадачными операционными системами с большой эффективностью. С другой стороны, для прикладного программиста этот вопрос не представляет особого интереса, так как сброс сегментов на диск и подкачка их с диска осуществляются операционной системой, а не программой, и вмешательство эту процедуру вряд ли целесообразно.