Want more features on Pastebin? Sign Up, it's FREE!
Guest

Untitled

By: a guest on Apr 26th, 2012  |  syntax: D  |  size: 6.07 KB  |  views: 70  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. // Written in the D programming language.
  2.  
  3.  
  4. /**
  5.  * Forwards function pointers to delegates.
  6.  * Parameters are converted between calling conventions.
  7.  *
  8.  * Currently supports:
  9.  *
  10.  *  extern(Windows) function -> extern(D) delegate
  11.  *
  12.  *  extern(C) function -> extern(D) delegate
  13.  *
  14.  *  extern(D) function -> extern(D) delegate
  15.  *
  16.  * Author:
  17.  *    Daniel Murphy (yebblies@gmail.com)
  18.  *
  19.  * Adapted from:
  20.  *    www.codeproject.com/KB/cpp/thunk32.aspx?msg=2168100
  21.  *
  22.  *    See site for license
  23.  *
  24.  */
  25.  
  26. module yebblies.thunk;
  27.  
  28. version(Windows)
  29. {
  30.     import core.sys.windows.windows : VirtualAlloc, VirtualFree, FlushInstructionCache, MEM_COMMIT, PAGE_EXECUTE_READWRITE, MEM_DECOMMIT, GetCurrentProcess;
  31. } else version(posix)
  32. {
  33.     import core.sys.posix.sys.mman : mmap, PROT_WRITE, PROT_EXEC, MAP_PRIVATE, MAP_FAILED, munmap;
  34. } else {
  35.     static assert(0);
  36. }
  37.  
  38.  
  39.  
  40. class Thunk(string linkage, U : R delegate(P), R, P...) if (linkage == "Windows" || linkage == "C" || linkage == "D")
  41. {
  42. public:
  43.     static if (linkage == "Windows")
  44.     {
  45.         extern(Windows) R function(P) ptr;
  46.     } else static if (linkage == "C") {
  47.         extern(C) R function(P) ptr;
  48.     } else static if (linkage == "D") {
  49.         extern(D) R function(P) ptr;
  50.     } else {
  51.         static assert(0);
  52.     }
  53. private:
  54.     align(1)
  55.     struct ThunkCode
  56.     {
  57.         static if (linkage != "D")
  58.         {
  59.             ubyte mov_eax;
  60.             void* this_ptr;
  61.         }
  62.  
  63.         ubyte mov_ecx;
  64.         void* func_ptr;
  65.  
  66.         ubyte mov_edx;
  67.         void* tt_ptr;
  68.  
  69.         ushort jmp_edx;
  70.     };
  71.  
  72.     static if (linkage == "Windows")
  73.     {
  74.         extern(Windows) static R ThunkThis(P p)
  75.         {
  76.             U fdg = void;
  77.             asm {
  78.                 mov [fdg], EAX;
  79.                 mov [fdg+4], ECX;
  80.             };
  81.             return fdg(p);
  82.         }
  83.     } else static if (linkage == "C")
  84.     {
  85.         extern(C) static R ThunkThis(P p)
  86.         {
  87.             U fdg = void;
  88.             asm {
  89.                 mov [fdg], EAX;
  90.                 mov [fdg+4], ECX;
  91.             };
  92.             return fdg(p);
  93.         }
  94.     } else static if (linkage == "D")
  95.     {
  96.         U dgstore;
  97.         extern(D) static R ThunkThis(P p)
  98.         {
  99.             U* dgptr = void;
  100.             asm {
  101.                 mov [dgptr], ECX;
  102.             };
  103.             return (*dgptr)(p);
  104.         }
  105.     }
  106. public:
  107.     this(U dg)
  108.     {
  109.         version(Windows)
  110.         {
  111.             auto tc = cast(ThunkCode*)VirtualAlloc(null, ThunkCode.sizeof, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  112.         } else {
  113.             auto p = mmap(null, ThunkCode.sizeof, PROT_WRITE | PROT_EXEC, MAP_PRIVATE, 0, 0);
  114.             assert(p != MAP_FAILED);
  115.             auto tc = cast(ThunkCode*)p;
  116.         }
  117.  
  118.         static if (linkage == "Windows" || linkage == "C")
  119.         {
  120.  
  121.             // Put ptr and fptr in some registers that aren't touched by the
  122.             // function call, then jump to the handler above.
  123.             // Indirect jump using edx
  124.             //
  125.             // mov eax, thisptr
  126.             // mov ecx, funcptr
  127.             // mov edx, &ThunkThis
  128.             // jmp edx
  129.  
  130.             tc.mov_eax = 0xB8;
  131.             tc.this_ptr = dg.ptr;
  132.             tc.mov_ecx = 0xB9;
  133.             tc.func_ptr = dg.funcptr;
  134.             tc.mov_edx = 0xBA;
  135.             tc.tt_ptr = &ThunkThis;
  136.             tc.jmp_edx = 0xE2FF;
  137.  
  138.         } else { // Linkage == "D"
  139.  
  140.             // We can't touch eax because D uses it for passing parameters sometimes.
  141.             // Instead store the delegate information inside this class instance, and pass a ptr in ECX
  142.  
  143.             // mov eax, thisptr
  144.             // mov ecx, funcptr
  145.             // mov edx, &ThunkThis
  146.             // jmp edx
  147.  
  148.             dgstore = dg;
  149.             tc.mov_ecx = 0xB9;
  150.             tc.func_ptr = &dgstore;
  151.             tc.mov_edx = 0xBA;
  152.             tc.tt_ptr = &ThunkThis;
  153.             tc.jmp_edx = 0xE2FF;
  154.         }
  155.  
  156.         version(Windows)
  157.         {
  158.             FlushInstructionCache(GetCurrentProcess(), tc, ThunkCode.sizeof);
  159.         } else {
  160.         }
  161.         ptr = cast(typeof(ptr))tc;
  162.         //writefln("%d", tc.lea_ecx);//, *cast(ushort*)(ptr));
  163.     }
  164.     ~this()
  165.     {
  166.         version(Windows)
  167.         {
  168.             VirtualFree(ptr, ThunkCode.sizeof, MEM_DECOMMIT);
  169.         } else {
  170.             munmap(ptr, ThunkCode.sizeof);
  171.         }
  172.     }
  173. };
  174.  
  175.  
  176. /**
  177.  * Creates a Thunk object
  178.  *
  179.  * Example:
  180.     ----------------
  181. import std.stdio;
  182.  
  183. void main()
  184. {
  185.     class C
  186.     {
  187.        int a;
  188.        void func(int b) { writeln("a == ", a, "\nb == ", b); }
  189.     }
  190.     auto c = new C();
  191.     c.a = 7;
  192.     auto th = thunk!"C"(&c.func);
  193.     // th.ptr is extern(C) void function(int)
  194.     th.ptr(3);
  195.     // prints a == 7, b == 3
  196. }
  197. ---------------
  198.  */
  199. Thunk!(linkage, U, R, P) thunk(string linkage, U : R delegate(P), R, P...)(U dg) if (linkage == "Windows" || linkage == "C" || linkage == "D")
  200. {
  201.     return new Thunk!(linkage, U, R, P)(dg);
  202. }
  203.  
  204. unittest
  205. {
  206.     class C
  207.     {
  208.         float receiver(int n, int b, real c)
  209.         {
  210.             return (n + b) * c;
  211.         }
  212.     };
  213.  
  214.     auto g = 12.f;
  215.  
  216.     float fn(int n, real b, float c)
  217.     {
  218.         return (n + b) * c + g;
  219.     }
  220.  
  221.     auto c = new C();
  222.     version(Windows)
  223.     {
  224.         auto th1 = thunk!"Windows"( &c.receiver);
  225.         auto th2 = thunk!"Windows"( &fn);
  226.     }
  227.     auto th3 = thunk!"C"( &c.receiver);
  228.     auto th4 = thunk!"C"( &fn);
  229.     auto th5 = thunk!"D"( &c.receiver);
  230.     auto th6 = thunk!"D"( &fn);
  231.  
  232.     version(Windows)
  233.     {
  234.         assert(th1.ptr(3, 7, 10.f) == 100.f);
  235.         assert(th2.ptr(3, 7354.L, 10.f) == (3 + 7354.L) * 10.f + 12.f);
  236.     }
  237.     assert(th3.ptr(3, 7, 10.f) == 100.f);
  238.     assert(th4.ptr(3, 7354.L, 10.f) == (3 + 7354.L) * 10.f + 12.f);
  239.     assert(th5.ptr(3, 7, 10.f) == 100.f);
  240.     assert(th6.ptr(3, 7354.L, 10.f) == (3 + 7354.L) * 10.f + 12.f);
  241.  
  242.     class D
  243.     {
  244.         int func(int a) { return a + 17; }
  245.     }
  246.     auto d = new D;
  247.     auto th7 = thunk!"D"(&d.func);
  248.     assert(th7.ptr(12) == 29);
  249. }
  250. void main() {}
clone this paste RAW Paste Data