summaryrefslogtreecommitdiffstats
path: root/llvm/tools/llvm-objcopy/Object.cpp
diff options
context:
space:
mode:
authorJake Ehrlich <jakehehrlich@google.com>2017-11-02 23:24:04 +0000
committerJake Ehrlich <jakehehrlich@google.com>2017-11-02 23:24:04 +0000
commit13153eef561c5eb3295e1d0f3018ff32b54510af (patch)
tree08d75e8f895fe9076c7fb099adefc6da24e3b1bb /llvm/tools/llvm-objcopy/Object.cpp
parent086c04c8a795778f60a243f080e18bca3a4de144 (diff)
downloadbcm5719-llvm-13153eef561c5eb3295e1d0f3018ff32b54510af.tar.gz
bcm5719-llvm-13153eef561c5eb3295e1d0f3018ff32b54510af.zip
[llvm-objcopy] Fix bug in how segment alignment was being handled
Just aligning segment offsets to segment alignment is incorrect and also wastes more space than is needed. The requirement is that p_offset == p_addr modulo p_align *not* that p_offset == 0 modulo p_align. Generally speaking we've been using p_addr == 0 modulo p_align. In fact yaml2obj can't even produce a valid situation which causes llvm-objcopy to produce incorrect results because alignment and offset were both inherited from the sections the program header covers. This change fixes this bad behavior in llvm-objcopy. Differential Revision: https://reviews.llvm.org/D39132 llvm-svn: 317284
Diffstat (limited to 'llvm/tools/llvm-objcopy/Object.cpp')
-rw-r--r--llvm/tools/llvm-objcopy/Object.cpp20
1 files changed, 17 insertions, 3 deletions
diff --git a/llvm/tools/llvm-objcopy/Object.cpp b/llvm/tools/llvm-objcopy/Object.cpp
index 22ae47f1cac..5f9864d9cc0 100644
--- a/llvm/tools/llvm-objcopy/Object.cpp
+++ b/llvm/tools/llvm-objcopy/Object.cpp
@@ -685,6 +685,19 @@ template <class ELFT> void ELFObject<ELFT>::sortSections() {
CompareSections);
}
+static uint64_t alignToAddr(uint64_t Offset, uint64_t Addr, uint64_t Align) {
+ // Calculate Diff such that (Offset + Diff) & -Align == Addr & -Align.
+ if (Align == 0)
+ Align = 1;
+ auto Diff =
+ static_cast<int64_t>(Addr % Align) - static_cast<int64_t>(Offset % Align);
+ // We only want to add to Offset, however, so if Diff < 0 we can add Align and
+ // (Offset + Diff) & -Align == Addr & -Align will still hold.
+ if (Diff < 0)
+ Diff += Align;
+ return Offset + Diff;
+}
+
template <class ELFT> void ELFObject<ELFT>::assignOffsets() {
// We need a temporary list of segments that has a special order to it
// so that we know that anytime ->ParentSegment is set that segment has
@@ -728,7 +741,7 @@ template <class ELFT> void ELFObject<ELFT>::assignOffsets() {
Segment->Offset =
Parent->Offset + Segment->OriginalOffset - Parent->OriginalOffset;
} else {
- Offset = alignTo(Offset, Segment->Align == 0 ? 1 : Segment->Align);
+ Offset = alignToAddr(Offset, Segment->VAddr, Segment->Align);
Segment->Offset = Offset;
}
Offset = std::max(Offset, Segment->Offset + Segment->FileSize);
@@ -829,8 +842,9 @@ template <class ELFT> void BinaryObject<ELFT>::finalize() {
uint64_t Offset = 0;
for (auto &Segment : this->Segments) {
- if (Segment->Type == PT_LOAD && Segment->firstSection() != nullptr) {
- Offset = alignTo(Offset, Segment->Align);
+ if (Segment->Type == llvm::ELF::PT_LOAD &&
+ Segment->firstSection() != nullptr) {
+ Offset = alignToAddr(Offset, Segment->VAddr, Segment->Align);
Segment->Offset = Offset;
Offset += Segment->FileSize;
}
OpenPOWER on IntegriCloud