Виртуальные и физические адреса
Понятие «адрес памяти» может рассматриваться с двух точек зрения. С одной стороны, при написании любой программы ее автор либо явно указывает, по каким адресам должны размещаться переменные и команды (так бывает при программировании на языке ассемблера), либо присвоение конкретных адресов доверяется системе программирования. Те адреса памяти, которые записаны в программе, принято называть виртуальными адресами.
С другой стороны, каждой ячейке памяти компьютера соответствует ее адрес, который должен помещаться на шину адреса при каждом обращении к ячейке. Эти адреса называются физическими.
В ЭВМ первого поколения не делалось различия между виртуальными и физическими адресами: в программе требовалось указывать физические адреса. Это означало, что такая программа могла правильно работать, только если сама программа и все ее данные при каждом запуске (и на любом компьютере) должны были размещаться по одним и тем же физическим адресам. Такой подход стал крайне неудобным, как только была поставлена задача передать распределение памяти под управление ОС.
В настоящее время программирование в физических адресах может использоваться лишь в очень специальных случаях. Как правило, ни программист, пишущий программу, ни компилятор, транслирующий ее в машинные коды, не должны рассчитывать на использование конкретных физических адресов.
Но тогда возникает вопрос, когда и каким образом должен происходить переход от виртуальных адресов к физическим.
Есть два принципиально разных ответа на этот вопрос.
В системах, не рассчитанных на использование специальных аппаратных средств преобразования адресов, замена виртуальных адресов на физические может быть выполнена только программным путем. Это должно быть сделано до начала работы программы, либо на этапе компоновки программы, либо (в более поздних системах) при загрузке программы из файла в память.
В современных системах, предназначенных для работы на процессорах с сегментной или страничной организацией памяти (см. об этом ниже), программа даже после загрузки в память содержит виртуальные адреса. Преобразование в физические адреса выполняется при выборке каждой команды из памяти, при обращении к ячейкам данных — т.е. при каждом использовании адреса. Конечно, это возможно только в том случае, если имеется специальная аппаратура, позволяющая преобразовывать адреса практически без потери времени.
Распределение памяти без использования виртуальных адресов
Настройка адресов
Если в программе используются значения физических адресов, то правильность ее работы зависит от того, по каким адресам загружена в память сама программа. Это особенно очевидно для команд перехода: если в программе есть команда «Перейти по адресу 1000», то сдвиг этой программы в памяти приведет к тому, что переход будет выполнен на совсем другую команду, хотя и по тому же адресу.
В то же время трудно рассчитывать, что при каждом запуске программы ОС сможет загрузить ее по одним и тем же адресам. Если это еще в принципе возможно для однозадачной ОС, то в случае нескольких задач их программы могут претендовать на одни и те же адреса.
Для решения этой проблемы в составе файла программы приходится хранить словарь перемещений— список всех тех мест в программе, которые содержат адреса, требующие настройки на адрес загрузки программы. Такая настройка в большинстве случаев представляет собой просто сложение адреса загрузки с адресом, хранящимся в файле программы, и выполняется при загрузке программы в память. Выполнение настройки приводит к некоторой задержке при запуске программ.
Более поздние архитектуры ЭВМ позволили в значительной мере упростить дело за счет использования относительной адресации — указания адреса как смещения относительно значения в некотором базовом регистре. Теперь настройка требовалась лишь для нескольких команд, загружающих значения в базовые регистры. Более того, для многих не слишком сложных программ стало возможно обойтись вообще без словаря перемещений (например, если все адреса указаны только как смещения относительно начала программы). Подобные программы, способные без изменений правильно работать при загрузке по любому адресу, называются позиционно-независимыми, в отличие от перемещаемых программ, требующих настройки адресов.
В системе MS-DOS все файлы типа COM содержат позиционно-независимые программы, а файлы EXE — перемещаемые.