From f163abbd16d35032e4450a09c548cb804cf36a85 Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Thu, 20 Jun 2019 12:04:54 -0700 Subject: JIT: use register indirect for indirect jumps (#25251) If we are jumping to another method via an indirection cell, the cell address may be too far from the jump to address via a RIP-relative indirection. So instead, load the target address into RAX and jump register indirect. Fixes #22342. --- src/jit/codegencommon.cpp | 28 ++++++++++++++++++++++------ src/jit/emitxarch.cpp | 8 ++++---- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/jit/codegencommon.cpp b/src/jit/codegencommon.cpp index bb81361d9b..34be5f7de7 100644 --- a/src/jit/codegencommon.cpp +++ b/src/jit/codegencommon.cpp @@ -8905,24 +8905,40 @@ void CodeGen::genFnEpilog(BasicBlock* block) NO_WAY("Unsupported JMP indirection"); } - const emitter::EmitCallType callType = - (addrInfo.accessType == IAT_VALUE) ? emitter::EC_FUNC_TOKEN : emitter::EC_FUNC_TOKEN_INDIR; + // If we have IAT_PVALUE, jump via register indirect, as sometimes the + // indirection cell can't be reached by the jump. - // Simply emit a jump to the methodHnd. This is similar to a call so we can use - // the same descriptor with some minor adjustments. + emitter::EmitCallType callType; + void* addr; + regNumber indCallReg; + + if (addrInfo.accessType == IAT_PVALUE) + { + callType = emitter::EC_INDIR_ARD; + indCallReg = REG_RAX; + addr = nullptr; + instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indCallReg, (ssize_t)addrInfo.addr); + regSet.verifyRegUsed(indCallReg); + } + else + { + callType = emitter::EC_FUNC_TOKEN; + addr = addrInfo.addr; + indCallReg = REG_NA; + } // clang-format off getEmitter()->emitIns_Call(callType, methHnd, INDEBUG_LDISASM_COMMA(nullptr) - addrInfo.addr, + addr, 0, // argSize EA_UNKNOWN // retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(EA_UNKNOWN), // secondRetSize gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur, gcInfo.gcRegByrefSetCur, - BAD_IL_OFFSET, REG_NA, REG_NA, 0, 0, /* iloffset, ireg, xreg, xmul, disp */ + BAD_IL_OFFSET, indCallReg, REG_NA, 0, 0, /* iloffset, ireg, xreg, xmul, disp */ true /* isJump */ ); // clang-format on diff --git a/src/jit/emitxarch.cpp b/src/jit/emitxarch.cpp index 157a57e432..1f529ff694 100644 --- a/src/jit/emitxarch.cpp +++ b/src/jit/emitxarch.cpp @@ -7057,7 +7057,7 @@ void emitter::emitIns_Call(EmitCallType callType, if (isJump) { - assert(callType == EC_FUNC_TOKEN || callType == EC_FUNC_TOKEN_INDIR); + assert(callType == EC_FUNC_TOKEN || callType == EC_INDIR_ARD); if (callType == EC_FUNC_TOKEN) { ins = INS_l_jmp; @@ -7853,9 +7853,9 @@ void emitter::emitDispAddrMode(instrDesc* id, bool noDetail) printf("reloc "); } printf("J_M%03u_DS%02u", Compiler::s_compMethodsCount, id->idDebugOnlyInfo()->idMemCookie); - } - disp -= id->idDebugOnlyInfo()->idMemCookie; + disp -= id->idDebugOnlyInfo()->idMemCookie; + } } bool frameRef = false; @@ -8351,7 +8351,7 @@ void emitter::emitDispIns( emitDispAddrMode(id, isNew); emitDispShift(ins); - if (ins == INS_call) + if ((ins == INS_call) || (ins == INS_i_jmp)) { assert(id->idInsFmt() == IF_ARD); -- cgit v1.2.3