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