Change relocations in ngen-ed code with PC-relative constants for Linux ARM32.
authorRuben Ayrapetyan <r.ayrapetyan@samsung.com>
Wed, 3 May 2017 14:01:07 +0000 (17:01 +0300)
committerRuben Ayrapetyan <r.ayrapetyan@samsung.com>
Mon, 15 May 2017 13:00:24 +0000 (16:00 +0300)
Commit migrated from https://github.com/dotnet/coreclr/commit/faf5d86e0f575bdb459f0cf8ace7a89ca3dc43c1

15 files changed:
src/coreclr/src/inc/corinfo.h
src/coreclr/src/inc/corjit.h
src/coreclr/src/inc/zapper.h
src/coreclr/src/jit/codegen.h [changed mode: 0755->0644]
src/coreclr/src/jit/codegenarm.cpp
src/coreclr/src/jit/codegencommon.cpp
src/coreclr/src/jit/codegenlegacy.cpp
src/coreclr/src/jit/emit.cpp
src/coreclr/src/jit/emit.h
src/coreclr/src/jit/emitarm.cpp
src/coreclr/src/jit/instr.cpp
src/coreclr/src/jit/jitee.h
src/coreclr/src/zap/zapinfo.cpp
src/coreclr/src/zap/zapper.cpp
src/coreclr/src/zap/zaprelocs.cpp

index 97f3958..2495de2 100644 (file)
@@ -3074,4 +3074,19 @@ public:
 #define IMAGE_REL_BASED_REL32           0x10
 #define IMAGE_REL_BASED_THUMB_BRANCH24  0x13
 
+// The identifier for ARM32-specific PC-relative address
+// computation corresponds to the following instruction
+// sequence:
+//  l0: movw rX, #imm_lo  // 4 byte
+//  l4: movt rX, #imm_hi  // 4 byte
+//  l8: add  rX, pc <- after this instruction rX = relocTarget
+//
+// Program counter at l8 is address of l8 + 4
+// Address of relocated movw/movt is l0
+// So, imm should be calculated as the following:
+//  imm = relocTarget - (l8 + 4) = relocTarget - (l0 + 8 + 4) = relocTarget - (l_0 + 12)
+// So, the value of offset correction is 12
+//
+#define IMAGE_REL_BASED_REL_THUMB_MOV32_PCREL   0x14
+
 #endif // _COR_INFO_H_
index e6d067c..e6e8257 100644 (file)
@@ -148,6 +148,12 @@ public:
         CORJIT_FLAG_DESKTOP_QUIRKS          = 38, // The JIT should generate desktop-quirk-compatible code
         CORJIT_FLAG_TIER0                   = 39, // This is the initial tier for tiered compilation which should generate code as quickly as possible
         CORJIT_FLAG_TIER1                   = 40, // This is the final tier (for now) for tiered compilation which should generate high quality code
+
+#if defined(_TARGET_ARM_)
+        CORJIT_FLAG_RELATIVE_CODE_RELOCS    = 41, // JIT should generate PC-relative address computations instead of EE relocation records
+#else // !defined(_TARGET_ARM_)
+        CORJIT_FLAG_UNUSED11                = 41
+#endif // !defined(_TARGET_ARM_)
     };
 
     CORJIT_FLAGS()
index a55ddbe..b846274 100644 (file)
@@ -448,6 +448,8 @@ class ZapperOptions
 
     bool        m_fNoMetaData;          // Do not copy metadata and IL to native image
 
+    void SetCompilerFlags(void);
+
     ZapperOptions();
     ~ZapperOptions();
 };
old mode 100755 (executable)
new mode 100644 (file)
index e50e640..471434c
@@ -361,6 +361,10 @@ protected:
                          /* IN OUT */ bool* pUnwindStarted,
                          bool               jmpEpilog);
 
+    void genMov32RelocatableDisplacement(BasicBlock* block, regNumber reg);
+    void genMov32RelocatableDataLabel(unsigned value, regNumber reg);
+    void genMov32RelocatableImmediate(emitAttr size, unsigned value, regNumber reg);
+
     bool genUsedPopToReturn; // True if we use the pop into PC to return,
                              // False if we didn't and must branch to LR to return.
 
