Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Информатика

.pdf
Скачиваний:
94
Добавлен:
11.05.2015
Размер:
1.73 Mб
Скачать

211

Begin:

mov

dx, Msg

; DX Å адрес сообщения

 

mov

ah, 9

; Вывод строки

 

int

21h

;

на экран

 

mov

ax, 4c00h

; Возврат в DOS с

 

int

21h

;

кодом завершения 0

Во-первых, обратим внимание на наличие виртуального сегмента кода. В п.2.3 шла речь о логических сегментах программы. Напомним, что каждый виртуальный сегмент начинается с рассмотренного ранее псевдооператора absolute или с псевдооператора segment. Параметром этого оператора является тип сегмента – code. Это слово “code” может использоваться в программе в качестве имени (метки) этого сегмента.

Кроме сегмента code в программе возможно наличие сегментов других типов – data (данные) и stack (стек). Отсутствие других виртуальных сегментов в рассматриваемой исходной программе обусловлено тем, что она ориентирована на получение машинной com-программы. Поэтому наличие других виртуальных сегментов является излишним, так как после загрузки com- программы загрузчик копирует содержимое регистра CS в качестве содержимого других сегментных регистров – DS, ES и SS.

Во-вторых, обратим внимание на отсутствие псевдооператора “org”. Данный оператор нельзя использовать в исходных программах, предназначенных для получения объектных модулей. Вместо него в начале виртуального сегмента может использоваться знакомый нам псевдооператор resb. Данный оператор задает адрес-смещение для самой первой команды сегмента кода внутри сегмента ОП, выделенного машинной программе. Обратите внимание на порядок записи операторов segment и resb. Если их поменять местами, то сегмент кода будет начинаться не от начала сегмента памяти, а со смещением 100h, что не соответствует размещению логических сегментов для com-программы (см. рис. 61).

212

В-третьих, первый исполнительный оператор виртуального сегмента кода имеет стандартную метку входа в программу “..start:”.

Для получения объектного модуля программы с помощью транслятора NASM необходимо использовать при вызове этой программы дополнительный параметр “-f obj”, уточняющий тип целевого файла. Допустим, что приведенная выше программа записана в исходный файл test.asm. Тогда для получения объектного файла можно воспользоваться командой DOS:

nasm test.asm -f obj -o test.obj

Вданном примере первый параметр команды задает имя исходного файла, второй параметр – тип целевого файла, а третий – имя целевого файла.

Преобразование одного или нескольких объектных модулей в загрузочный модуль (com- или exe-файл) выполняет редактор связей ALINK. В качестве одного или нескольких параметров команды запуска ALINK задается имя одного или нескольких объектных модулей. В качестве следующего параметра

тип целевого файла (загрузочного модуля). А в качестве последнего параметра – имя загрузочного модуля. Пример команды запуска ALINK:

alink test.obj -oCOM -o test.com

Обратите внимание, что второй параметр записан слитно, а тип файла (COM) записан большими буквами. П о л у ч и т е com-файл для приведенной выше «вежливой» программы, а затем выполните ее.

17.4.Программа типа exe

Вотличие от com-программы, загружаемой по умолчанию в один стандартный сегмент ОП объемом 64K, программа типа exe может занимать несколько таких сегментов. Следствием этого является наличие в программе команд, выполняющих запись в регистры адресов-сегментов, требующих своей настройки во время загрузки.

Врезультате, получение exe-программы требует не простого копирования соответствующего файла в ОП, а предполагает преобразование этого файла

213

загрузчиком. В результате, загрузчик не только записывает PSP программы (это он делает и для com-файла), но и настраивает некоторые адреса в полях машинных команд. В начале exe-файла находится заголовок, размер которого кратен 512 байтам, содержащий управляющую информацию, используемую загрузчиком для получения exe-программы.

Свою работу по созданию exe-файла редактор связей начинает с того, что последовательно записывает в свою память код (команды), данные и стек будущей программы. Порядок расположения этих частей программы, в отличие от com-файла, может быть любым. Их содержимое редактор связей считывает из доступных ему объектных модулей программы. Выполняя размещение программы в памяти, редактор связей обращается с ее адресами так, как будто программа загружена в ОП, начиная с условного адреса 00000h. Поэтому считается, что часть программы (код, данные или стек), размещаемая первой, имеет начальный логический адрес 0000h:0000h. Если, например, вторая часть программы начинается с условного реального адреса 000E7h, то ему соответствует начальный логический адрес 000Eh:0007h. Применение таких условных адресов позволяет редактору связей выполнить запись численных значений для всех внешних адресов, оставшихся не проставленными после трансляции.

Исключение составляют команды, выполняющие запись в регистры значений адресов-сегментов. К таким командам относятся, во-первых, команды дальнего перехода jmp и call (они выполняют запись адреса-сегмента в регистр CS), а во-вторых, команды mov, выполняющие запись адресов-сегментов в регистры данных (из регистров данных другие команды mov переписывают значения в регистры сегментов DS, ES, SS). Например, следующие два оператора исходной программы выполняют запись в регистр DS того адресасегмента, который соответствует точке исходной программы с меткой Msg:

