@@ -133,8 +133,16 @@ bool TextOutputSection::needsThunks() const {
133
133
// we've already processed in this segment needs thunks, so do the
134
134
// rest.
135
135
bool needsThunks = parent && parent->needsThunks ;
136
+
137
+ // Calculate the total size of all branch target sections
138
+ uint64_t branchTargetsSize = in.stubs ->getSize ();
139
+
140
+ // Add the size of __objc_stubs section if it exists
141
+ if (in.objcStubs && in.objcStubs ->isNeeded ())
142
+ branchTargetsSize += in.objcStubs ->getSize ();
143
+
136
144
if (!needsThunks &&
137
- isecAddr - addr + in. stubs -> getSize () <=
145
+ isecAddr - addr + branchTargetsSize <=
138
146
std::min (target->backwardBranchRange , target->forwardBranchRange ))
139
147
return false ;
140
148
// Yes, this program is large enough to need thunks.
@@ -148,11 +156,11 @@ bool TextOutputSection::needsThunks() const {
148
156
auto *sym = cast<Symbol *>(r.referent );
149
157
// Pre-populate the thunkMap and memoize call site counts for every
150
158
// InputSection and ThunkInfo. We do this for the benefit of
151
- // estimateStubsInRangeVA ().
159
+ // estimateBranchTargetThresholdVA ().
152
160
ThunkInfo &thunkInfo = thunkMap[sym];
153
161
// Knowing ThunkInfo call site count will help us know whether or not we
154
162
// might need to create more for this referent at the time we are
155
- // estimating distance to __stubs in estimateStubsInRangeVA ().
163
+ // estimating distance to __stubs in estimateBranchTargetThresholdVA ().
156
164
++thunkInfo.callSiteCount ;
157
165
// We can avoid work on InputSections that have no BRANCH relocs.
158
166
isec->hasCallSites = true ;
@@ -161,19 +169,20 @@ bool TextOutputSection::needsThunks() const {
161
169
return true ;
162
170
}
163
171
164
- // Since __stubs is placed after __text, we must estimate the address
165
- // beyond which stubs are within range of a simple forward branch.
166
- // This is called exactly once, when the last input section has been finalized.
167
- uint64_t TextOutputSection::estimateStubsInRangeVA (size_t callIdx) const {
172
+ // Estimate the address beyond which branch targets (like __stubs and
173
+ // __objc_stubs) are within range of a simple forward branch. This is called
174
+ // exactly once, when the last input section has been finalized.
175
+ uint64_t
176
+ TextOutputSection::estimateBranchTargetThresholdVA (size_t callIdx) const {
168
177
// Tally the functions which still have call sites remaining to process,
169
178
// which yields the maximum number of thunks we might yet place.
170
179
size_t maxPotentialThunks = 0 ;
171
180
for (auto &tp : thunkMap) {
172
181
ThunkInfo &ti = tp.second ;
173
182
// This overcounts: Only sections that are in forward jump range from the
174
183
// currently-active section get finalized, and all input sections are
175
- // finalized when estimateStubsInRangeVA () is called. So only backward
176
- // jumps will need thunks, but we count all jumps.
184
+ // finalized when estimateBranchTargetThresholdVA () is called. So only
185
+ // backward jumps will need thunks, but we count all jumps.
177
186
if (ti.callSitesUsed < ti.callSiteCount )
178
187
maxPotentialThunks += 1 ;
179
188
}
@@ -200,7 +209,8 @@ uint64_t TextOutputSection::estimateStubsInRangeVA(size_t callIdx) const {
200
209
assert (isecEnd - isecVA <= forwardBranchRange &&
201
210
" should only finalize sections in jump range" );
202
211
203
- // Estimate the maximum size of the code, right before the stubs section.
212
+ // Estimate the maximum size of the code, right before the branch target
213
+ // sections.
204
214
uint64_t maxTextSize = 0 ;
205
215
// Add the size of all the inputs, including the unprocessed ones.
206
216
maxTextSize += isecEnd;
@@ -214,21 +224,35 @@ uint64_t TextOutputSection::estimateStubsInRangeVA(size_t callIdx) const {
214
224
// 'maxPotentialThunks' overcounts, this is an estimate of the upper limit.
215
225
maxTextSize += maxPotentialThunks * target->thunkSize ;
216
226
217
- // Estimated maximum VA of last stub.
218
- uint64_t maxVAOfLastStub = maxTextSize + in.stubs ->getSize ();
227
+ // Calculate the total size of all late branch target sections
228
+ uint64_t branchTargetsSize = 0 ;
229
+
230
+ // Add the size of __stubs section
231
+ branchTargetsSize += in.stubs ->getSize ();
232
+
233
+ // Add the size of __objc_stubs section if it exists
234
+ if (in.objcStubs && in.objcStubs ->isNeeded ())
235
+ branchTargetsSize += in.objcStubs ->getSize ();
236
+
237
+ // Estimated maximum VA of the last branch target.
238
+ uint64_t maxVAOfLastBranchTarget = maxTextSize + branchTargetsSize;
219
239
220
- // Estimate the address after which call sites can safely call stubs
240
+ // Estimate the address after which call sites can safely call branch targets
221
241
// directly rather than through intermediary thunks.
222
- uint64_t stubsInRangeVA = maxVAOfLastStub - forwardBranchRange;
242
+ uint64_t branchTargetThresholdVA =
243
+ maxVAOfLastBranchTarget - forwardBranchRange;
223
244
224
245
log (" thunks = " + std::to_string (thunkMap.size ()) +
225
246
" , potential = " + std::to_string (maxPotentialThunks) +
226
- " , stubs = " + std::to_string (in.stubs ->getSize ()) + " , isecVA = " +
227
- utohexstr (isecVA) + " , threshold = " + utohexstr (stubsInRangeVA) +
228
- " , isecEnd = " + utohexstr (isecEnd) +
247
+ " , stubs = " + std::to_string (in.stubs ->getSize ()) +
248
+ (in.objcStubs && in.objcStubs ->isNeeded ()
249
+ ? " , objc_stubs = " + std::to_string (in.objcStubs ->getSize ())
250
+ : " " ) +
251
+ " , isecVA = " + utohexstr (isecVA) + " , threshold = " +
252
+ utohexstr (branchTargetThresholdVA) + " , isecEnd = " + utohexstr (isecEnd) +
229
253
" , tail = " + utohexstr (isecEnd - isecVA) +
230
254
" , slop = " + utohexstr (forwardBranchRange - (isecEnd - isecVA)));
231
- return stubsInRangeVA ;
255
+ return branchTargetThresholdVA ;
232
256
}
233
257
234
258
void ConcatOutputSection::finalizeOne (ConcatInputSection *isec) {
@@ -254,7 +278,7 @@ void TextOutputSection::finalize() {
254
278
255
279
uint64_t forwardBranchRange = target->forwardBranchRange ;
256
280
uint64_t backwardBranchRange = target->backwardBranchRange ;
257
- uint64_t stubsInRangeVA = TargetInfo::outOfRangeVA;
281
+ uint64_t branchTargetThresholdVA = TargetInfo::outOfRangeVA;
258
282
size_t thunkSize = target->thunkSize ;
259
283
size_t relocCount = 0 ;
260
284
size_t callSiteCount = 0 ;
@@ -297,16 +321,18 @@ void TextOutputSection::finalize() {
297
321
if (!isec->hasCallSites )
298
322
continue ;
299
323
300
- if (finalIdx == endIdx && stubsInRangeVA == TargetInfo::outOfRangeVA) {
301
- // When we have finalized all input sections, __stubs (destined
302
- // to follow __text) comes within range of forward branches and
303
- // we can estimate the threshold address after which we can
304
- // reach any stub with a forward branch. Note that although it
305
- // sits in the middle of a loop, this code executes only once.
324
+ if (finalIdx == endIdx &&
325
+ branchTargetThresholdVA == TargetInfo::outOfRangeVA) {
326
+ // When we have finalized all input sections, branch target sections (like
327
+ // __stubs and __objc_stubs) (destined to follow __text) come within range
328
+ // of forward branches and we can estimate the threshold address after
329
+ // which we can reach any branch target with a forward branch. Note that
330
+ // although it sits in the middle of a loop, this code executes only once.
306
331
// It is in the loop because we need to call it at the proper
307
332
// time: the earliest call site from which the end of __text
308
- // (and start of __stubs) comes within range of a forward branch.
309
- stubsInRangeVA = estimateStubsInRangeVA (callIdx);
333
+ // (and start of branch target sections) comes within range of a forward
334
+ // branch.
335
+ branchTargetThresholdVA = estimateBranchTargetThresholdVA (callIdx);
310
336
}
311
337
// Process relocs by ascending address, i.e., ascending offset within isec
312
338
std::vector<Reloc> &relocs = isec->relocs ;
@@ -328,10 +354,14 @@ void TextOutputSection::finalize() {
328
354
auto *funcSym = cast<Symbol *>(r.referent );
329
355
ThunkInfo &thunkInfo = thunkMap[funcSym];
330
356
// The referent is not reachable, so we need to use a thunk ...
331
- if (funcSym->isInStubs () && callVA >= stubsInRangeVA) {
357
+ if ((funcSym->isInStubs () ||
358
+ (in.objcStubs && in.objcStubs ->isNeeded () &&
359
+ ObjCStubsSection::isObjCStubSymbol (funcSym))) &&
360
+ callVA >= branchTargetThresholdVA) {
332
361
assert (callVA != TargetInfo::outOfRangeVA);
333
- // ... Oh, wait! We are close enough to the end that __stubs
334
- // are now within range of a simple forward branch.
362
+ // ... Oh, wait! We are close enough to the end that branch target
363
+ // sections (__stubs, __objc_stubs) are now within range of a simple
364
+ // forward branch.
335
365
continue ;
336
366
}
337
367
uint64_t funcVA = funcSym->resolveBranchVA ();
0 commit comments