[LLD] Check too large offsets into merge sections earlier

This patch moves the checking for too large offsets into merge sections
earlier.

Without this change the large offset generated in the added test-case
will cause an assert (as it happens to be a value reserved as a
"tombstone" in the DenseMap implementation) when OffsetMap is queried in
getSectionPiece().

To simplify the code and avoid future mistakes I have refactored so that
there is only one function that looks up offsets in the OffsetMap.

Differential Revision: https://reviews.llvm.org/D51180

llvm-svn: 341206
This commit is contained in:
Ben Dunbobbin 2018-08-31 11:51:51 +00:00
parent fc774e29d2
commit df6f0ad210
3 changed files with 12 additions and 23 deletions

View File

@ -1149,43 +1149,32 @@ static It fastUpperBound(It First, It Last, const T &Value, Compare Comp) {
return Comp(Value, *First) ? First : First + 1;
}
// Do binary search to get a section piece at a given input offset.
static SectionPiece *findSectionPiece(MergeInputSection *Sec, uint64_t Offset) {
if (Sec->Data.size() <= Offset)
fatal(toString(Sec) + ": entry is past the end of the section");
// Find the element this offset points to.
auto I = fastUpperBound(
Sec->Pieces.begin(), Sec->Pieces.end(), Offset,
[](const uint64_t &A, const SectionPiece &B) { return A < B.InputOff; });
--I;
return &*I;
}
SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) {
if (this->Data.size() <= Offset)
fatal(toString(this) + ": offset is outside the section");
// Find a piece starting at a given offset.
auto It = OffsetMap.find(Offset);
if (It != OffsetMap.end())
return &Pieces[It->second];
// If Offset is not at beginning of a section piece, it is not in the map.
// In that case we need to search from the original section piece vector.
return findSectionPiece(this, Offset);
// In that case we need to do a binary search of the original section piece vector.
auto I = fastUpperBound(
Pieces.begin(), Pieces.end(), Offset,
[](const uint64_t &A, const SectionPiece &B) { return A < B.InputOff; });
--I;
return &*I;
}
// Returns the offset in an output section for a given input offset.
// Because contents of a mergeable section is not contiguous in output,
// it is not just an addition to a base output offset.
uint64_t MergeInputSection::getParentOffset(uint64_t Offset) const {
// Find a string starting at a given offset.
auto It = OffsetMap.find(Offset);
if (It != OffsetMap.end())
return Pieces[It->second].OutputOff;
// If Offset is not at beginning of a section piece, it is not in the map.
// In that case we need to search from the original section piece vector.
const SectionPiece &Piece =
*findSectionPiece(const_cast<MergeInputSection *>(this), Offset);
*(const_cast<MergeInputSection *>(this)->getSectionPiece (Offset));
uint64_t Addend = Offset - Piece.InputOff;
return Piece.OutputOff + Addend;
}

View File

@ -8,4 +8,4 @@
.data
.long .rodata.str1.1 + 4
// CHECK: merge-string-error.s.tmp.o:(.rodata.str1.1): entry is past the end of the section
// CHECK: merge-string-error.s.tmp.o:(.rodata.str1.1): offset is outside the section

View File

@ -1,7 +1,7 @@
// REQUIRES: x86
// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
// RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s
// CHECK: relocation-past-merge-end.s.tmp.o:(.foo): entry is past the end of the section
// CHECK: relocation-past-merge-end.s.tmp.o:(.foo): offset is outside the section
.data
.long .foo + 10