Предыдущий раздел РАЗДЕЛЬНАЯ ТРАНСЛЯЦИЯ ПРОГРАММЫ Следующая глава

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

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

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

 

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

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

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

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

После того, как программа загружена, загрузчик передает ей управление. На рис.62 приведено содержимое сегментных регистров и указателя стека SP в момент передачи управления exe-программе. В этот момент сегментные регистры данных содержат номер начального параграфа PSP. Благодаря этому программа может использовать полезную информацию, содержащуюся в 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 с

int     21h                                ;    кодом завершения 0

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

Msg            db     ‘Здравствуйте’, cr, lf, ‘$’      ; Выводимое сообщение

 

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

 

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

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-файл для приведенной выше программы, а затем выполните его.

 


Предыдущий раздел В начало Следующая глава