Многопроходное ассемблирование
При ассемблировании с использованием меток возникает
специфическая проблема: команды могут ссылаться на метки, определенные
как до, так и после них по тексту программы. Следовательно, операндом
команды может оказаться метка, которая еще не определена. Адрес, соответствующий
этой метке, еще неизвестен, поэтому мы должны будем, так или иначе, вернуться
к ссылающейся на нее команде и записать адрес. Эта же проблема возникает
и при компиляции ЯВУ: предварительное определение переменных и процедур
указывает тип переменной и количество и типы параметров процедуры, но
не их размещение в памяти, а именно оно нас и интересует при генерации
кода.
Две техники решения этой проблемы называются одно-
и двухпроходным ассемблированием [Баррон 1974].
При двухпроходном ассемблировании, на первом проходе мы определяем адреса
всех описанных в программе символов и сохраняем их в промежуточной таблице.
На втором проходе мы осуществляем собственно ассемблирование — генерацию
кода и расстановку адресов. Если адресное поле имеет переменную длину,
определение адреса метки может привести к изменению длины ссылающегося
на нее кода, поэтому на таких архитектурах оказывается целесообразным
трех- и более проходное ассемблирование. При однопроходном ассемблировании,
мы запоминаем все точки, из которых происходят ссылки вперед, и, определив
адрес символа, возвращаемся к этим точкам и записываем в них адрес. При
однопроходном ассемблировании целесообразно хранить код, в котором еще
не все метки расставлены, в оперативной памяти, поэтому в старых компьютерах
двухпроходные ассемблеры были широко распространены. Впрочем, современные
многопроходные ассемблеры также хранят промежуточные представления программы
в памяти, поэтому количество проходов в конкретной реализации ассемблера
представляет разве что теоретический интерес.
|