Где хранить константы кода при написании JIT-компилятора?
Я пишу JIT-компилятор для x86-64, и у меня есть вопрос относительно наилучшей практики для включения констант в машинный код, который я генерирую.
Мой подход пока прост:
- Выделите кусок памяти RW с помощью
VirtualAlloc
или жеmmap
- Загрузите машинный код в указанную область памяти.
- Пометить страницу как исполняемую
VirtualProtect
или жеmprotect
(и удалите привилегию записи для безопасности). - Выполнить.
Когда я генерирую код, я должен включать константы (числовые, строковые), и я не уверен, как лучше всего это сделать. Я имею в виду несколько подходов:
- Сохраните все константы как непосредственные значения в кодах операций инструкций. Это кажется плохой идеей для всего, кроме, может быть, небольших скалярных значений.
- Выделите отдельную область памяти для констант. Это кажется мне лучшей идеей, но это немного усложняет управление памятью и рабочий процесс компиляции - мне нужно знать место в памяти, прежде чем я смогу начать писать исполняемый код. Также я не уверен, что это как-то влияет на производительность из-за худшего локального пространства памяти
- Сохраните константы в той же области, что и код, и получайте к ним доступ с помощью RIP-относительной адресации. Мне нравится этот подход, так как он объединяет соответствующие части программы, но мне немного неловко смешивать инструкции и данные.
- Что-то совершенно другое?
Каков предпочтительный способ пойти по этому поводу?
1 ответ
Многое зависит от того, как вы генерируете свой двоичный код. Если вы используете JIT-ассемблер, который обрабатывает метки и вычисляет смещения, все довольно просто. Вы можете прикрепить константы в блоке после конца кода, используя относительные к ПК ссылки на эти метки, и в итоге получите один блок байтов с кодом и константами (простое управление). Если вы пытаетесь сгенерировать двоичный код на лету, у вас уже есть проблема выяснения того, как обрабатывать прямые относительные ссылки на ПК (например, для прямых ветвей). Если вы используете back-patch, вам нужно расширить его для поддержки ссылок на ваш блок констант.
Вы можете избежать вычислений относительного смещения для ПК, поместив константы в отдельный блок и передав адрес этого блока в качестве параметра в свой код. Это в значительной степени "Выделите отдельный регион для констант", который вы предлагаете. Вам не нужно знать адрес блока, если вы передаете его в качестве аргумента.