Оформление и размещение в памяти ассемблерных программ
Тексты исполняемых программ могут быть представлены в ЕХЕ- или СОМ форматах. Различие между программами в ЕХЕ- и СОМ-файлах заключается в следующем.
Размер программы. Программа в ЕХЕ может иметь любой размер, в то время как СОМ-файл ограничен размером одного сегмента (≤64к). Размер СОМ-файла всегда меньше, чем размер соответствующего ЕХЕ-файла, так как в СОМ-файле отсутствует заголовок (512 байт) ЕХЕ-файла. Заголовок хранится на диске в начале ехе-файла. В заголовке содержится информация о размере выполняемого модуля, области загрузки в памяти, адрес стека и относительное смещение. В нем также указывается число байтов в последнем блоке ехе-файла, число настраиваемых параметров, количество параграфов в заголовке и некоторые другие данные.
Сегмент стека. В ЕХЕ следует задавать сегмент стека, в то время как СОМ-программа генерирует стек автоматически.
Сегмент данных. В ЕХЕ-программах обычно определяется сегмент данных, а регистр DS инициализируется адресом этого сегмента. В СОМ-программах все данные должны быть определены в сегменте кода.
Инициализация. В ЕХЕ-программе следует записать 0-слово в стек и инициализировать регистр DS. Так как в СОМ стек и сегмент данных не определены, то эти шаги отсутствуют.
При запуске СОМ-программы сегментные регистры содержат адрес префикса программного сегмента (256 байт=100Н), который резервируется DОS непосредственно перед СОМ- или ЕХЕ –программой в памяти. Так как адресация начинается со смещения 100Н от начала префикса, то в программе после директивы SEGMENT следует вносить директиву ORG 100H.
Для преобразования ЕХЕ-файла в СОМ-файл используется программа ЕХЕ2BIN.
Если в программе отсутствует явное объявление стека, то система сама создает стек по умолчанию в конце сегмента команд. Эот объясняется следующим образом. Если запустить программу, то можно увидеть (с помощью отладчика), что в SS находится тот же адрес, что и в CS, а в SP=0. Первая же команда PUSH уменьшает содержание SP на 2, то есть поместит в SP-2 которое равно FFFEh (0-2). При дальнейшей записи в стек его указатель будет смещаться в сторону меньших адресов. При интенсивном использовании стека в программе может получиться, что стек дорастет до последних команд сегмента команд и начнет затирать эти команды. В связи с этим следует использовать отдельный сегмент стека SS.
При размещение .ЕХЕ-программы в памяти регистры CS и SS указывает на начало сегмента команд (DOS делает автоматически). Поскольку сегмент данных оказывается не адресуемым, то необходимо инициализировать регистр DS (и ES).
begin: mov ax, data; data – начало сегмента данных
mov ds, ax
push DS
pop ES
.
mov ax, 4c00h; функция завершения программы
int 21h; вызов DOS
Префикс программного сегмента PSP: первые два байта префикса программного сегмента содержат команду INT20h завершение программы (DOS восстанавливает векторы критических прерываний по значениям, хранящимся в PSP; очищает буфер файлов и передает управление процедуре завершения). Затем указывается общий размер доступной памяти XXXXOh.
Программа в памяти начинается с префикса программного сегмента (PSP), который образуется и заполняется DOS в процессе загрузки программы в память. Затем в памяти располагаются сегменты в том порядке, как они объявлены в тексте программы (рисунок 5.11а).
В процессе загрузки в память сегментные регистры автоматически инициализируется следующим образом: ES и DS указывают на начало PSP. Поэтому перед началом выполнения программы нужно сохранить их значения, чтобы после окончания можно было обратиться к PSP. Потом размещается адрес подпрограммы завершения, а также адреса п/п реакции на Ctrl/Break, на фатальную ошибку.
В ячейках с 80 по FF располагается буфер передачи данных, который используется как буферная область ввода/вывода для текущего дисковода
а) | б) |
Рисунок 6.11 – Схема размещения программ ЕХЕ (а) и СОМ (б) в памяти |
Схема размещение СОМ-программы в памяти показано на рисунке 5.11б. Под команды, данные и стек выделяется только один сегмент. В начале сегмента размещается префикс программного сегмента PSP. Заполняет PSP операционная система DOS, но место под него в начале программы должен зарезервировать программист. В программе нет необходимости инициализировать регистр DS, поскольку его, как и другие сегментные регистры инициализирует ОС.
Пример 1 программы на ассемблере МП 8086.
NAME EXAMPLE
ASSUME CS: CODE, SS: STACK, DS: DATA
DATA SEGMENT
VAR-1 DW 0; определить и инициализировать
VAR-2 DW 0; две переменные
DATA ENDS
STACK SEGMENT
DW 10DUP(?); зарезервировать 10 слов
STK_TOP LABEL WORD; вершина стека
STACK ENDS
CODE SEGMENT
START: MOV AX, DATA; инициализация регистров DS и SS
MOV DS,AX
MOV AX, STACK
MOV SS, AX
MOV SP, OFSET STK_TOP
PROG: PUSH AX; заполнить (AX)
MOV AX, VAR-1; увеличить на 5 значение VAR-1
ADD AX,5
MOV VAR-2, AX; присвоить VAR-2
POP AX; восстановить AX
CODE ENDS
END START; конец исходного модуля
В первой строке программы находится директива NAME (наименовать), которая присваивает внутреннее имя объектному модулю, генерируемому ассемблером. Имя модуля EXAMPLE нельзя путать с именем файла – оно хранится внутри объектного файла.
Программа состоит из трех различных логических сегментов DATA, STACK, CODE. Каждый сегмент начинается с директивы SEGMENT и заканчивается директивой ENDS, причем обе директивы для одного и того же сегмента имеют одинаковые имена. Логические сегменты соответствуют физическим сегментам в памяти, но привязки логических сегментов к физическим адресам памяти в этом исходном модуле нет.
Директива ASSUME сообщает ассемблеру, что регистр CS будет содержать базовый адрес сегмента CODE, а регистр DS – базовый адрес сегмента DATA. Регистр ES не используется, поэтому указание о нем в директиве отсутствует.
Сегмент данных DATA содержит всего две переменные, которые инициализированы с помощью директив DW. В сегменте STACK резервируются 10 слов памяти, т.е. для стека в программе резервируется 10 слов (глубина стека 10 слов). Директива LABEL (отметить) определяет имя STK_TOP, которое идентифицирует вершину пока пустого стека.
Сегмент кода начинается с пяти команд, обеспечивающих инициализацию сегментных регистров и указателя стека SP. Выражение OFFSET STK_TOP представляет собой смещение метки STK_TOP от начала содержащего ее сегмента STACK. Собственно программа начинается с метки PROG. Директива END с операндом START сообщает ассемблеру о достижении конца исходного модуля и необходимости начать выполнение программы с команды, отмеченной меткой START.
Пример 2 ассемблерной программы:
Page 60, 132
TITLE EXAMPLE (EXE)
;--------------------------------------------
STACKSG SEGMENT PARA STACK ‘stack’; Указывать обязательно, т.к. по ней осуществляется. ; автомати ческая инициализация SS и SP
; Если тип объединения STACK, то при компоновке ; одноименные сегменты располагаются рядом, при ;COMMON – накладываются друг на друга
DW 10 DUP(?);
STACKSG ENDS
;--------------------------------------------------------------------------------------
DATASG SEGMENT PARA ‘Data’
NAME1 DB ‘ASSEMBLERS’;
NAME2 DB 10DUP(‘ ‘) ; зарезервировать 10 слов
DATASG ENDS
;--------------------------------------------------------------------------------
; --------------------------------------------------------------------------------------
CODESG SEGMENT PARA ‘Code’ ; для правильной работы LINK необходимо указать ‘Code’
BEGIN PROC FAR
ASSUME CS:CODESG; DS:DATASG, SS:STACKSG, ES:DATASG
; Показывает транслятору, какие регистры закрепляются за
; сег ментами, которые затем используются по умолчанию
PUSH DS ; записать DS в стек
SUB AX, AX ; записать 0 в стек
PUSH AX
MOV AX, DATASG ; регистры CS и SS инициализируются автоматически
MOV DS, AX
MOV ES, AX
; --------------------------------------------------------------------------------------------------------
MOV AX, 0123H
ADD AX, 0025H
MOV BX, AX
ADD BX, AX
SUB AX, AX
NOP
; ---------------------------------------------------------------------------------------------------------
CLD
LEA SI, NAME1
LEA DI, NAME2
MOV CX, 10
REP MOUSB ; переслать 10 байтов из NAME1 NAME2
; ----------------------------------------------------------------------------------------------------------
RET ; возврат в DOS
BEGIN ENDP
CODESG ENDS
END [BEGIN]; операнд может быть опущен, если эта программа должна быть скомпонована
;с другим (главным) модулем. Для обычных программ операнд содеожит имя, указанное в ;директивве PROG, (то есть в точку входа в главную процедуру). Этим адресом
; загружается IP.
Программа в формате ЕХЕ, созданная компоновщиком, состоит из следующих двух частей: 1) заголовка – записи, содержащей информацию по управлению и настройке программы, и 2) собственно загрузочного модуля.
В заголовке находится информация о размере выполняемого модуля, области загрузки в памяти, адресе стека и относительных смещениях, которые должны заполнить машинные адреса в соответствии с относительными 16-ричными позициями.
Заголовок имеет минимальный размер 512 байт и может быть больше, если программа содержит большое число настраиваемых элементов. Позиция 06 в заголовке указывает число элементов в выполняемом модуле, нуждающихся в настройке. Каждый элемент настройки в таблице, начинающейся в позиции 1С заголовка, состоит из двухбайтовых величин смещений и двухбайтовых сегментных значений.
Операционная система строит префикс программного сегмента (PSP) следом за резидентной частью COMMAND.COM, которая выполняет операцию загрузки. Затем COMMAND.COM осуществляет следующее:
§ Считывает форматированную часть заголовка в память;
§ Вычисляет размер выполнимого модуля (общий размер файла в позиции 04 минус размер заголовка в позиции 08) и загружает модуль в память с начала сегмента;
§ Считывает элементы таблицы настройки в рабочую область и прибавляет адрес начала сегмента;
§ Устанавливает в регистрах SS и SP значения из заголовка и прибавляет адрес начала сегмента;
§ Устанавливает в регистрах DS и ES сегментный адрес префикса программного сегмента;
§ Устанавливает в регистре CS адрес PSP и прибавляет величину смещения в заголовке (позиция 16) к регистру CS. Если сегмент кода непосредственно следует за PSP, то смещение в заголовке равно 256 (100h). Регистровая пара CS:IP содержит стартовый адрес в кодовом сегменте, т.е. начальный адрес программы.
После инициализации регистры CS и SS содержат правильные адреса сегментов, а регистр DS (и ES) должен быть настроен в программе на собственный сегмент данных.
При завершении программы команда RET заносит в регистр IP нулевое значение, которое было помещено в стек в начале выполнения программы. В регистровой паре CS:IP в этом случае получается адрес, который является адресом первого байта PSP, где расположена команда INT 20h. Когда эта команда будет выполнена, управление перейдет в DOS.
Пример 3 оформления СОМ-программы
Page 60,80
TITLE EXAMPLE_COM для пересылки и сложения
Codes SEGMENT PARA ‘Code’
ASSUME CS:CODESG, DS:CODESG, SS:CODESG, ES:CODESG
ORG 100H ; начало в конце PSP
BEGIN: JMP MAIN ; обход через данные
;---------------------------------------------------------------------------------
ALPHA DW 250
BETA DW 125
GAMMA DW ?
;---------------------------------------------------------------------------------
MAIN PROC NEAR
MOV AX, ALPHA
ADD AX, BETA
MOV GAMMA, AX
RET ; вернуться в DOS
; можно вместо RET INT20H
MAIN ENDP
Codes ENDS
END BEGIN
В отличие от ЕХЕ-файла СОМ-файл не содержит заголовка на диске. Так как организация СОМ-файла намного проще, то для DOS необходимо знать только то, что тип файла СОМ. Как уже упоминалось выше, загруженным в память СОМ- и ЕХЕ-файлам предшествует префикс программного сегмента. Первые два байта этого префикса содержат команду INT20h (возврат в DOS).
При загрузке СОМ-программы DOS устанавливает в четырех сегментных регистрах адрес первого байта PSP. Затем устанавливается указатель стека на конец сегмента объемом 64 Кбайт (FFFE), т.е. на конец памяти. В вершину стека заносится нулевое слово. В командный указатель помещается 100Н (размер PSP). После этого управление передается по адресу регистровой пары CS:IP, т. е. на адрес непосредственно после PSP. Этот адрес является началом выполняемой СОМ-программы и должен содержать выполнимую команду.
При выходе из программы команда RET заносит в регистр IP нулевое слово, которое было записано в вершину стека при инициализации. В этом случае в регистровой паре CS:IP получается адрес первого байта PSP, где находится команда INT20h. При выполнении этой команды управление передается в резидентную часть COMMAND.COM. Если программа завершается по команде INT20h (Завершение программы, управление передается DOS) вместо RET, то управление непосредственно передается в COMMAND.COM.
Примечание.
Коды команд, данные и стек в СОМ-программах располагаются в одном сегменте. Вследствие этого СОМ-программа занимает в памяти 64 Кбайт, независимо от ее размера на диске. Этот факт является одной из причин предпочтительного использования ЕХЕ-формата.
Хотя ЕХЕ-файл может занимать больше дискового пространства (т.к. в него включена дополнительная информация), небольшие ЕХЕ-программы занимают при исполнении в памяти значительно меньше места, чем эквивалентные им СОМ-программы.
СОМ-формат файла наследуется из ОС СР/М. Полезный в ряде случаев, формат не рекомендуется использовать для РС-программ.
Команды СОМ-программ загружаются в память с адреса 100h относительно начала кодового сегмента программы. По такому же адресу загружаются программы в ОС СР/М, на которой во многом основана DOS и которая используется в компьютерах, имеющих 64К общей памяти. Под управлением DOS СОМ-программы работают в режиме псевдо-СР/М адресного пространства, несмотря на то, что современные компиляторы имеют объем памяти в десятки раз больший. Т.о. сегодня уже нет разумных причин для этого устаревшего формата файла.
Компания Microsoft объявила о своем намерении отказаться от использования СОМ-формата, хотя эти попытки не являются успешными.
Дата добавления: 2016-02-09; просмотров: 1156;