I would expect to generate SIGSEGV, catch it, process it and resume it, would have more performances than on the original equipment, so attach it to ensure that this happens only when there really was an error, which can be slow.
This is a good technique for checking memory / array protection when violations are rare and it is normal if they are slow. Speeding up a common cause is a bit of a gain, even if it makes an exceptional case much slower, it is a victory when an exceptional case does not occur in normal emulated code.
I heard that Javascript emulators do this in order to get a cheaper check on the bounds of the array: select the array so that it ends at the top of the page where the next page was not displayed.
Take this with salt: I have not used any of this code that I wrote. I just heard about it and I think I understand how it works, and some of the consequences.
I hope this helps you take a look at the documents that will tell you what can actually be done.
Updating page tables is pretty slow . Try to find a balance in which you can use user space memory protection for some checks, but you do not constantly display / untie pages from your memory space during the “general case” of what your emulated code does. Predicted branches work very fast, especially. if they are not accepted to predict.
I saw a Linux kernel discussion / notes indicating that playing tricks with mmap is not only worth one page on memcpy . For more memory or less re-access checks, the advantage will exceed the setup overhead.
You want to use mprotect(2) to change the permissions on the (ranges) of pages. No, comparisons cannot overlap. See the MAP_FIXED parameter in mmap(2) :
If the memory area indicated by addr and len overlaps the pages of any existing mapping (s), then the overlapping portion of the existing mapping will be discarded.
IDK, if you can do anything useful using the x86 segment registers when accessing emulated memory, map address 0 to another address in the virtual address space of the process. You can map virtual address 0, but Linux disables it by default, so NULL pointers don't work silently!
Your software users will have to futz with sysctl (same as for WINE) to enable it:
# Ubuntu /etc/sysctl.d/10-zeropage.conf
As I said, you can use segment redefinition for all downloads / storages to guest (emulated) memory in order to reassign it to a more reasonable page. Or maybe just use a constant offset of 64kiB (or more, maybe lay it out over the text / data / bss (bunch) of emulation software). Or not a constant offset, using the pointer to the base of your guest memory mmapped region, so everything relates to a global variable. With gcc, this can be a good candidate for requesting that gcc keep this global register in your functions. IDK, you would have to make sure that it helped to perforate or not. A constant offset will ultimately result in each team accessing the guest memory requiring an offset field 32b in addressing mode, rather than 0 or 8b.
Segment register, if it works the way I think, it (since a constant offset that can be applied with a segment redefinition prefix instead of an offset modifier 32b) would be much harder to get a compiler to generate, AFAIK, If it were only downloads / stores , this would be one: you could use the asm built-in shell to load and store the insn. But for efficient x86 code, all kinds of ALU instructions should use memory operands to reduce interface bottlenecks through micro-merging.
Perhaps you can simply define the global char *const guest_mem = (void*)0x2000000; or something else and then use mmap with MAP_FIXED to make it display memory there? Then access to guest memory can be compiled into more efficient single-register modes.