mov dx, seg Msg mov ds, dx

214

Первый оператор mov транслируется в трех-, а второй – в двухбайтовую машинную команду. При этом второй и третий байты первой команды используются для размещения адреса-сегмента, загружаемого в регистр DX.

Так как адреса-сегменты зависят от фактического размещения будущей программы в ОП, которое редактор связей «не знает», то он не может проставить численные значения адресов-сегментов в поля машинных команд. Тем не менее, он выполняет значительную подготовку для будущей простановки этих значений загрузчиком. Для этого, во-первых, редактор связей помещает в эти поля условные адреса-сегменты, полученные в предположении, что программа загружается в память, начиная с нулевого адреса.

Во-вторых, редактор связей создает таблицу настройки, занимающую почти весь объем заголовка exe-файла. Эта таблица состоит из четырехбайтовых полей, каждое из которых соответствует одному адресусегменту, используемому какой-то командой программы, и который требует настройки в зависимости от фактического размещения программы в памяти. В качестве содержимого этого поля редактор связей записывает условный логический адрес (сегмент и смещение) той ячейки (двух байтов) программы, которая содержит адрес-сегмент, требующий настройки.

Сама настройка адресов-сегментов программы производится загрузчиком сразу же после размещения программы (в том числе и PSP) в ОП. Для этого загрузчик последовательно просматривает таблицу настройки, считывая из нее указатель на очередную последовательность из двух байтов программы, требующую настройки. А затем он прибавляет к их содержимому (то есть к условному адресу-сегменту) номер того параграфа ОП, начиная с которого программа загружена фактически.

После того, как программа загружена, загрузчик передает ей управление. На рис.62 приведено содержимое сегментных регистров и указателя стека SP в момент передачи управления exe-программе. В этот момент сегментные регистры данных содержат номер начального параграфа PSP. Благодаря этому

215

программа может использовать полезную информацию, содержащуюся в PSP. (Запомнив где-то первоначальное значение этих регистров, программа обычно записывает в них новое значение, указывающее на начало области данных программы.) Что касается CS, то в него загрузчик помещает начальный номер параграфа не PSP, а области кода программы. Аналогично содержимое SS указывает на границу области стека программы.

Исходная программа на ассемблере, ориентированная на получение exe- программы, обязательно имеет кроме виртуальных сегментов кода и данных виртуальный сегмент стека. Порядок записи этих сегментов в программе значения не имеет. В качестве точки входа в программу может быть задан любой исполнительный оператор программы. Для этого он должен иметь в исходной программе стандартную метку “..start:”.

Пример. Приведем исходный текст “вежливой” программы, ориентированной на получение загрузочного модуля типа exe:

;Программа выводит сообщение “Здравствуйте” на экран

;-------------------------------------------------------------------------

;

 

 

 

 

 

cr

equ

0dh

 

; Код ASCII возврата каретки

lf

equ

0ah

 

;

Код ASCII перевода строки

 

segment

stack

; Сегмент

 

times

64

db 0

;

стека

 

segment

code

; Сегмент кода

..start:

 

 

 

 

 

 

mov

ax, data

; Сделаем сегмент данных

 

mov

ds, ax

 

;

адресуемым

 

mov

dx, Msg

; DX Å адрес сообщения

 

mov

ah, 9

 

; Вывод строки

 

int

21h

 

;

на экран

 

mov

ax, 4c00h

; Возврат в DOS с

216

 

 

 

 

 

 

int

21h

 

;

кодом завершения 0

 

segment

data

; Сегмент данных

Msg

db

‘Здравствуйте’, cr, lf, ‘$’

; Выводимое сообщение

Адрес

 

 

 

ОП

 

 

(сегмент:смещение)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

DS:0000h

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ES:0000h

 

 

 

PSP

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

CS:0000h

 

 

 

 

 

 

 

 

 

Команды

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Данные

 

 

 

 

 

 

 

 

 

 

 

 

 

SS:0000h

 

 

 

 

 

 

 

 

 

 

Заполнение стека

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SS:SP

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Рис. 62. Результат загрузки exe-программы

В данной исходной программе три виртуальных сегмента – сегмент кода code, сегмент данных data и сегмент стека stack. Параметр code, data или stack оператора segment означает тип виртуального сегмента – код, данные или стек. Одновременно единственный параметр оператора segment задает и имя своего виртуального сегмента. Если виртуальному сегменту требуется присвоить какое-то другое имя, то это имя записывается в качестве дополнительного параметра оператора segment. Причем этот параметр записывается первым. Например, следующий оператор присваивает сегменту кода имя “Program”:

217

segment Program code

Все одноименные виртуальные сегменты, независимо от того, в каких исходных файлах и фрагментах они находятся, представлены в готовой машинной программе в виде единого логического сегмента.

