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

Unknown Author

Как это сделать? Имя сегмента В не описано в модуле Ml и не является для него внешним, т. к. не указано в директиве EXTRN (отметим, что имена сегментов и не могут быть объявлены как внешние имена), поэтому указывать имя В в модуле Ml вообще нельзя. Но указывать явно это имя и не надо, если вспомнить про оператор SEG: SEG X - это как раз и есть начало того сегмента, где описано имя X, т. е. SEG X = В. Поэтому нам надо на самом деле выполнить присваивание DS:=SEG X.

С учетом этого и того, что, скорее всего, надо сохранять текущее значение (А) регистра DS, пересылка X:=Y должна реализовываться так:

MOV AX,Y PUSH DS MOV BX,SEG X MOV DS,BX MOV X,AX POP DS

;AX:«Y

;спасти DS (*A)

;DS:«B

;X:«AX

восстановить DS (*A)

Как видно, получилось громоздко и неуклюже, причем все это приходится повторять при каждом обращении к внешнему имени. Почему так произошло? А потому, что мы пытаемся работать с разными сегментами данных, используя только один сегментный регистр. Из-за этого нам приходится устанавливать этот регистр на начало то одного сегмента, то другого, приходится то спасать этот регистр, то восстанавливать. Ясно, что мы существенно облегчим себе жизнь, если для каждого сегмента будем использовать свой собственный регистр, например, регистр DS для сегмента А и регистр ES для сегмента В. Давайте так и сделаем: установим один раз регистр ES на начало внешнего сегмента В, а затем будем использовать ES при каждом обращении к именам из этого сегмента:

MOV АХ,SEG X MOV ES,AX

MOV AX,Y MOV ES:X,AX

Отметим, что в этом случае уже нет необходимости специально помещать директиву EXTRN X:WORD внутрь сегмента А, никакой выгоды это нам не даст. Эту директиву можно разместить и вне программных сегментов, например, в самом начале модуля Ml, где ее проще всего заметить.

Так обычно решается проблема доступа к внешним переменным. Что же касается доступа к внешним меткам или процедурам, то здесь ситуация существенно проще.

Рассмотрим такой пример:

; модуль Ml EXTRN L:FAR

JMP L

; модуль М2 PUBLIC L С SEGMENT

L: ...

Как уже было сказано, внешние метки всегда сегментируются по регистру CS, причем если они объявлены как дальние, то для них формируются дальние переходы. Поэтому в нашем примере команда JMP L будет восприниматься как команда JMP FAR PTR L, машинный эквивалент которой выглядит так:

КОП eeg(L):ofs(L)

По этой машинной команде в регистр CS заносится seg(L)=C, а в регистр IP записывается ofs(L), т. е. переход в сегмент С на метку L произойдет правильно без каких-либо дополнительных мер с нашей стороны.

12.2.5. Пример многомодульной программы

Для иллюстрации всего сказанного рассмотрим конкретный пример многомодульной программы, которая вводит текст, содержащий не более 100 символов и оканчивающийся точкой, и затем выводит его в обратном порядке, заменив в нем все большие латинские буквы на соответствующие малые буквы.