Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
212-235.docx
Скачиваний:
0
Добавлен:
01.03.2025
Размер:
179.35 Кб
Скачать

Проходы ассемблера

Основные действия ассемблера на 1-м проходе.

Цель 1-го прохода - выявить в программе все имена и собрать информацию о них; эта информация записывается в таблицу имен (ТИ) и таблицу сегментов (ТС), которые будут нужны на 2-м проходе. Вначале эти таблицы, а также таблица распределения сегментных регистров (ТРСР) пусты, а затем они заполняются по мере просмотра текста программы.

Основные действия ассемблера на 2-м проходе.

Теперь рассмотрим действия ассемблера на 2-м проходе. К этому моменту в ТИ и ТС уже собрана вся информация об именах программы. Ассемблер заново просматривает строчка за строчкой текст программы и, используя информацию из ТИ, уже переводит программу с ЯА на машинный язык.

Формируемые машинные команды ассемблер записывает в последовательные ячейки памяти начиная с некоторого адреса, кратного 16. Какой это конкретно адрес - не важно. Дело в том, что машинная программа, сформированная ассемблером, не будет тут же выполняться, а будет лишь записана во внешнюю память, поэтому ее можно формировать в любом месте памяти. Учитывая это, мы будем указывать адрес первой свободной ячейки, отсчитанный от начала этого места, и будем обозначать этот адрес как АДР. В начале АДР=0.

225

СТРУКТУРА ОБЪЕКТНОГО МОДУЛЯ

Объектные модули обычно состоят из шести частей:

1. Идентификация.

2. Таблица точек входа.

3. Таблица внешних ссылок.

4. Машинные команды и константы.

5. Словарь перераспределения.

6. Конец модуля.

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

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

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

Четвертая часть объектного модуля - машинные команды и константы. Это единственная часть объектного модуля, которая загружается в память для выполнения. Остальные пять частей используются компоновщиком, а затем отбрасываются еще до начала выполнения программы.

Пятая часть объектного модуля - это словарь перераспределения памяти. К командам, которые содержат адреса памяти, должна прибавляться константа перераспределения (см. рис. 7.4). Компоновщик сам не может определить, какие слова в части 4 содержат машинные команды, а какие - константы. Поэтому в этой таблице содержится информация о том, какие адреса нужно перераспределять. Это может быть битовая таблица, где на каждый бит приходится потенциально перераспределяемый адрес, либо явный список перераспределяемых адресов.

Шестая часть содержит указание на конец модуля, а иногда - контрольную сумму для определения ошибок, сделанных во время чтения модуля, и адрес, с которого должно начинаться исполнение.

Большинству компоновщиков требуется два прохода. На первом проходе компоновщик считывает все объектные модули и строит таблицу имен и размеров модулей, а также глобальную таблицу символов, которая состоит из всех точек входа и внешних ссылок. На втором проходе модули поочередно считывают-ся, перераспределяются в памяти и компонуются.

Компоновка программы

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

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

LINK [ключи] список_объектных_файлов [,имя_загрузочного_модуля] [.имя_файла_карты] [,имя_файла_библиотеки] [,имя_файла_определений] [,имя_ресурсного_файла]

Параметры командной строки для запуска компоновщика перечислены далее.

  • ключи — необязательные параметры, управляющие работой компоновщика. Каждому ключу должен предшествовать символ - (дефис) или / (слеш). При задании имен ключей имеет значение регистр символов.

  • список_объектных_файлов — обязательный параметр, содержащий список компонуемых файлов с расширением .obj. Файлы должны быть разделены пробелами или знаком + (плюс), например:

tlink /v prog + mdf + fdr

При необходимости имена файлов снабжают указанием пути к ним.

  • имя_загрузочного_модуля — необязательный параметр, обозначающий имя формируемого загрузочного модуля. Если оно не указано, то имя загрузочного модуля будет совпадать с первым именем в списке имен объектных файлов.

  • имя_файла_карты — необязательный параметр, наличие которого обязывает компоновщик создать специальный файл с картой загрузки. В ней перечисляются имена, адреса загрузки и размеры всех сегментов, входящих в программу.

  • имя_файла_библиотеки — необязательный параметр, который представляет собой путь к файлу библиотеки (.lib). Этот файл создается и обслуживается специальной утилитой tlib.exe пакета TASM. Утилита позволяет объединить часто используемые подпрограммы в виде объектных модулей в один файл. В дальнейшем можно просто указывать в командной строке tlink.exe имена нужных для компоновки объектных модулей и файл библиотеки, в котором следует искать эти подпрограммы. Если компонуется Windows-приложение, то на месте параметра имя_файла_библиотеки должно указываться имя библиотеки им порта.

  • имя_файла_определений — необязательный параметр, который представляет собой путь к файлу определений (.def). Этот файл используется при компоновке Windows-приложений.

  • имя_ресурсного_файла — необязательный параметр, который представляет собой путь к файлу с ресурсами Windows-приложения (.res). Этот файл используется при компоновке Windows-приложений

  • Теперь вспомним, что общее имя одного модуля - это внешнее имя другого модуля. Значит, ОТОБ - это одновременно и таблица всех внешних имен с указанием их адресов. Поэтому компоновщик теперь может сделать то, что в свое время не удалось сделать ассемблеру, - заменить все внешние ссылки во всех модулях на соответствующие им адреса.

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

