Hmm, the choice of challenge does not seem great. The calculator code you’re supposed to JIT takes no input, so you can just do all the math at JIT compile time and emit something like
You are right that an optimizing JIT could do this (it was also pointed out in the r/rust discussion). However, the target audience for this challenge are people who are new to JITs in the first place, so the challenge is about generating unoptimized instructions (see this thread for details). If you already know how to do that, then it won’t be a challenge at all, as you point out.
I hadn’t thought about it from that angle! My personal goal with this challenge, which I invented for myself and only published afterwards, was to dive deeper into machine code. From that perspective, hardcoding the answer in the machine code would limit the learning opportunity that I wanted to create.
Pretty much all systems (outside some microcontrollers that are strict harvard-architecture) have some way of doing JITs. Processor-side, they only provide the infrastructure needed to prevent doing so: pages can be marked as executable or not, and the MMU will enforce that. OSes need to do that, and provide APIs to applications to control it (often with policies to control to what degree applications are allowed to use it - if you know a program doesn’t ever JIT/load code, its of course safer to forbid it ever allocating executable memory).
What OSes commonly do is enforce that memory is never both writeable and executable at the same time - JITs then need to flip that at the correct time.
All desktop operating systems allow it. So many apps just wouldn’t work otherwise especially in the media field (audio, video etc) where it is a necessity to ink out the last inches of performance to be competitive.
Does anyone here know the way in rust to jump to the first instruction after they are written to memory? Seems obviously unsafe but even in an unsafe block I’m unclear on how to cast a raw pointer to a function. Does it just have to use inline asm?
I found an answer on StackOverflow showing how to use transmute for this. The part that wasn’t obvious to me is the safe cast to *const (); so that the Dst type is understood by the compiler.
Hmm, the choice of challenge does not seem great. The calculator code you’re supposed to JIT takes no input, so you can just do all the math at JIT compile time and emit something like
You are right that an optimizing JIT could do this (it was also pointed out in the r/rust discussion). However, the target audience for this challenge are people who are new to JITs in the first place, so the challenge is about generating unoptimized instructions (see this thread for details). If you already know how to do that, then it won’t be a challenge at all, as you point out.
Hmm, maybe I’m weird but actually emitting the instructions to do the math sounds harder to me than baking in the result.
I hadn’t thought about it from that angle! My personal goal with this challenge, which I invented for myself and only published afterwards, was to dive deeper into machine code. From that perspective, hardcoding the answer in the machine code would limit the learning opportunity that I wanted to create.
Don’t most operating systems and processors prevent you from executing data?
The OS will let you change MMU permissions for your own pages.
For Linux and other UNIXes, you could use
mprotectto enable the exec permission for the pages containing your data/instructions.Pretty much all systems (outside some microcontrollers that are strict harvard-architecture) have some way of doing JITs. Processor-side, they only provide the infrastructure needed to prevent doing so: pages can be marked as executable or not, and the MMU will enforce that. OSes need to do that, and provide APIs to applications to control it (often with policies to control to what degree applications are allowed to use it - if you know a program doesn’t ever JIT/load code, its of course safer to forbid it ever allocating executable memory).
What OSes commonly do is enforce that memory is never both writeable and executable at the same time - JITs then need to flip that at the correct time.
Sort of a spoiler, since this post didn’t get there yet:
Hello, JIT World! - https://blog.reverberate.org/2012/12/hello-jit-world-joy-of-simple-jits.html
See the
mmap()call, which is in POSIX - https://pubs.opengroup.org/onlinepubs/9799919799/functions/mmap.htmlSo you don’t need anything unportable to make a JIT, I think that code will work exactly the same way on Linux, BSD, Minix, etc.
All desktop operating systems allow it. So many apps just wouldn’t work otherwise especially in the media field (audio, video etc) where it is a necessity to ink out the last inches of performance to be competitive.
Does anyone here know the way in rust to jump to the first instruction after they are written to memory? Seems obviously unsafe but even in an unsafe block I’m unclear on how to cast a raw pointer to a function. Does it just have to use inline asm?
You have to transmute pointers into functions
I found an answer on StackOverflow showing how to use
transmutefor this. The part that wasn’t obvious to me is the safe cast to*const ();so that theDsttype is understood by the compiler.