Changeset View
Changeset View
Standalone View
Standalone View
llvm/trunk/tools/llvm-objcopy/Object.cpp
Show First 20 Lines • Show All 403 Lines • ▼ Show 20 Lines | |||||
// range. | // range. | ||||
static bool segmentOverlapsSegment(const Segment &Child, | static bool segmentOverlapsSegment(const Segment &Child, | ||||
const Segment &Parent) { | const Segment &Parent) { | ||||
return Parent.OriginalOffset <= Child.OriginalOffset && | return Parent.OriginalOffset <= Child.OriginalOffset && | ||||
Parent.OriginalOffset + Parent.FileSize > Child.OriginalOffset; | Parent.OriginalOffset + Parent.FileSize > Child.OriginalOffset; | ||||
} | } | ||||
static bool compareSegments(const Segment *A, const Segment *B) { | static bool compareSegmentsByOffset(const Segment *A, const Segment *B) { | ||||
// Any segment without a parent segment should come before a segment | // Any segment without a parent segment should come before a segment | ||||
// that has a parent segment. | // that has a parent segment. | ||||
if (A->OriginalOffset < B->OriginalOffset) | if (A->OriginalOffset < B->OriginalOffset) | ||||
return true; | return true; | ||||
if (A->OriginalOffset > B->OriginalOffset) | if (A->OriginalOffset > B->OriginalOffset) | ||||
return false; | return false; | ||||
return A->Index < B->Index; | return A->Index < B->Index; | ||||
} | } | ||||
static bool compareSegmentsByPAddr(const Segment *A, const Segment *B) { | |||||
if (A->PAddr < B->PAddr) | |||||
return true; | |||||
if (A->PAddr > B->PAddr) | |||||
return false; | |||||
return A->Index < B->Index; | |||||
} | |||||
template <class ELFT> | template <class ELFT> | ||||
void Object<ELFT>::readProgramHeaders(const ELFFile<ELFT> &ElfFile) { | void Object<ELFT>::readProgramHeaders(const ELFFile<ELFT> &ElfFile) { | ||||
uint32_t Index = 0; | uint32_t Index = 0; | ||||
for (const auto &Phdr : unwrapOrError(ElfFile.program_headers())) { | for (const auto &Phdr : unwrapOrError(ElfFile.program_headers())) { | ||||
ArrayRef<uint8_t> Data{ElfFile.base() + Phdr.p_offset, | ArrayRef<uint8_t> Data{ElfFile.base() + Phdr.p_offset, | ||||
(size_t)Phdr.p_filesz}; | (size_t)Phdr.p_filesz}; | ||||
Segments.emplace_back(llvm::make_unique<Segment>(Data)); | Segments.emplace_back(llvm::make_unique<Segment>(Data)); | ||||
Segment &Seg = *Segments.back(); | Segment &Seg = *Segments.back(); | ||||
Show All 21 Lines | void Object<ELFT>::readProgramHeaders(const ELFFile<ELFT> &ElfFile) { | ||||
// segments. | // segments. | ||||
for (auto &Child : Segments) { | for (auto &Child : Segments) { | ||||
for (auto &Parent : Segments) { | for (auto &Parent : Segments) { | ||||
// Every segment will overlap with itself but we don't want a segment to | // Every segment will overlap with itself but we don't want a segment to | ||||
// be it's own parent so we avoid that situation. | // be it's own parent so we avoid that situation. | ||||
if (&Child != &Parent && segmentOverlapsSegment(*Child, *Parent)) { | if (&Child != &Parent && segmentOverlapsSegment(*Child, *Parent)) { | ||||
// We want a canonical "most parental" segment but this requires | // We want a canonical "most parental" segment but this requires | ||||
// inspecting the ParentSegment. | // inspecting the ParentSegment. | ||||
if (compareSegments(Parent.get(), Child.get())) | if (compareSegmentsByOffset(Parent.get(), Child.get())) | ||||
if (Child->ParentSegment == nullptr || | if (Child->ParentSegment == nullptr || | ||||
compareSegments(Parent.get(), Child->ParentSegment)) { | compareSegmentsByOffset(Parent.get(), Child->ParentSegment)) { | ||||
Child->ParentSegment = Parent.get(); | Child->ParentSegment = Parent.get(); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
template <class ELFT> | template <class ELFT> | ||||
▲ Show 20 Lines • Show All 309 Lines • ▼ Show 20 Lines | static uint64_t alignToAddr(uint64_t Offset, uint64_t Addr, uint64_t Align) { | ||||
// (Offset + Diff) & -Align == Addr & -Align will still hold. | // (Offset + Diff) & -Align == Addr & -Align will still hold. | ||||
if (Diff < 0) | if (Diff < 0) | ||||
Diff += Align; | Diff += Align; | ||||
return Offset + Diff; | return Offset + Diff; | ||||
} | } | ||||
// Orders segments such that if x = y->ParentSegment then y comes before x. | // Orders segments such that if x = y->ParentSegment then y comes before x. | ||||
static void OrderSegments(std::vector<Segment *> &Segments) { | static void OrderSegments(std::vector<Segment *> &Segments) { | ||||
std::stable_sort(std::begin(Segments), std::end(Segments), compareSegments); | std::stable_sort(std::begin(Segments), std::end(Segments), | ||||
compareSegmentsByOffset); | |||||
} | } | ||||
// This function finds a consistent layout for a list of segments starting from | // This function finds a consistent layout for a list of segments starting from | ||||
// an Offset. It assumes that Segments have been sorted by OrderSegments and | // an Offset. It assumes that Segments have been sorted by OrderSegments and | ||||
// returns an Offset one past the end of the last segment. | // returns an Offset one past the end of the last segment. | ||||
static uint64_t LayoutSegments(std::vector<Segment *> &Segments, | static uint64_t LayoutSegments(std::vector<Segment *> &Segments, | ||||
uint64_t Offset) { | uint64_t Offset) { | ||||
assert(std::is_sorted(std::begin(Segments), std::end(Segments), | assert(std::is_sorted(std::begin(Segments), std::end(Segments), | ||||
compareSegments)); | compareSegmentsByOffset)); | ||||
// The only way a segment should move is if a section was between two | // The only way a segment should move is if a section was between two | ||||
// segments and that section was removed. If that section isn't in a segment | // segments and that section was removed. If that section isn't in a segment | ||||
// then it's acceptable, but not ideal, to simply move it to after the | // then it's acceptable, but not ideal, to simply move it to after the | ||||
// segments. So we can simply layout segments one after the other accounting | // segments. So we can simply layout segments one after the other accounting | ||||
// for alignment. | // for alignment. | ||||
for (auto &Segment : Segments) { | for (auto &Segment : Segments) { | ||||
// We assume that segments have been ordered by OriginalOffset and Index | // We assume that segments have been ordered by OriginalOffset and Index | ||||
// such that a parent segment will always come before a child segment in | // such that a parent segment will always come before a child segment in | ||||
▲ Show 20 Lines • Show All 137 Lines • ▼ Show 20 Lines | template <class ELFT> void BinaryObject<ELFT>::finalize() { | ||||
// that will affect layout of allocated sections so we only add those. | // that will affect layout of allocated sections so we only add those. | ||||
std::vector<Segment *> OrderedSegments; | std::vector<Segment *> OrderedSegments; | ||||
for (auto &Section : this->Sections) { | for (auto &Section : this->Sections) { | ||||
if ((Section->Flags & SHF_ALLOC) != 0 && | if ((Section->Flags & SHF_ALLOC) != 0 && | ||||
Section->ParentSegment != nullptr) { | Section->ParentSegment != nullptr) { | ||||
OrderedSegments.push_back(Section->ParentSegment); | OrderedSegments.push_back(Section->ParentSegment); | ||||
} | } | ||||
} | } | ||||
OrderSegments(OrderedSegments); | |||||
// For binary output, we're going to use physical addresses instead of | |||||
// virtual addresses, since a binary output is used for cases like ROM | |||||
// loading and physical addresses are intended for ROM loading. | |||||
// However, if no segment has a physical address, we'll fallback to using | |||||
// virtual addresses for all. | |||||
if (std::all_of(std::begin(OrderedSegments), std::end(OrderedSegments), | |||||
[](const Segment *Segment) { return Segment->PAddr == 0; })) | |||||
for (const auto &Segment : OrderedSegments) | |||||
Segment->PAddr = Segment->VAddr; | |||||
std::stable_sort(std::begin(OrderedSegments), std::end(OrderedSegments), | |||||
compareSegmentsByPAddr); | |||||
// Because we add a ParentSegment for each section we might have duplicate | // Because we add a ParentSegment for each section we might have duplicate | ||||
// segments in OrderedSegments. If there were duplicates then LayoutSegments | // segments in OrderedSegments. If there were duplicates then LayoutSegments | ||||
// would do very strange things. | // would do very strange things. | ||||
auto End = | auto End = | ||||
std::unique(std::begin(OrderedSegments), std::end(OrderedSegments)); | std::unique(std::begin(OrderedSegments), std::end(OrderedSegments)); | ||||
OrderedSegments.erase(End, std::end(OrderedSegments)); | OrderedSegments.erase(End, std::end(OrderedSegments)); | ||||
uint64_t Offset = 0; | |||||
// Modify the first segment so that there is no gap at the start. This allows | // Modify the first segment so that there is no gap at the start. This allows | ||||
// our layout algorithm to proceed as expected while not out writing out the | // our layout algorithm to proceed as expected while not out writing out the | ||||
// gap at the start. | // gap at the start. | ||||
if (!OrderedSegments.empty()) { | if (!OrderedSegments.empty()) { | ||||
auto Seg = OrderedSegments[0]; | auto Seg = OrderedSegments[0]; | ||||
auto Sec = Seg->firstSection(); | auto Sec = Seg->firstSection(); | ||||
auto Diff = Sec->OriginalOffset - Seg->OriginalOffset; | auto Diff = Sec->OriginalOffset - Seg->OriginalOffset; | ||||
Seg->OriginalOffset += Diff; | Seg->OriginalOffset += Diff; | ||||
// The size needs to be shrunk as well | // The size needs to be shrunk as well. | ||||
Seg->FileSize -= Diff; | Seg->FileSize -= Diff; | ||||
Seg->MemSize -= Diff; | // The PAddr needs to be increased to remove the gap before the first | ||||
// The VAddr needs to be adjusted so that the alignment is correct as well | // section. | ||||
Seg->VAddr += Diff; | Seg->PAddr += Diff; | ||||
Seg->PAddr = Seg->VAddr; | uint64_t LowestPAddr = Seg->PAddr; | ||||
// We don't want this to be shifted by alignment so we need to set the | for (auto &Segment : OrderedSegments) { | ||||
// alignment to zero. | Segment->Offset = Segment->PAddr - LowestPAddr; | ||||
Seg->Align = 0; | Offset = std::max(Offset, Segment->Offset + Segment->FileSize); | ||||
} | |||||
} | } | ||||
uint64_t Offset = LayoutSegments(OrderedSegments, 0); | |||||
// TODO: generalize LayoutSections to take a range. Pass a special range | // TODO: generalize LayoutSections to take a range. Pass a special range | ||||
// constructed from an iterator that skips values for which a predicate does | // constructed from an iterator that skips values for which a predicate does | ||||
// not hold. Then pass such a range to LayoutSections instead of constructing | // not hold. Then pass such a range to LayoutSections instead of constructing | ||||
// AllocatedSections here. | // AllocatedSections here. | ||||
std::vector<SectionBase *> AllocatedSections; | std::vector<SectionBase *> AllocatedSections; | ||||
for (auto &Section : this->Sections) { | for (auto &Section : this->Sections) { | ||||
if ((Section->Flags & SHF_ALLOC) == 0) | if ((Section->Flags & SHF_ALLOC) == 0) | ||||
Show All 34 Lines |