Почему эта каирская программа хранит в памяти степень двойки?
Я пытаюсь решить этот бонусный вопрос из учебника «Как работает Каир». Я запустил следующую функцию, открыл трассировщик Cairo и увидел, что память заполнена степенями двойки. Почему?
func main():
[fp + 1] = 2; ap++
[fp] = 5201798304953761792; ap++
jmp rel -1
end
1 ответ
Вот несколько наводящих вопросов, которые помогут вам найти ответ. Ответы на вопросы после перерыва:
- Куда переходит инструкция?
- Что делает целевая инструкция? Что происходит после этого?
- Как эта инструкция оказалась в программном разделе памяти?
- кодируется в памяти по адресам 5-6. При его выполнении имеем
pc = 5
, таким образом, после перехода мы выполним инструкцию вpc = 4
, который . - Этот байт-код кодирует инструкцию
[ap] = [ap - 1] + [ap - 1]; ap++
(для проверки можно вручную декодировать флаги и смещения или просто написать программу cairo с этой инструкцией и посмотреть, во что она скомпилируется). После его выполнения увеличивается на 1, поэтому мы снова выполняем и так далее в бесконечном цикле. Должно быть понятно, почему это заполняет память степенями числа 2 (первые 2 по адресу 10 были записаны[fp + 1] = 2; ap++
инструкция). - Инструкция
[fp] = 5201798304953761792; ap++
имеет непосредственный аргумент (правая часть, 5201798304953761792). Инструкции с непосредственными аргументами кодируются как два элемента поля в памяти, первый кодирует общую инструкцию (например,[fp] = imm; ap++
), а второе — само непосредственное значение. Таким образом, это непосредственное значение записывается по адресу 4, и действительно 5201798304953761792 совпадает с0x48307fff7fff8000
. Точно так же2
по адресу 2 находится непосредственный аргумент инструкции[fp + 1] = 2
, и-1
по адресу 6 находится ближайший кjmp rel -1
.
Подводя итог, можно сказать, что это странное поведение связано с тем, что относительный переход перемещается на адрес с немедленным значением и анализируется как отдельная инструкция. Обычно этого не происходит, так как
pc
увеличивается на 2 после выполнения инструкции с немедленным значением и на 1 при выполнении инструкции без него, поэтому всегда переходит к следующей скомпилированной инструкции. Здесь был необходим прыжок без метки, чтобы добраться до этого неожиданного счетчика программ.