I recently wrote a toy compiler for x86_64. I use an external assembler.
My dream is to write a JIT compiler runtime.
https://GitHub.com/samsquire/compiler
My understanding is that you generate machine code and then mprotect the code to be executable then jump to the void * as a function pointer to execute generated instructions.
What I would like to understand more is tracing compilers and how they optimise hot loops. And how they deoptimise and optimise at runtime based on runtime information.