Home | History | Annotate | Download | only in Orc
      1 //===------------- OrcABISupport.cpp - ABI specific support code ----------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
     11 #include "llvm/ADT/Triple.h"
     12 #include "llvm/Support/Process.h"
     13 
     14 namespace llvm {
     15 namespace orc {
     16 
     17 void OrcAArch64::writeResolverCode(uint8_t *ResolverMem, JITReentryFn ReentryFn,
     18                                    void *CallbackMgr) {
     19 
     20   const uint32_t ResolverCode[] = {
     21     // resolver_entry:
     22     0xa9bf47fd,        // 0x000:  stp  x29, x17, [sp, #-16]!
     23     0x910003fd,        // 0x004:  mov  x29, sp
     24     0xa9bf73fb,        // 0x008:  stp  x27, x28, [sp, #-16]!
     25     0xa9bf6bf9,        // 0x00c:  stp  x25, x26, [sp, #-16]!
     26     0xa9bf63f7,        // 0x010:  stp  x23, x24, [sp, #-16]!
     27     0xa9bf5bf5,        // 0x014:  stp  x21, x22, [sp, #-16]!
     28     0xa9bf53f3,        // 0x018:  stp  x19, x20, [sp, #-16]!
     29     0xa9bf3fee,        // 0x01c:  stp  x14, x15, [sp, #-16]!
     30     0xa9bf37ec,        // 0x020:  stp  x12, x13, [sp, #-16]!
     31     0xa9bf2fea,        // 0x024:  stp  x10, x11, [sp, #-16]!
     32     0xa9bf27e8,        // 0x028:  stp   x8,  x9, [sp, #-16]!
     33     0xa9bf1fe6,        // 0x02c:  stp   x6,  x7, [sp, #-16]!
     34     0xa9bf17e4,        // 0x030:  stp   x4,  x5, [sp, #-16]!
     35     0xa9bf0fe2,        // 0x034:  stp   x2,  x3, [sp, #-16]!
     36     0xa9bf07e0,        // 0x038:  stp   x0,  x1, [sp, #-16]!
     37     0xadbf7ffe,        // 0x03c:  stp  q30, q31, [sp, #-32]!
     38     0xadbf77fc,        // 0x040:  stp  q28, q29, [sp, #-32]!
     39     0xadbf6ffa,        // 0x044:  stp  q26, q27, [sp, #-32]!
     40     0xadbf67f8,        // 0x048:  stp  q24, q25, [sp, #-32]!
     41     0xadbf5ff6,        // 0x04c:  stp  q22, q23, [sp, #-32]!
     42     0xadbf57f4,        // 0x050:  stp  q20, q21, [sp, #-32]!
     43     0xadbf4ff2,        // 0x054:  stp  q18, q19, [sp, #-32]!
     44     0xadbf47f0,        // 0x058:  stp  q16, q17, [sp, #-32]!
     45     0xadbf3fee,        // 0x05c:  stp  q14, q15, [sp, #-32]!
     46     0xadbf37ec,        // 0x060:  stp  q12, q13, [sp, #-32]!
     47     0xadbf2fea,        // 0x064:  stp  q10, q11, [sp, #-32]!
     48     0xadbf27e8,        // 0x068:  stp   q8,  q9, [sp, #-32]!
     49     0xadbf1fe6,        // 0x06c:  stp   q6,  q7, [sp, #-32]!
     50     0xadbf17e4,        // 0x070:  stp   q4,  q5, [sp, #-32]!
     51     0xadbf0fe2,        // 0x074:  stp   q2,  q3, [sp, #-32]!
     52     0xadbf07e0,        // 0x078:  stp   q0,  q1, [sp, #-32]!
     53     0x580004e0,        // 0x07c:  ldr   x0, Lcallbackmgr
     54     0xaa1e03e1,        // 0x080:  mov   x1, x30
     55     0xd1003021,        // 0x084:  sub   x1,  x1, #12
     56     0x58000442,        // 0x088:  ldr   x2, Lreentry_fn_ptr
     57     0xd63f0040,        // 0x08c:  blr   x2
     58     0xaa0003f1,        // 0x090:  mov   x17, x0
     59     0xacc107e0,        // 0x094:  ldp   q0,  q1, [sp], #32
     60     0xacc10fe2,        // 0x098:  ldp   q2,  q3, [sp], #32
     61     0xacc117e4,        // 0x09c:  ldp   q4,  q5, [sp], #32
     62     0xacc11fe6,        // 0x0a0:  ldp   q6,  q7, [sp], #32
     63     0xacc127e8,        // 0x0a4:  ldp   q8,  q9, [sp], #32
     64     0xacc12fea,        // 0x0a8:  ldp  q10, q11, [sp], #32
     65     0xacc137ec,        // 0x0ac:  ldp  q12, q13, [sp], #32
     66     0xacc13fee,        // 0x0b0:  ldp  q14, q15, [sp], #32
     67     0xacc147f0,        // 0x0b4:  ldp  q16, q17, [sp], #32
     68     0xacc14ff2,        // 0x0b8:  ldp  q18, q19, [sp], #32
     69     0xacc157f4,        // 0x0bc:  ldp  q20, q21, [sp], #32
     70     0xacc15ff6,        // 0x0c0:  ldp  q22, q23, [sp], #32
     71     0xacc167f8,        // 0x0c4:  ldp  q24, q25, [sp], #32
     72     0xacc16ffa,        // 0x0c8:  ldp  q26, q27, [sp], #32
     73     0xacc177fc,        // 0x0cc:  ldp  q28, q29, [sp], #32
     74     0xacc17ffe,        // 0x0d0:  ldp  q30, q31, [sp], #32
     75     0xa8c107e0,        // 0x0d4:  ldp   x0,  x1, [sp], #16
     76     0xa8c10fe2,        // 0x0d8:  ldp   x2,  x3, [sp], #16
     77     0xa8c117e4,        // 0x0dc:  ldp   x4,  x5, [sp], #16
     78     0xa8c11fe6,        // 0x0e0:  ldp   x6,  x7, [sp], #16
     79     0xa8c127e8,        // 0x0e4:  ldp   x8,  x9, [sp], #16
     80     0xa8c12fea,        // 0x0e8:  ldp  x10, x11, [sp], #16
     81     0xa8c137ec,        // 0x0ec:  ldp  x12, x13, [sp], #16
     82     0xa8c13fee,        // 0x0f0:  ldp  x14, x15, [sp], #16
     83     0xa8c153f3,        // 0x0f4:  ldp  x19, x20, [sp], #16
     84     0xa8c15bf5,        // 0x0f8:  ldp  x21, x22, [sp], #16
     85     0xa8c163f7,        // 0x0fc:  ldp  x23, x24, [sp], #16
     86     0xa8c16bf9,        // 0x100:  ldp  x25, x26, [sp], #16
     87     0xa8c173fb,        // 0x104:  ldp  x27, x28, [sp], #16
     88     0xa8c17bfd,        // 0x108:  ldp  x29, x30, [sp], #16
     89     0xd65f0220,        // 0x10c:  ret  x17
     90     0x01234567,        // 0x110:  Lreentry_fn_ptr:
     91     0xdeadbeef,        // 0x114:      .quad 0
     92     0x98765432,        // 0x118:  Lcallbackmgr:
     93     0xcafef00d         // 0x11c:      .quad 0
     94   };
     95 
     96   const unsigned ReentryFnAddrOffset = 0x110;
     97   const unsigned CallbackMgrAddrOffset = 0x118;
     98 
     99   memcpy(ResolverMem, ResolverCode, sizeof(ResolverCode));
    100   memcpy(ResolverMem + ReentryFnAddrOffset, &ReentryFn, sizeof(ReentryFn));
    101   memcpy(ResolverMem + CallbackMgrAddrOffset, &CallbackMgr,
    102          sizeof(CallbackMgr));
    103 }
    104 
    105 void OrcAArch64::writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
    106                                   unsigned NumTrampolines) {
    107 
    108   unsigned OffsetToPtr = alignTo(NumTrampolines * TrampolineSize, 8);
    109 
    110   memcpy(TrampolineMem + OffsetToPtr, &ResolverAddr, sizeof(void *));
    111 
    112   // OffsetToPtr is actually the offset from the PC for the 2nd instruction, so
    113   // subtract 32-bits.
    114   OffsetToPtr -= 4;
    115 
    116   uint32_t *Trampolines = reinterpret_cast<uint32_t *>(TrampolineMem);
    117 
    118   for (unsigned I = 0; I < NumTrampolines; ++I, OffsetToPtr -= TrampolineSize) {
    119     Trampolines[3 * I + 0] = 0xaa1e03f1;                      // mov x17, x30
    120     Trampolines[3 * I + 1] = 0x58000010 | (OffsetToPtr << 3); // mov x16, Lptr
    121     Trampolines[3 * I + 2] = 0xd63f0200;                      // blr x16
    122   }
    123 
    124 }
    125 
    126 Error OrcAArch64::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
    127                                          unsigned MinStubs,
    128                                          void *InitialPtrVal) {
    129   // Stub format is:
    130   //
    131   // .section __orc_stubs
    132   // stub1:
    133   //                 ldr     x0, ptr1       ; PC-rel load of ptr1
    134   //                 br      x0             ; Jump to resolver
    135   // stub2:
    136   //                 ldr     x0, ptr2       ; PC-rel load of ptr2
    137   //                 br      x0             ; Jump to resolver
    138   //
    139   // ...
    140   //
    141   // .section __orc_ptrs
    142   // ptr1:
    143   //                 .quad 0x0
    144   // ptr2:
    145   //                 .quad 0x0
    146   //
    147   // ...
    148 
    149   const unsigned StubSize = IndirectStubsInfo::StubSize;
    150 
    151   // Emit at least MinStubs, rounded up to fill the pages allocated.
    152   unsigned PageSize = sys::Process::getPageSize();
    153   unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize;
    154   unsigned NumStubs = (NumPages * PageSize) / StubSize;
    155 
    156   // Allocate memory for stubs and pointers in one call.
    157   std::error_code EC;
    158   auto StubsMem = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
    159       2 * NumPages * PageSize, nullptr,
    160       sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
    161 
    162   if (EC)
    163     return errorCodeToError(EC);
    164 
    165   // Create separate MemoryBlocks representing the stubs and pointers.
    166   sys::MemoryBlock StubsBlock(StubsMem.base(), NumPages * PageSize);
    167   sys::MemoryBlock PtrsBlock(static_cast<char *>(StubsMem.base()) +
    168                                  NumPages * PageSize,
    169                              NumPages * PageSize);
    170 
    171   // Populate the stubs page stubs and mark it executable.
    172   uint64_t *Stub = reinterpret_cast<uint64_t *>(StubsBlock.base());
    173   uint64_t PtrOffsetField = static_cast<uint64_t>(NumPages * PageSize)
    174                             << 3;
    175 
    176   for (unsigned I = 0; I < NumStubs; ++I)
    177     Stub[I] = 0xd61f020058000010 | PtrOffsetField;
    178 
    179   if (auto EC = sys::Memory::protectMappedMemory(
    180           StubsBlock, sys::Memory::MF_READ | sys::Memory::MF_EXEC))
    181     return errorCodeToError(EC);
    182 
    183   // Initialize all pointers to point at FailureAddress.
    184   void **Ptr = reinterpret_cast<void **>(PtrsBlock.base());
    185   for (unsigned I = 0; I < NumStubs; ++I)
    186     Ptr[I] = InitialPtrVal;
    187 
    188   StubsInfo = IndirectStubsInfo(NumStubs, std::move(StubsMem));
    189 
    190   return Error::success();
    191 }
    192 
    193 void OrcX86_64_Base::writeTrampolines(uint8_t *TrampolineMem,
    194                                       void *ResolverAddr,
    195                                       unsigned NumTrampolines) {
    196 
    197   unsigned OffsetToPtr = NumTrampolines * TrampolineSize;
    198 
    199   memcpy(TrampolineMem + OffsetToPtr, &ResolverAddr, sizeof(void *));
    200 
    201   uint64_t *Trampolines = reinterpret_cast<uint64_t *>(TrampolineMem);
    202   uint64_t CallIndirPCRel = 0xf1c40000000015ff;
    203 
    204   for (unsigned I = 0; I < NumTrampolines; ++I, OffsetToPtr -= TrampolineSize)
    205     Trampolines[I] = CallIndirPCRel | ((OffsetToPtr - 6) << 16);
    206 }
    207 
    208 Error OrcX86_64_Base::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
    209                                              unsigned MinStubs,
    210                                              void *InitialPtrVal) {
    211   // Stub format is:
    212   //
    213   // .section __orc_stubs
    214   // stub1:
    215   //                 jmpq    *ptr1(%rip)
    216   //                 .byte   0xC4         ; <- Invalid opcode padding.
    217   //                 .byte   0xF1
    218   // stub2:
    219   //                 jmpq    *ptr2(%rip)
    220   //
    221   // ...
    222   //
    223   // .section __orc_ptrs
    224   // ptr1:
    225   //                 .quad 0x0
    226   // ptr2:
    227   //                 .quad 0x0
    228   //
    229   // ...
    230 
    231   const unsigned StubSize = IndirectStubsInfo::StubSize;
    232 
    233   // Emit at least MinStubs, rounded up to fill the pages allocated.
    234   unsigned PageSize = sys::Process::getPageSize();
    235   unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize;
    236   unsigned NumStubs = (NumPages * PageSize) / StubSize;
    237 
    238   // Allocate memory for stubs and pointers in one call.
    239   std::error_code EC;
    240   auto StubsMem = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
    241       2 * NumPages * PageSize, nullptr,
    242       sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
    243 
    244   if (EC)
    245     return errorCodeToError(EC);
    246 
    247   // Create separate MemoryBlocks representing the stubs and pointers.
    248   sys::MemoryBlock StubsBlock(StubsMem.base(), NumPages * PageSize);
    249   sys::MemoryBlock PtrsBlock(static_cast<char *>(StubsMem.base()) +
    250                                  NumPages * PageSize,
    251                              NumPages * PageSize);
    252 
    253   // Populate the stubs page stubs and mark it executable.
    254   uint64_t *Stub = reinterpret_cast<uint64_t *>(StubsBlock.base());
    255   uint64_t PtrOffsetField = static_cast<uint64_t>(NumPages * PageSize - 6)
    256                             << 16;
    257   for (unsigned I = 0; I < NumStubs; ++I)
    258     Stub[I] = 0xF1C40000000025ff | PtrOffsetField;
    259 
    260   if (auto EC = sys::Memory::protectMappedMemory(
    261           StubsBlock, sys::Memory::MF_READ | sys::Memory::MF_EXEC))
    262     return errorCodeToError(EC);
    263 
    264   // Initialize all pointers to point at FailureAddress.
    265   void **Ptr = reinterpret_cast<void **>(PtrsBlock.base());
    266   for (unsigned I = 0; I < NumStubs; ++I)
    267     Ptr[I] = InitialPtrVal;
    268 
    269   StubsInfo = IndirectStubsInfo(NumStubs, std::move(StubsMem));
    270 
    271   return Error::success();
    272 }
    273 
    274 void OrcX86_64_SysV::writeResolverCode(uint8_t *ResolverMem,
    275                                        JITReentryFn ReentryFn,
    276                                        void *CallbackMgr) {
    277 
    278   const uint8_t ResolverCode[] = {
    279       // resolver_entry:
    280       0x55,                                     // 0x00: pushq     %rbp
    281       0x48, 0x89, 0xe5,                         // 0x01: movq      %rsp, %rbp
    282       0x50,                                     // 0x04: pushq     %rax
    283       0x53,                                     // 0x05: pushq     %rbx
    284       0x51,                                     // 0x06: pushq     %rcx
    285       0x52,                                     // 0x07: pushq     %rdx
    286       0x56,                                     // 0x08: pushq     %rsi
    287       0x57,                                     // 0x09: pushq     %rdi
    288       0x41, 0x50,                               // 0x0a: pushq     %r8
    289       0x41, 0x51,                               // 0x0c: pushq     %r9
    290       0x41, 0x52,                               // 0x0e: pushq     %r10
    291       0x41, 0x53,                               // 0x10: pushq     %r11
    292       0x41, 0x54,                               // 0x12: pushq     %r12
    293       0x41, 0x55,                               // 0x14: pushq     %r13
    294       0x41, 0x56,                               // 0x16: pushq     %r14
    295       0x41, 0x57,                               // 0x18: pushq     %r15
    296       0x48, 0x81, 0xec, 0x08, 0x02, 0x00, 0x00, // 0x1a: subq      0x208, %rsp
    297       0x48, 0x0f, 0xae, 0x04, 0x24,             // 0x21: fxsave64  (%rsp)
    298       0x48, 0xbf,                               // 0x26: movabsq   <CBMgr>, %rdi
    299 
    300       // 0x28: Callback manager addr.
    301       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    302 
    303       0x48, 0x8b, 0x75, 0x08,                   // 0x30: movq      8(%rbp), %rsi
    304       0x48, 0x83, 0xee, 0x06,                   // 0x34: subq      $6, %rsi
    305       0x48, 0xb8,                               // 0x38: movabsq   <REntry>, %rax
    306 
    307       // 0x3a: JIT re-entry fn addr:
    308       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    309 
    310       0xff, 0xd0,                               // 0x42: callq     *%rax
    311       0x48, 0x89, 0x45, 0x08,                   // 0x44: movq      %rax, 8(%rbp)
    312       0x48, 0x0f, 0xae, 0x0c, 0x24,             // 0x48: fxrstor64 (%rsp)
    313       0x48, 0x81, 0xc4, 0x08, 0x02, 0x00, 0x00, // 0x4d: addq      0x208, %rsp
    314       0x41, 0x5f,                               // 0x54: popq      %r15
    315       0x41, 0x5e,                               // 0x56: popq      %r14
    316       0x41, 0x5d,                               // 0x58: popq      %r13
    317       0x41, 0x5c,                               // 0x5a: popq      %r12
    318       0x41, 0x5b,                               // 0x5c: popq      %r11
    319       0x41, 0x5a,                               // 0x5e: popq      %r10
    320       0x41, 0x59,                               // 0x60: popq      %r9
    321       0x41, 0x58,                               // 0x62: popq      %r8
    322       0x5f,                                     // 0x64: popq      %rdi
    323       0x5e,                                     // 0x65: popq      %rsi
    324       0x5a,                                     // 0x66: popq      %rdx
    325       0x59,                                     // 0x67: popq      %rcx
    326       0x5b,                                     // 0x68: popq      %rbx
    327       0x58,                                     // 0x69: popq      %rax
    328       0x5d,                                     // 0x6a: popq      %rbp
    329       0xc3,                                     // 0x6b: retq
    330   };
    331 
    332   const unsigned ReentryFnAddrOffset = 0x3a;
    333   const unsigned CallbackMgrAddrOffset = 0x28;
    334 
    335   memcpy(ResolverMem, ResolverCode, sizeof(ResolverCode));
    336   memcpy(ResolverMem + ReentryFnAddrOffset, &ReentryFn, sizeof(ReentryFn));
    337   memcpy(ResolverMem + CallbackMgrAddrOffset, &CallbackMgr,
    338          sizeof(CallbackMgr));
    339 }
    340 
    341 void OrcX86_64_Win32::writeResolverCode(uint8_t *ResolverMem,
    342                                         JITReentryFn ReentryFn,
    343                                         void *CallbackMgr) {
    344 
    345   // resolverCode is similar to OrcX86_64 with differences specific to windows x64 calling convention:
    346   // arguments go into rcx, rdx and come in reverse order, shadow space allocation on stack
    347   const uint8_t ResolverCode[] = {
    348       // resolver_entry:
    349       0x55,                                      // 0x00: pushq     %rbp
    350       0x48, 0x89, 0xe5,                          // 0x01: movq      %rsp, %rbp
    351       0x50,                                      // 0x04: pushq     %rax
    352       0x53,                                      // 0x05: pushq     %rbx
    353       0x51,                                      // 0x06: pushq     %rcx
    354       0x52,                                      // 0x07: pushq     %rdx
    355       0x56,                                      // 0x08: pushq     %rsi
    356       0x57,                                      // 0x09: pushq     %rdi
    357       0x41, 0x50,                                // 0x0a: pushq     %r8
    358       0x41, 0x51,                                // 0x0c: pushq     %r9
    359       0x41, 0x52,                                // 0x0e: pushq     %r10
    360       0x41, 0x53,                                // 0x10: pushq     %r11
    361       0x41, 0x54,                                // 0x12: pushq     %r12
    362       0x41, 0x55,                                // 0x14: pushq     %r13
    363       0x41, 0x56,                                // 0x16: pushq     %r14
    364       0x41, 0x57,                                // 0x18: pushq     %r15
    365       0x48, 0x81, 0xec, 0x08, 0x02, 0x00, 0x00,  // 0x1a: subq      0x208, %rsp
    366       0x48, 0x0f, 0xae, 0x04, 0x24,              // 0x21: fxsave64  (%rsp)
    367 
    368       0x48, 0xb9,                                // 0x26: movabsq   <CBMgr>, %rcx
    369       // 0x28: Callback manager addr.
    370       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    371 
    372       0x48, 0x8B, 0x55, 0x08,                    // 0x30: mov       rdx, [rbp+0x8]
    373       0x48, 0x83, 0xea, 0x06,                    // 0x34: sub       rdx, 0x6
    374 
    375       0x48, 0xb8,                                // 0x38: movabsq   <REntry>, %rax
    376       // 0x3a: JIT re-entry fn addr:
    377       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    378 
    379       // 0x42: sub       rsp, 0x20 (Allocate shadow space)
    380       0x48, 0x83, 0xEC, 0x20,
    381       0xff, 0xd0,                                // 0x46: callq     *%rax
    382 
    383       // 0x48: add       rsp, 0x20 (Free shadow space)
    384       0x48, 0x83, 0xC4, 0x20,
    385 
    386       0x48, 0x89, 0x45, 0x08,                    // 0x4C: movq      %rax, 8(%rbp)
    387       0x48, 0x0f, 0xae, 0x0c, 0x24,              // 0x50: fxrstor64 (%rsp)
    388       0x48, 0x81, 0xc4, 0x08, 0x02, 0x00, 0x00,  // 0x55: addq      0x208, %rsp
    389       0x41, 0x5f,                                // 0x5C: popq      %r15
    390       0x41, 0x5e,                                // 0x5E: popq      %r14
    391       0x41, 0x5d,                                // 0x60: popq      %r13
    392       0x41, 0x5c,                                // 0x62: popq      %r12
    393       0x41, 0x5b,                                // 0x64: popq      %r11
    394       0x41, 0x5a,                                // 0x66: popq      %r10
    395       0x41, 0x59,                                // 0x68: popq      %r9
    396       0x41, 0x58,                                // 0x6a: popq      %r8
    397       0x5f,                                      // 0x6c: popq      %rdi
    398       0x5e,                                      // 0x6d: popq      %rsi
    399       0x5a,                                      // 0x6e: popq      %rdx
    400       0x59,                                      // 0x6f: popq      %rcx
    401       0x5b,                                      // 0x70: popq      %rbx
    402       0x58,                                      // 0x71: popq      %rax
    403       0x5d,                                      // 0x72: popq      %rbp
    404       0xc3,                                      // 0x73: retq
    405   };
    406 
    407 
    408   const unsigned ReentryFnAddrOffset = 0x3a;
    409   const unsigned CallbackMgrAddrOffset = 0x28;
    410 
    411   memcpy(ResolverMem, ResolverCode, sizeof(ResolverCode));
    412   memcpy(ResolverMem + ReentryFnAddrOffset, &ReentryFn, sizeof(ReentryFn));
    413   memcpy(ResolverMem + CallbackMgrAddrOffset, &CallbackMgr,
    414          sizeof(CallbackMgr));
    415 }
    416 
    417 void OrcI386::writeResolverCode(uint8_t *ResolverMem, JITReentryFn ReentryFn,
    418                                 void *CallbackMgr) {
    419 
    420   const uint8_t ResolverCode[] = {
    421       // resolver_entry:
    422       0x55,                               // 0x00: pushl    %ebp
    423       0x89, 0xe5,                         // 0x01: movl     %esp, %ebp
    424       0x54,                               // 0x03: pushl    %esp
    425       0x83, 0xe4, 0xf0,                   // 0x04: andl     $-0x10, %esp
    426       0x50,                               // 0x07: pushl    %eax
    427       0x53,                               // 0x08: pushl    %ebx
    428       0x51,                               // 0x09: pushl    %ecx
    429       0x52,                               // 0x0a: pushl    %edx
    430       0x56,                               // 0x0b: pushl    %esi
    431       0x57,                               // 0x0c: pushl    %edi
    432       0x81, 0xec, 0x18, 0x02, 0x00, 0x00, // 0x0d: subl     $0x218, %esp
    433       0x0f, 0xae, 0x44, 0x24, 0x10,       // 0x13: fxsave   0x10(%esp)
    434       0x8b, 0x75, 0x04,                   // 0x18: movl     0x4(%ebp), %esi
    435       0x83, 0xee, 0x05,                   // 0x1b: subl     $0x5, %esi
    436       0x89, 0x74, 0x24, 0x04,             // 0x1e: movl     %esi, 0x4(%esp)
    437       0xc7, 0x04, 0x24, 0x00, 0x00, 0x00,
    438       0x00,                               // 0x22: movl     <cbmgr>, (%esp)
    439       0xb8, 0x00, 0x00, 0x00, 0x00,       // 0x29: movl     <reentry>, %eax
    440       0xff, 0xd0,                         // 0x2e: calll    *%eax
    441       0x89, 0x45, 0x04,                   // 0x30: movl     %eax, 0x4(%ebp)
    442       0x0f, 0xae, 0x4c, 0x24, 0x10,       // 0x33: fxrstor  0x10(%esp)
    443       0x81, 0xc4, 0x18, 0x02, 0x00, 0x00, // 0x38: addl     $0x218, %esp
    444       0x5f,                               // 0x3e: popl     %edi
    445       0x5e,                               // 0x3f: popl     %esi
    446       0x5a,                               // 0x40: popl     %edx
    447       0x59,                               // 0x41: popl     %ecx
    448       0x5b,                               // 0x42: popl     %ebx
    449       0x58,                               // 0x43: popl     %eax
    450       0x8b, 0x65, 0xfc,                   // 0x44: movl     -0x4(%ebp), %esp
    451       0x5d,                               // 0x48: popl     %ebp
    452       0xc3                                // 0x49: retl
    453   };
    454 
    455   const unsigned ReentryFnAddrOffset = 0x2a;
    456   const unsigned CallbackMgrAddrOffset = 0x25;
    457 
    458   memcpy(ResolverMem, ResolverCode, sizeof(ResolverCode));
    459   memcpy(ResolverMem + ReentryFnAddrOffset, &ReentryFn, sizeof(ReentryFn));
    460   memcpy(ResolverMem + CallbackMgrAddrOffset, &CallbackMgr,
    461          sizeof(CallbackMgr));
    462 }
    463 
    464 void OrcI386::writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
    465                                unsigned NumTrampolines) {
    466 
    467   uint64_t CallRelImm = 0xF1C4C400000000e8;
    468   uint64_t Resolver = reinterpret_cast<uint64_t>(ResolverAddr);
    469   uint64_t ResolverRel =
    470       Resolver - reinterpret_cast<uint64_t>(TrampolineMem) - 5;
    471 
    472   uint64_t *Trampolines = reinterpret_cast<uint64_t *>(TrampolineMem);
    473   for (unsigned I = 0; I < NumTrampolines; ++I, ResolverRel -= TrampolineSize)
    474     Trampolines[I] = CallRelImm | (ResolverRel << 8);
    475 }
    476 
    477 Error OrcI386::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
    478                                       unsigned MinStubs, void *InitialPtrVal) {
    479   // Stub format is:
    480   //
    481   // .section __orc_stubs
    482   // stub1:
    483   //                 jmpq    *ptr1
    484   //                 .byte   0xC4         ; <- Invalid opcode padding.
    485   //                 .byte   0xF1
    486   // stub2:
    487   //                 jmpq    *ptr2
    488   //
    489   // ...
    490   //
    491   // .section __orc_ptrs
    492   // ptr1:
    493   //                 .quad 0x0
    494   // ptr2:
    495   //                 .quad 0x0
    496   //
    497   // ...
    498 
    499   const unsigned StubSize = IndirectStubsInfo::StubSize;
    500 
    501   // Emit at least MinStubs, rounded up to fill the pages allocated.
    502   unsigned PageSize = sys::Process::getPageSize();
    503   unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize;
    504   unsigned NumStubs = (NumPages * PageSize) / StubSize;
    505 
    506   // Allocate memory for stubs and pointers in one call.
    507   std::error_code EC;
    508   auto StubsMem = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
    509       2 * NumPages * PageSize, nullptr,
    510       sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
    511 
    512   if (EC)
    513     return errorCodeToError(EC);
    514 
    515   // Create separate MemoryBlocks representing the stubs and pointers.
    516   sys::MemoryBlock StubsBlock(StubsMem.base(), NumPages * PageSize);
    517   sys::MemoryBlock PtrsBlock(static_cast<char *>(StubsMem.base()) +
    518                                  NumPages * PageSize,
    519                              NumPages * PageSize);
    520 
    521   // Populate the stubs page stubs and mark it executable.
    522   uint64_t *Stub = reinterpret_cast<uint64_t *>(StubsBlock.base());
    523   uint64_t PtrAddr = reinterpret_cast<uint64_t>(PtrsBlock.base());
    524   for (unsigned I = 0; I < NumStubs; ++I, PtrAddr += 4)
    525     Stub[I] = 0xF1C40000000025ff | (PtrAddr << 16);
    526 
    527   if (auto EC = sys::Memory::protectMappedMemory(
    528           StubsBlock, sys::Memory::MF_READ | sys::Memory::MF_EXEC))
    529     return errorCodeToError(EC);
    530 
    531   // Initialize all pointers to point at FailureAddress.
    532   void **Ptr = reinterpret_cast<void **>(PtrsBlock.base());
    533   for (unsigned I = 0; I < NumStubs; ++I)
    534     Ptr[I] = InitialPtrVal;
    535 
    536   StubsInfo = IndirectStubsInfo(NumStubs, std::move(StubsMem));
    537 
    538   return Error::success();
    539 }
    540 
    541 } // End namespace orc.
    542 } // End namespace llvm.
    543