I'm toying with the idea of writing a JIT compiler and am just wondering if it is even theoretically possible to write the whole thing in managed code. In particular, once you've generated assembler into a byte array how do you jump into it to begin execution?
-
I don't believe there is - whilst you can work in an unsafe context at times in managed languages, I don't *believe* you can synthesize a delegate from a pointer - and how else would you jump to the generated code? – Damien_The_Unbeliever Mar 04 '12 at 17:48
-
@Damien: wouldn't unsafe code let you write to a function pointer? – H H Mar 04 '12 at 17:51
-
2With a title like "how to dynamically transfer control to unmanaged code" you may have a lower risk of being closed. It looks more to the point too. Generating the code isn't the issue. – H H Mar 04 '12 at 17:54
-
@HenkHolterman - maybe, if you could *find* a function pointer... – Damien_The_Unbeliever Mar 04 '12 at 17:55
-
8The simplest idea would be to write down the byte array into a file and let the OS run it. After all, you need a _compiler_, not an _interpreter_ (which would be possible as well, but more complicated). – Vlad Mar 04 '12 at 17:56
-
There's also the obstacle the, from managed code, you tend to have access to managed memory, which tends to be marked as data, not executable. – Damien_The_Unbeliever Mar 04 '12 at 18:07
-
3Once you've JIT compiled the code you want, you could use Win32 APIs to allocate some unmanaged memory (marked as executable), copy the compiled code into that memory space, then use the IL `calli` opcode to call the compiled code. – Jack P. Mar 04 '12 at 19:21
-
I'd support Vlad's argument -- output your assembly instructions to a DLL, then let the OS load and execute it. You could do that via a P/Invoke call to [`LoadLibrary`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms684175.aspx) or similar. – stakx - no longer contributing Mar 05 '12 at 18:52
4 Answers
Yes, you can. In fact, it's my job :)
I've written GPU.NET entirely in F# (modulo our unit tests) -- it actually disassembles and JITs IL at run-time, just like the .NET CLR does. We emit native code for whatever underlying acceleration device you want to use; currently we only support Nvidia GPU's, but I've designed our system to be retargetable with a minimum of work so it's likely we'll support other platforms in the future.
As for performance, I have F# to thank -- when compiled in optimized mode (with tailcalls), our JIT compiler itself is probably about as fast as the compiler within the CLR (which is written in C++, IIRC).
For execution, we have the benefit of being able to pass control to hardware drivers to run the jitted code; however, this wouldn't be any harder to do on the CPU since .NET supports function pointers to unmanaged/native code (though you'd lose any safety/security normally provided by .NET).

- 11,487
- 1
- 29
- 34
-
4Isn't the whole point of NoExecute that you cannot jump to code that you've created yourself? Rather than being possible to jump to native code through a function pointer: isn't it **not** possible to jump to native code through a function pointer? – Ian Boyd Mar 05 '12 at 00:13
-
Awesome project, though I think you guys would get a lot more exposure if you made it free for not-for-profit applications. You'd lose the chump-change from the "enthusiast" tier, but it'd be well worth it for the increased exposure from more people using it *(I know I definitely would ;) )*! – BlueRaja - Danny Pflughoeft Jul 26 '12 at 23:02
-
@IanBoyd NoExecute is mostly yet another way to avoid trouble from buffer overruns and related issues. It's not a protection from your own code, it's something to help mitigate illegal code execution. – Luaan May 16 '16 at 08:39
And for the full proof of concept here is a fully capable translation of Rasmus' approach to JIT into F#
open System
open System.Runtime.InteropServices
type AllocationType =
| COMMIT=0x1000u
type MemoryProtection =
| EXECUTE_READWRITE=0x40u
type FreeType =
| DECOMMIT = 0x4000u
[<DllImport("kernel32.dll", SetLastError=true)>]
extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, AllocationType flAllocationType, MemoryProtection flProtect);
[<DllImport("kernel32.dll", SetLastError=true)>]
extern bool VirtualFree(IntPtr lpAddress, UIntPtr dwSize, FreeType freeType);
let JITcode: byte[] = [|0x55uy;0x8Buy;0xECuy;0x8Buy;0x45uy;0x08uy;0xD1uy;0xC8uy;0x5Duy;0xC3uy|]
[<UnmanagedFunctionPointer(CallingConvention.Cdecl)>]
type Ret1ArgDelegate = delegate of (uint32) -> uint32
[<EntryPointAttribute>]
let main (args: string[]) =
let executableMemory = VirtualAlloc(IntPtr.Zero, UIntPtr(uint32(JITcode.Length)), AllocationType.COMMIT, MemoryProtection.EXECUTE_READWRITE)
Marshal.Copy(JITcode, 0, executableMemory, JITcode.Length)
let jitedFun = Marshal.GetDelegateForFunctionPointer(executableMemory, typeof<Ret1ArgDelegate>) :?> Ret1ArgDelegate
let mutable test = 0xFFFFFFFCu
printfn "Value before: %X" test
test <- jitedFun.Invoke test
printfn "Value after: %X" test
VirtualFree(executableMemory, UIntPtr.Zero, FreeType.DECOMMIT) |> ignore
0
that happily executes yielding
Value before: FFFFFFFC
Value after: 7FFFFFFE

