2015-02-25 4 views
0

Я написал JITting VM для Brainfuck. Для этого требуется создание области записи с возможностью записи и записи (то есть, char*, но не созданной с помощью malloc или new), которая заполняется машинным кодом операции (x64 в моем случае), а затем вызывается после преобразования char* в указатель функции. Эта вновь созданная функция имеет параметры. А именно, указатель на память и некоторые другие внутренние вещи.Как узнать, какие параметры функции регистров будут отображаться?

Он работает, но предполагает определенное отображение регистров. Это сопоставление изменилось, когда-то, потому что я изменил код вокруг вызова в char*, и компилятор решил, что он будет работать лучше с другими регистрами. Поэтому мне пришлось изменить схему генерации кода.

Я боюсь, что смогу сделать что-то, что заставит компилятор изменить его или, что еще хуже, использовать стек, который я не знаю, как вытащить параметры из (пока).

Так что мне нужно:

  • способ, чтобы сообщить компилятору о том, что регистры поставить параметры (`регистр ... ассемблер («r0»), как описано here, не работает с параметрами)
  • еще один способ узнать, как регистрируются параметры. Это будет сложнее, но это все еще возможно.
  • еще способ узнать, если и в каком порядке были переданы параметры в стек

Я использую GCC 4.8.2.

+1

Какой компилятор вы используете? Если вы используете 'gcc', вы можете написать встроенную ассемблерную оболочку, которая вызывает jit-сгенерированный код. Затем вы можете использовать свои собственные соглашения о вызовах. – swegi

+1

Если вы обнаружили параметры в разных регистрах, то я сильно подозреваю, что вы не искали нужного места для начала. Скорее, я подозреваю, что вы * произошли *, чтобы найти нужное вам значение в регистре, но вызывающий абонент просто использовал этот регистр как временное местоположение, прежде чем копировать параметр в нужное место. Вы полагались на остатки. Вызывающая конвенция должна быть хорошо установлена; он не изменится с одной сборки на другую, если вы явно не используете директиву, которая определяет соглашение о вызове. –

+0

@RobKennedy, я смотрел на разборку, а не на значения в регистрах. Я не могу вспомнить слишком хорошо сейчас, что я тогда сделал, но оказалось, что у меня есть один дополнительный параметр, используя% rdi и перестановку остальных в% rsi ->% r9 вместо% rdi ->% r8, м, используя теперь. Тогда я плохой. – Gabriel

ответ

1

Когда вы вызываете функцию, компилятор обычно не имеет выбора о том, куда положить аргументы для вызова. Это продиктовано ABI. Если хост-программа написана на C++ и работает на Linux/x86-64 машины, она будет испускать код, который соответствует конвенции вызова, описанной в SysV ABI, который содержит следующие правила для передачи параметров:

Если класс INTEGER, используется следующий доступный регистр последовательности% rdi, % rsi,% rdx,% rcx,% r8 и% r9.

Следует отметить, что класс INTEGER включает также указатели указателя.

Суть в том, что ваш jitted-код должен быть в состоянии выбрать свои аргументы из перечисленных выше регистров. Если это все еще не работает, я подозреваю, что вы можете неправильно кодировать свои инструкции. Попробуйте просмотреть разборку с GDB.

(*) Ну, компилятору может быть предоставлена ​​дополнительная гибкость, если функция не может быть вызвана из-за пределов единицы перевода.

+0

Ницца! Это те регистры, которые я действительно использовал. Таким образом, есть некоторый уровень гарантии в конце концов. Примечание. Я использую 'objdump', чтобы получить ASM/binary из моего цикла интерпретатора без JIT и использовать то, что генерирует gcc. – Gabriel

+1

Если вы хотите просмотреть сгенерированный код, вы можете либо a) просмотреть его в gdb, используя 'disas

' или b) записать его в файл из вашей виртуальной машины и использовать 'objdump -b binary -D '. –

 Смежные вопросы

  • Нет связанных вопросов^_^