diff options
-rw-r--r-- | src/jit/codegen.h | 3 | ||||
-rw-r--r-- | src/jit/codegenarmarch.cpp | 38 | ||||
-rw-r--r-- | src/jit/codegencommon.cpp | 56 | ||||
-rw-r--r-- | src/jit/codegenxarch.cpp | 64 | ||||
-rw-r--r-- | src/jit/instr.cpp | 33 | ||||
-rw-r--r-- | tests/src/JIT/Regression/JitBlue/GitHub_24278/GitHub_24278.il | 67 | ||||
-rw-r--r-- | tests/src/JIT/Regression/JitBlue/GitHub_24278/GitHub_24278.ilproj | 24 |
7 files changed, 188 insertions, 97 deletions
diff --git a/src/jit/codegen.h b/src/jit/codegen.h index fcbf4d8ec9..ef1443d0fa 100644 --- a/src/jit/codegen.h +++ b/src/jit/codegen.h @@ -1413,9 +1413,6 @@ public: void instGen_Store_Reg_Into_Lcl(var_types dstType, regNumber srcReg, int varNum, int offs); - void instGen_Store_Imm_Into_Lcl( - var_types dstType, emitAttr sizeAttr, ssize_t imm, int varNum, int offs, regNumber regToUse = REG_NA); - #ifdef DEBUG void __cdecl instDisp(instruction ins, bool noNL, const char* fmt, ...); #endif diff --git a/src/jit/codegenarmarch.cpp b/src/jit/codegenarmarch.cpp index 87cbd6d1d5..9476e6595d 100644 --- a/src/jit/codegenarmarch.cpp +++ b/src/jit/codegenarmarch.cpp @@ -568,6 +568,44 @@ void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFla } //--------------------------------------------------------------------- +// genSetGSSecurityCookie: Set the "GS" security cookie in the prolog. +// +// Arguments: +// initReg - register to use as a scratch register +// pInitRegZeroed - OUT parameter. *pInitRegZeroed is set to 'false' if and only if +// this call sets 'initReg' to a non-zero value. +// +// Return Value: +// None +// +void CodeGen::genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed) +{ + assert(compiler->compGeneratingProlog); + + if (!compiler->getNeedsGSSecurityCookie()) + { + return; + } + + if (compiler->gsGlobalSecurityCookieAddr == nullptr) + { + noway_assert(compiler->gsGlobalSecurityCookieVal != 0); + // initReg = #GlobalSecurityCookieVal; [frame.GSSecurityCookie] = initReg + genSetRegToIcon(initReg, compiler->gsGlobalSecurityCookieVal, TYP_I_IMPL); + getEmitter()->emitIns_S_R(INS_str, EA_PTRSIZE, initReg, compiler->lvaGSSecurityCookie, 0); + } + else + { + instGen_Set_Reg_To_Imm(EA_PTR_DSP_RELOC, initReg, (ssize_t)compiler->gsGlobalSecurityCookieAddr); + getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, initReg, initReg, 0); + regSet.verifyRegUsed(initReg); + getEmitter()->emitIns_S_R(INS_str, EA_PTRSIZE, initReg, compiler->lvaGSSecurityCookie, 0); + } + + *pInitRegZeroed = false; +} + +//--------------------------------------------------------------------- // genIntrinsic - generate code for a given intrinsic // // Arguments diff --git a/src/jit/codegencommon.cpp b/src/jit/codegencommon.cpp index 4edcda90b9..bb81361d9b 100644 --- a/src/jit/codegencommon.cpp +++ b/src/jit/codegencommon.cpp @@ -6483,62 +6483,6 @@ void CodeGen::genReportGenericContextArg(regNumber initReg, bool* pInitRegZeroed #endif // !ARM64 !ARM } -/*----------------------------------------------------------------------------- - * - * Set the "GS" security cookie in the prolog. - */ - -void CodeGen::genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed) -{ - assert(compiler->compGeneratingProlog); - - if (!compiler->getNeedsGSSecurityCookie()) - { - return; - } - - noway_assert(compiler->gsGlobalSecurityCookieAddr || compiler->gsGlobalSecurityCookieVal); - - if (compiler->gsGlobalSecurityCookieAddr == nullptr) - { -#ifdef _TARGET_AMD64_ - // eax = #GlobalSecurityCookieVal64; [frame.GSSecurityCookie] = eax - getEmitter()->emitIns_R_I(INS_mov, EA_PTRSIZE, REG_RAX, compiler->gsGlobalSecurityCookieVal); - getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_RAX, compiler->lvaGSSecurityCookie, 0); -#else - // mov dword ptr [frame.GSSecurityCookie], #GlobalSecurityCookieVal - instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, compiler->gsGlobalSecurityCookieVal, - compiler->lvaGSSecurityCookie, 0, initReg); -#endif - } - else - { - regNumber reg; -#ifdef _TARGET_XARCH_ - // Always use EAX on x86 and x64 - // On x64, if we're not moving into RAX, and the address isn't RIP relative, we can't encode it. - reg = REG_EAX; -#else - // We will just use the initReg since it is an available register - reg = initReg; -#endif - - *pInitRegZeroed = false; - -#if CPU_LOAD_STORE_ARCH - instGen_Set_Reg_To_Imm(EA_PTR_DSP_RELOC, reg, (ssize_t)compiler->gsGlobalSecurityCookieAddr); - getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, reg, reg, 0); - regSet.verifyRegUsed(reg); -#else - // mov reg, dword ptr [compiler->gsGlobalSecurityCookieAddr] - // mov dword ptr [frame.GSSecurityCookie], reg - getEmitter()->emitIns_R_AI(INS_mov, EA_PTR_DSP_RELOC, reg, (ssize_t)compiler->gsGlobalSecurityCookieAddr); - regSet.verifyRegUsed(reg); -#endif - getEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, reg, compiler->lvaGSSecurityCookie, 0); - } -} - #ifdef PROFILING_SUPPORTED //----------------------------------------------------------------------------------- diff --git a/src/jit/codegenxarch.cpp b/src/jit/codegenxarch.cpp index 9184c09b39..521aaca407 100644 --- a/src/jit/codegenxarch.cpp +++ b/src/jit/codegenxarch.cpp @@ -49,6 +49,61 @@ void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFla } } +//--------------------------------------------------------------------- +// genSetGSSecurityCookie: Set the "GS" security cookie in the prolog. +// +// Arguments: +// initReg - register to use as a scratch register +// pInitRegZeroed - OUT parameter. *pInitRegZeroed is set to 'false' if and only if +// this call sets 'initReg' to a non-zero value. +// +// Return Value: +// None +// +void CodeGen::genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed) +{ + assert(compiler->compGeneratingProlog); + + if (!compiler->getNeedsGSSecurityCookie()) + { + return; + } + + if (compiler->gsGlobalSecurityCookieAddr == nullptr) + { + noway_assert(compiler->gsGlobalSecurityCookieVal != 0); +#ifdef _TARGET_AMD64_ + if ((int)compiler->gsGlobalSecurityCookieVal != compiler->gsGlobalSecurityCookieVal) + { + // initReg = #GlobalSecurityCookieVal64; [frame.GSSecurityCookie] = initReg + genSetRegToIcon(initReg, compiler->gsGlobalSecurityCookieVal, TYP_I_IMPL); + getEmitter()->emitIns_S_R(INS_mov, EA_PTRSIZE, initReg, compiler->lvaGSSecurityCookie, 0); + *pInitRegZeroed = false; + } + else +#endif + { + // mov dword ptr [frame.GSSecurityCookie], #GlobalSecurityCookieVal + getEmitter()->emitIns_S_I(INS_mov, EA_PTRSIZE, compiler->lvaGSSecurityCookie, 0, + (int)compiler->gsGlobalSecurityCookieVal); + } + } + else + { + // Always use EAX on x86 and x64 + // On x64, if we're not moving into RAX, and the address isn't RIP relative, we can't encode it. + // mov eax, dword ptr [compiler->gsGlobalSecurityCookieAddr] + // mov dword ptr [frame.GSSecurityCookie], eax + getEmitter()->emitIns_R_AI(INS_mov, EA_PTR_DSP_RELOC, REG_EAX, (ssize_t)compiler->gsGlobalSecurityCookieAddr); + regSet.verifyRegUsed(REG_EAX); + getEmitter()->emitIns_S_R(INS_mov, EA_PTRSIZE, REG_EAX, compiler->lvaGSSecurityCookie, 0); + if (initReg == REG_EAX) + { + *pInitRegZeroed = false; + } + } +} + /***************************************************************************** * * Generate code to check that the GS cookie wasn't thrashed by a buffer @@ -325,10 +380,9 @@ BasicBlock* CodeGen::genCallFinally(BasicBlock* block) curNestingSlotOffs = (unsigned)(filterEndOffsetSlotOffs - ((finallyNesting + 1) * TARGET_POINTER_SIZE)); // Zero out the slot for the next nesting level - instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, 0, compiler->lvaShadowSPslotsVar, - curNestingSlotOffs - TARGET_POINTER_SIZE); - instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, LCL_FINALLY_MARK, compiler->lvaShadowSPslotsVar, - curNestingSlotOffs); + getEmitter()->emitIns_S_I(INS_mov, EA_PTRSIZE, compiler->lvaShadowSPslotsVar, + curNestingSlotOffs - TARGET_POINTER_SIZE, 0); + getEmitter()->emitIns_S_I(INS_mov, EA_PTRSIZE, compiler->lvaShadowSPslotsVar, curNestingSlotOffs, LCL_FINALLY_MARK); // Now push the address where the finally funclet should return to directly. if (!(block->bbFlags & BBF_RETLESS_CALL)) @@ -1914,7 +1968,7 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) unsigned curNestingSlotOffs; curNestingSlotOffs = filterEndOffsetSlotOffs - ((finallyNesting + 1) * TARGET_POINTER_SIZE); - instGen_Store_Imm_Into_Lcl(TYP_I_IMPL, EA_PTRSIZE, 0, compiler->lvaShadowSPslotsVar, curNestingSlotOffs); + getEmitter()->emitIns_S_I(INS_mov, EA_PTRSIZE, compiler->lvaShadowSPslotsVar, curNestingSlotOffs, 0); break; #endif // !FEATURE_EH_FUNCLETS diff --git a/src/jit/instr.cpp b/src/jit/instr.cpp index 020a783e66..dd3854600d 100644 --- a/src/jit/instr.cpp +++ b/src/jit/instr.cpp @@ -2365,39 +2365,6 @@ void CodeGen::instGen_Store_Reg_Into_Lcl(var_types dstType, regNumber srcReg, in getEmitter()->emitIns_S_R(ins_Store(dstType), size, srcReg, varNum, offs); } -/***************************************************************************** - * - * Machine independent way to move an immediate into a stack based local variable - */ -void CodeGen::instGen_Store_Imm_Into_Lcl( - var_types dstType, emitAttr sizeAttr, ssize_t imm, int varNum, int offs, regNumber regToUse) -{ -#ifdef _TARGET_XARCH_ -#ifdef _TARGET_AMD64_ - if ((EA_SIZE(sizeAttr) == EA_8BYTE) && (((int)imm != (ssize_t)imm) || EA_IS_CNS_RELOC(sizeAttr))) - { - assert(!"Invalid immediate for instGen_Store_Imm_Into_Lcl"); - } - else -#endif // _TARGET_AMD64_ - { - getEmitter()->emitIns_S_I(ins_Store(dstType), sizeAttr, varNum, offs, (int)imm); - } -#elif defined(_TARGET_ARMARCH_) - // Load imm into a register - regNumber immReg = regToUse; - assert(regToUse != REG_NA); - instGen_Set_Reg_To_Imm(sizeAttr, immReg, (ssize_t)imm); - instGen_Store_Reg_Into_Lcl(dstType, immReg, varNum, offs); - if (EA_IS_RELOC(sizeAttr)) - { - regSet.verifyRegUsed(immReg); - } -#else // _TARGET_* -#error "Unknown _TARGET_" -#endif // _TARGET_* -} - /*****************************************************************************/ /*****************************************************************************/ /*****************************************************************************/ diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_24278/GitHub_24278.il b/tests/src/JIT/Regression/JitBlue/GitHub_24278/GitHub_24278.il new file mode 100644 index 0000000000..e20cc03a79 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_24278/GitHub_24278.il @@ -0,0 +1,67 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Runtime { } +.assembly GitHub_24278 { } +.module GitHub_24278.exe + +// GitHub 24278: a bug is reproduced when +// 1) a register is used in the prolog for initializing GSSecurityCookie (i.e. the register contains a random non-zero value) and +// 2) the same register holds a must-init GC variable in the next basic block and +// 3) the variable is live at the beginning of this basic block. +// The register was not zeroed at the end of the prolog and this was causing segmentation fault during GC.Collect(). +// +// This happens in MainMethod at IL_0013: +// V_0 is not initialized by IL instructions of one of the path to IL_0013 and must be zeroed in the prolog since it is live at IL_0013. + +.class private auto ansi beforefieldinit GitHub_24278.Program + extends [System.Runtime]System.Object +{ + .method private hidebysig static bool True() cil managed noinlining + { + // Code size 2 (0x2) + .maxstack 8 + IL_0000: ldc.i4.1 + IL_0001: ret + } // end of method Program::True + + .method private hidebysig static void Use(int32 arg0) cil managed noinlining + { + // Code size 6 (0x6) + .maxstack 8 + IL_0000: call void [System.Runtime]System.GC::Collect() + IL_0005: ret + } // end of method Program::Use + + .method private hidebysig static void MainMethod() cil managed noinlining + { + // + .maxstack 1 + .locals init (object V_0) + IL_0000: call bool GitHub_24278.Program::True() + IL_0005: brtrue.s IL_000d + + IL_0007: newobj instance void [System.Runtime]System.Object::.ctor() + IL_000c: stloc.0 + IL_000d: ldc.i4.s 32 + IL_000f: conv.u + IL_0010: localloc + IL_0012: ldind.i4 + IL_0013: call void GitHub_24278.Program::Use(int32) + IL_0018: ldloc.0 + IL_0019: call void [System.Runtime]System.GC::KeepAlive(object) + IL_001e: ret + } // end of method Program::MainMethod + + .method private hidebysig static int32 + Main(string[] args) cil managed + { + .entrypoint + // Code size 8 (0x8) + .maxstack 8 + IL_0000: call void GitHub_24278.Program::MainMethod() + IL_0005: ldc.i4.s 100 + IL_0007: ret + } // end of method Program::Main +} diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_24278/GitHub_24278.ilproj b/tests/src/JIT/Regression/JitBlue/GitHub_24278/GitHub_24278.ilproj new file mode 100644 index 0000000000..506f235e2f --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_24278/GitHub_24278.ilproj @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <AssemblyName>$(MSBuildProjectName)</AssemblyName> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "></PropertyGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize>True</Optimize> + </PropertyGroup> + <ItemGroup> + <Compile Include="GitHub_24278.il" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> + </PropertyGroup> +</Project> |