Читать «Assembler. Программирование на языке ассемблера IBM PC» онлайн - страница 161

Unknown Author

Пример:

модуль Ml

модуль М2

модуль М3

программа

A SEGMENT PUBLIC 'Q'

В SEGMENT

С SEGMENT

A SEGMENT

ртУвыс

PUBLIC

'Q' A SEGMENT 'Q'

'Q'

А(М1)

А (М2)

С

А(МЗ)

В

В окончательной программе сегменты А из модулей Ml и М2 объединены в один сегмент, а сегменты С из М2 и А из М3 располагаются рядом с этим общим сегментом, т. к. имеют тот же класс Q, но не объединяются с ним, поскольку у С иное имя, а у А из М3 не указан параметр PUBLIC. Отметим, что если бы сегмент А из модуля М2 не объединялся с сегментом А из модуля Ml, то он располагался бы вслед за сегментом С, но объединяемые сегменты, конечно, размещаются рядом, ”отодвигая" остальные сегменты.

Теперь уточним, в чем разница между объединением сегментов и просто расположением сегментов рядом в памяти. Пусть имеются два модуля:

;модуль Ml

ofs

;модуль М2

EXTRN Z:WORD

PUBLIC Z

A SEGMENT PUBLIC 'Q'

A SEGMENT PUBLIC

X DW ?

0

Z DW ?

Y DB ?

2

A ENDS

A ENDS

. ..

ofs

и пусть регистр ES установлен на начато сегмента А из Ml. Рассмотрим, как будет транслироваться и выполняться команда MOV BX,ES:Z из модуля Ml.

Если бы оба сегмента А не были объединены (например, у одного из них не было бы параметра PUBLIC), тогда смещения имен в каждом из них отсчитывались бы от начала сегмента (см. колонки ofs). Поэтому имя Z в нашей команде было бы заменено на смещение 0:

MOV BX,ES:Z ==> MOV BX,ES:0

Поскольку, согласно нашему предположению, регистр ES указывает на сегмент А из модуля Ml, то эта команда проработает неправильно: в регистр ВХ будет записано значение переменной X, а не переменной Z. Для правильного доступа к переменной Z надо перед нашей командой установить регистр ES на начало сегмента А из модуля М2, а это лишние команды. И здесь не играет никакой роли, рядом ли в памяти расположены сегменты или нет.

Если же оба сегмента А объединены, тогда сегмент А из модуля М2 считается продолжением сегмента А из модуля Ml:

A SEGMENT    ; ofs

X DW ?    ; 0

Y DB ?    ,    ; 2

; (пропуск 13 байтов)

Z DW ?    ; lOh

A ENDS

Это означает, что теперь смещения всех имен этого объединенного сегмента будут отсчитываться от начала данного сегмента и именно на эти смещения будут заменяться имена (таким пересчетом и коррекцией команд занимается компоновщик). Например, имя Z теперь будет заменяться не на смещение 0, а на смещение 10h. Почему на 10h (=16), а не на 3? Здесь надо вспомнить, что сегменты располагаются в памяти с адресов, кратных 16, и это правило действует, даже если сегменты объединяются. Поэтому сегмент А из М2 подсоединяется к сегменту А из Ml, но не впритык, а с ближайшего адреса, кратного 16, и тем самым между переменными Y и Z будет оставлено свободными 13 байтов (от этого зазора можно и избавиться - см. разд. 12.3.3). Итак, смещение имени Z равно 10h, поэтому в нашей команде имя Z будет заменено на 10h: