GNU ld -r can create .rela.eh_frame with unordered r_offset values.
(With LLD, we can craft such a case by reordering sections in .eh_frame.)
This is currently unsupported and will trigger
assert(pieces[i].inputOff <= off ... in OffsetGetter::get
(the content is corrupted in a -DLLVM_ENABLE_ASSERTIONS=off build).
This patch supports this case.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
lld/ELF/InputSection.cpp | ||
---|---|---|
1329 | It is unfortunate that there are two pieces of code. |
Can (and if so should - perhaps not) we avoid this patch by fixing the input in the first place? Under what circumstances can the relocations appear out of order?
lld/ELF/InputSection.cpp | ||
---|---|---|
1329 | I might be missing something, but surely you could have some templated function that would allow you to avoid the code duplication at least? | |
1335 | This sounds like this check could cost quite a bit in a large link. Have you done any performance comparisons of before and after of such a link? Given that the normal case is that things are sorted, I think we need to be somewhat careful here. Same goes below. |
My understanding is that there is no requirement in ELF for relocations being in r_offset order even if that is how must object producers naturally generate them. This would make the inputs legal if unconventional. Although I have no numbers I'd expect a linear scan of the relocations for just EHInputSection with little computation to be small, but of course every linear scan costs. It may be possible to set a flag in EHInputSection after the first llvm::is_sorted so that only one test for the relocations being sorted is necessary.
One possible alternative, although I have little confidence it would be a better solution, is to effectively run something like a cut down scanRelocs() early for EHInputSections only. This would need to be done prior to split(). This could by construction ensure the relocations in EHInputSection were added in r_offset order and split() could use these relocations.
GNU ld -r can create out of order .rela.eh_frame, even if I *don't* use a construct like .eh_frame : { *b.o(.eh_frame) *a.o(.eh_frame) }.
This sounds like this check could cost quite a bit in a large link.
I cannot observe any performance difference adding a linear scan.
lld/ELF/InputSection.cpp | ||
---|---|---|
1329 | Not clear the trade-off is worthwhile. The template function needs to live in one header (our usage are in two .cpp files). On the other hand, there are only few lines and allocating a SmallVector and rels = sorted; cannot be dropped with a common function. |
lld/ELF/InputSection.cpp | ||
---|---|---|
1329 | The assignment can be folded in with the function call easily enough, I think. The advantage is that we don't have two places doing the same thing, potentially resulting in the code diverging in future patches. It also allows for future code reuse, and it seems not implausible we'll need this sorting elsewhere in the future. template <typename RelTy> ArrayRef<RelTy> sortRels(ArrayRef<RelTy> rels, ArrayRef<RelTy> storage) { auto cmp = [](const RelTy &a, const RelTy &b) { return a.r_offset < b.r_offset; }; if (!llvm::is_sorted(rels, cmp)) { sorted.assign(rels.begin(), rels.end()); llvm::stable_sort(storage, cmp); rels = sorted; } return rels; } template <class ELFT, class RelTy> void EhInputSection::split(ArrayRef<RelTy> rels) { SmallVector<RelTy, 0> sorted; rels = sortRels(rels, sorted); ... } |
It is unfortunate that there are two pieces of code.
RelTy is parametric so we cannot add a member in EhInputSection caching the input relocations.