Программные модули в N9000

В этих архитектурах каждый объектный модуль соответствует одному модулю в смысле языка высокого уровня Oberon (или NIL— N9000 Instrumental Language). Далее мы будем описывать архитектуру системы N9000, поскольку автор с ней лучше знаком. Модуль может иметь не более 256 процедур, не более 256 переменных и ссы­латься не более чем на 256 других модулей. Код модуля является позиционно-независимым. Данные модуля собраны в отдельный сегмент, и для каждой ис­пользуемой копии модуля, т. е. для каждой программы, которая этот модуль использует, создается своя копия сегмента данных. В начале сегмента содер­жится таблица переменных. Строки этой таблицы содержат либо значения — для скалярных переменных, таких как целое число или указатель, либо адреса в сегменте данных. Кроме того, сегмент данных содержит ссылку на сегмент кода. Этот сегмент кода содержит в себе таблицу адресов точек входа всех оп­ределенных в нем функций.

Ссылки на все внешние модули собраны в таблицу, которая также содержите в сегменте данных. Внешний модуль определяется началом его сегмента данных.

Все ссылки на объекты в данном модуле осуществляются через индекс в соответствующей таблице. Ссылки на внешние модули имеют вид индекс модуля индекс объекта.

Сегмент данных не может содержать никаких статически инициализованных данных. Вся инициализация производится специальной процедурой, которая вызывается при каждом новом использовании модуля. Все эти свойства реализованы в системе команд, поэтому накладные расходы относительно невелики

Точнее, они невелики по сравнению с Intel 80286, но уже великоваты по сравнению с i386, а по сравнению с современными RISC-процессорами или системами типа транспьютера они становятся недопустимыми. Впрочем, в разд. 5.4 мы увидим, как подобная структура используется и на "обычных" процессорах.

Видно, что в системе может существовать несколько программ, обращающихся к одним и тем же модулям и использующих одну и ту же копию кода модуля. Проблем с абсолютной/относительной загрузкой вообще не возникает. Опера­ционная система ТС для N9000 была (автор не уверен, существует ли в на­стоящее время хотя бы одна работоспособная машина этой архитектуры) ос­нована на сборке программ в момент загрузки. В системе имелась специальная команда load— "загрузить все модули, используемые программой, и размес­тить для них сегменты данных, но саму программу не запускать". В памяти мог­ло находиться одновременно несколько программ; при этом модули, исполь­зуемые несколькими из них, загружались в одном экземпляре. Это значительно ускоряло работу. Например, можно было загрузить в память текстовый редак­тор, и запуск его занимал бы доли секунды, вместо десятков секунд, которые нужны для загрузки с жесткого диска фирмы ИЗОТ.

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

На практике, подобная архитектура более характерна для байт-кодов - прекомпилированных представлений программы, предназначенных для дальней­шей обработки интерпретатором — Java Virtual Machine, интерпретатором Smalltalk и т. д., чем для аппаратно реализованных систем команд. В таких сис­темах команд порой используются и более экстравагантные решения.

Архитектура AS/400

Система команд AS/400 (сервер баз данных среднего уровня, производимый IBM) представляет собой машинно-независимый байт-код. При загрузке про­граммы этот байт-код компилируется в бинарный код "реального" процессора, подобно тому, как это делается в большинстве современных реализаций Java Virtual Machine. Точнее, наоборот, успех AS/400 был одним из важных факто­ров, которые подвигли фирму Sun на разработку Java, поэтому правильнее го­ворить, что современные JVM основаны на том же принципе компиляции при загрузке, что и AS/400.

Это решение обеспечивает невысокую стоимость аппаратуры (современные AS/400 основаны на микропроцессорах архитектуры Power PC. Их более высо­кая по сравнению с машинами, основанными на процессорах х86, цена обу­словлена более производительными системной шиной и периферией), высокую производительность и возможность заменять архитектуру "реального" процес­сора без перекомпиляции пользовательского программного обеспечения. За время выпуска машин этой серии такая замена происходила дважды.

С другой стороны, отсутствие необходимости думать о том, как та или иная возможность может быть реализована аппаратно, позволила принимать весьма авангардистские решения, на которые не решался никто из разработчиков аппаратно реализованных CISC-архитектур, таких как VAX, Eclipse и даже апо­феоза CISC, Intel 432.

AS/400 имеет единое адресное пространство в том смысле, что адресуемыми объектами являются не только сегменты кода и скалярных данных, но и объек­ты реляционной СУБД, такие, как таблицы, индексы, курсоры и т. д.

Фактически, адресации подлежит вся память системы как оперативная, так и дисковая. Адрес имеет два представления: его сегментная часть может хранить имя адресуемого объекта (в контексте этой главы это можно уподобить неразрешенной внешней ссылке) или собственно адрес, 64-битовое бинарное значение. Перед тем, как обратиться к объекту, адрес-имя надо преобразовать в бинарный формат, для чего существуют специальные команды.

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

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

В большинстве современных ОС, в действительности, сборка в момент за­грузки происходит не из объектных модулей, а из предварительно собранных разделяемых библиотек. Такие библиотеки отличаются от обсуждавшихся в разд. 3.8, во-первых, тем, что из них невозможно извлечь отдельный модуль: все межмодульные ссылки внутри такой библиотеки разрешены, и ее необходимо всегда загружать как целое; и, во-вторых, тем, что список символов, экспортируемых такой библиотекой, не является объединением списков экспорта составляющих ее объектных модулей. При сборке такой библиотеки необходимо указать, какие из символов будут экспортироваться. Некоторые редакторы связей позволяют на этом этапе создавать дополни­тельные символы.