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