관리되는 .NET 언어로 JIT 컴파일러 (네이티브 코드로)를 작성할 수 있습니까?
나는 JIT 컴파일러를 작성하는 아이디어를 가지고 놀면서 관리 코드에서 모든 것을 이론적으로 작성할 수 있는지 궁금합니다. 특히 어셈블러를 바이트 배열로 생성 한 후 실행을 시작하려면 어떻게해야합니까?
그리고 완전한 개념 증명을 위해 여기 에 Rasmus의 JIT 접근 방식을 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
행복하게 양보를 실행하는
Value before: FFFFFFFC
Value after: 7FFFFFFE
그래 넌 할수있어. 사실, 그것은 내 직업입니다 :)
저는 GPU.NET을 완전히 F #으로 작성했습니다 (단위 테스트 모듈로)-실제로 .NET CLR과 마찬가지로 런타임에 IL을 분해하고 JIT합니다. 사용하려는 기본 가속 장치에 대해 네이티브 코드를 내 보냅니다. 현재 우리는 Nvidia GPU 만 지원하지만 최소한의 작업으로 리 타겟팅 할 수 있도록 시스템을 설계 했으므로 향후 다른 플랫폼을 지원할 가능성이 높습니다.
성능에 관해서는 F #이 있습니다. 최적화 된 모드 (꼬리 호출 포함)에서 컴파일 할 때 JIT 컴파일러 자체는 아마도 CLR (C ++, IIRC로 작성 됨) 내의 컴파일러만큼 빠릅니다.
실행을 위해, jitted 코드를 실행하기 위해 하드웨어 드라이버에 제어를 전달할 수 있다는 이점이 있습니다. 그러나 .NET은 관리되지 않는 / 네이티브 코드에 대한 함수 포인터를 지원하기 때문에 CPU에서 수행하기가 더 어렵지 않을 것입니다 (일반적으로 .NET에서 제공하는 안전 / 보안을 잃을 수 있음).
트릭이 있어야 할 VirtualAlloc을 와 EXECUTE_READWRITE
-flag와 (P / 호출 필요) Marshal.GetDelegateForFunctionPointer는 .
다음은 회전 정수 예제의 수정 된 버전입니다 (여기에는 안전하지 않은 코드가 필요하지 않습니다).
[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);
}
전체 예제 (이제 X86 및 X64 모두에서 작동).
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...)
'programing' 카테고리의 다른 글
루비 문자열의 클래스 이름을 실제 클래스로 변환 (0) | 2020.09.23 |
---|---|
파일 이름을 변경하면 파일의 MD5 해시에 영향을 줍니까? (0) | 2020.09.23 |
자바 스크립트는 문자열에서 동적으로 객체 메소드를 호출합니다. (0) | 2020.09.23 |
cronjob을 실행하는 AWS Elastic Beanstalk (0) | 2020.09.23 |
onPause, onStop 및 onDestroy 메서드에서 슈퍼 클래스 메서드를 호출하는 올바른 순서는 무엇입니까? (0) | 2020.09.22 |