index 0795299..fb7c067 100644 (file)
@@ -44,8 +44,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block)
 
     // Load the address where the finally funclet should return into LR.
     // The funclet prolog/epilog will do "push {lr}" / "pop {pc}" to do the return.
-    getEmitter()->emitIns_R_L(INS_movw, EA_4BYTE_DSP_RELOC, bbFinallyRet, REG_LR);
-    getEmitter()->emitIns_R_L(INS_movt, EA_4BYTE_DSP_RELOC, bbFinallyRet, REG_LR);
+    genMov32RelocatableDisplacement(bbFinallyRet, REG_LR);
 
     // Jump to the finally BB
     inst_JMP(EJ_jmp, block->bbJumpDest);
@@ -63,8 +62,7 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block)
 // genEHCatchRet:
 void CodeGen::genEHCatchRet(BasicBlock* block)
 {
-    getEmitter()->emitIns_R_L(INS_movw, EA_4BYTE_DSP_RELOC, block->bbJumpDest, REG_INTRET);
-    getEmitter()->emitIns_R_L(INS_movt, EA_4BYTE_DSP_RELOC, block->bbJumpDest, REG_INTRET);
+    genMov32RelocatableDisplacement(block->bbJumpDest, REG_INTRET);
 }
 
 //------------------------------------------------------------------------
@@ -82,8 +80,7 @@ void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm,
 
     if (EA_IS_RELOC(size))
     {
-        getEmitter()->emitIns_R_I(INS_movw, size, reg, imm);
-        getEmitter()->emitIns_R_I(INS_movt, size, reg, imm);
+        genMov32RelocatableImmediate(size, imm, reg);
     }
     else if (imm == 0)
     {
@@ -1068,8 +1065,7 @@ void CodeGen::genJumpTable(GenTree* treeNode)
 
     getEmitter()->emitDataGenEnd();
 
-    getEmitter()->emitIns_R_D(INS_movw, EA_HANDLE_CNS_RELOC, jmpTabBase, treeNode->gtRegNum);
-    getEmitter()->emitIns_R_D(INS_movt, EA_HANDLE_CNS_RELOC, jmpTabBase, treeNode->gtRegNum);
+    genMov32RelocatableDataLabel(jmpTabBase, treeNode->gtRegNum);
 
     genProduceReg(treeNode);
 }