226

Aтрибутом любого ассемблера является наличие компоновщика (linker), в задачи которого входит:

– объединение объектных фалов (*.obj) в один;

– корректировка значений адресов во всех операндах команд, которые ссылаются на объект, чье расположение в памяти установлено либо изменено в процессе конкатенации.

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

Как только программа скомпонована, на выходе получаем абсолютный объектный файл (*.abs или *.cod), который может использоваться как для отладки в эмуляторе, так и для прошивки EPROM микроконтроллера.

Результатом работы компоновщика являются (рис. 2.4):

– абсолютный объектный файл (*.cod или *.abs);

– файл таблицы имен (*.sym);

– файл распределения (*.map).

К омпоновщик объединяет отдельные адресные пространства объектных модулей в единое линейное адресное пространство. Для этого совершаются следующие шаги:

Компоновщик строит таблицу объектных модулей и их размеров.

На основе этой таблицы он приписывает начальные адреса каждому объектному модулю.

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

Рис. 7.4. Объектные модули после размещения в двоичном образе, но до перераспределения памяти и компоновки (а); те же объектные модули после компоновки и перераспределения памяти (б). В результате получается исполняемый двоичный код, который можно запускать

Редактирование межмодульных связей

Такая корректировка заключается в замене внешних имен, использовавшихся в модулях, на соответствующие адреса. Делается это так.

Напомним, что в заголовке каждого ОМ есть таблица общих имен (ТОБ), в которой для каждого общего имени данного модуля указано само имя и его адрес внутри модуля. Компоновщик выделяет из заголовков эти таблицы и объединяет их в общую таблицу общих имен (ОТОБ).

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

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

227

Создание загрузочного модуля (компоновка программы)

После устранения ошибок и получения объектного модуля, можно приступать к следующему шагу — созданию исполняемого (загрузочного)

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

Главная цель этого шага — преобразовать код и данные в объектных файлах

в их перемещаемое выполняемое отображение. Чтобы понять, в чем здесь

суть, нужно разобраться, зачем вообще разделяют процесс создания

исполняемого модуля на два шага — трансляцию и компоновку. Это

сделано намеренно для того, чтобы можно было объединять вместе

несколько модулей (написанных на одном или нескольких языках). Формат

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

несколько отдельно оттранслированных исходных модулей в один модуль.

При этом в функции компоновщика входит разрешение внешних ссылок

(ссылок на процедуры и переменные) в этих модулях. Результатом работы

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

или .com. После этого операционная система может загрузить такой файл в

память и выполнить его.

228

Файл EXE, который строит компоновщик состоит из двух частей:

- управляющая информация для загрузчика.

- собственно загрузочный модулъ.

Информация для загрузчика, описанная ниже, расположена в начале

файла и образует так называемый заголовок. Сразу за ним следует тело

загрузочного модуля. Тело загрузочного модуля начинается на границе блока

и представляет собой копию образа памяти задачи, которую построил компоновщик.

Стандартная частъ заголовка имеет следующий формат:

Смещение Содержимое

00-01 "подписъ" компоновщика, указывающая,

что файл является файлов EXE.

02-03 Длина образа задачи по модулю 512 (т.е.

число полезных байт в последнем блоке).

(Компоновшики версий до 1.10 помещали в это

поле 04; если оно имеет такое значение,

его рекомендуется игнорироватъ).

04-05 Длина файла в блоках.

06-07 Число элементов таблицы настройки адресов.

08-09 Длина заголовка в 16-ти байтных параграфах.

Исполъзуется для выяснения начала тела

загрузочного модуля.

0A-0B Минималъный объем памяти, которую нужно

выделитъ после конца образа задачи.

(в 16-ти байтных параграфах).

0C-0D Максималъный объем памяти, которую нужно

выделитъ после конца образа задачи.

(в 16-ти байтных параграфах).

0E-0F Сегментный адрес начала стекового сегмента относителъно начала образа задачи.

10-11 Значение SP при входе в задачу.

12-13 Контролъная сумма - нолъ минус

резулътат сложения без переноса всех

слов файла.

14-15 Значение IP (счетчика команд)

при входе в задачу.

16-17 Сегментный адрес начала кодового сегмента

относителъно начала образа задачи.

18-19 Адрес первого элемента таблицы настройки адресов

относителъно начала файла.

1A-1B Номер сегмента перекрытий.

(0 для корневого сегмента программы).

Далее следует таблица настройки адресов. Таблица состоит из эле-

ментов, число которых записано в байтах 06-07. Элемент таблицы настрой-

