Skip to content

Commit 1ea127e

Browse files
SixWeiningAmi-zhang
authored andcommitted
[lld][LoongArch] Handle extreme code model relocs according to psABI v2.30 (#73387)
psABI v2.30 requires the extreme code model instructions sequence (pcalau12i+addi.d+lu32i.d+lu52i.d) to be adjacent. See llvm/llvm-project#71907 and loongson-community/discussions#17 for details. (cherry picked from commit 38394a3)
1 parent 11d61b0 commit 1ea127e

File tree

4 files changed

+93
-138
lines changed

4 files changed

+93
-138
lines changed

lld/ELF/Arch/LoongArch.cpp

Lines changed: 27 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -85,89 +85,33 @@ static uint64_t getLoongArchPage(uint64_t p) {
8585
static uint32_t lo12(uint32_t val) { return val & 0xfff; }
8686

8787
// Calculate the adjusted page delta between dest and PC.
88-
uint64_t elf::getLoongArchPageDelta(uint64_t dest, uint64_t pc) {
89-
// Consider the large code model access pattern, of which the smaller code
90-
// models' access patterns are a subset:
91-
//
92-
// pcalau12i U, %foo_hi20(sym) ; b in [-0x80000, 0x7ffff]
93-
// addi.d T, zero, %foo_lo12(sym) ; a in [-0x800, 0x7ff]
94-
// lu32i.d T, %foo64_lo20(sym) ; c in [-0x80000, 0x7ffff]
95-
// lu52i.d T, T, %foo64_hi12(sym) ; d in [-0x800, 0x7ff]
96-
// {ldx,stx,add}.* dest, U, T
97-
//
98-
// Let page(pc) = 0xRRR'QQQQQ'PPPPP'000 and dest = 0xZZZ'YYYYY'XXXXX'AAA,
99-
// with RQ, P, ZY, X and A representing the respective bitfields as unsigned
100-
// integers. We have:
101-
//
102-
// page(dest) = 0xZZZ'YYYYY'XXXXX'000
103-
// - page(pc) = 0xRRR'QQQQQ'PPPPP'000
104-
// ----------------------------------
105-
// 0xddd'ccccc'bbbbb'000
106-
//
107-
// Now consider the above pattern's actual effects:
108-
//
109-
// page(pc) 0xRRR'QQQQQ'PPPPP'000
110-
// pcalau12i + 0xiii'iiiii'bbbbb'000
111-
// addi + 0xjjj'jjjjj'kkkkk'AAA
112-
// lu32i.d & lu52i.d + 0xddd'ccccc'00000'000
113-
// --------------------------------------------------
114-
// dest = U + T
115-
// = ((RQ<<32) + (P<<12) + i + (b<<12)) + (j + k + A + (cd<<32))
116-
// = (((RQ+cd)<<32) + i + j) + (((P+b)<<12) + k) + A
117-
// = (ZY<<32) + (X<<12) + A
118-
//
119-
// ZY<<32 = (RQ<<32)+(cd<<32)+i+j, X<<12 = (P<<12)+(b<<12)+k
120-
// cd<<32 = (ZY<<32)-(RQ<<32)-i-j, b<<12 = (X<<12)-(P<<12)-k
121-
//
122-
// where i and k are terms representing the effect of b's and A's sign
123-
// extension respectively.
124-
//
125-
// i = signed b < 0 ? -0x10000'0000 : 0
126-
// k = signed A < 0 ? -0x1000 : 0
127-
//
128-
// The j term is a bit complex: it represents the higher half of
129-
// sign-extended bits from A that are effectively lost if i == 0 but k != 0,
130-
// due to overwriting by lu32i.d & lu52i.d.
131-
//
132-
// j = signed A < 0 && signed b >= 0 ? 0x10000'0000 : 0
133-
//
134-
// The actual effect of the instruction sequence before the final addition,
135-
// i.e. our desired result value, is thus:
136-
//
137-
// result = (cd<<32) + (b<<12)
138-
// = (ZY<<32)-(RQ<<32)-i-j + (X<<12)-(P<<12)-k
139-
// = ((ZY<<32)+(X<<12)) - ((RQ<<32)+(P<<12)) - i - j - k
140-
// = page(dest) - page(pc) - i - j - k
141-
//
142-
// when signed A >= 0 && signed b >= 0:
143-
//
144-
// i = j = k = 0
145-
// result = page(dest) - page(pc)
146-
//
147-
// when signed A >= 0 && signed b < 0:
148-
//
149-
// i = -0x10000'0000, j = k = 0
150-
// result = page(dest) - page(pc) + 0x10000'0000
151-
//
152-
// when signed A < 0 && signed b >= 0:
153-
//
154-
// i = 0, j = 0x10000'0000, k = -0x1000
155-
// result = page(dest) - page(pc) - 0x10000'0000 + 0x1000
156-
//
157-
// when signed A < 0 && signed b < 0:
158-
//
159-
// i = -0x10000'0000, j = 0, k = -0x1000
160-
// result = page(dest) - page(pc) + 0x1000
161-
uint64_t result = getLoongArchPage(dest) - getLoongArchPage(pc);
162-
bool negativeA = lo12(dest) > 0x7ff;
163-
bool negativeB = (result & 0x8000'0000) != 0;
164-
165-
if (negativeA)
166-
result += 0x1000;
167-
if (negativeA && !negativeB)
168-
result -= 0x10000'0000;
169-
else if (!negativeA && negativeB)
170-
result += 0x10000'0000;
88+
uint64_t elf::getLoongArchPageDelta(uint64_t dest, uint64_t pc, RelType type) {
89+
// Note that if the sequence being relocated is `pcalau12i + addi.d + lu32i.d
90+
// + lu52i.d`, they must be adjancent so that we can infer the PC of
91+
// `pcalau12i` when calculating the page delta for the other two instructions
92+
// (lu32i.d and lu52i.d). Compensate all the sign-extensions is a bit
93+
// complicated. Just use psABI recommended algorithm.
94+
uint64_t pcalau12i_pc;
95+
switch (type) {
96+
case R_LARCH_PCALA64_LO20:
97+
case R_LARCH_GOT64_PC_LO20:
98+
case R_LARCH_TLS_IE64_PC_LO20:
99+
pcalau12i_pc = pc - 8;
100+
break;
101+
case R_LARCH_PCALA64_HI12:
102+
case R_LARCH_GOT64_PC_HI12:
103+
case R_LARCH_TLS_IE64_PC_HI12:
104+
pcalau12i_pc = pc - 12;
105+
break;
106+
default:
107+
pcalau12i_pc = pc;
108+
break;
109+
}
110+
uint64_t result = getLoongArchPage(dest) - getLoongArchPage(pcalau12i_pc);
111+
if (dest & 0x800)
112+
result += 0x1000 - 0x1'0000'0000;
113+
if (result & 0x8000'0000)
114+
result += 0x1'0000'0000;
171115
return result;
172116
}
173117

lld/ELF/InputSection.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -712,8 +712,8 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
712712
return sym.getGotVA() + a - p;
713713
case R_LOONGARCH_GOT_PAGE_PC:
714714
if (sym.hasFlag(NEEDS_TLSGD))
715-
return getLoongArchPageDelta(in.got->getGlobalDynAddr(sym) + a, p);
716-
return getLoongArchPageDelta(sym.getGotVA() + a, p);
715+
return getLoongArchPageDelta(in.got->getGlobalDynAddr(sym) + a, p, type);
716+
return getLoongArchPageDelta(sym.getGotVA() + a, p, type);
717717
case R_MIPS_GOTREL:
718718
return sym.getVA(a) - in.mipsGot->getGp(file);
719719
case R_MIPS_GOT_GP:
@@ -763,7 +763,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
763763
return 0;
764764
}
765765
case R_LOONGARCH_PAGE_PC:
766-
return getLoongArchPageDelta(sym.getVA(a), p);
766+
return getLoongArchPageDelta(sym.getVA(a), p, type);
767767
case R_PC:
768768
case R_ARM_PCA: {
769769
uint64_t dest;
@@ -798,7 +798,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
798798
case R_PPC64_CALL_PLT:
799799
return sym.getPltVA() + a - p;
800800
case R_LOONGARCH_PLT_PAGE_PC:
801-
return getLoongArchPageDelta(sym.getPltVA() + a, p);
801+
return getLoongArchPageDelta(sym.getPltVA() + a, p, type);
802802
case R_PLT_GOTPLT:
803803
return sym.getPltVA() + a - in.gotPlt->getVA();
804804
case R_PPC32_PLTREL:
@@ -860,7 +860,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
860860
case R_TLSGD_PC:
861861
return in.got->getGlobalDynAddr(sym) + a - p;
862862
case R_LOONGARCH_TLSGD_PAGE_PC:
863-
return getLoongArchPageDelta(in.got->getGlobalDynAddr(sym) + a, p);
863+
return getLoongArchPageDelta(in.got->getGlobalDynAddr(sym) + a, p, type);
864864
case R_TLSLD_GOTPLT:
865865
return in.got->getVA() + in.got->getTlsIndexOff() + a - in.gotPlt->getVA();
866866
case R_TLSLD_GOT:

lld/ELF/Target.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ void addPPC64SaveRestore();
229229
uint64_t getPPC64TocBase();
230230
uint64_t getAArch64Page(uint64_t expr);
231231
template <typename ELFT> void writeARMCmseImportLib();
232-
uint64_t getLoongArchPageDelta(uint64_t dest, uint64_t pc);
232+
uint64_t getLoongArchPageDelta(uint64_t dest, uint64_t pc, RelType type);
233233
void riscvFinalizeRelax(int passes);
234234
void mergeRISCVAttributesSections();
235235
void addArmInputSectionMappingSymbols();

0 commit comments

Comments
 (0)