АССЕМБЛЕР. Компоновщик. Загрузчик. Макрогенератор


Объединение модулей.


Свою работу компоновщик начинает с того, что считывает в оперативную память заголовки всех ОМ, указанных в приказе LINK. Далее он определяет, в каком порядке будут располагаться в окончательной программе сегменты из ее модулей и фиксирует эту информацию в общей таблице сегментов

(ОТС).

Эта таблица строится на основе таблиц сегментов (ТС) из модулей. Пусть, к примеру, в программе имеются два модуля М1 и М2 с такими ТС:

             модуль М1:                         модуль М1:

  сегмент  нач.адрес  размер  класс      сегмент  нач.адрес  размер  класс

          (в модуле)                         (в модуле)

------------------------------------  ------------------------------------

     S1         0      1000   STACK         Q1          0       22    DATA

     S2      1000         8    DATA         Q2         30      103    CODE

     S3      1010       625    CODE

Тогда ОТС будет иметь следующий вид:

           сегмент  модуль    начальный адрес  размер  класс

                             в модуле  в пр-ме



           ----------------------------------------------------

              S1       M1          0        0    1000   STACK

              S2       M1       1000     1000       8    DATA

              Q1       M2          0     1010      22    DATA

              S3       M1       1010     1040     625    CODE

              Q2       M2         30     1670     103    CODE

                    -------------------------------------------

                        длина программы: 1670 + 103 = 1773

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

Первое, что должен сделать компоновщик, - это так расположить сегменты, чтобы сегменты одного класса оказались рядом. Решается эта задача следующим образом. Из заголовка ОМ, указанного в приказе LINK первым (у нас это M1), берется ТС и информация из нее переносится в ОТС (колонка "нач. адрес в программе" пока пуста). Затем берется ТС из ОМ, указанного в приказе LINK вторым (у нас - из M2), и последовательно рассматриваются перечисленные в ней сегменты. Первым идет сегмент Q1; смотрится, какого он класса и нет ли уже в ОТС сегмента того же класса. Есть, это S2. Значит, S2 и Q1 должны располагаться рядом. Поэтому строка с S3


сдвигается вниз, а после S2
записывается информация о Q1. Берется следующий сегмент Q2; он того же класса, что и сегмент S3; значит, S3 и Q2 должны быть расположены рядом. Однако в данном случае ничего в ОТС сдвигать не надо и информация о Q2 записывается в конец ОТС. Поскольку больше модулей и сегментов нет, то получившееся расположение сегментов является окончательным, именно так они и будут расположены в объединенной программе.
Итак, манипулируя строками из ТС разных модулей, компоновщик расположил сегменты этих модулей так, чтобы сегменты одного класса оказались рядом. При этом сами сегменты, т.е. их машинные коды, никак не переставляются, не переписываются с места на место (их вообще пока не в ОП), что было бы долго. Перестановки идут только на уровне строк таблиц сегментов, а это делается просто.
Далее компоновщик пересчитывает начальные адреса сегментов. Дело в том, что в ТС модулей указаны адреса сегментов относительно начала модулей, а теперь нужны адреса сегментов относительно начала всей программы. Такой пересчет делается просто. Первый сегмент S1, естественно, получает смещение 0. Поскольку он занимает 1000h байтов, то адрес первой свободной ячейки за ним равен 1000h. Это адрес кратен 16, поэтому с него можно начинать размещать следующий сегмент, поэтому этот адрес становится начальным адресом сегмента S2. Этот сегмент занимает 8 байтов, поэтому первый свободный адрес за ним - 1008h, но этот адрес не кратен 16 и с него нельзя начинать сегмент. Компоновщик берет ближайший адрес, кратный 16 (у нас это 1010h), и именно его делает начальным адресом следующего сегмента Q1. Аналогично по адресу и длине сегмента Q1
определяется начальный адрес для сегмента S3
(это 1040h), а по адресу и длине сегмента S3
определяется начальный адрес сегмента Q2
(это 1670h). Тем самым адреса всех сегментов относительно начала программы установлены.
Отметим попутно, что если сложить начальный адрес последнего сегмента (1670h) и длину этого сегмента (103h), то мы получим размер всей программы (1773h). Это число запоминается, оно еще пригодится.


Составив ОТС и тем самым определив, как внутри программы должны располагаться сегменты, компоновщик далее считывает с диска машинные коды (тела) ОМ в оперативную память и размещает их сегменты согласно указанному в ОТС порядку. Делается это так. В какое-то свободное место ОП считываются весь машинный код модуля M1, а затем сегменты этого модуля переносятся в соответствующие места той части ОП, где формируется машинный код всей программы (сколько переписывать, откуда и куда - все это определяется по ОТС). В нашем случае первые 1000h байтов из M1
переписываются в программу по адресу 0, затем 8 байтов из M1 начиная с его адреса 1000h переписываются в программу по адресу 1000h и, наконец, переписываются 625h байтов из M1 начиная с его адреса 1010h переписываются в программу по адресу 1040h. Затем аналогично поступают с сегментами из модуля M2:
            M1                M               M2
        0 -----¬         0 -----¬         0 -----¬
          ¦ S1 ¦ ---->     ¦ S1 ¦   ------- ¦ Q1 ¦
     1000 ¦----¦      1000 ¦----¦   ¦    30 ¦----¦
          ¦ S2 ¦ ---->     ¦ S2 ¦   ¦ ----- ¦ Q2 ¦
     1010 ¦----¦      1010 ¦----¦   ¦ ¦     L-----
          ¦ S3 ¦ -¬        ¦ Q1 ¦ <-- ¦
          L-----  ¦   1040 ¦----¦     ¦
                  L-->     ¦ S3 ¦     ¦
                      1670 ¦----¦     ¦
                           ¦ Q2 ¦ <----
                           L-----
Собранные таким образом машинные коды сегментов и образуют машинный код единой программы. На этом этап объединения модулей завершен. После некоторой корректировки этот код станет телом ЗМ.

Содержание раздела