@@ -154,6 +154,10 @@ static uint32_t setJ20(uint32_t insn, uint32_t imm) {
154154 return (insn & 0xfe00001f ) | (extractBits (imm, 19 , 0 ) << 5 );
155155}
156156
157+ static uint32_t setJ5 (uint32_t insn, uint32_t imm) {
158+ return (insn & 0xfffffc1f ) | (extractBits (imm, 4 , 0 ) << 5 );
159+ }
160+
157161static uint32_t setK12 (uint32_t insn, uint32_t imm) {
158162 return (insn & 0xffc003ff ) | (extractBits (imm, 11 , 0 ) << 10 );
159163}
@@ -761,10 +765,10 @@ static bool isPairRelaxable(ArrayRef<Relocation> relocs, size_t i) {
761765
762766// Relax code sequence.
763767// From:
764- // pcalau12i $a0, %pc_hi20(sym)
765- // addi.w/d $a0, $a0, %pc_lo12(sym)
768+ // pcalau12i $a0, %pc_hi20(sym) | %ld_pc_hi20(sym) | %gd_pc_hi20 (sym)
769+ // addi.w/d $a0, $a0, %pc_lo12(sym) | %got_pc_lo12(sym) | %got_pc_lo12(sym)
766770// To:
767- // pcaddi $a0, %pc_lo12(sym)
771+ // pcaddi $a0, %pc_lo12(sym) | %got_pc_lo12(sym) | %got_pc_lo12(sym)
768772//
769773// From:
770774// pcalau12i $a0, %got_pc_hi20(sym_got)
@@ -778,6 +782,10 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
778782 if (!((rHi20.type == R_LARCH_PCALA_HI20 &&
779783 rLo12.type == R_LARCH_PCALA_LO12) ||
780784 (rHi20.type == R_LARCH_GOT_PC_HI20 &&
785+ rLo12.type == R_LARCH_GOT_PC_LO12) ||
786+ (rHi20.type == R_LARCH_TLS_GD_PC_HI20 &&
787+ rLo12.type == R_LARCH_GOT_PC_LO12) ||
788+ (rHi20.type == R_LARCH_TLS_LD_PC_HI20 &&
781789 rLo12.type == R_LARCH_GOT_PC_LO12)))
782790 return ;
783791
@@ -798,6 +806,8 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
798806 else if (rHi20.expr == RE_LOONGARCH_PAGE_PC ||
799807 rHi20.expr == RE_LOONGARCH_GOT_PAGE_PC)
800808 dest = rHi20.sym ->getVA (ctx);
809+ else if (rHi20.expr == RE_LOONGARCH_TLSGD_PAGE_PC)
810+ dest = ctx.in .got ->getGlobalDynAddr (*rHi20.sym );
801811 else {
802812 Err (ctx) << getErrorLoc (ctx, (const uint8_t *)loc) << " unknown expr ("
803813 << rHi20.expr << " ) against symbol " << rHi20.sym
@@ -827,7 +837,12 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
827837 return ;
828838
829839 sec.relaxAux ->relocTypes [i] = R_LARCH_RELAX;
830- sec.relaxAux ->relocTypes [i + 2 ] = R_LARCH_PCREL20_S2;
840+ if (rHi20.type == R_LARCH_TLS_GD_PC_HI20)
841+ sec.relaxAux ->relocTypes [i + 2 ] = R_LARCH_TLS_GD_PCREL20_S2;
842+ else if (rHi20.type == R_LARCH_TLS_LD_PC_HI20)
843+ sec.relaxAux ->relocTypes [i + 2 ] = R_LARCH_TLS_LD_PCREL20_S2;
844+ else
845+ sec.relaxAux ->relocTypes [i + 2 ] = R_LARCH_PCREL20_S2;
831846 sec.relaxAux ->writes .push_back (insn (PCADDI, getD5 (nextInsn), 0 , 0 ));
832847 remove = 4 ;
833848}
@@ -863,6 +878,33 @@ static void relaxCall36(Ctx &ctx, const InputSection &sec, size_t i,
863878 }
864879}
865880
881+ // Relax code sequence.
882+ // From:
883+ // lu12i.w $rd, %le_hi20_r(sym)
884+ // add.w/d $rd, $rd, $tp, %le_add_r(sym)
885+ // addi/ld/st.w/d $rd, $rd, %le_lo12_r(sym)
886+ // To:
887+ // addi/ld/st.w/d $rd, $tp, %le_lo12_r(sym)
888+ static void relaxTlsLe (Ctx &ctx, const InputSection &sec, size_t i,
889+ uint64_t loc, Relocation &r, uint32_t &remove) {
890+ uint64_t val = r.sym ->getVA (ctx, r.addend );
891+ // Check if the val exceeds the range of addi/ld/st.
892+ if (!isInt<12 >(val))
893+ return ;
894+ uint32_t currInsn = read32le (sec.content ().data () + r.offset );
895+ switch (r.type ) {
896+ case R_LARCH_TLS_LE_HI20_R:
897+ case R_LARCH_TLS_LE_ADD_R:
898+ sec.relaxAux ->relocTypes [i] = R_LARCH_RELAX;
899+ remove = 4 ;
900+ break ;
901+ case R_LARCH_TLS_LE_LO12_R:
902+ sec.relaxAux ->writes .push_back (setJ5 (currInsn, R_TP));
903+ sec.relaxAux ->relocTypes [i] = R_LARCH_TLS_LE_LO12_R;
904+ break ;
905+ }
906+ }
907+
866908static bool relax (Ctx &ctx, InputSection &sec) {
867909 const uint64_t secAddr = sec.getVA ();
868910 const MutableArrayRef<Relocation> relocs = sec.relocs ();
@@ -903,6 +945,8 @@ static bool relax(Ctx &ctx, InputSection &sec) {
903945 }
904946 case R_LARCH_PCALA_HI20:
905947 case R_LARCH_GOT_PC_HI20:
948+ case R_LARCH_TLS_GD_PC_HI20:
949+ case R_LARCH_TLS_LD_PC_HI20:
906950 // The overflow check for i+2 will be carried out in isPairRelaxable.
907951 if (isPairRelaxable (relocs, i))
908952 relaxPCHi20Lo12 (ctx, sec, i, loc, r, relocs[i + 2 ], remove);
@@ -911,6 +955,12 @@ static bool relax(Ctx &ctx, InputSection &sec) {
911955 if (relaxable (relocs, i))
912956 relaxCall36 (ctx, sec, i, loc, r, remove);
913957 break ;
958+ case R_LARCH_TLS_LE_HI20_R:
959+ case R_LARCH_TLS_LE_ADD_R:
960+ case R_LARCH_TLS_LE_LO12_R:
961+ if (relaxable (relocs, i))
962+ relaxTlsLe (ctx, sec, i, loc, r, remove);
963+ break ;
914964 }
915965
916966 // For all anchors whose offsets are <= r.offset, they are preceded by
@@ -1015,8 +1065,21 @@ void LoongArch::finalizeRelax(int passes) const {
10151065 r.expr = r.sym ->hasFlag (NEEDS_PLT) ? R_PLT_PC : R_PC;
10161066 break ;
10171067 case R_LARCH_B26:
1068+ case R_LARCH_TLS_LE_LO12_R:
1069+ skip = 4 ;
1070+ write32le (p, aux.writes [writesIdx++]);
1071+ break ;
1072+ case R_LARCH_TLS_GD_PCREL20_S2:
1073+ // Note: R_LARCH_TLS_LD_PCREL20_S2 must also use R_TLSGD_PC instead
1074+ // of R_TLSLD_PC due to historical reasons. In fact, right now TLSLD
1075+ // behaves exactly like TLSGD on LoongArch.
1076+ //
1077+ // This reason has also been mentioned in mold commit:
1078+ // https://github.com/rui314/mold/commit/5dfa1cf07c03bd57cb3d493b652ef22441bcd71c
1079+ case R_LARCH_TLS_LD_PCREL20_S2:
10181080 skip = 4 ;
10191081 write32le (p, aux.writes [writesIdx++]);
1082+ r.expr = R_TLSGD_PC;
10201083 break ;
10211084 default :
10221085 llvm_unreachable (" unsupported type" );
0 commit comments