Обратите внимание, что в начале сегмента кода в регистр DS загружается адрес-сегмент, соответствующий началу данных программы. Это делается для того, чтобы фактическое размещение данных в памяти никак не зависило от размещения в ней PSP, а также от размещения в памяти других сегментов программы. (Напомним, что для com-программы адрес-смещение данных вычисляется относительно начала PSP.) Обратите внимание, что запись значения в сегментный регистр DS производится не непосредственно, а через рабочий регистр AX.

Еще одним отличием исходных exe- и com-программ является то, что в exe- программе никак не задается расположение сегмента кода в памяти. Это полностью остается на усмотрение редактора связей и загрузчика.

Допустим, что записанная выше исходная exe-программа имеет имя test1.asm. Тогда для получения соответствующего объектного модуля можно использовать следующую команду DOS:

nasm test1.asm -f obj -o test1.obj

Команда DOS для получения exe-файла: alink test1.obj -oEXE -o test1.exe

П о л у ч и т е exe-файл для приведенной выше программы, а затем выполните его.

17.5. Применение нескольких объектных модулей

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

218

трансляторы и, следовательно, эти исходные фрагменты могут быть написаны на разных языках программирования.

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

Третье преимущество многомодульной объектной структуры программы не используется в рассматриваемой простой ВС (DOS + i8086), но применяется очень широко в более сложных системах. Его сущность состоит в том, что фрагменты машинной программы, каждый из которых получается в результате преобразования своего объектного модуля, могут быть загружены в различные разделы (сегменты) ОП так, что последующая работа программ с этими разделами будет производиться по отличным друг от друга правилам. Например, для некоторых разделов ОП допустима только операция “чтение”. В такие разделы целесообразно помещать неизменяемые данные программы, то есть ее константы. Для других разделов ОП система допускает только операцию “выполнение”. Сюда целесообразно помещать команды (“код”) машинной программы. Некоторые разделы ОП могут содержать данные (в том числе и “код”), одновременно используемые (разделяемые) несколькими программами. Подобное свойство широко используется в мультипрограммных ВС для реализации DLL – динамически связываемых библиотек.

Многомодульная объектная структура оказывает влияние на тексты исходных фрагментов. Причиной этого является наличие в тексте рассматриваемого исходного фрагмента внешних имен (см. п.17.2). При этом внешние выходные имена (метки) должны быть описаны с помощью псевдооператоров global. А внешние входные имена – с помощью псевдооператоров extern.

219

Например, переделаем последнюю exe-программу так, чтобы она была получена не из одного, а из двух исходных фрагментов. В первый исходный файл test1a.asm включим виртуальные сегменты кода и стека, а во второй test1b.asm – виртуальный сегмент данных. Текст первого исходного файла:

; Программа выводит сообщение “Здравствуйте” на экран

; -------------------------------------------------------------------------

;

segment

data

; Сегмент данных в другом файле

segment

stack

; Сегмент

times

64

db 0

;

стека

segment

code

; Сегмент кода

..start:

 

 

 

 

extern

 

Msg

; Сообщение в другом модуле

mov

ax, data

; Сделаем сегмент данных

mov

ds, ax

 

;

адресуемым

mov

dx, Msg

; DX Å адрес сообщения

mov

ah, 9

 

; Вывод строки

int

21h

 

;

на экран

mov

ax, 4c00h

; Возврат в DOS с

int

21h

 

;

кодом завершения 0

Текст второго файла:

;Сегмент данных программы, которая выводит

;сообщение “Здравствуйте” на экран

;

-------------------------------------------------------------------------

 

 

 

;

 

 

 

 

cr

equ

0dh

;

Код ASCII возврата каретки

lf

equ

0ah

;

Код ASCII перевода строки

220

 

 

 

 

 

segment

data

; Сегмент данных

 

global

Msg

; Используется в другом файле

Msg

db ‘Здравствуйте’, cr, lf, ‘$’

; Выводимое сообщение

Обратите внимание на то, что, несмотря на то, что виртуальный сегмент данных находится во втором файле, его заголовок “segment data” присутствует и в первом (главном) файле. Кроме заголовка этот виртуальный сегмент может содержать и любые данные. В любом случае редактор связей соединяет в один логический сегмент одноименные виртуальные сегменты данных, кода или стека, объявленные в разных фрагментах исходной программы. Напомним, что фрагмент исходной программы состоит из одного или нескольких исходных файлов (исходных модулей), соединяемых в единое целое с помощью операторов %include.

Что касается имени виртуального сегмента, то оно может быть задано с помощью необязательного первого параметра оператора segment. Если этот параметр оператора segment опущен, то виртуальному сегменту присваивается имя, совпадающее с его типом. Например, в приведенном выше примере виртульные сегменты имеют имена: code, data и stack. Пример оператора, который присваивает виртуальному сегменту данных имя “data3”:

segment data3 data

На б е р и т е и выполните приведенную выше программу.

17.6.Лабораторная работа 15

Требуется переделать полученную на предыдущей лабораторной работе программу редактирования, внеся в нее следующие изменения:

1)имя редактируемого файла передается в командной строке DOS в качестве параметра команды запуска программы редактирования. Если это имя отсутствует, то производится редактирование ОП;