avva (
avva) wrote2025-06-28 12:02 am
![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Entry tags:
еще раз про waste
Задолжал объяснение странной функции waste() в очень старой версии компилятора C Денниса Ритчи. Этот компилятор был написан для компьютера PDP-11. Он работает в два прохода, как свойственно многим компиляторам (почему именно? разузнайте, если вам интересно). Эти два прохода - отдельные программы c0 и c1, первая пишет в временный файл, вторая читает из его и пишет в файл ассемблера. Когда это необходимо, первый проход передает второму напрямую синтаксическое дерево (AST, Abstracy Syntax Tree) данного выражения в исходном коде. Это дерево хранится в памяти как массив, содержащий ссылки-указатели внутрь самого себя. c0 "сериализует" это дерево просто записью массива как набора чисел во временный файл, а потом c1 читает его из файла на то же самое место в памяти, в котором оно было в c0, и поэтому все внутренние указатели продолжают работать.
Но как найти место в памяти, которое гарантированно имеет одинаковый адрес в c0 и в c1? Ритчи для этого использует сам код компилятора, в котором функции выставлены в известном порядке и первая загружается по известному фиксированному адресу в том конкретном компьютере и в той версии Юникса. В c0 для этого буфера AST используется место, которое занимает код функции init(), которая к этому моменту уже не нужна. В c1 не оказалось такой удобной функции, и Ритчи написал waste(), чтобы просто зарезервировать нужное число байтов.
Я не знаю подробностей насчет того, как устроена AST, почему первый проход должен передавать ее второму (обычно второму проходу нужно лишь зафиксировать адреса переменных и функций в уже готовом коде, но возможно Ритчи по-другому распределил работу), и как именно обеспечивается загрузка по идентичному адресу. Возможно, я найду время разобраться в этом (интересно!), и посмотреть на это дело в работе. Warren Toomey (он смог запустить этот компилятор в 2008-м) прислал мне ссылку на репозиторию юникса за июнь 72 года (DoctorWkt/unix-jun72 на гитхабе), где лежат скомпилированные c0 и c1, не вполне ясно, какой версии компилятора, но скорее всего в симуляторе PDP-11 apout, который написал Уоррен, можно будет их запустить, скомпилировать компилятор и скомпилировать им себя, и тогда уже будет легче разбираться. Привожу эту информацию на случай, если кто-то захочет попробовать, дайте знать, если получится.
Но как найти место в памяти, которое гарантированно имеет одинаковый адрес в c0 и в c1? Ритчи для этого использует сам код компилятора, в котором функции выставлены в известном порядке и первая загружается по известному фиксированному адресу в том конкретном компьютере и в той версии Юникса. В c0 для этого буфера AST используется место, которое занимает код функции init(), которая к этому моменту уже не нужна. В c1 не оказалось такой удобной функции, и Ритчи написал waste(), чтобы просто зарезервировать нужное число байтов.
Я не знаю подробностей насчет того, как устроена AST, почему первый проход должен передавать ее второму (обычно второму проходу нужно лишь зафиксировать адреса переменных и функций в уже готовом коде, но возможно Ритчи по-другому распределил работу), и как именно обеспечивается загрузка по идентичному адресу. Возможно, я найду время разобраться в этом (интересно!), и посмотреть на это дело в работе. Warren Toomey (он смог запустить этот компилятор в 2008-м) прислал мне ссылку на репозиторию юникса за июнь 72 года (DoctorWkt/unix-jun72 на гитхабе), где лежат скомпилированные c0 и c1, не вполне ясно, какой версии компилятора, но скорее всего в симуляторе PDP-11 apout, который написал Уоррен, можно будет их запустить, скомпилировать компилятор и скомпилировать им себя, и тогда уже будет легче разбираться. Привожу эту информацию на случай, если кто-то захочет попробовать, дайте знать, если получится.