Автор: Пользователь скрыл имя, 10 Марта 2013 в 15:44, курс лекций
Один из основных принципов машины фон Неймана — то, что и программы, и данные хранятся в одной и той же памяти. Сохраняемая в памяти программа представляет собой некоторые коды, которые могут рассматриваться как данные. Возможно, с точки зрения программиста программа — активный компонент, она выполняет некоторые действия. Но с точки зрения процессора команды программы — это данные, которые процессор читает и интерпретирует. С другой стороны программа — это данные с точки зрения обслуживающих программ, например, с точки зрения компилятора, который на входе получает одни данные — программу на языке высокого уровня (ЯВУ), а на выходе выдает другие данные — программу в машинных кодах.
Используя команду dir, можно проверить наличие ваших файлов на диске:
DIR C:имя программы.*
В результате на экране появится следующие имена файлов: имя программы.BAK (если для корректировки имя программы.ASM использовался редактор EDLIN), имя программы.ASM, имя программы.OBJ, имя программы.LST, имя программы.EXE и имя программы.CRF.
Последовательность этих файлов может быть иной в зависимости от того, что уже находится на диске.
Очевидно, что разработка ряда программ
приведет к занятию дискового пространства.
Для проверки оставшегося свободного
места
на диске полезно использовать команду DOS CHKDSK. Для удаления
OBJ-, CRF-, BAK- и LST-файлов с диска следует использовать
команду ERASE (или DEL):
ERASE C:имя программы.OBJ, ...
Следует оставить (сохранить) ASM-файл для последующих изменений и EXE-файл для выполнения.
4
Файл перекрестных ссылок
В процессе трансляции
Ассемблер создает таблицу
cross-reference [NUL.CRF]:C: [Enter]
Далее необходимо
преобразовать полученный CRF-файл в
отсортиpованную таблицу
После успешного
ассемблирования введите
Cref filename [.CRF]: List filename [cross-ref.REF]:
На первый запрос введите имя CRF-файла, то есть, C:имя программы. На второй запрос можно ввести только номер дисковода и получить имя по умолчанию.
Такой выбор приведет к записи CRF в файл перекрестных ссылок по имени имя программы.REF на дисководе C.
Для распечатки файла перекрестных ссылок используйте команду DOS PRINT.
Важно:
u Ассемблер преобразует исходную программу в OBJ-файл, а компоновщик — OBJ-файл в загрузочный EXE-файл.
u Внимательно проверяйте запросы и ответы на них для программ (M)ASM, LINK и CREF прежде чем нажать клавишу Enter. Будьте особенно внимательны при указании дисковода.
u Программа CREF создает распечатку перекрестных ссылок.
u Удаляйте ненужные файлы с вашего диска. Регулярно пользуйтесь программой CHKDSK для проверки свободного места на диске. Кроме того периодически создавайте резервные копии вашей программы, храните резервную дискету и копируйте ее заново для последующего программирования.
Лекция 10.
Алгоритмы работы Ассемблеров
4
Двухпроходный Ассемблер — первый проход
Ассемблер просматривает
исходный программный модуль один или
несколько раз. Наиболее распространенными
являются двухпроходные Ассемблеры,
выполняющие два просмотра
Алгоритм работы 1-го прохода двухпроходного Ассемблера показан на рисунке.
F Блок1: Начало 1-го прохода ассемблирования.
F Блок2: Начальные установки:
u установка в 0 счетчика адреса PC;
u создание пустой таблицы символов;
u создание пустой таблицы литералов;
u открытие файла исходного модуля;
u установка в FASLE признака окончания.
F Блок3: Признак окончания TRUE?
F Блок4: Считывание следующей строки исходного модуля. Добавка к счетчику адреса устанавливается равной 0.
F Блок5: При считывании был обнаружен конец файла?
F Блок6: Если конец файла обнаружен до того, как обработана директива END, — ошибка (преждевременный конец файла), при этом также устанавливается признак окончания обработки.
F Блок7: Лексический разбор оператора программы. При этом:
u выделяется метка/имя, если она есть;
u выделяется мнемоника операции;
u выделяется поле операндов;
u удаляются комментарии в операторе;
u распознается строка, содержащая только комментарий.
F Блок8: Строка содержит только комментарий? В этом случае обработка оператора не производится.
F Блок9: Мнемоника операции ищется в таблице директив.
F Блок10: Завершился ли поиск в таблице директив успешно?
F Блок11: Если мнемоника была найдена в таблице директив, происходит ветвление, в зависимости от того, какая директива была опознана.
F Блок12: Обработка директив типа DD (определения данных) включает в себя:
u выделение элементов списка операндов (одной директивой DD может определяться несколько объектов данных);
u определение типа и, следовательно, размера объекта данных, заданного операндом;
u обработка для каждого операнда возможного коэффициента повторения.
F Блок13: Добавка к счетчику адреса устанавливается равной суммарному размеру объектов данных, определяемых директивой.
F Блок14: Обработка директив типа BSS подобна обработке директив типа DD.
F Блок15: Добавка к счетчику адреса устанавливается равной суммарному объему памяти, резервируемому директивой.
F Блок16: Обработка директивы END состоит в установке в TRUE признака окончания обработки.
F Блок17: Обработка директивы включает в себя вычисление значения имени и занесение его в таблицу символов.
F Блок18: Обработка прочих директив ведется по индивидуальным для каждой директивы алгоритмам. Существенно, что никакие директивы, кроме DD и BSS, не изменяют нулевого значения добавки к счетчику адреса.
F Блок19: Если мнемоника операции не найдена в таблице директив, она ищется в таблице команд.
F Блок20: Завершился ли поиск в таблице команд успешно?
F Блок21: Если мнемоника не была найдена в таблице команд, — ошибка (неправильная мнемоника).
F Блок22: Если мнемоника найдена в таблице команд — определение длины команды, она же будет добавкой к счетчику адреса.
F Блок23: Есть ли в операторе литерал?
F Блок24: Занесение литерала в таблицу литералов (если его еще нет в таблице).
F Блок25: Была ли в операторе метка?
F Блок26: Поиск имени в таблице символов.
F Блок27: Имя в таблице символов найдено?
F Блок28: Если имя найдено в таблице символов — ошибка (повторяющееся имя).Если имя не найдено в таблице символов — занесение имени в таблицу символов.
F Блок29: Формирование и печать строки листинга.
F Блок30: Модификация счетчика адреса вычисленной добавкой к счетчику
F Блок31: Печать строки листинга и переход к чтению следующего оператора.
F Блок32: При окончании обработки — закрытие файла исходного модуля.
F Блок33: Были ли ошибки на 1-м проходе ассемблирования?
F Блок34: Формирование литерального пула.
F Блок35: Выполнение 2-го прохода ассемблирования.
F Блок36: Конец работы Ассемблера.
Определение длины команды
Эта задача может решаться существенно разным образом для разных языков. В языках некоторых Ассемблеров мнемоника команды однозначно определяет ее формат и длину (S/390, все RISC-процессоры). В этом случае длина команды просто выбирается из таблицы команд. В других языках длина и формат зависит от того, с какими операндами употреблена команда (Intel). В этом случае длина вычисляется по некоторому специфическому алгоритму, в который входит выделение отдельных операндов и определение их типов. В последнем случае должна производиться также необходимая проверка правильности кодирования операндов (количество операндов, допустимость типов).
Обнаружение литералов
Требует, как минимум, выделения операндов команды.
Листинг
Строка листинга печатается в конце каждой итерации обработки команды. Строка листинга 1-го прохода содержит: номер оператора, значение счетчика адреса (только для команд и директив, приводящих к выделению памяти), текст оператора. Листинг 1-го прохода не является окончательным, фактически он используется только для поиска ошибок, поэтому печатать его необязательно. Режим печати листинга 1-го прохода может определяться параметром Ассемблера или специальной директивой. После листинга программы может (опционно) печататься таблица символов.
Ошибки
На первом проходе выявляются не все ошибки, а только те, которые связаны с выполнением задачи 1-го прохода. Сообщение об ошибке включает в себя: код ошибки, диагностический текст, номер и текст оператора программы, в котором обнаружена ошибка.
Некоторые структуры данных 1-го прохода
Таблица команд содержит одну строку для каждой мнемоники машинной команды. Ниже приведен пример структуры такой таблицы для простого случая, когда мнемоника однозначно определяет формат и длину команды. Обработка команд происходит по всего нескольким алгоритмам, зависящим от формата команды, поэтому в данном случае все параметры обработки могут быть представлены в виде данных, содержащихся в таблице.
Таблица директив содержит одну строку для каждой директивы Обработка каждой директивы происходит по индивидуальному алгоритму, поэтому параметры обработки нельзя представить в виде данных единого для всех директив формата. Для каждой директивы в таблице хранится только идентификация (имя или адрес, или номер) процедуры Ассемблера, выполняющей эту обработку. Некоторые директивы обрабатываются только на 1-м проходе, некоторые — только на 2-м, для некоторых обработка распределяется между двумя проходами.
Таблица символов
является основным результатом 1-го прохода
Ассемблера. Каждое имя, определенное
в программе, должно быть записано в
таблице символов. Для каждого
имени в таблице хранится его
значение, размер объекта, связанного с этим именем и признак
перемещаемости/
Перемещаемость рассматривается в разделе, посвященном Загрузчикам, здесь укажем только, что значение перемещаемого имени должно изменяться при загрузке программы в память. Имена, относящиеся к командам или к памяти, выделяемой директивами DD, BSS, как правило, являются перемещаемыми (относительными), имена, значения которых определяются директивой EQU, являются неперемещаемыми (абсолютными).
Таблица литералов содержит запись для каждого употребленного в модуле литерала. Для каждого литерала в таблице содержится его символьное обозначение, длина и ссылка на значение. Литерал представляет собой константу, записанную в памяти. Обращение к литералам производится так же, как и к именам ячеек программы. По мере обнаружения в программе литералов Ассемблер заносит их данные в так называемый литеральный пул. Значение, записываемое в таблицу литералов является смещением литерала в литеральном пуле. После окончания 1-го прохода Ассемблер размещает литеральный пул в конце программы (то есть, назначает ему адрес, соответствующий последнему значению счетчик адреса) и корректирует значения в таблице литералов, заменяя их смещениями относительно начала программы. После выполнения этой корректировки таблица литералов может быть совмещена с таблицей символов.
4
Структура таблиц Ассемблера
Структура таблиц Ассемблера выбирается таким образом, чтобы обеспечить максимальную скорость поиска в них.
Таблицы команд и директив являются постоянной базой данных. Они заполняются один раз — при разработке Ассемблера, а затем остаются неизменными.
Эти таблицы
целесообразно строить как
Имеет смысл
постараться и подобрать
Таблица символов формируется динамически — в процессе работы 1-го прохода. Поиск же в этой таблице осуществляется как в 1-м проходе (перед занесением в таблицу нового имени, проверяется, нет ли его уже в таблице).
Построение этой
таблицы как таблицы прямого
доступа не очень целесообразно,
так как неизбежно
Поскольку новые
имена добавляются в таблицу
«по одному», и после каждого
добавления упорядоченность таблицы
должна восстанавливаться, целесообразно
применять алгоритму
Эти же соображения
относятся и к другим таблицам,
формируемым Ассемблером в
4
Двухпроходный Ассемблер — второй проход
Обычно 2-й проход Ассемблера читает исходный модуль с самого начала и отчасти повторяет действия 1-го прохода (лексический разбор, распознавание команд и директив, подсчет адресов). Это, однако, скорее дань традиции — с тех времен, когда в вычислительных системах ощущалась нехватка (или даже полное отсутствие) внешней памяти. В те далекие времена колода перфокарт или рулон перфоленты, содержащие текст модуля, вставлялись в устройство ввода повторно. В системах с эволюционным развитием сохраняются перфокарты и перфоленты (виртуальные), так что схема работы Ассемблера — та же. В новых системах Ассемблер может создавать промежуточный файл — результат 1-го прохода, который является входом для 2-го прохода. Каждому оператору исходного модуля соответствует одна запись промежуточного файла, и формат этой записи приблизительно такой: