Почему эта каирская программа хранит в памяти степень двойки?

Я пытаюсь решить этот бонусный вопрос из учебника «Как работает Каир». Я запустил следующую функцию, открыл трассировщик Cairo и увидел, что память заполнена степенями двойки. Почему?

      func main():
    [fp + 1] = 2; ap++
    [fp] = 5201798304953761792; ap++
    jmp rel -1
end

1 ответ

Вот несколько наводящих вопросов, которые помогут вам найти ответ. Ответы на вопросы после перерыва:

  1. Куда переходит инструкция?
  2. Что делает целевая инструкция? Что происходит после этого?
  3. Как эта инструкция оказалась в программном разделе памяти?

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

Подводя итог, можно сказать, что это странное поведение связано с тем, что относительный переход перемещается на адрес с немедленным значением и анализируется как отдельная инструкция. Обычно этого не происходит, так как pcувеличивается на 2 после выполнения инструкции с немедленным значением и на 1 при выполнении инструкции без него, поэтому всегда переходит к следующей скомпилированной инструкции. Здесь был необходим прыжок без метки, чтобы добраться до этого неожиданного счетчика программ.

Другие вопросы по тегам