@@ -154,6 +154,10 @@ static uint32_t setJ20(uint32_t insn, uint32_t imm) {
154
154
return (insn & 0xfe00001f ) | (extractBits (imm, 19 , 0 ) << 5 );
155
155
}
156
156
157
+ static uint32_t setJ5 (uint32_t insn, uint32_t imm) {
158
+ return (insn & 0xfffffc1f ) | (extractBits (imm, 4 , 0 ) << 5 );
159
+ }
160
+
157
161
static uint32_t setK12 (uint32_t insn, uint32_t imm) {
158
162
return (insn & 0xffc003ff ) | (extractBits (imm, 11 , 0 ) << 10 );
159
163
}
@@ -761,10 +765,10 @@ static bool isPairRelaxable(ArrayRef<Relocation> relocs, size_t i) {
761
765
762
766
// Relax code sequence.
763
767
// 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)
766
770
// To:
767
- // pcaddi $a0, %pc_lo12(sym)
771
+ // pcaddi $a0, %pc_lo12(sym) | %got_pc_lo12(sym) | %got_pc_lo12(sym)
768
772
//
769
773
// From:
770
774
// pcalau12i $a0, %got_pc_hi20(sym_got)
@@ -778,6 +782,10 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
778
782
if (!((rHi20.type == R_LARCH_PCALA_HI20 &&
779
783
rLo12.type == R_LARCH_PCALA_LO12) ||
780
784
(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 &&
781
789
rLo12.type == R_LARCH_GOT_PC_LO12)))
782
790
return ;
783
791
@@ -798,6 +806,8 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
798
806
else if (rHi20.expr == RE_LOONGARCH_PAGE_PC ||
799
807
rHi20.expr == RE_LOONGARCH_GOT_PAGE_PC)
800
808
dest = rHi20.sym ->getVA (ctx);
809
+ else if (rHi20.expr == RE_LOONGARCH_TLSGD_PAGE_PC)
810
+ dest = ctx.in .got ->getGlobalDynAddr (*rHi20.sym );
801
811
else {
802
812
Err (ctx) << getErrorLoc (ctx, (const uint8_t *)loc) << " unknown expr ("
803
813
<< rHi20.expr << " ) against symbol " << rHi20.sym
@@ -827,7 +837,12 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i,
827
837
return ;
828
838
829
839
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;
831
846
sec.relaxAux ->writes .push_back (insn (PCADDI, getD5 (nextInsn), 0 , 0 ));
832
847
remove = 4 ;
833
848
}
@@ -863,6 +878,33 @@ static void relaxCall36(Ctx &ctx, const InputSection &sec, size_t i,
863
878
}
864
879
}
865
880
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
+
866
908
static bool relax (Ctx &ctx, InputSection &sec) {
867
909
const uint64_t secAddr = sec.getVA ();
868
910
const MutableArrayRef<Relocation> relocs = sec.relocs ();
@@ -903,6 +945,8 @@ static bool relax(Ctx &ctx, InputSection &sec) {
903
945
}
904
946
case R_LARCH_PCALA_HI20:
905
947
case R_LARCH_GOT_PC_HI20:
948
+ case R_LARCH_TLS_GD_PC_HI20:
949
+ case R_LARCH_TLS_LD_PC_HI20:
906
950
// The overflow check for i+2 will be carried out in isPairRelaxable.
907
951
if (isPairRelaxable (relocs, i))
908
952
relaxPCHi20Lo12 (ctx, sec, i, loc, r, relocs[i + 2 ], remove );
@@ -911,6 +955,12 @@ static bool relax(Ctx &ctx, InputSection &sec) {
911
955
if (relaxable (relocs, i))
912
956
relaxCall36 (ctx, sec, i, loc, r, remove );
913
957
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 ;
914
964
}
915
965
916
966
// For all anchors whose offsets are <= r.offset, they are preceded by
@@ -1015,8 +1065,21 @@ void LoongArch::finalizeRelax(int passes) const {
1015
1065
r.expr = r.sym ->hasFlag (NEEDS_PLT) ? R_PLT_PC : R_PC;
1016
1066
break ;
1017
1067
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:
1018
1080
skip = 4 ;
1019
1081
write32le (p, aux.writes [writesIdx++]);
1082
+ r.expr = R_TLSGD_PC;
1020
1083
break ;
1021
1084
default :
1022
1085
llvm_unreachable (" unsupported type" );
0 commit comments