index 1f5bec8..f92088e 100644 (file)
@@ -6359,6 +6359,53 @@ void CodeGen::genFreeLclFrame(unsigned frameSize, /* IN OUT */ bool* pUnwindStar
 
 /*-----------------------------------------------------------------------------
  *
+ *  Move of relocatable displacement value to register
+ */
+void CodeGen::genMov32RelocatableDisplacement(BasicBlock* block, regNumber reg)
+{
+    getEmitter()->emitIns_R_L(INS_movw, EA_4BYTE_DSP_RELOC, block, reg);
+    getEmitter()->emitIns_R_L(INS_movt, EA_4BYTE_DSP_RELOC, block, reg);
+
+    if (compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_RELATIVE_CODE_RELOCS))
+    {
+        getEmitter()->emitIns_R_R_R(INS_add, EA_4BYTE_DSP_RELOC, reg, reg, REG_PC);
+    }
+}
+
+/*-----------------------------------------------------------------------------
+ *
+ *  Move of relocatable data-label to register
+ */
+void CodeGen::genMov32RelocatableDataLabel(unsigned value, regNumber reg)
+{
+    getEmitter()->emitIns_R_D(INS_movw, EA_HANDLE_CNS_RELOC, value, reg);
+    getEmitter()->emitIns_R_D(INS_movt, EA_HANDLE_CNS_RELOC, value, reg);
+
+    if (compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_RELATIVE_CODE_RELOCS))
+    {
+        getEmitter()->emitIns_R_R_R(INS_add, EA_HANDLE_CNS_RELOC, reg, reg, REG_PC);
+    }
+}
+
+/*-----------------------------------------------------------------------------
+ *
+ * Move of relocatable immediate to register
+ */
+void CodeGen::genMov32RelocatableImmediate(emitAttr size, unsigned value, regNumber reg)
+{
+    _ASSERTE(EA_IS_RELOC(size));
+
+    getEmitter()->emitIns_R_I(INS_movw, size, reg, value);
+    getEmitter()->emitIns_R_I(INS_movt, size, reg, value);
+
+    if (compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_RELATIVE_CODE_RELOCS))
+    {
+        getEmitter()->emitIns_R_R_R(INS_add, size, reg, reg, REG_PC);
+    }
+}
+
+/*-----------------------------------------------------------------------------
+ *
  *  Returns register mask to push/pop to allocate a small stack frame,
  *  instead of using "sub sp" / "add sp". Returns RBM_NONE if either frame size
  *  is zero, or if we should use "sub sp" / "add sp" instead of push/pop.
index d653511..f2144ad 100644 (file)
@@ -13095,8 +13095,7 @@ void CodeGen::genCodeForBBlist()
                 // Load the address where the finally funclet should return into LR.
                 // The funclet prolog/epilog will do "push {lr}" / "pop {pc}" to do
                 // the return.
-                getEmitter()->emitIns_R_L(INS_movw, EA_4BYTE_DSP_RELOC, bbFinallyRet, REG_LR);
-                getEmitter()->emitIns_R_L(INS_movt, EA_4BYTE_DSP_RELOC, bbFinallyRet, REG_LR);
+                genMov32RelocatableDisplacement(bbFinallyRet, REG_LR);
                 regTracker.rsTrackRegTrash(REG_LR);
 #endif // 0
 
@@ -13123,8 +13122,7 @@ void CodeGen::genCodeForBBlist()
 
             case BBJ_EHCATCHRET:
                 // set r0 to the address the VM should return to after the catch
-                getEmitter()->emitIns_R_L(INS_movw, EA_4BYTE_DSP_RELOC, block->bbJumpDest, REG_R0);
-                getEmitter()->emitIns_R_L(INS_movt, EA_4BYTE_DSP_RELOC, block->bbJumpDest, REG_R0);
+                genMov32RelocatableDisplacement(block->bbJumpDest, REG_R0);
                 regTracker.rsTrackRegTrash(REG_R0);
 
                 __fallthrough;
@@ -15509,8 +15507,7 @@ void CodeGen::genTableSwitch(regNumber reg, unsigned jumpCnt, BasicBlock** jumpT
     // Pick any register except the index register.
     //
     regNumber regTabBase = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(reg));
-    getEmitter()->emitIns_R_D(INS_movw, EA_HANDLE_CNS_RELOC, jmpTabBase, regTabBase);
-    getEmitter()->emitIns_R_D(INS_movt, EA_HANDLE_CNS_RELOC, jmpTabBase, regTabBase);
+    genMov32RelocatableDataLabel(jmpTabBase, regTabBase);
     regTracker.rsTrackRegTrash(regTabBase);
 
     // LDR PC, [regTableBase + reg * 4] (encoded as LDR PC, [regTableBase, reg, LSL 2]
index ff2475a..535fb21 100644 (file)
@@ -7107,6 +7107,29 @@ void emitter::emitRecordRelocation(void* location,            /* IN */
 #endif // defined(LATE_DISASM)
 }
 
+#ifdef _TARGET_ARM_
+/*****************************************************************************
+ *  A helper for handling a Thumb-Mov32 of position-independent (PC-relative) value
+ *
+ *  This routine either records relocation for the location with the EE,
+ *  or creates a virtual relocation entry to perform offset fixup during
+ *  compilation without recording it with EE - depending on which of
+ *  absolute/relocative relocations mode are used for code section.
+ */
+void emitter::emitHandlePCRelativeMov32(void* location, /* IN */
+                                        void* target)   /* IN */
+{
+    if (emitComp->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_RELATIVE_CODE_RELOCS))
+    {
+        emitRecordRelocation(location, target, IMAGE_REL_BASED_REL_THUMB_MOV32_PCREL);
+    }
+    else
+    {
+        emitRecordRelocation(location, target, IMAGE_REL_BASED_THUMB_MOV32);
+    }
+}
+#endif // _TARGET_ARM_
+
 /*****************************************************************************
  *  A helper for recording a call site with the EE.
  */