ки состоит из двух полей: 2-х байтного смещения и 2-х байтного сегмен-

та, и указывает слова в загрузочном модуле, содержащее адрес, который

должен бытъ настроен на место памяти, в которое загруежается задача.

229

ЗАГРУЗЧИК.

Итак, компоновщик построил Загрузочный модуль и записал его в файл M.EXE. Чтобы выполнить его, нужно дать приказ ОС, состоящий из названия этого файла:

M.EXE или M

Этот приказ ОС трактует как внешний, т.е. ищет на диске файл указанным именем (расширение EXE подразумевается по умолчанию), считывает его в ОП и передает на него управление. Но поскольку, как мы видим, в этом файле находится машинная программа, которая не до конца оттранслирована, то взять и просто считать эту программу в ОП и передать ей управление нельзя. Эту программу еще надо довести "до кондиции". Это замечание справедливо для всех программ, хранящихся в файлах с расширением EXE. Поэтому, если в приказе операционной системе указан файл с расширением EXE, то она вызывает специальную программу, называемую загрузчиком, и передает ей управление, а уже этот загрузчик считывает нашу программу из внешней памяти, доводит ее трансляцию до конца и запускает ее на счет.

Основные задачи загрузчика.

Загрузчик решает следующие основные задачи:

1. Загрузка программы. Загрузчик должен найти место в оперативной памяти для программы и переписать ее сюда с диска.

2. Настройка программы на место (привязка к месту). Загрузчик обязан закончить трансляцию программы в тех ее точках, что зависят от местоположения программы в памяти.

3. Запуск программы на счет. Загрузчик должен записать в определенные регистры соответствующие значения и передать управление на программу.

Рассмотрим, как загрузчик решает эти задачи.

Загрузка программы.

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

Настройка программы на место.

Итак, только в этот момент становится известным начальный адрес программы и лишь теперь можно полностью завершить трансляцию программы. Такое завершение трансляции заключается, как говорят, в настройке программы на занимаемое ею место в памяти, в привязке ее к этому месту. Делается это так.

Напомним, что в программе остались недотранслированными имена сегментов: не зная настоящих начальных адреса сегментов, компоновщик запомнил их относительные адреса, т.е. отсчитанные от начала программы, и запомнил адреса ячеек программы, в которые надо затем записать настоящие адреса сегментов. Эта информация хранится в ТПА загрузочного модуля. Теперь же, когда стал известным начальный адрес программы, уже можно получить и абсолютные адреса сегментов. Для этого надо к их относительным адресам добавить начальный адрес.

232

Запуск на выполнение программы Ассемблера

Запуск на выполнение построенной исполнимой программы выполняется таким же образом как и запускается любая программа Возможны следующие варианты :

Запуск из командной строки.

Запуск под управлением отладчика.

Запуск из файлового менеджера.

Запуск в среде WINDOWS.

При запуске из командной строки мы должны точно знать имя формируемого исполнимого модуля и обеспечить путь к программе в среде операционной системы( Команды CD или переменная PATH).

При запуске из командной строки нужно ввести C:\BORLANDC\TASM>first.exe

При запуске из файлового менеджера запуск производиться простым нажатием клавиши Enter” после выделения конкретной программы в панели просмотра файлов Для программы при необходимости будет запущено окно командной строки а  результаты можно наблюдать

в этом окне.

При запуске в среде WINDOWS ( любым известным Вам способом будет автоматически запущена командная строка а в ней программа. Если в программе не предусмотрено ожидание ввода клавиши то окно после этого также автоматически закроется. Поэтому желательно в программе предусмотреть еще несколько команд вида перед завершением программы;

Ожидание завершения программы:

  MOV AH, 01H

INT 021H

В этом случае окно командной строки не будет закрыто автоматически но после нажатия на любую клавишу программа и окно командной строки закроется.

Управление выполнением программы

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

  • выполнять программу по шагам (по одной машинной инструкции или строке исходного кода);

  • выполнять как один шаг вызовы функций;

  • выполнять программу до заданного места;

  • выполнять программу до возврата из текущей функции;

  • трассировать программу;

  • выполнять программу в обратном направлении;

  • выполнять программу до точки останова;

  • выполнять программу до появления определенного сообщения Windows;

  • приостанавливать программу при возникновении исключитель ной ситуации С++ или Си.

Кроме точек останова, сообщений Windows и исключительных си туаций С++ все механизмы управления выполнением находятся в меню Run.

233

Debug — Программа-отладчик, которую используют для проверки и отладки выполняемых файлов. Использовалась при операционной системе MS-DOS. Под более поздние версии операционных систем работает через эмулятор MS-DOS и имеет ограниченные возможности.

Данная программа является консольным приложением и предназначена для создания или изменения кода файлов. С помощью неё можно создавать простые приложение под MS-DOS и отслеживать их работу. Данный отладчик находится на самом низком уровне компиляторов assembler. Но обладает неплохими возможностями такими как просмотр, изменение памяти и получение состояния регистров.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]