В.Н. Пильщиков - Программирование на языке ассемблера IBM PC (1110551), страница 10
Текст из файла (страница 10)
Пример мнегемедульней программы Ддя иллюстрации всего сказанного рассмотрим конкретный пример ыногомодульной программы, которая вводит текст, содержащий не более 100 символов и оканчивающийся точкой, и затем выводит его в обратном порядке, заиенив в неы все большие латинские буквы на соответствующие ыалые буквы. Обычно в в)ще молуля описмвают набор процедур и данных, используемых другими модулями.
Так же поступим и мы, для чего разделим нашу програыму на два ыодуля - головной и вспомогательный. Во вспомогательном модуле опишем переменную ВОТ, значением которой является символ, служащий концом ввода текста, и процедуру ЬО%1.АТ, заменяющую большую латинскую букву на мю)ую. Головной же модуль будет вводить текст, записывать его в некоторый ыассив в обратном порядке, попупю заменяя с помощью функции 1.О%1АТ большие букам на малые, и в конце распечатает этот массив. 230 Программнраааннв на замка ассемблера (ВМ РС СИР АЬ,'А' ,тв иоьат са иоьат ЬОО ЬЬ,-'А'+'а' )ЬЬг (И 'А')+'а' иоьатз ккт ьоаьат еиоу 01 ВЕЕ ЬЬ» А ала И,> Х -> ИОЬАт ; золозаое модуль хисьоок 1о.алм кхтаи котзвтте, ьовьатзуьк е ексихит етаск РВ 128 ОСР(2) 3 ЕИОЗ Р ВЕСИЕИТ тхт ов 100 РЧР(2) 0' Р ЕИ08 с Весиеит ЬЗЗОИЕ 8828, Резо, С82С ЗТАДТ2 ИОЧ АХ,О иоч ое ьх ИОЧ АХ,880 ЕОТ ИОЧ ВЕ,АХ )ВВ 01 (для досвупа к ЕОТ) ИОЧ 81,100 ООТСВ '>' 1иуз 1ИСЕ АЬ сиР ьь,еззВОТ дк РЕ СЬЬЬ ЬОВЬАТ ;замела самвола ОЕС 81 ИОЧ тХт[81),И, ;запаса свмэола в коавц тХт СИР 1ИР Рд: ьеА Ох,тхт(81) ООЗ.'ЗТВ 21И18Н с виов ез)о зтькт ое о (для д сеула к тхт) поатлаавваа к вводу ввод сазпгола коавц ззода2 завод ТХТ 12З, Параметры директивы ЯЕСМЕХТ В многомодульной программе вознюгает еще одна проблема, связанная с взаимным располоиеннем сегментов ее модулей.
Если не предпринимать каких-либо специальных мер, то в обьеднненной программе сегьгенты будут располагатьса вследугощеьг порядке: сначала будут идти сегменты молуля, указанного первым Многомодульные программы 231 <иил овгмвата> яяаИХИТ [<эираааиэаюгв>[ [<обэадиаввие>1 ['<власе>'1 Любые параметры могут отсутствовать, но если они есть, то должны быль перечислены в указанном порядке. Причем друг от друга эти параметры отделяются пробелами, а не запятыми. Расськл'рим каждмй из этих параметров. 13З.1. Параметр "класс" В этом параыетре в одиночных кавычках указывается некоторое шы, которое рассматривается как имя класса, к которому мы решили отнести наш сегмент.
Зачем нужны эти классы? Как уже сказано, при обьединении модулей в единую программу компоновщик будет располагать сегменты этих ьюдулей в слелующем порядке: сначала в программе будут идти все сегменты модуля, указанного в директиве [.Е>К первыы, затем - все сепченты второго молуля и т. д. Но иногда желательно размещать сегменты в ином порядке. Наприыер, часто хотят разместить рядом "родственные" сегменты (скажеы, сегменты команд или сегменты данных) из разных модулей.
Так вот, если какие-то сегменты отнесены к одному классу, то в окончательной программе компоновщик расположит их рядоы. Отметим при этом, что все сегменты, для которых не указан класс, считаются относящимися к одному и тоыу же классу с "пустым" именем. Пусть, к примеру, в программе имеются лгсдули М1 и МЗ, состоящие из следующих сегыентов (см. слева; для краткости для каждого сегмента указывается только его директива ЗЕОМЕ.>Т): врогроммо М класс модуль М2 модуль М! А явагщит РАТА с аваивит Ратх А с в в Р РАТА РАТА в яваивит Р ввамхнт сопя в яваихит СОРВ и пусть ыы обьединяем эти модули по приказу: ХХНК И[.ОВл+иг.овз,и.ляк; Тогда в програыме М сегменты будут расположены так, как указано справа. -димюог.миеи в приказе [2[ь К, по которому вызван компоновщик, затем будут идти сегменты модуля, укаэанного вторым, и т.
д. Это не всегда удобно. Иногда н)окно расположить сегменты в иноы порядке или желательно объединение ("слияние") некоторых сегментов из разных модулей в единый сепвент. Так аот, в ЯА имеется средство, с помощью которого можно влиять на расположение сегментов в окончательной прогрыз>ге. Этим средством являются параметры директивы ЗЕОМЕ[ЧТ, с которой начинаяпся описания программных сегментов.
В общем случае директива ЗЕОМЕХТ имеет следующий вид: 232 Прсграммиросение не языке ассемблере!ВМ рп Почему именно так? Сначала компоновщик просматривает первый из указанных еыу модулей, т. е. М1. Его сегменты, относящиеся к разным классам, не пере- упорядочиваются, а распачагвются в том порядке, как они записаны в модуле: А В. Далее компоновщик просьгатрнвает сегменты модуля М2. Первый из них - сегмент С - имеет класс РАТА. Компоновщик сыотрит, был ли ранее сегмент того же класса. Да, был, это сепчент А, поэтому компоновщик размещает С вслед за А, "отодвигая" В: А С В.
Следующий сегмент Р имеет класс СОРЕ, но среди предыдугпих сегментов не было сегмента такого класса, поэтому компоновщик размещает Р в конце последовательности: А С В Р. Последний сегмент Е относится к классу с "пустым" именем, а так как до этого уже был сепеент В того же класса, то компоновщик располагает его вслед за В и перед Р. Поскольку других сегментов и модулей нет, то данное расположение сепчентов является окончательным.
133Л. Параметр иебьединенпен Этот параметр может принимать следующие значения: Р11В1.1С, ЗТАСК, АТ и СОММО)Ч. Значение РЮВИС Как уже сказано, сегменты одного класса всегда располагаются в памяти рядом. Однако кюкдый из них сохраняет свою независимость. Это означает, что прежде чем обратиться к любому из этих сегментов, надо установить соответствующий сегментнмй регистр на начало данного сегмента.
А это лишние команды, лишний расход времени. Этого можно избежать, если обьединить сегменты в единый сегмент. Наприьгер, можно считать, что в нашей программе имелся только один сегмент данных, но по каким-то причинам мм описали его по частям в разных мслулях, и вот теперь, при компоновке программы из модулей, мы собрали эти части вместе и получили единый исходный сегмент данных. Теперь достаточно один раз установить соответствующий сепеентный регистр на начало единого сегмента и далее, не меняя значение регистра, осуществлять по нему доступ ко всем ячейкам сегмента. Такое объединение сегментов происходит, если в качестве параьгетра "обьединение" в директивах ЗЕОМЕХГ, начинающих эти сегменты, указано слово Р1)В1.1С.
Более точно правило обьединения следующее: коыпоновщик объединяет в один сегмент такие сегменты 1из любых вюдулей), у которых одно и то же ньи, которые относятся к одному и тому же классу и в директивах ЗЕОМЕХТ которых указан тип обьединения Р1)В1.)С. Если хотя бы одно из этих трех условий нарушено (у сегментов разные югена, разные классы илм разнме типы объединения), тогда сегменты не обьединяются. В частности, сегмент, для которого не указан параметр "обьединение", не будет обьединяться ни с каким другим сепгенгом. Многомодульные ллаграыыы 233 Пример: модуль М2 мм)уль М! модуль МУ арал)мама А веамкнт тввыс а с вканент г выс а А веамант а В аещ(аят А яеанент РОВьхс 'я' В окончательной программе сегменты А из модулей М1 и М2 обьедннены в один сегмент, а сегменты С из М2 и А из МЗ располагаются рядом с этим общим сегментом, т. к. имеют тот же класс О, но не обьединяются с нны, поскольку у С иное имя, а у А из МЗ не указан параметр РОВ(ЛС.
Отметим, что если бы сепчент А из модуля М2 не обьединялся с сегментом А из ыодуля М1, то он располагался бы вслед за сегментом С, но объединяемые сепаенты, конечно, размещаются рядом, "отодвигая" остальные сегменты. Теперь уточним, в чем разнипа между обьединением сегментов и просто расположениеы сегментов рядом в пэьыти. Пусть имеются два модуля: ота и пусть регистр Еб установлен на начало сею(ента А из М1. Рассмотрим, как будет транслироваться и выполюпъся команда МОЧ ВХ,ЕЗ:Е из модуля М1. Если бы оба сепаента А не были обьединены (например, у одного из них не было бы параметра Р()В(ЗС), тогда смещения имен в каждом из них отсчитывались бы от начала сегмента (сьг.
колонки о(э). Поэтому имя Е в нашей команде было бы заменено на смещение О: НОО ВХ,КВья > МОО ВХ,Еаьэ Поскольку, согласно нашему предположению, регистр ЕЯ указывает на сегмент А из модуля М1, то эта команда проработает неправильно: в регистр ВХ будет записано значение переменной Х, а не переменной 2. Для правильного достуси к псрсьюнной Е надо перед нашей командой установить регистр ЕЕ на начало сегмента А из модула М2, а это лишние команды.
И здесь не играет никакой роли, рядом ли в пюыти расположены сегменты или нет. Если же оба сегмента А обьединены, тогда сегмент А из модуля М2 считается продолжениеы сегмента А из модуля М1: отэ э А яеамент Х ов г "диалог-миФи )модуль м1 ехтвн хгиово А аеаиент тввыс а х ов г т ов г А кноа ;модуль м2 РОВЬХС Х А веаиент говьхс 'а х ов г А ЕНОЯ А(М1) А(И2) с А(ИЗ) В 234 Программирование нв язмнв вссвмлнврв 18Ы рп 2 (пропуск 13 байтов] 1,0Ь зов з е вв? ь езюв ИОЧ ВХ,ЕЯ:Я > ИОЧ ВХ,ЕВз10Ь Эта команда уже проработает правильно, менять перед ней значение регистра ЕЗ не надо.