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