- 62,044
- 9
- 127
- 211

- 10,270
- 1
- 34
- 54
-
Despite my upvote, I beg to differ: this is **arbitrary code execution**, not JIT - JIT means "just in time **compilation**", but I can't see the "compilation" aspect from this code example. – rwong Dec 25 '15 at 01:09
-
4@rwong: "compilation" aspect never was in scope of original question concerns. Managed code ability of implementing *IL -> native code* transformation is kinda apparent. – Gene Belitski Dec 27 '15 at 01:19
The trick should be VirtualAlloc with the EXECUTE_READWRITE
-flag (needs P/Invoke) and Marshal.GetDelegateForFunctionPointer.
Here is a modified version of the rotate integer example (note that no unsafe code is needed here):
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint Ret1ArgDelegate(uint arg1);
public static void Main(string[] args){
// Bitwise rotate input and return it.
// The rest is just to handle CDECL calling convention.
byte[] asmBytes = new byte[]
{
0x55, // push ebp
0x8B, 0xEC, // mov ebp, esp
0x8B, 0x45, 0x08, // mov eax, [ebp+8]
0xD1, 0xC8, // ror eax, 1
0x5D, // pop ebp
0xC3 // ret
};
// Allocate memory with EXECUTE_READWRITE permissions
IntPtr executableMemory =
VirtualAlloc(
IntPtr.Zero,
(UIntPtr) asmBytes.Length,
AllocationType.COMMIT,
MemoryProtection.EXECUTE_READWRITE
);
// Copy the machine code into the allocated memory
Marshal.Copy(asmBytes, 0, executableMemory, asmBytes.Length);
// Create a delegate to the machine code.
Ret1ArgDelegate del =
(Ret1ArgDelegate) Marshal.GetDelegateForFunctionPointer(
executableMemory,
typeof(Ret1ArgDelegate)
);
// Call it
uint n = (uint)0xFFFFFFFC;
n = del(n);
Console.WriteLine("{0:x}", n);
// Free the memory
VirtualFree(executableMemory, UIntPtr.Zero, FreeType.DECOMMIT);
}
Full example (now works with both X86 and X64).

- 48,631
- 24
- 141
- 189
Using unsafe code, you can "hack" a delegate and make it point to an arbitrary assembly code that you generated and stored in an array. The idea is that delegate has a _methodPtr
field, which can be set using Reflection. Here is some sample code:
This is, of course, a dirty hack that may stop working at any time when the .NET runtime changes.
I guess that, in principle, fully managed safe code cannot be allowed to implement JIT, because that would break any security assumptions that the runtime relies on. (Unless, the generated assembly code came with a machine-checkable proof that it does not violate the assumptions...)

- 263,252
- 30
- 330
- 514

- 240,744
- 19
- 378
- 553
-
1Nice hack. Maybe you could copy some parts of the code into this post to avoid later issues with broken links. ( Or just write a small description into this post ). – Felix K. Mar 04 '12 at 18:16
-
I get a `AccessViolationException` if I try to run your example. I guess it only works if DEP is disabled. – Rasmus Faber Mar 04 '12 at 21:02
-
1But if I allocate memory with the EXECUTE_READWRITE flag and use that in the _methodPtr field it works fine. Looking through the Rotor-code, it seems to be basically what Marshal.GetDelegateForFunctionPointer() does, except that it adds some extra thunks around the code for setting up the stack and handling security. – Rasmus Faber Mar 04 '12 at 22:06
-
I think the link is dead, alas, I would edit it, but I couldn't find a relocation of the original. – Abel Dec 23 '16 at 02:32