 |
МИРЭА кафедра МОВС |
Перемещение программ
Перемещение программ
Как было отмечено ранее, очень часто желательно иметь возможность одновременно выполнять несколько программ, разделяющих между собой оперативную память и другие ресурсы машины. Если бы нам заранее было точно известно, какие программы будут выполняться одновременно, то мы могли бы во время ассемблирования назначить каждой программе подходящие адреса таким образом, чтобы не было ни взаимного перекрытия программ, ни потери места в оперативной памяти. Однако чаще всего столь точное планирование выполнения программ не пригодно с практической точки зрения. (Обычно мы не знаем абсолютно точно, когда задания начнут выполняться, сколько времени займет их выполнение и т. п.). Поэтому хотелось бы иметь возможность загружать программу на любое место в оперативной памяти, где для нее имеется достаточно пространства. В этом случае фактический начальный адрес программы не известен до момента загрузки.
Программа, которую мы рассмотрели в разд. 2.1, представляет собой пример абсолютной программы (или абсолютного ассемблирования). Для того чтобы она правильно выполнялась, ее необходимо загрузить с адреса 1000 (т. е. с адреса, назначенного при ассемблировании). Чтобы убедиться в этом, рассмотрим команду
55 101В LDA THREE 00102D
из программы, представленной на рис.2.2. В объектной программе (рис. 2.3) этому предложению соответствует команда 001020, которая обеспечивает загрузку содержимого оперативной памяти по адресу 102D в регистр А. Предположим, что мы попытались загрузить и выполнить эту программу, с адреса 2000 (вместо 1000). В этом случае адрес 102D не будет содержать ожидаемого значения. Скорее всего данный адрес будет принадлежать какой-либо другой пользовательской программе.
Очевидно, для того чтобы программа могла правильно работать, начиная с адреса 2000, мы должны сделать определенные изменения в адресной части данной команды. С другой стороны, некоторые фрагменты программы (например, константа 3, сгенерированная в строке 85) должны остаться неизменными вне зависимости от начального адреса загрузки. Если рассматривать объектный код отдельно, то в общем случае невозможно определить какие значения представляют адреса, зависящие от месторасположения программы, а какие - неизменяемые объекты.
Поскольку ассемблеру не известен фактический адрес начала загрузки, он не может выполнить необходимую настройку адресов, используемых программой. Однако ассемблер может указать загрузчику те части объектной программы, которые нуждаются в настройке при загрузке. Объектная программа, содержащая информацию, необходимую для выполнения подобной модификации, называется перемещаемой программой.
Для того чтобы детально обсудить возникающие здесь проблемы, рассмотрим программу на рис.2.5 и 2.6. В предыдущем разделе мы ассемблировали данную программу с нулевым начальным адресом. На рис. 2.7а показана ее загрузка с адреса 0. Команда JSUB (строка 15) загружается, начиная с адреса 0006. Ее адресное поле содержит значение 01036, которое является адресом команды с меткой RDREC. (Это, конечно, те же самые адреса, которые были назначены ассемблером.).
Предположим теперь, что мы хотим загрузить эту же программу с адреса 5000, как показано на рис. 2.7б. Теперь команда с меткой RDREC имеет адрес 6036. Таким образом, адресная часть команды JSUB должна быть модифицирована так, как показано на рисунке. Аналогично, если бы мы загрузили программу с адреса 7420 (рис. 2.7в), то потребовалось бы приведение команды JSUB к виду 4В108456, чтобы ее адресная часть соответствовала новому значению адреса RDREC.
Обратите внимание, что независимо от того, куда загружается программа, разница между адресом RDREC и началом программы составляет 1036 байт. Это означает, что мы можем
0000 ╥
╥ ╥
╥ ╥
╥ ╥
0006 4В101036 (+JSUB RDREC)
╥ ╥
╥ ╥
╥ ╥
╥ ╥
╥ ╥
1036 В410 RDREC
╥ ╥
╥ ╥
╥ ╥
╥ ╥
╥ ╥
1076 ╥
5000 ╥
╥ ╥
╥ ╥
╥ ╥
5006 4В106036 (+JSUB RDREC)
╥ ╥
╥ ╥
╥ ╥
╥ ╥
╥ ╥
6036 В410 RDREC
╥ ╥
╥ ╥
╥ ╥
╥ ╥
╥ ╥
6076 ╥
7420 ╥
╥ ╥
╥ ╥
╥ ╥
7426 4В108456 (+JSUB RDREC)
╥ ╥
╥ ╥
╥ ╥
╥ ╥
╥ ╥
8456 В410 RDREC
╥ ╥
╥ ╥
╥ ╥
╥ ╥
╥ ╥
8496 ╥
а б в
Рис. 2.7. Примеры перемещения программ.
решить проблему перемещения программы следующим образом:
1. Когда ассемблер генерирует объектный код команды JSUB, мы полагаем, что он заносит адрес метки RDREC относительно начала программы. (Вот почему мы установили вначале счетчик адреса равным 0.).
2. Ассемблер, кроме того, вырабатывает команду для загрузчика, которая предписывает ему прибавить к содержимому адресного поля команды JSUB начальный адрес программы.
Естественно, что команда загрузчика должна быть составной частью объектной программы. Это можно сделать с помощью дополнительного типа записи объектного формата - записи-модификатора. Эта запись имеет следующий формат:
Запись-модификатор:
Столбец 1 М.
Столбцы 2-7 Начальный адрес модифицируемого адресного поля
относительно начала программы
(шестнадцатеричный).
Столбцы 8-9 Длина модифицируемого адресного поля в
полубайтах (шестнадцатеричная).
Длина хранится с полубайтах (а не в байтах), так как модифицируемое адресное поле не обязательно содержит целое число байтов. (Например, адресное поле в рассмотренной выше команде JSUB занимает 20 разрядов, что составляет 5 полубайтов.) Месторасположение модифицируемого адресного поля задается адресом байта, в котором содержатся старшие разряды адресного поля. Если модифицируемое адресное поле занимает нечетное количество полубайтов, то предполагается, что оно начинается с середины байта, адрес которого задан в столбцах 2-7.
Эти соглашения, естественно, тесно связаны с архитектурой УУМ/ДС. Для других типов машин представление длины адресного поля в полубайтах может оказаться неудобным (см. упр. 2.2.7).
Для команды JSUB, которую мы используем в качестве примера, запись-модификатор должна иметь вид
М00000705
Она указывает на то, что начальный адрес программы необходимо добавить к полю, которое начинается с адреса 00007 (относительно начала программы), и что длина адресного поля равна 5 полубайтам. Таким образом, в ассемблированной команде 4В101036 первые 12 разрядов (код 4В1) останутся неизменными. Адрес начала загрузки программы будет добавлен к последним 20 разрядам (01036) для того, чтобы получить правильный адрес операнда. (Вам следует самостоятельно убедиться в том, что это даст результат, показанный на рис. 2.7.).
Точно такие же действия необходимо выполнить для перемещения команд, заданных в строках 35 и 65 (распечатка 4). Остальные команды не требуют модификации при загрузке. В одних случаях потому, что операнды команд расположены не в оперативной памяти (например, CLEAR S или LDA #З). В других потому, что для задания операнда использована относительная адресация. Например, команда в строке 10 (STL RETADR) ассемблируется с помощью адресации относительно счетчика команд со смещением 02D. Неважно, с какого адреса будет фактически загружена программа. В любом случае слово, помеченное меткой RETADR, будет смещено на заданную величину (2D) относительно команды STL. Поэтому данную команду модифицировать не нужно, так как во время ее выполнения счетчик команд будет содержать реальный адрес следующей команды и, таким образом, процесс вычисления целевого адреса обеспечит получение правильного реального адреса, соответствующего RETADR.
Точно так же расстояние между LENGTH и BUFFER всегда будет равно трем байтам. Таким образом, после смещения команды в строке 160, использующей адресацию относительно базы, не будет требовать модификации при перемещении программы. (Содержимое базового регистра будет, конечно, зависеть от месторасположения программы однако его значение устанавливается автоматически при выполнении команды LDB #LENGTH, в которой используется адресация относительно счетчика команд.)
H_COPY _000000_001077 T_000000_1D_17202D_69202D_4B101036_032026_290000_332007_4B10105D_3F2FIC_032010 T_00001D_13_0F2016_010003_0F200D_4B10105D_3E2003_454F46 T_001036_1D_B410_B400_B440_75101000_E32019_332FFA_DB2013_A004_332008_57C003_B850 T_001053_1D_3B2FEA_134000_4F0000_F1_B410_774000_E32011_332FFA_53C003_DF2008_B850 T_001070_07_3B2FEF_4F0000_05
M_000007_05
M_000014_05
M_000027_05
E_000000
Рис. 2.8. Объектная программа, соответствующая рис.2.6.
Рис. 2.8. Объектная программа, соответствующая рис.2.6.
Теперь нам абсолютно ясно, что модификация во время загрузки требуется только в командах, использующих прямую (как альтернатива относительной) адресацию. Для программ УУМ/ДС прямая адресация используется только в расширенном (4-байтовом) командном формате. Это существенное преимущество относительной адресации. Если бы мы попытались переместить программу, приведенную на рис.2.1, то увидели бы, что почти все команды требуют модификации.
На рис. 2.8 показано объектное представление, соответствующее исходной программе на рис.2.5. Обратите внимание, что записи тела программы остались такими же, как если бы они были подготовлены абсолютным ассемблером (с нулевым начальным адресом). Однако теперь адреса загрузки рассматриваются не как абсолютные, а как относительные величины. (То же самое, конечно, справедливо для адресов в записях-модификаторах и записи-конце.) Для каждого адресного поля, требующего настройки при перемещении программы, имеется своя запись-модификатор (в нашем случае их 3 и они все для команд +JSUB). Вам следует самостоятельно проверить каждую запись-модификатор и убедиться, что вы поняли, как она формируется. В гл. 3 мы детально рассмотрим, как загрузчик осуществляет требуемую модификацию программ. Сейчас важно, чтобы вы хорошо уяснили изложенные здесь концепции, так как они послужат основой для материала, обсуждаемого в следующем разделе.