Я пишу JIT-компилятор на C для x86_64 linux.
В настоящее время идея состоит в том, чтобы сгенерировать некоторый байт-код в буфере исполняемой памяти (например, полученный с помощью вызова mmap) и перейти к нему с помощью указателя на функцию.
Я хотел бы иметь возможность связать несколько блоков исполняемой памяти вместе, чтобы они могли переключаться между собой, используя только собственные инструкции.
В идеале указатель C-уровня на исполняемый блок может быть записан в другой блок как абсолютный адрес перехода примерно так:
unsigned char *code_1 = { 0xAB, 0xCD, ... };
void *exec_block_1 = mmap(code1, ... );
write_bytecode(code_1, code_block_1);
...
unsigned char *code_2 = { 0xAB, 0xCD, ... , exec_block_1, ... };
void *exec_block_2 = mmap(code2, ... );
write_bytecode(code_2, exec_block_2); // bytecode contains code_block_1 as a jump
// address so that the code in the second block
// can jump to the code in the first block
Однако я нахожу здесь ограничения x86_64 довольно серьезным препятствием. В x86_64 невозможно перейти к абсолютному 64-битному адресу, поскольку все доступные 64-битные операции перехода относятся к указателю инструкции. Это означает, что я не могу использовать C-указатель в качестве цели перехода для сгенерированного кода.
Есть ли решение этой проблемы, которое позволит мне связать блоки так, как я описал? Возможно, инструкция x86_64, о которой я не знаю?
jmp rax
. - person Hans Passant   schedule 22.04.2015mmap
с адресом подсказки, поэтому вы может использовать прямую кодировкуcall
илиjmp rel32
. - person Peter Cordes   schedule 12.04.2019