BAULA1 (1110624), страница 13

Файл №1110624 BAULA1 (Лекции Баулы) 13 страницаBAULA1 (1110624) страница 132019-04-28СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 13)

всё ещё будет иметь незаполненное поле Data формата i16 на месте второго операнда, так как конкретное значение этого поля будет известно только перед самым началом счёта программы, когда все её сегменты будут размещены в памяти компьютера.

При вызове редактора внешних связей ему в качестве параметров передаются имена всех объектных модулей, а также имя загрузочного модуля, который необходимо построить. Для нашего примера вызов редактора внешних связей (его имя link) будет выглядеть, например, так

link p1+p2+ioproc,p

Здесь p1,p2 и ioproc – имена объектных модулей (не забывайте о третьем объектном модуле с именем ioproc), а p – имя загрузочного модуля, который надо построить.1 Первый из перечисленных объектных модулей считается головным модулем, с него начинается процесс сборки загрузочного модуля. Работа редактора внешних связей включает в себя два этапа. На первом этапе происходит обработка сегментов, а на втором – собственно редактирование внешних связей и построение загрузочного модуля (загрузочные модули для нашего компьютера имеют расширение .exe). Разберёмся сначала с первым этапом.

В нашем примере (если не принимать во внимание объектный модуль ioproc.obj) имеется пять сегментов: три сегмента с именами St,Data и Code в модуле p1.obj и два сегмента с именами Data и Code в модуле p2.obj. Спрашивается, сколько сегментов будет в загрузочном модуле p.exe ? Здесь логически возможны три случая.

  • Все сегменты переходят в загрузочный модуль. В этом случае в нашем модуле p.exe должно было бы быть 5 сегментов: один стековый, два кодовых и два сегмента данных.

  • Некоторые из сегментов склеиваются, то есть один сегмент присоединяется в конец другого сегмента.

  • Некоторые из сегментов накладываются друг на друга (если сегменты имеют разную длину, то, конечно, более длинный сегмент будет "торчать" из-под более короткого сегмента). Разумеется, почти всегда накладывать друг на друга имеет смысл только сегменты данных, в этом случае у нескольких модулей будут общие сегменты данных (или, как иногда говорят, общие области данных).

Как именно будут обрабатываться сегменты при сборке загрузочного модуля из объектных модулей, определяет программист, задавая определённые параметры в директивах segment. Существуют следующие параметры, управляющие обработкой сегментов.

Параметр public у одноимённых сегментов означает их склеивание.1 Так как сборка начинается с головного модуля, то из двух одноимённых сегментов с параметром public сегмент из головного модуля будет первым, в его конец будут добавляться соответствующие сегменты из других объектных модулей. В том случае, если одноимённые сегменты с параметром public встречаются не в головном модуле, то их порядок при склейке определяется конкретным редактором внешних связей (надо читать документацию к нему).2

Для нашего примера сегмент данных с именем 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

St segment common

dw 64 dup (?)

St ends

N equ 1000

Data segment public

A dw N dup (?)

S dw ?

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 S; синоним имени Summa

newline

finish

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

Error:lea dx,T

outstr

finish

Code ends

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

Comment * модуль p2.asm

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

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

Стек головного модуля не увеличивается

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

*

M equ 1000

Data segment common

B dw M dup (?)

Summa dw ?

Data ends

Code segment public

assume cs:Code,ds:Data

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

Sum proc far

push ax

push cx

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

xor ax,ax

mov cx,M

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

L: add ax,B[bx]

jno L1

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

pop bx

pop cx

pop ax

extrn Error:near

jmp Error

L1: add bx,type B

loop L

mov Summa,ax

pop bx

pop cx

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

ret

Code ends

end

Теперь сегменты данных будут накладываться друг на друга (в головном модуле сегмент данных немного длиннее, так что длина итогового сегмента данных будет равна максимальной длине накладываемых сегментов). Как видим, почти все имена в модулях теперь являются локальными, однако из-за наложения сегментов данных друг на друга получается, что имя A является синонимом имени B (это имена одной и той же области памяти – нашего массива). Аналогично имена S и Summa также будут обозначать одну и ту же переменную в сегменте данных.

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

Заметим, что во всех предыдущих примерах нам было всё равно, в каких именно конкретных областях памяти будут располагаться сегменты нашей программы во время счёта. Более того, считается хорошим стилем так писать программы, чтобы их сегменты на этапе счёта могли располагаться в любых свободных областях оперативной памяти компьютера. Однако очень редко может понадобиться расположить определённый сегмент с явно заданного программистом адреса оперативной памяти. Для обеспечения такой возможности на языке Ассемблер служит параметр at <адрес сегмента> директивы segment. Здесь <адрес сегмента> является адресом начала сегмента в оперативной памяти, делённым на 16. В качестве примера рассмотрим такое описание сегмента с именем Interrupt_Vector.

Interrupt_Vector Segment at 0

Divide_by_Zero dd ?

Trace_Program dd ?

Fatal_Interrupt dd ?

Int_Command dd ?

Into_Command dd Code:Error

Interrupt_Vector ends

Этот сегмент во время счёта программы будет накладываться на начало вектора прерываний, а переменные этого сегмента будут обозначать конкретные адреса процедур обработки прерываний. Так заданный сегмент данных может облегчить написание собственных процедур-обработчиков прерываний.

