Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторный практикум «Основы разработки приложений Windows» книга 2.DOC
Скачиваний:
91
Добавлен:
10.05.2014
Размер:
827.9 Кб
Скачать

Адресация памяти

Как уже отмечалось, адрес любого байта памяти состоит из двух компонентов – содержимого сегментного регистра (оно называется селектором) и смещения. Получение из этих двух компонентов истинного физического адреса памяти осуществляется процессором посредством довольно сложной цепочки преобразований (рис. 1.5).

Рис. 1.5. Цепочка преобразования адресов в защищенном режиме

При расшифровке кодов команд процессор имеет дело с содержимым сегментных регистров (селекторами) и смещениями, которые могут храниться в тех или иных регистрах или входить в коды команд в виде операндов. Их же наблюдает программист, отлаживая программу с помощью отладчика. Комбинацию селектора и смещения иногда называют виртуальным адресом.

Получив из программы виртуальный адрес, процессор преобразует его в линейный. Делается это следующим образом.

В состав селекторов входят номера (индексы) ячеек специальной таблицы, содержащей дескрипторы сегментов программы. Эта таблица заранее строится операционной системой и размещается в системных полях памяти. Каждый дескриптор таблицы дескрипторов имеет размер 8 байт, и в нем хранятся все характеристики, необходимые процессору для обслуживания этого сегмента: базовый линейный адрес сегмента, его граница, которая представляет собой номер последнего байта сегмента, а также атрибуты сегмента, определяющие его свойства (рис. 1.6). Таким образом, селекторы в конечном счете характеризуют сегменты памяти.

Рис. 1.6. Преобразование виртуального адреса в линейный

Процессор с помощью селектора определяет индекс дескриптора адресуемого сегмента, извлекает из него базовый линейный 32-разрядный адрес сегмента и, прибавив к нему 32-разрядное же смещение, образует адрес адресуемой ячейки памяти. Этот адрес называется линейным, потому что в отличие от виртуального адреса, состоящего из двух частей, он представляет собой одно 32-разрядное число, которое может принимать, в принципе, любое значение от 0 до 0xFFFFFFFF, т. е. до 4 Г – 1.

Существенной характеристикой 32-разрядных приложений Windows является то, что они работают в так называемой плоской модели памяти (иногда для обозначения плоской памяти используют англоязычный термин “FLAT”, являющийся, кстати, ключевым словом некоторых языков программирования). Базовым адресам всех сегментов, хранящимся в таблице дескрипторов, присваивается значение 0, а границам сегментов – значение 4 Г – 1. Таким образом, все сегменты в плоской модели памяти имеют размер 4 Гбайт и накладываются друг на друга. Однако различным участкам программ (как прикладных, так и системных) назначаются различные смещения. Поскольку базовые адреса всех сегментов равны 0, смещения, действующие в программе, совпадают с линейными адресами. Это дает основание говорить, что 32-разрядные программы работают в линейном пространстве адресов.

Из всего пространства линейных адресов система Windows выделяет первые два гигабайта для прикладных программ, а вторые два гигабайта – для системных (рис. 1.7).

Рис. 1.7.Распределение линейного адресного пространства

Прикладные программы размещаются начиная с 5-го мегабайта линейного пространства, т. е. с адреса 0x400000 (первые 4 мегабайта зарезервированы для системного использования), поэтому функцияWinMainможет начинаться, например, с адреса 0x40107C, глобальные данные размещаться по адресам, начинающимся с 0x402074, а стек начинаться с адреса 0x68FE30.

Реально размер прикладных программ редко превышает несколько единиц или десятков мегабайт (часто гораздо меньше), поэтому “залезть” во второй гигабайт прикладная программа может лишь в том случае, если она обрабатывает очень большие массивы данных, например массив из 250 миллионов целых чисел, который займет в памяти, действительно, около одного гигабайта.

Большая часть системных программ располагается в 4-м гигабайте. Поэтому линейные адреса (и смещения) системных программ обычно имеют значения, начинающиеся с 0xC(например, 0xC0141A90).

Получив линейный адрес адресуемого байта, процессор с помощью таблиц страниц (их еще называют таблицами страничной трансляции) преобразует его в 32-разрядный физический адрес того байта памяти, где находится или, точнее, с которого начинается конкретная команда или конкретное данное. Этот адрес зависит от объема памяти, установленной на компьютере, и может располагаться в любом месте физической памяти (кроме 1-го мегабайта, где размещаются программы MS-DOS, видеопамять и ПЗУBIOS).

Страничная трансляция представляет собой довольно сложный механизм, в котором принимают участие аппаратные средства процессора и находящиеся в памяти таблицы страничной трансляции. Упрощенно процедуру страничной трансляции можно представить следующим образом.

Все пространство линейных адресов так же, как и пространство физических адресов реально установленной на компьютере памяти, делится на страницы объемом по 4 Кбайт. Каждой странице линейных адресов соответствует своя ячейка, или запись в таблице страниц. В эту ячейку (она имеет размер всего 4 байта) система заносит физический адрес той страницы памяти, в которую в настоящий момент загружена часть программы, соответствующая данной странице линейных адресов, чем и осуществляется отображение смещений программы на физические адреса памяти (рис. 1.8).

Если в процессе поддержки многозадачного режима система выгрузит из памяти текущую программу (или ее часть), в соответствующих ячейках таблицы страниц делается отметка “не загружена”, и связь между линейными и физическими адресами для данной программы разрывается. В дальнейшем, при повторной загрузке той же программы, она может попасть уже в другие участки физической памяти, и система соответствующим образом модифицирует таблицу страниц. В результате физические адреса, по которым загружаются части программы, в процессе работы системы динамически изменяются (и, разумеется, на разных компьютерах будут разными), в то время, как линейные адреса (смещения) конкретной программы, назначаемые ей в процессе компиляции, жестко фиксированы.

Рис. 1.8. Страничная трансляция адресов

Любопытным следствием из рассмотренного механизма преобразования адресов является тот факт, что всепрограммы в процессе компиляции получают одни и те же линейные адреса. Однако для каждой программы система образует свою таблицу страниц, переключая их при передаче управления от одной программы к другой. Поэтому, хотя все программы выполняются в одном и том же линейном адресном пространстве, их коды находятся в разных местах физической памяти и не затирают друг друга.