Схема работы редактора внешних связей.
Целью работы редактора внешних связей является построение из объектных модулей почти готового к счёту программного модуля, который называется загрузочным модулем. Загрузочный модуль всё ещё не является полностью готовой к счёту программой на машинном языке, в этом модуле остаются незаполненными некоторые поля. Например, наша команда
mov ax,Data
всё ещё будет иметь незаполненное поле Data формата i16 на месте второго операнда, так как конкретное значение этого поля будет известно только перед самым началом счёта программы, когда все её сегменты будут размещены в памяти компьютера.
При вызове редактора внешних связей ему в качестве параметров передаются имена всех объектных модулей, а также имя загрузочного модуля, который необходимо построить. Для нашего примера вызов редактора внешних связей (его имя link) будет выглядеть, например, так
link p1+p2+ioproc,p
Здесь p1,p2 и ioproc – имена объектных модулей (не забывайте о третьем объектном модуле с именем ioproc), а p – имя загрузочного модуля, который надо построить.[48] Первый из перечисленных объектных модулей считается головным модулем, с него начинается процесс сборки загрузочного модуля. Работа редактора внешних связей включает в себя два этапа. На первом этапе происходит обработка сегментов, а на втором – собственно редактирование внешних связей и построение загрузочного модуля (загрузочные модули для нашего компьютера имеют расширение .exe). Разберёмся сначала с первым этапом.
В нашем примере (если не принимать во внимание объектный модуль ioproc.obj) имеется пять сегментов: три сегмента с именами St,Data и Code в модуле p1.obj и два сегмента с именами Data и Code в модуле p2.obj. Спрашивается, сколько сегментов будет в загрузочном модуле p.exe ? Здесь логически возможны три случая.
· Все сегменты переходят в загрузочный модуль. В этом случае в нашем модуле p.exe должно было бы быть 5 сегментов: один стековый, два кодовых и два сегмента данных.
· Некоторые из сегментов склеиваются, то есть один сегмент присоединяется в конец другого сегмента.
· Некоторые из сегментов накладываются друг на друга (если сегменты имеют разную длину, то, конечно, более длинный сегмент будет "торчать" из-под более короткого сегмента). Разумеется, почти всегда накладывать друг на друга имеет смысл только сегменты данных, в этом случае у нескольких модулей будут общие сегменты данных (или, как иногда говорят, общие области данных).
Как именно будут обрабатываться сегменты при сборке загрузочного модуля из объектных модулей, определяет программист, задавая определённые параметры в директивах segment. Существуют следующие параметры, управляющие обработкой сегментов.
Параметр public у одноимённых сегментов означает их склеивание.[49] Так как сборка начинается с головного модуля, то из двух одноимённых сегментов с параметром public сегмент из головного модуля будет первым, в его конец будут добавляться соответствующие сегменты из других объектных модулей. В том случае, если одноимённые сегменты с параметром public встречаются не в головном модуле, то их порядок при склейке определяется конкретным редактором внешних связей (надо читать документацию к нему).[50]
Для нашего примера сегмент данных с именем Data объектного модуля p2.obj будет добавлен в конец одноимённого сегмента данных головного модуля p1.obj. Такая же операция будет проведена и для сегментов кода этих двух модулей. Таким образом, в загрузочном модуле останутся только три сегмента: сегмент стека St, сегмент данных Data и кодовый сегмент Code. При склейке кодовых сегментов редактору внешних связей придётся изменить некоторые адреса в командах перехода внутри добавляемого модуля. Правда, как легко понять, меняются адреса только в командах абсолютного перехода и не меняются относительные переходы (это ещё одно достоинство команд перехода, которые реализуют относительный переход).
Для склеиваемых сегментов данных могут измениться начальные значения переменных во втором сегменте, например, пусть в сегменте данных второго модуля находится такое предложение резервирования памяти
Z dw Z
Здесь начальным значением переменной Z служит её собственный адрес (смешение от начала сегмента данных). При склейке сегментов это значение увеличится на длину сегмента данных первого модуля.
Отметим также, что параметр директивы сегмента stack, кроме того, что определяет сегмент стека, даёт такое же указание о склейке одноимённых сегментов одного класса, как и параметр public. Другими словами, одноимённые сегменты стека тоже склеиваются, это позволяет каждому модулю увеличивать размер стека на нужное этому модулю число байт. Таким образом, головной модуль (что вполне естественно) может не знать, какой дополнительный размер стека необходим для правильной работы остальных модулей.
Для указания наложения одноимённых сегментов одного класса друг на друга при сборке программы из объектных модулей предназначен параметр common директивы segment. В качестве примера использования параметра common рассмотрим другое решения предыдущей задачи, при этом сегменты данных двух наших модулей будут накладываться друг на друга. Итак, новые варианты модулей p1.asm и p2.asm приведены ниже.
; p1.asm
; Ввод массива, вызов внешней процедуры
include io.asm
Дата добавления: 2015-10-05; просмотров: 948;