index a63242f..49d81c1 100644 (file)
@@ -2174,6 +2174,11 @@ public:
                               WORD  slotNum   = 0,  /* IN */
                               INT32 addlDelta = 0); /* IN */
 
+#ifdef _TARGET_ARM_
+    void emitHandlePCRelativeMov32(void* location, /* IN */
+                                   void* target);  /* IN */
+#endif
+
     void emitRecordCallSite(ULONG                 instrOffset,   /* IN */
                             CORINFO_SIG_INFO*     callSig,       /* IN */
                             CORINFO_METHOD_HANDLE methodHandle); /* IN */
index 2b8eb25..9ec8e07 100644 (file)
@@ -5387,7 +5387,7 @@ BYTE* emitter::emitOutputLJ(insGroup* ig, BYTE* dst, instrDesc* i)
             {
                 assert(ins == INS_movt || ins == INS_movw);
                 if ((ins == INS_movt) && emitComp->info.compMatchedVM)
-                    emitRecordRelocation((void*)(dst - 8), (void*)distVal, IMAGE_REL_BASED_THUMB_MOV32);
+                    emitHandlePCRelativeMov32((void*)(dst - 8), (void*)distVal);
             }
         }
         else
@@ -6011,7 +6011,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
                 assert((ins == INS_movt) || (ins == INS_movw));
                 dst += emitOutput_Thumb2Instr(dst, code);
                 if ((ins == INS_movt) && emitComp->info.compMatchedVM)
-                    emitRecordRelocation((void*)(dst - 8), (void*)imm, IMAGE_REL_BASED_THUMB_MOV32);
+                    emitHandlePCRelativeMov32((void*)(dst - 8), (void*)imm);
             }
             else
             {
index 5bbfdde..670a709 100644 (file)
@@ -3915,8 +3915,7 @@ void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm,
 
         if (EA_IS_RELOC(size))
         {
-            getEmitter()->emitIns_R_I(INS_movw, size, reg, imm);
-            getEmitter()->emitIns_R_I(INS_movt, size, reg, imm);
+            genMov32RelocatableImmediate(size, imm, reg);
         }
         else if (arm_Valid_Imm_For_Mov(imm))
         {
index 7b0e4a0..7a03dd6 100644 (file)
@@ -80,6 +80,12 @@ public:
         JIT_FLAG_DESKTOP_QUIRKS          = 38, // The JIT should generate desktop-quirk-compatible code
         JIT_FLAG_TIER0                   = 39, // This is the initial tier for tiered compilation which should generate code as quickly as possible
         JIT_FLAG_TIER1                   = 40, // This is the final tier (for now) for tiered compilation which should generate high quality code
+
+#if defined(_TARGET_ARM_)
+        JIT_FLAG_RELATIVE_CODE_RELOCS    = 41, // JIT should generate PC-relative address computations instead of EE relocation records
+#else // !defined(_TARGET_ARM_)
+        JIT_FLAG_UNUSED11                = 41
+#endif // !defined(_TARGET_ARM_)
     };
     // clang-format on
 
@@ -192,6 +198,12 @@ public:
         FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_TIER0, JIT_FLAG_TIER0);
         FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_TIER1, JIT_FLAG_TIER1);
 
+#if defined(_TARGET_ARM_)
+
+        FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_RELATIVE_CODE_RELOCS, JIT_FLAG_RELATIVE_CODE_RELOCS);
+
+#endif // _TARGET_ARM_
+
 #undef FLAGS_EQUAL
     }
 
