Преобразование адресов

 

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

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

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

В технологии преобразования виртуальных адресов в физические адреса существует два принципиально отличающихся подхода.

Способ 1: статическое преобразование адресов. Это простейший способ загрузки программного модуля в память и его выполнения. Операционная система сообщает перемещающему загрузчику (специальной системной программе) базовый адрес, по которому следует поместить модуль. Размер области памяти, на которую указывает этот адрес, должен быть достаточен для размещения программы. Перемещающий загрузчик на основании имеющихся у него исходных данных о начальном адресе физической памяти, в которую предстоит загружать программу, и информации, предоставленной транслятором об адресно-зависимых константах программы, выполняет загрузку программы, совмещая ее с заменой виртуальных адресов абсолютными физическими адресами. Эта процедура называется статической настройкой (static relocation) или статическим преобразованием адресов.

После выполнения процедур преобразования адресов и загрузки программы в память адреса больше не меняются и код или данные по этим адресам нельзя перемещать без повторной настройки. Операционной системе предоставляется только единственная возможность выгрузить программу во внешнюю память на определенное время и впоследствии заново загрузить ее в то же самое место основной памяти.

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

 
 

В системе, предназначенной для выполнения единственной задачи (например, мониторинг производственного процесса или предоставление некоторого сервиса), загруженная в память программа может выполняться бесконечно. Поэтому в подобных случаях используется стратегия статической настройки адресов во время загрузки. Все выполняемые в такой системе процессы используют одно и то же физическое адресное пространство и работают с абсолютными машинными адресами. Следовательно, они не защищены от ошибок адресации, в результате которых один процесс может ненамеренно обратиться к памяти другого, а код операционной системы не защищен от процессов прикладного уровня[20].

 

Способ 2: динамическое преобразование адресов. Программа загружается в память в неизмененном виде в виртуальных адресах, при этом операционная система фиксирует смещение действительного расположения программного кода относительно виртуального адресного пространства. Во время выполнения программы при каждом обращении к оперативной памяти выполняется преобразование виртуального адреса в физический адрес. На рис. 5.8. показана описанная структура преобразования адресов.

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

Динамическое отображение виртуального адресного пространства программы в физическую память производится аппаратным обеспечением во время выполнения программы, так как настройка адресов требуется при каждом обращении к памяти. В линейно-структурированном виртуальном адресном пространстве каждый модуль располагается в памяти непрерывным блоком, а все адреса в нем задаются относительно его начала. Физический адрес начала модуля называется базой процесса.

Пусть выбранная и декодированная процессором команда содержит некоторый адрес. Этот адрес задан относительно базы, поэтому к нему нужно прибавить значение базы (смещение) для получения физического адреса, направляемого в контроллер памяти. Простейшее аппаратное обеспечение для динамической настройки адресов состоит из базового регистра и диспетчера памяти (Memory Management Unit, MMU). В ходе настройки состояния процесса перед передачей ему управления операционная система должна загрузить в базовый регистр нужное значение.


Этот простой механизм настройки адресов не обеспечивает процессам защиты, так как добавление базового адреса к каждому адресу, по которому обращается программа, не гарантирует, что полученные адреса укажут на память, выделенную данной программе. Для обеспечения защиты вводится второй предельный (граничный) регистр, который определяет верхнюю границу адресного пространства программы. На рис. 5.10 показан типичный цикл выполнения команды, включающий настройку адресов и их защитную проверку.

Аппаратное обеспечение для настройки адресов, преобразующее виртуальные адреса в реальные во время выполнения программы, впервые было применено в начале 1960-х годов. Но еще до его появления во многих компьютерах использовались регистры защиты. Существовали разные формы защиты, но их основная идея была одинаковой: проверка каждого адреса на основе значений, заданных в аппаратных регистрах. Так, выбрав для выполнения очередной процесс, операционная система загружала адреса верхней и нижней границы его физической памяти в пару специально предназначенных для этого регистров, и процессор сравнивал с ними каждый адрес, прежде чем обратиться по нему к памяти.

Динамическое преобразование адресов является более гибким и обладает следующим преимуществами:

1.Выполнение программы не зависит от ее расположения в физической памяти, операционная система может свободно ее перемещать. Используемые в программе адреса заданы относительно ее собственного виртуального адресного пространства. При использовании первого способа перемещающий загрузчик жестко привязывает программу к первоначально выделенному ей участку памяти.

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

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