6 ms·
Is this emulating x86? Can I run it on an M1?
by jonny_eh 5y ago
Is this emulating x86? Can I run it on an M1?
- woodruffw 5y agoIt's not emulating x86: it looks like it's assembling instructions on the fly and executing them in a mmap'd region. In other words, it's a very simple JIT. But you probably can run it on an M1 anyways, since Apple's Rosetta will do the dynamic binary translation for you under the hood. YMMV.
- a-dub 5y agowould it? rosetta is a jit translator isn't it? how would it know to translate the instructions that are being generated on the fly interactively? unless there's hardware support in the m1 for translation or some other interrupt that gets triggered to do translation on the fly...
- jsmith45 5y agoI'd assume Rosetta works for newly marked executable pages by not actually flagging them as executable. When control flow attempts to transfer there, a page fault will occur since the page is not actually executable, this is the interrupt that allows Rosetta to step in, see what code was about to be executed, and write out a new ARM equivalent of the code to other memory, and redirect execution to the new equivalent ARM code, before resuming. This basic sort of support is needed for any application that targeting x86 that uses any form of dynamic code generation, which is probably a whole lot more than most people think (even some forms of dynamic linking utilize small amounts of generated code, due to being more efficient than calling a method though a pointer to a pointer to the method).
- a-dub 5y agoso every write to an executable page would have to clear that bit then, triggering an interrupt on jump to let the translator jump in? i'd venture a guess that the rosetta jit stuff probably does some kind of prelinking. kinda makes me wish i had an m1 mac to play with...
- anyfoo 5y agox86 code is never actually marked as executable from the CPU's point of view, since that CPU does not know how to execute x86 code. The pages which contain the translated code are, but those are not something the x86 code knows about.
- chrisseaton 5y ago> x86 code is never actually marked as executable from the CPU's point of view, since that CPU does not know how to execute x86 code. The pages which contain the translated code are, but those are not something the x86 code knows about. No, pages and the executable bit are something that the processor knows about.
- a-dub 5y agoyou think that x86 pages are marked executable by the arm processor? probably not. maybe arm pages with an arm wrapper that calls the jit for big literals filled with x86 code are, or arm pages loaded with stubs that jump into the jit to compile x86 code sitting in data pages are... but if the arm processor cannot execute x86 pages directly, then it wouldn't make a lot of sense for them to be marked executable, would it?
- chrisseaton 5y agoNo the AMD64 page executable bit system is implemented in software by Rosetta.
- saagarjha 5y agoNo, it doesn't need to. Rosetta only emulates userspace, so it just needs to give the illusion of protections to the program.
- anyfoo 5y agoAh, in this case I took "x86 execution semantics" just as how it behaves from user space, i.e. what permissions you can set and that they behave the same from an x86 observer (no matter what shenanigans is actually going behind the scenes).
- woodruffw 5y agoRosetta contains both an AOT static binary translator and a JIT dynamic binary translator. That’s how Apple managed to get JS engines working even when the host browser was running as x86-on-M1.
- chrisseaton 5y ago> rosetta is a jit translator > how would it know to translate the instructions that are being generated on the fly interactively? Just answered your own question.
- jcranmer 5y agoDynamic JIT translation for x86 is pretty old-hat at this point; the general state of the art can be summarized in the (now 16 years old) Pin paper: https://www.cin.ufpe.br/~rmfl/ADS_MaterialDidatico/PDFs/profiling/PIN%20Building%20Customized%20Program%20Analysis%20Tools%20with%20Dynamic%20Instrumentation.pdf https://www.cin.ufpe.br/~rmfl/ADS_MaterialDidatico/PDFs/prof... In general, the way you handle translation of machine code tends to resolve around compiling small dynamic traces (basically, the code from the current instruction pointer to the next branch instruction), with a lot of optimizations on top of that to make very common code patterns much faster than having to jump back to your translation engine every couple of instructions. The interactive generation this article implies is most likely to be effected with use of the x86 trap flag (which causes a trap interrupt after every single instruction is executed), which is infrequent enough that it's likely to be fully interpreted instead of using any sort of dynamic trace caching. In the case of x86 being generated by a JIT of some sort, well, you're already looking at code only when it's being jumped to, so whether the code comes from the program, some dynamic library being loaded later, or being generated on the fly doesn't affect its execution.
- bdowling 5y agoIt's a bit more complicated than that. Code is assembled into a shared memory buffer. The application spawns a child process that runs the code in the shared memory buffer. The parent process attaches to the child using ptrace to inspect and manipulate the CPU state and memory of the subprocess. The app is entirely written in Ruby. So, it might run on Apple M1, but only if you're running an x86 Ruby interpreter through Rosetta.
- woodruffw 5y agoAh, great point! I had assumed that the Ruby interpreter would be x86, but that isn’t a reasonable assumption now that native builds are common.
- spiffistan 5y agoJIT makes sense given his other current project: https://github.com/tenderlove/tenderjit https://github.com/tenderlove/tenderjit