Студопедия

Главная страница Случайная страница

КАТЕГОРИИ:

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






St segment stack






dw 64 dup (?)

St ends

N equ 1000

Data segment public

A dw N dup (?)

public A, N; Входные точки

extrn Summa: word; Внешняя переменная

Diagn db 'Переполнение! ', 13, 10, '$'

Data ends

Code segment public

assume cs: Code, ds: Data, ss: St

Start: mov ax, Data

mov ds, ax

mov cx, N

sub bx, bx; индекс массива

L: inint A[bx]; Ввод массива A

add bx, type A

loop L

extrn Sum: far; Внешнее имя

call Sum; Процедура суммирования

outint Summa

Newline

; А теперь вызов с ошибкой

mov A, 7FFFh; Maxint

mov A+2, 1; Для переполнения

call Sum

outint Summa; Сюда возврата не будет

Newline

finish; Вообще-то не нужен

public Error; Входная точка

Error: lea dx, T

Outstr

Finish

Code ends

end Start; головной модуль

 

В нашем головном модуле три входные точки с именами A, N и Error и два внешних имени: Sum, которое имеет тип дальней метки, и Summa, которое имеет тип слова. Работу программы подробно рассмотрим после написания текста второго модуля с именем p2.asm.

Comment * модуль p2.asm

Суммирование массива, контроль ошибок

include io.asm не нужен – нет ввода/вывода

Используется стек головного модуля

В конечном end не нужна метка Start

*

Data segment public

Summa dw?

public Summa; Входная точка

extrn N: abs; Внешняя константа

extrn A: word; Внешний адрес

Data ends

Code segment public

assume cs: Code, ds: Data

public Sum; Входная точка

Sum proc far

push ax

push cx

push bx; сохранение регистров

xor ax, ax; ax: =0

mov cx, N

xor bx, bx; индекс 1-го элемента

L: add ax, A[bx]

jno L1

; Обнаружена ошибка

pop bx

pop cx

pop ax

extrn Error: near

jmp Error

L1: add bx, type A

loop L

mov Summa, ax

pop bx

pop cx

pop ax; восстановление регистров

Ret

Code ends

End

Наш второй модуль не является головным, поэтому в его директиве end нет метки первой команды программы. Модуль p2.asm имеет три внешних имени A, N и Error и две входные точки с именами Sum и Summa. Так как второй модуль не производит никаких операций ввода/вывода, то он не подключает к себе файл io.asm. Оба наших модуля используют общий стек объёмом 64 слова, что, наверное, достаточно, так как стековый кадр процедуры Sum невелик.

Разберём работу нашей программы. После ввода массива A головной модуль вызывает внешнюю процедуру Sum. Это статическая связь модулей по управлению, дальний адрес процедуры Sum будет известен головному модулю до начала счёта. Этот адрес будет расположен в формате i32 на месте операнда Sum команды call Sum.

Между основной программой и процедурой установлены следующие (нестандартные) соглашения о связях. Суммируемый массив знаковых чисел расположен в головном модуле и имеет общедоступное имя A. Длина массива является общедоступной константой с именем N, описанной в головном модуле. Вычисленная сумма массива помещается в общедоступную переменную с именем Summa, описанную во втором модуле. Всё это примеры статических связей по данным. Наша программа не содержит динамических связей по данным, в качестве примера такой связи можно привести передачу параметра по ссылке в процедуру другого модуля. Действительно, адрес переменной становится известным процедуре только во время счёта программы, когда он передан ей вызывающей программой (обычно в стеке).

В том случае, если при суммировании массива обнаружена ошибка (переполнение), второй модуль передаёт управление на общедоступную метку с именем Error, описанную в головном модуле. Остальные имена являются локальными в модулях, например, обратите внимание, что в обоих модулях используется одинаковая метка c именем L.

Здесь необходимо отметить важную особенность использования внешних адресов. Рассмотрим, например, команду

L: add ax, A[bx]

во втором модуле. При получении из этого предложения языка Ассемблера машинной команды необходимо знать, по какому сегментному регистру базируется наш внешний адрес A. На это во втором модуле (а только его и видит во время перевода программа Ассемблера, первый модуль недоступен!) указывает местоположение директивы

