When you're running out of registers while writing a JIT, you might resort to more unconventional methods for memory access. You might choose to resort to segment registers if you need a fixed register for memory offsets.
Instructions such as:
lea rax,gs:[rcx+rdx*8]
mov rax,gs:[rcx+rdx*8]
would then be available for your use.
This document documents what I have found about fs and gs on modern operating systems.
Doesn't care. Do what you want with gs
.
#include <asm/prctl.h>
static int arch_prctl(int func, void *ptr) {
return syscall(__NR_arch_prctl, func, ptr);
}
arch_prctl(ARCH_SET_FS, (void*)fsbase);
arch_prctl(ARCH_SET_GS, (void*)gsbase);
Doesn't care.
amd64_set_fsbase((void*)fsbase);
amd64_set_gsbase((void*)gsbase);
Doesn't care.
sysarch(X86_64_SET_FSBASE, (void*)fsbase);
sysarch(X86_64_SET_GSBASE, (void*)gsbase);
The 32 bit ABI for Windows allows you to modify the equivalent of gsbase using an LDT entry.
int (*NtSetLdtEntries)(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD);
*(FARPROC*)(&NtSetLdtEntries) = GetProcAddress(LoadLibrary("ntdll.dll"), "NtSetLdtEntries");
DWORD base = /* ... */;
DWORD limit = /* ... */;
LDT_ENTRY ll;
ll.BaseLow = base & 0xFFFF;
ll.HighWord.Bytes.BaseMid = base >> 16;
ll.HighWord.Bytes.BaseHi = base >> 24;
ll.LimitLow = limit & 0xFFFF;
ll.HighWord.Bits.LimitHi = limit >> 16;
ll.HighWord.Bits.Granularity = 0;
ll.HighWord.Bits.Default_Big = 1;
ll.HighWord.Bits.Reserved_0 = 0;
ll.HighWord.Bits.Sys = 0;
ll.HighWord.Bits.Pres = 1;
ll.HighWord.Bits.Dpl = 3;
ll.HighWord.Bits.Type = 0x13;
int ret = NtSetLdtEntries(0x80, *(DWORD*)&ll, *((DWORD*)(&ll)+1), 0, 0, 0);
assert(ret >= 0);
// Then use assembly to set gs to refer to the LDT entry
Win 8.1 onwards enables fsgsbase
instructions when they are available. This requires the application to be non-UMS.
Win 8.1 onwards explicitly allows you to use the wrgsbase
instruction to directly write gsbase for user-level threading.
However, the kernel checks for a valid TEB and may modify your gsbase if it doesn't point to a valid one.
Presence of this feature can be detected using IsProcessorFeaturePresent(PF_RDWRFSGSBASE_AVAILABLE)
.
I currently do not know if wrfsbase
is available for use.
Edit: @shuffle2 has a useful post on using fs here: http://ghettohaxxx-blog.azurewebsites.net/executing-bsd-elfs-in-windows/
Fuck you.
Very nice, thank you so much !