index af0c41c..a242cef 100644 (file)
@@ -2481,7 +2481,25 @@ void ZapInfo::recordRelocation(void *location, void *target,
 
 #if defined(_TARGET_ARM_)
     case IMAGE_REL_BASED_THUMB_MOV32:
+    case IMAGE_REL_BASED_REL_THUMB_MOV32_PCREL:
     case IMAGE_REL_BASED_THUMB_BRANCH24:
+
+# ifdef _DEBUG
+    {
+        CORJIT_FLAGS jitFlags = m_zapper->m_pOpt->m_compilerFlags;
+
+        if (jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_RELATIVE_CODE_RELOCS))
+        {
+            _ASSERTE(fRelocType == IMAGE_REL_BASED_REL_THUMB_MOV32_PCREL
+                     || fRelocType == IMAGE_REL_BASED_THUMB_BRANCH24);
+        }
+        else
+        {
+            _ASSERTE(fRelocType == IMAGE_REL_BASED_THUMB_MOV32
+                     || fRelocType == IMAGE_REL_BASED_THUMB_BRANCH24);
+        }
+    }
+# endif // _DEBUG
         break;
 #endif
 
@@ -2584,6 +2602,7 @@ void ZapInfo::recordRelocation(void *location, void *target,
 
 #if defined(_TARGET_ARM_)
     case IMAGE_REL_BASED_THUMB_MOV32:
+    case IMAGE_REL_BASED_REL_THUMB_MOV32_PCREL:
         PutThumb2Mov32((UINT16 *)location, targetOffset);
         break;
 
index 4d1330e..6b45bc2 100644 (file)
@@ -278,8 +278,7 @@ ZapperOptions::ZapperOptions() :
   m_legacyMode(false)
   ,m_fNoMetaData(s_fNGenNoMetaData)
 {
-    m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_RELOC);
-    m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_PREJIT);
+    SetCompilerFlags();
 
     m_zapSet = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ZapSet);
     if (m_zapSet != NULL && wcslen(m_zapSet) > 3)
@@ -319,6 +318,18 @@ ZapperOptions::~ZapperOptions()
         delete [] m_repositoryDir;
 }
 
+void ZapperOptions::SetCompilerFlags(void)
+{
+    m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_RELOC);
+    m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_PREJIT);
+
+#if defined(_TARGET_ARM_)
+# if defined(PLATFORM_UNIX)
+    m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_RELATIVE_CODE_RELOCS);
+# endif // defined(PLATFORM_UNIX)
+#endif // defined(_TARGET_ARM_)
+}
+
 /* --------------------------------------------------------------------------- *
  * Zapper class
  * --------------------------------------------------------------------------- */
@@ -370,8 +381,7 @@ Zapper::Zapper(NGenOptions *pOptions, bool fromDllHost)
     pOptions = &currentVersionOptions;
 
     zo->m_compilerFlags.Reset();
-    zo->m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_RELOC);
-    zo->m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_PREJIT);
+    zo->SetCompilerFlags();
     zo->m_autodebug = true;
 
     if (pOptions->fDebug)
index 04708c2..059d9a5 100644 (file)
@@ -84,6 +84,22 @@ void ZapBaseRelocs::WriteReloc(PVOID pSrc, int offset, ZapNode * pTarget, int ta
             break;
         }
 
+    case IMAGE_REL_BASED_REL_THUMB_MOV32_PCREL:
+        {
+            TADDR pSite = (TADDR)m_pImage->GetBaseAddress() + rva;
+
+            // For details about how the value is calculated, see
+            // description of IMAGE_REL_BASED_REL_THUMB_MOV32_PCREL
+            const UINT32 offsetCorrection = 12;
+
+            UINT32 imm32 = pActualTarget - (pSite + offsetCorrection);
+
+            PutThumb2Mov32((UINT16 *)pLocation, imm32);
+
+            // IMAGE_REL_BASED_REL_THUMB_MOV32_PCREL does not need base reloc entry
+            return;
+        }
+
     case IMAGE_REL_BASED_THUMB_BRANCH24:
         {
             TADDR pSite = (TADDR)m_pImage->GetBaseAddress() + rva;
@@ -282,6 +298,7 @@ void ZapBlobWithRelocs::Save(ZapWriter * pZapWriter)
 
 #if defined(_TARGET_ARM_)
             case IMAGE_REL_BASED_THUMB_MOV32:
+            case IMAGE_REL_BASED_REL_THUMB_MOV32_PCREL:
                 targetOffset = (int)GetThumb2Mov32((UINT16 *)pLocation);
                 break;