extrn A: word; Внешний адрес

внутри второго модуля. Эта директива располагается в сегменте с именем Data, а директива

assume cs: Code, ds: Data

определяет, что во время счёта на этот сегмент будет установлен регистр ds. Следовательно, адрес A соответствует области памяти в том сегменте, на который указывает регистр ds.[46] Как видим, директива assume нам снова пригодилась.

Продолжим рассмотрение работы нашей программы. Получив управление, процедура Sum сохраняет в стеке используемые регистры (эта часть соглашения о связях выполняется), и накапливает сумму всех элементов массива A в регистре ax. При ошибке переполнения процедура восстанавливает значения регистров и передаёт управление на метку Error в головном модуле. В нашем примере второй вызов процедуры Sum специально сделан так, чтобы вызвать ошибку переполнения. Заметим, что переход на внешнюю метку Error – это тоже статическая связь по управлению, так как адрес метки известен до начала счёта. В то же время возврат из внешней процедуры по команде ret является динамической связью по управлению, так как конкретный адрес возврата в другой модуль будет помещён в стек только во время счёта программы.

Программа Ассемблера не в состоянии перевести каждый исходный модуль в готовый к счёту фрагмент программы на машинном языке, так как, во-первых, не может определить внешние адреса модуля, а, во-вторых, не знает будущего расположения сегментов модуля в памяти. Говорят, что Ассемблер переводит исходный модуль на специальный промежуточный язык, который называется объектным языком. Следовательно, программа Ассемблер преобразует входной модуль в объектный модуль. Полученный объектный модуль оформляется в виде файла, имя этого файла обычно совпадает с именем исходного файла на языке Ассемблер, но имеет другое расширение. Так, наши исходные файлы p1.asm и p2.asm будут переводиться (или, как чаще говорят, компилироваться или транслироваться) в объектные файлы с именами p1.obj и p2.obj.

Рассмотрим теперь, чего не хватает в объектном модуле, чтобы быть готовым к счёту фрагментом программы на машинном языке. Например, самая первая команда всех наших программ

mov ax, Data

должна переводится в машинную команду пересылки формата mov ax, i16, однако значение константы i16, которая равна физическому адресу начала сегмента Data в памяти, делённому на 16, неизвестна программе Ассемблера и поле операнда i16 в команде пересылки остаётся незаполненным. Таким образом, в объектном модуле некоторые адреса остаются неизвестными (неопределёнными). До начала счёта программы, однако, все такие адреса обязательно должны получить конкретные значения.

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

· Сведения обо всех сегментах модуля (длина сегмента, его спецификация).

· Сведения обо всех общедоступных (экспортируемых) именах модуля, с каждым таким именем связан его тип (abs, byte, word, near и т.д.) и адрес (входная точка) внутри какого-либо сегмента модуля (для константы типа abs это просто целое число).

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

· Сведения о местоположении всех остальных незаполненных адресов в модуле, для каждого такого адреса содержится информация о способе его заполнения перед началом счёта.

· Другая информация, необходимая для сборки программы из модулей.

На рис. 10.1 показано схематическое изображение объектных модулей p1.obj и p2.obj, полученных программой Ассемблера, для каждого модуля изображены его сегменты, входные точки и внешние адреса. Вся эта информация содержится в паспортах объектных модулей.[47]

p1.obj     p2.obj
       
St segment stack       Data segment public extrn A: word extrn N: abs public Summa: word
Data segment public public A: word public N: abs extrn Summa: word     A N Summa A N Summa
Code segment public Extrn Sum: far public Error: near   Sum Error   Sum Error Code segment public publicSum: far extrnError: near
       
Рис. 10.1. Схематический вид объектных модулей с внешними адресами и входными точками.

Обратимся теперь к проблеме сборки программы из модулей. Как мы уже упоминали, эту работу выполняет специальная системная программа, которая называется редактором внешних связей. Из этого названия хорошо видно одно из назначений этой программы – устанавливать связи между внешними адресами и входными точками модулей. Рассмотрим схему работы редактора внешних связей на нашем примере.


Поделиться с друзьями:

mylektsii.su - Мои Лекции - 2015-2024 год. (0.011 сек.)Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав Пожаловаться на материал