I’m working on a piece of software which generates assembler code at runtime. For instance,
here’s a very simple function which generates assembler code for calling the GetCurrentProcess function (for the Win64 ABI):
void genGetCurrentProcess( char *codePtr, FARPROC addressForGetCurrentProcessFunction )
{
#ifdef _WIN64
// mov rax, addressForGetCurrentProcessFunction
*codePtr++ = 0x48
*codePtr++ = 0xB8;
*((FARPROC *)codePtr)++ = addressForGetCurrentProcessFunction;
// call rax
*codePtr++ = 0xFF;
*codePtr++ = 0xD0;
#else
// mov eax, addressForGetCurrentProcessfunction
*codePtr++ = 0xB8;
*((FARPROC *)codePtr)++ = addressForGetCurrentProcessFunction;
// call eax
*codePtr++ = 0xFF;
*codePtr++ = 0xD0;
#endif
}
Usually I’d use inline assembler, but alas – this doesn’t seem to be possible with the 64bit MSVC compilers anymore. While I’m at it – this code should work with MSVC6 up to MSVC10 and also MinGW. There are many more functions like genGetCurrentProcess, they all emit assembler code and many of them get function pointers to be called passed as arguments.
The annoying thing about this is that modifying this code is error-prone and we’ve got to take care of ABI-specific things manually (for instance, reserving 32 bytes stack space before calling functions for register spilling).
So my question is – can I simplify this code for generating assembler code at runtime? My hope was that I could somehow write the assembler code directly (possibly in an external file which is then assembled using ml/ml64) but it’s not clear to me how this would work if some of the bytes in the assembled code are only known at runtime (the addressForGetcurrentProcessFunction value in the above example, for instance). Maybe it’s possible to assemble some code but assign ‘labels’ to certain locations in the code so that I can easily modify the code at runtime and then copy it into my buffer?
Take a look at asmjit. It is a C++ library for runtime code-generation. Supports x64 and probably most of the existing extensions (FPU, MMX, 3dNow, SSE, SSE2, SSE3, SSE4). Its interface resembles assembly syntax and it encodes the instructions correctly for you.