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

Редактирование межмодульных связей


Такая корректировка заключается в замене внешних имен, использовавшихся в модулях, на соответствующие адреса. Делается это так.

Напомним, что в заголовке каждого ОМ есть таблица общих имен (ТОБ), в которой для каждого общего имени данного модуля указано само имя и его адрес внутри модуля. Компоновщик выделяет из заголовков эти таблицы и объединяет их в общую таблицу общих имен (ОТОБ). Например, если в программе имеется два модуля М1

и М2 с такими ТОБ:

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

    общее имя    адрес            общее имя    адрес

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

        B         S2:2                X        Q1:20

                                 P        Q2:0

тогда ОТОБ будет выглядеть так:

   Общая ТОБ:      общее имя     адрес

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

                      B           S2:2

                      X           Q1:20



                      P           Q2:0

Теперь вспомним, что общее имя одного модуля - это внешнее имя другого модуля. Значит, ОТОБ - это одновременно и таблица всех внешних имен с указанием их адресов. Поэтому компоновщик теперь может сделать то, что в свое время не удалось сделать ассемблеру, - заменить все внешние ссылки во всех модулях на соответствующие им адреса.

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

Пусть, к примеру, в модуле М1 была такая ТВН:

           внеш.имя   адрес вхождения   тип вхождения

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

              X         S2:0               ofs

              X         S2:2               seg

              P         S2:6               segofs

Первая ее строка указывает, что смещение имени X


надо записать в ячейку с адресом S2:0, т.е. в 0- ю ячейку сегмента S2. Смещение имени X компоновщик узнает по ОТОБ, оно равно 20h, а начальный адрес сегмента узнает по ОТС,  он равен 1000h, поэтому число 20h он заносит в ячейку с адресом 1000h+0=1000h, отсчитанным от начала программы.
Следующая строка таблицы указывает, что в ячейку с адресом S2:2 надо записать номер сегмента (начальный адрес без последнего 0), в котором находится ячейка с именем X. По ОТОБ компоновщик узнает, что сегментом имени X
является Q1. Однако компоновщик не знает настоящий начальный адрес этого сегмента: он знает только его адрес относительно начала программы, а настоящий же адрес зависит от того, с какого места памяти будет расположена вся программа при счете, а это пока неизвестно. Что делать компоновщику? Напомним, что с такой же проблемой сталкивается и ассемблер. Как поступает ассемблер? Он ничего не записывает в соответствующую ячейку, но в таблице перемещаемых адресов (ТПА) запоминает, что затем в эту ячейку надо будет записать номер этого сегмента. Аналогично поступает и компоновщик: он строит свою (новую) ТПА, где запоминает, в какие ячейки он должен был бы записать номера каких сегментов, но не смог этого сделать. У нас в этой ТПА появится первая из следующих строк:
     имя сегмента   адрес вхождения
     ------------------------------
          Q1           S2:2
     Q2           S2:8
               ...
Третья строка ТВН из модуля M1 указывает, что в ячейку S2:6 надо записать и смещение, и номер сегмента имени P, т.е. здесь объединены два уже рассмотренных нами случая. Узнав по ОТОБ, что смещение имени P равно 0, компоновщик записывает 0 в ячейку S2:6. Из ОТОБ компоновщик узнает, что имя P
- из сегмента Q2, однако записать номер этого сегмента во вторую половину данной ячейки (в S2:8) не может, поэтому он добавляет в свою ТПА новый элемент - вторую из указанных выше строк.
Далее компоновщик просматривает ТВН из следующих модулей и поступает с ними аналогично.
На этом заканчивается замена внешних имен на их адреса, т.е. редактирование межмодульных связей. Полученный таким образом машинный код и является телом загрузочного модуля. Ничего более в нем компоновщик не будет менять.

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