Skip to content

Commit cb44773

Browse files
alx32BaiXilin
authored andcommitted
[lld-macho] Fix branch extension thunk estimation logic (llvm#120529)
This patch improves the linker’s ability to estimate stub reachability in the `TextOutputSection::estimateStubsInRangeVA` function. It does so by including thunks that have already been placed ahead of the current call site address when calculating the threshold for direct stub calls. Before this fix, the estimation process overlooked existing forward thunks. This could result in some thunks not being inserted where needed. In rare situations, particularly with large and specially arranged codebases, this might lead to branch instructions being out of range, causing linking errors. Although this patch successfully addresses the problem, it is not feasible to create a test for this issue. The specific layout and order of thunk creation required to reproduce the corner case are too complex, making test creation impractical. Example error messages the issue could generate: ``` ld64.lld: error: banana.o:(symbol OUTLINED_FUNCTION_24949_3875): relocation BRANCH26 is out of range: 134547892 is not in [-134217728, 134217727]; references objc_autoreleaseReturnValue ld64.lld: error: main.o:(symbol _main+0xc): relocation BRANCH26 is out of range: 134544132 is not in [-134217728, 134217727]; references objc_release ```
1 parent f9aa6a7 commit cb44773

File tree

1 file changed

+32
-4
lines changed

1 file changed

+32
-4
lines changed

lld/MachO/ConcatOutputSection.cpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,15 +184,43 @@ uint64_t TextOutputSection::estimateStubsInRangeVA(size_t callIdx) const {
184184
InputSection *isec = inputs[i];
185185
isecEnd = alignToPowerOf2(isecEnd, isec->align) + isec->getSize();
186186
}
187-
// Estimate the address after which call sites can safely call stubs
188-
// directly rather than through intermediary thunks.
187+
188+
// Tally up any thunks that have already been placed that have VA higher than
189+
// inputs[callIdx]. First, find the index of the first thunk that is beyond
190+
// the current inputs[callIdx].
191+
auto itPostcallIdxThunks =
192+
llvm::partition_point(thunks, [isecVA](const ConcatInputSection *t) {
193+
return t->getVA() <= isecVA;
194+
});
195+
uint64_t existingForwardThunks = thunks.end() - itPostcallIdxThunks;
196+
189197
uint64_t forwardBranchRange = target->forwardBranchRange;
190198
assert(isecEnd > forwardBranchRange &&
191199
"should not run thunk insertion if all code fits in jump range");
192200
assert(isecEnd - isecVA <= forwardBranchRange &&
193201
"should only finalize sections in jump range");
194-
uint64_t stubsInRangeVA = isecEnd + maxPotentialThunks * target->thunkSize +
195-
in.stubs->getSize() - forwardBranchRange;
202+
203+
// Estimate the maximum size of the code, right before the stubs section.
204+
uint64_t maxTextSize = 0;
205+
// Add the size of all the inputs, including the unprocessed ones.
206+
maxTextSize += isecEnd;
207+
208+
// Add the size of the thunks that have already been created that are ahead of
209+
// inputs[callIdx]. These are already created thunks that will be interleaved
210+
// with inputs[callIdx...end].
211+
maxTextSize += existingForwardThunks * target->thunkSize;
212+
213+
// Add the size of the thunks that may be created in the future. Since
214+
// 'maxPotentialThunks' overcounts, this is an estimate of the upper limit.
215+
maxTextSize += maxPotentialThunks * target->thunkSize;
216+
217+
// Estimated maximum VA of last stub.
218+
uint64_t maxVAOfLastStub = maxTextSize + in.stubs->getSize();
219+
220+
// Estimate the address after which call sites can safely call stubs
221+
// directly rather than through intermediary thunks.
222+
uint64_t stubsInRangeVA = maxVAOfLastStub - forwardBranchRange;
223+
196224
log("thunks = " + std::to_string(thunkMap.size()) +
197225
", potential = " + std::to_string(maxPotentialThunks) +
198226
", stubs = " + std::to_string(in.stubs->getSize()) + ", isecVA = " +

0 commit comments

Comments
 (0)