@@ -782,7 +782,9 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
782782 (rHi20.type == R_LARCH_TLS_GD_PC_HI20 &&
783783 rLo12.type == R_LARCH_GOT_PC_LO12) ||
784784 (rHi20.type == R_LARCH_TLS_LD_PC_HI20 &&
785- rLo12.type == R_LARCH_GOT_PC_LO12)))
785+ rLo12.type == R_LARCH_GOT_PC_LO12) ||
786+ (rHi20.type == R_LARCH_TLS_DESC_PC_HI20 &&
787+ rLo12.type == R_LARCH_TLS_DESC_PC_LO12)))
786788 return ;
787789
788790 // GOT references to absolute symbols can't be relaxed to use pcaddi in
@@ -804,6 +806,8 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
804806 symBase = rHi20.sym ->getVA (ctx);
805807 else if (rHi20.expr == RE_LOONGARCH_TLSGD_PAGE_PC)
806808 symBase = ctx.in .got ->getGlobalDynAddr (*rHi20.sym );
809+ else if (rHi20.expr == RE_LOONGARCH_TLSDESC_PAGE_PC)
810+ symBase = ctx.in .got ->getTlsDescAddr (*rHi20.sym );
807811 else {
808812 Err (ctx) << getErrorLoc (ctx, (const uint8_t *)loc) << " unknown expr ("
809813 << rHi20.expr << " ) against symbol " << rHi20.sym
@@ -837,6 +841,8 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
837841 sec.relaxAux ->relocTypes [i + 2 ] = R_LARCH_TLS_GD_PCREL20_S2;
838842 else if (rHi20.type == R_LARCH_TLS_LD_PC_HI20)
839843 sec.relaxAux ->relocTypes [i + 2 ] = R_LARCH_TLS_LD_PCREL20_S2;
844+ else if (rHi20.type == R_LARCH_TLS_DESC_PC_HI20)
845+ sec.relaxAux ->relocTypes [i + 2 ] = R_LARCH_TLS_DESC_PCREL20_S2;
840846 else
841847 sec.relaxAux ->relocTypes [i + 2 ] = R_LARCH_PCREL20_S2;
842848 sec.relaxAux ->writes .push_back (insn (PCADDI, getD5 (nextInsn), 0 , 0 ));
@@ -903,6 +909,33 @@ static void relaxTlsLe(Ctx &ctx, const InputSection &sec, size_t i,
903909 }
904910}
905911
912+ // Relax TLSDESC code sequence. In LoongArch, the conversion of TLSDESC GD/LD to
913+ // LE/IE is closely tied to relaxation, similar to how GCC handles it. (Due to
914+ // the lack of an efficient way for handling conversions in the extreme code
915+ // model and the difficulty in determining whether the extreme code model is
916+ // being used in handleTlsRelocation, this approach may seem like a workaround).
917+ // Consequently, the resulting code sequence depends on whether the conversion
918+ // to LE/IE is performed.
919+ //
920+ // Original code sequence:
921+ // * pcalau12i $a0, %desc_pc_hi20(sym_desc)
922+ // * addi.d $a0, $a0, %desc_pc_lo12(sym_desc)
923+ // * ld.d $ra, $a0, %desc_ld(sym_desc)
924+ // * jirl $ra, $ra, %desc_call(sym_desc)
925+ //
926+ // Cannot convert to LE/IE, but relax:
927+ // * pcaddi $a0, %desc_pcrel_20(sym_desc)
928+ // * ld.d $ra, $a0, %desc_ld(sym_desc)
929+ // * jirl $ra, $ra, %desc_call(sym_desc)
930+ //
931+ // FIXME: Implement TLSDESC GD/LD to LE/IE.
932+ static void relaxTlsdesc (Ctx &ctx, const InputSection &sec, size_t i,
933+ uint64_t loc, Relocation &rHi20, Relocation &rLo12,
934+ uint32_t &remove) {
935+ if (ctx.arg .shared && rHi20.type == R_LARCH_TLS_DESC_PC_HI20)
936+ return relaxPCHi20Lo12 (ctx, sec, i, loc, rHi20, rLo12, remove);
937+ }
938+
906939static bool relax (Ctx &ctx, InputSection &sec) {
907940 const uint64_t secAddr = sec.getVA ();
908941 const MutableArrayRef<Relocation> relocs = sec.relocs ();
@@ -959,6 +992,10 @@ static bool relax(Ctx &ctx, InputSection &sec) {
959992 if (relaxable (relocs, i))
960993 relaxTlsLe (ctx, sec, i, loc, r, remove);
961994 break ;
995+ case R_LARCH_TLS_DESC_PC_HI20:
996+ if (isPairRelaxable (relocs, i))
997+ relaxTlsdesc (ctx, sec, i, loc, r, relocs[i + 2 ], remove);
998+ break ;
962999 }
9631000
9641001 // For all anchors whose offsets are <= r.offset, they are preceded by
@@ -1078,6 +1115,11 @@ void LoongArch::finalizeRelax(int passes) const {
10781115 write32le (p, aux.writes [writesIdx++]);
10791116 r.expr = R_TLSGD_PC;
10801117 break ;
1118+ case R_LARCH_TLS_DESC_PCREL20_S2:
1119+ skip = 4 ;
1120+ write32le (p, aux.writes [writesIdx++]);
1121+ r.expr = R_TLSDESC_PC;
1122+ break ;
10811123 default :
10821124 llvm_unreachable (" unsupported type" );
10831125 }
0 commit comments