diff --git a/src/coreclr/jit/codegenarmarch.cpp b/src/coreclr/jit/codegenarmarch.cpp index 6e177b0a7ad3d9..699e1b103fe1d3 100644 --- a/src/coreclr/jit/codegenarmarch.cpp +++ b/src/coreclr/jit/codegenarmarch.cpp @@ -3353,6 +3353,14 @@ void CodeGen::genCallInstruction(GenTreeCall* call) // mrs emitter->emitIns_R(INS_mrs_tpid0, attr, REG_R1); + // We remove x0 here since the linker relaxation + // sequence will rewrite the instructions we are emitting here with + // instructions that may clobber these registers. + // (This is more important for the emitter, but we match it here + // for symmetry and to avoid confusion about the state of the + // registers.) + gcInfo.gcMarkRegSetNpt(RBM_R0); + // adrp // ldr // add diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index b8d5ffb8f9452c..a6b563e97aea01 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -484,6 +484,15 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre else if (con->IsIconHandle(GTF_ICON_TLSGD_OFFSET)) { attr = EA_SET_FLG(attr, EA_CNS_TLSGD_RELOC); + + // This marks the start of a TLS access linker relaxation + // sequence for linux-x64. The linker may rewrite to + // instructions that trash rax at this point, so we update + // GC state eagerly here. + // (This is more important for the emitter, but we match it here + // for symmetry and to avoid confusion about the state of the + // registers.) + gcInfo.gcMarkRegSetNpt(RBM_RAX); } } diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 3bf05d5936ecf4..01699a7d3d0a58 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -11725,6 +11725,17 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) emitRecordRelocation(odst, id->idAddr()->iiaAddr, id->idIsTlsGD() ? CorInfoReloc::ARM64_LIN_TLSDESC_ADR_PAGE21 : CorInfoReloc::ARM64_PAGEBASE_REL21); + + if (id->idIsTlsGD()) + { + // This is the beginning of the TLS access linker + // relaxation sequence for linux arm64. The linker may + // replace these with other instructions that may trash x0. + // We thus need to eagerly update GC for x0, in case the + // linker's instructions trashes it earlier than we would + // emit a mutating instruction that trashes it. + emitGCregDeadUpd(REG_R0, dst); + } } else { diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 06eec05ce90b60..32d20d45385819 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -18451,6 +18451,13 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) { dst = emitOutputData16(dst); sz = emitSizeOfInsDsc_NONE(id); + + // This may mark the beginning of a TLS access linker + // relaxation sequence. The linker can replace these general + // sequences by other instructions that trash rax. We need to + // eagerly invalidate GC info in rax before the linker's + // instructions would trash it. + emitGCregDeadUpd(REG_RAX, dst); break; }