Рассмотрим теперь второй этап работы редактора внешних связей – настройку всех внешних имён на соответствующие им входные точки в других модулях. На этом этапе редактор внешних связей начинает просматривать паспорта всех модулей и читать оттуда их внешние имена. Эта работа начинается с головного модуля, для всех его внешних имён ведётся поиск соответствующих им входных точек в других модулях. Если такой поиск оказывается безуспешным, то редактор внешних связей фиксирует ошибку: неразрешённое (в смысле ненайденное) внешнее имя.

Для некоторого внешнего имени могут существовать и несколько входных точек в разных модулях. При этом многие редакторы внешних связей такую ошибку не фиксируют и берут первое встреченное внешнее имя, так что программисту надо быть осторожным и обеспечить уникальность входных имён у всех модулей. К большому сожалению, некоторые редакторы внешних связей (в том числе и в Ассемблере MASM-4.0) не проверяют соответствие типов у внешнего имени и входной точки. Таким образом, например, внешнее имя-переменная размером в слово может быть связано с входной точкой – переменной размером в байт или вообще с меткой. При невнимательном программировании это может привести к серьёзным ошибкам, которые трудно найти при отладке программы.

Когда для некоторого внешнего имени найдена соответствующая входная точка, то устанавливается связь: адрес входной точки записывается в соответствующее поле внешнего имени. Например, для команды

call Sum; Формат i32=seg:off= call seg:off

на место поля off запишется смещение начала процедуры суммирования в объединённом после склеивания сегменте кода, а поле seg пока останется незаполненным, его значение (адрес начала сегмента кода, делённый на 16) будет известно только после размещения программы в оперативной памяти перед началом счёта. Аналогично, на место команды

mov cx,N

запишется команда

mov cx,1000

Итак, если для каждого внешнего имени найдена входная точка в другом объектном модуле, то редактор внешних связей нормально заканчивает свою работу, выдавая в качестве результата загрузочный модуль. Загрузочный модуль, как и объектный, состоит из тела модуля и паспорта. Тело загрузочного модуля содержит все его сегменты,2 а в паспорте собраны необходимые для дальнейшей работы данные:

  • информация обо всех сегментах (длина и класс сегмента), в частности, данные о сегменте стека;

  • информация обо всех ещё неопределённых полях в сегментах модуля;

  • информация о расположении входной точки программы (в нашем примере – метки Start);

  • другая необходимая информация.

На рис. 10.2 показан схематический вид загрузочного модуля, полученного для первого варианта нашего примера (со склеиваемыми сегментами). Внутри сегмента кода показаны незаполненные поля (они подчёркнуты). Метку Start можно рассматривать как единственную входную точку загрузочного модуля.

p.exe

St segment stack

Data segment

Code segment

Start: mov ax,Data

. . .

call Code:Sum

Рис. 10.2. Схематический вид загрузочного модуля, незаполненные поля подчёркнуты.

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

10.3. Схема работы статического загрузчика.

При своём вызове статический загрузчик (в дальнейшем – просто загрузчик) получает в качестве параметра имя файла загрузочного модуля. Работа начинается с чтения паспорта загрузочного модуля и определения объёма памяти, необходимого для счёта программы. Обычно это сумма длин всех сегментов программы, однако иногда в процессе счёта программа может запрашивать у операционной системы дополнительные сегменты (или, как говорят, блоки) памяти. Эти блоки чаще всего используются для размещения динамических переменных, так как заранее неизвестно, сколько памяти потребуется для хранения этих динамических переменных. Обычно в паспорте можно указать минимальный объём дополнительной памяти, без наличия которого нельзя запускать программу на счёт, и максимальный объём такой памяти, который может запросить программа.1

Итак, если на компьютере нет необходимого объёма свободной памяти, то загрузчик выдаёт аварийную диагностику и не запускает программу на счёт. В противном случае из загрузочного модуля читаются и размещаются в памяти все сегменты этого модуля,2 для каждого сегмента, таким образом, определяется адрес его начала в оперативной памяти.

Затем загрузчик просматривает паспорт загрузочного модуля и заполняет в сегментах все поля, которые ещё не имели необходимых значений. В нашем примере для загрузочного модуля p.exe это поля с именами Data и Code в сегменте команд (см. рис. 10.2). В эти поля загрузчик записывает соответственно адреса начал сегментов данных и кода, делённые на 16. На этом настройка программы на конкретное месторасположение в оперативной памяти заканчивается.

Далее загрузчик, анализируя паспорт, определяет тот сегмент, который будет начальным сегментом стека программы (как мы знаем, этот сегмент имеет параметр Stack в директиве начала сегмента). Адрес начала этого сегмента, делённый на 16, записывается в сегментный регистр SS, а длина этого сегмента – в регистр вершины стека SP. Таким образом, стек программы готов к работе.3

Характеристики

Тип файла
Документ
Размер
1,27 Mb
Материал
Тип материала
Высшее учебное заведение

Список файлов лекций

Свежие статьи
Популярно сейчас
Почему делать на заказ в разы дороже, чем купить готовую учебную работу на СтудИзбе? Наши учебные работы продаются каждый год, тогда как большинство заказов выполняются с нуля. Найдите подходящий учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6367
Авторов
на СтудИзбе
309
Средний доход
с одного платного файла
Обучение Подробнее