Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Commit c127e0c

Browse files
committed
[llvm-objcopy] Use physical instead of virtual address when aligning and placing sections in binary
For sections with different virtual and physical addresses, alignment and placement in the output binary should be based on the physical address. Ran into this problem with a bare metal ARM project where llvm-objcopy added a lot of zero-padding before the .data section that had differing addresses. GNU objcopy did not add the padding, and after this fix, neither does llvm-objcopy. Update a test case so a section has different physical and virtual addresses. Fixes B35708 Authored By: Owen Shaw (owenpshaw) Differential Revision: https://reviews.llvm.org/D41619 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@323144 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent ca19eaa commit c127e0c

File tree

7 files changed

+139
-28
lines changed

7 files changed

+139
-28
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# RUN: yaml2obj %s -o %t
2+
# RUN: llvm-objcopy -O binary %t %t2
3+
# RUN: od -t x2 -v %t2 | FileCheck %s
4+
# RUN: wc -c < %t2 | FileCheck %s --check-prefix=SIZE
5+
6+
!ELF
7+
FileHeader:
8+
Class: ELFCLASS64
9+
Data: ELFDATA2LSB
10+
Type: ET_EXEC
11+
Machine: EM_X86_64
12+
Sections:
13+
- Name: .text
14+
Type: SHT_PROGBITS
15+
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
16+
Address: 0x1000
17+
AddressAlign: 0x0000000000001000
18+
Content: "c3c3c3c3"
19+
- Name: .data
20+
Type: SHT_PROGBITS
21+
Flags: [ SHF_ALLOC ]
22+
Address: 0x1004
23+
AddressAlign: 0x0000000000000004
24+
Content: "3232"
25+
ProgramHeaders:
26+
- Type: PT_LOAD
27+
Flags: [ PF_X, PF_R ]
28+
VAddr: 0x1000
29+
PAddr: 0x0000
30+
Align: 0x1000
31+
Sections:
32+
- Section: .text
33+
- Type: PT_LOAD
34+
Flags: [ PF_R, PF_W ]
35+
VAddr: 0x1004
36+
PAddr: 0x0000
37+
Align: 0x1000
38+
Sections:
39+
- Section: .data
40+
41+
# CHECK: 0000000 c3c3 c3c3 3232
42+
# SIZE: 6
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# RUN: yaml2obj %s -o %t
2+
# RUN: llvm-objcopy -O binary %t %t2
3+
# RUN: od -t x2 %t2 | FileCheck %s
4+
# RUN: wc -c < %t2 | FileCheck %s --check-prefix=SIZE
5+
6+
!ELF
7+
FileHeader:
8+
Class: ELFCLASS64
9+
Data: ELFDATA2LSB
10+
Type: ET_EXEC
11+
Machine: EM_X86_64
12+
Sections:
13+
- Name: .text
14+
Type: SHT_PROGBITS
15+
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
16+
Address: 0x1000
17+
AddressAlign: 0x0000000000001000
18+
Content: "c3c3c3c3"
19+
- Name: .data
20+
Type: SHT_PROGBITS
21+
Flags: [ SHF_ALLOC ]
22+
Address: 0x2000
23+
AddressAlign: 0x0000000000001000
24+
Content: "3232"
25+
ProgramHeaders:
26+
- Type: PT_LOAD
27+
Flags: [ PF_X, PF_R ]
28+
VAddr: 0x1000
29+
PAddr: 0x1000
30+
Align: 0x1000
31+
Sections:
32+
- Section: .text
33+
- Type: PT_LOAD
34+
Flags: [ PF_R, PF_W ]
35+
VAddr: 0x2000
36+
PAddr: 0x4000
37+
Align: 0x1000
38+
Sections:
39+
- Section: .data
40+
41+
# CHECK: 0000000 c3c3 c3c3 0000 0000 0000 0000 0000 0000
42+
# CHECK-NEXT: 0000020 0000 0000 0000 0000 0000 0000 0000 0000
43+
# CHECK-NEXT: *
44+
# CHECK-NEXT: 0030000 3232
45+
# SIZE: 12290

test/tools/llvm-objcopy/basic-align-copy.test renamed to test/tools/llvm-objcopy/binary-segment-layout.test

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,25 @@ Sections:
1414
Type: SHT_PROGBITS
1515
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
1616
AddressAlign: 0x0000000000001000
17+
Address: 0x00
1718
Content: "c3c3c3c3"
1819
- Name: .data
1920
Type: SHT_PROGBITS
2021
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
21-
AddressAlign: 0x0000000000001000
22+
AddressAlign: 0x0000000000000008
23+
Address: 0x08
2224
Content: "3232"
2325
ProgramHeaders:
2426
- Type: PT_LOAD
2527
Flags: [ PF_X, PF_R ]
28+
VAddr: 0x00
2629
Sections:
2730
- Section: .text
2831
- Type: PT_LOAD
2932
Flags: [ PF_R ]
33+
VAddr: 0x08
3034
Sections:
3135
- Section: .data
3236

33-
# CHECK: 0000000 c3c3 c3c3 0000 0000 0000 0000 0000 0000
34-
# CHECK-NEXT: 0000020 0000 0000 0000 0000 0000 0000 0000 0000
35-
# CHECK-NEXT: *
36-
# CHECK-NEXT: 0010000 3232
37-
# SIZE: 4098
37+
# CHECK: 0000000 c3c3 c3c3 0000 0000 3232
38+
# SIZE: 10

test/tools/llvm-objcopy/two-seg-remove-end.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ ProgramHeaders:
4848
- Section: .text2
4949
- Type: PT_LOAD
5050
Flags: [ PF_R ]
51-
VAddr: 0x1000
52-
PAddr: 0x1000
51+
VAddr: 0x3000
52+
PAddr: 0x3000
5353
Sections:
5454
- Section: .text3
5555
- Section: .text4

test/tools/llvm-objcopy/two-seg-remove-first.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ ProgramHeaders:
4848
- Section: .text2
4949
- Type: PT_LOAD
5050
Flags: [ PF_R ]
51-
VAddr: 0x1000
52-
PAddr: 0x1000
51+
VAddr: 0x3000
52+
PAddr: 0x3000
5353
Sections:
5454
- Section: .text3
5555
- Section: .text4

test/tools/llvm-objcopy/two-seg-remove-third-sec.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ ProgramHeaders:
4848
- Section: .text2
4949
- Type: PT_LOAD
5050
Flags: [ PF_R ]
51-
VAddr: 0x1000
52-
PAddr: 0x1000
51+
VAddr: 0x3000
52+
PAddr: 0x3000
5353
Sections:
5454
- Section: .text3
5555
- Section: .text4

tools/llvm-objcopy/Object.cpp

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ static bool segmentOverlapsSegment(const Segment &Child,
409409
Parent.OriginalOffset + Parent.FileSize > Child.OriginalOffset;
410410
}
411411

412-
static bool compareSegments(const Segment *A, const Segment *B) {
412+
static bool compareSegmentsByOffset(const Segment *A, const Segment *B) {
413413
// Any segment without a parent segment should come before a segment
414414
// that has a parent segment.
415415
if (A->OriginalOffset < B->OriginalOffset)
@@ -419,6 +419,14 @@ static bool compareSegments(const Segment *A, const Segment *B) {
419419
return A->Index < B->Index;
420420
}
421421

422+
static bool compareSegmentsByPAddr(const Segment *A, const Segment *B) {
423+
if (A->PAddr < B->PAddr)
424+
return true;
425+
if (A->PAddr > B->PAddr)
426+
return false;
427+
return A->Index < B->Index;
428+
}
429+
422430
template <class ELFT>
423431
void Object<ELFT>::readProgramHeaders(const ELFFile<ELFT> &ElfFile) {
424432
uint32_t Index = 0;
@@ -456,9 +464,9 @@ void Object<ELFT>::readProgramHeaders(const ELFFile<ELFT> &ElfFile) {
456464
if (&Child != &Parent && segmentOverlapsSegment(*Child, *Parent)) {
457465
// We want a canonical "most parental" segment but this requires
458466
// inspecting the ParentSegment.
459-
if (compareSegments(Parent.get(), Child.get()))
467+
if (compareSegmentsByOffset(Parent.get(), Child.get()))
460468
if (Child->ParentSegment == nullptr ||
461-
compareSegments(Parent.get(), Child->ParentSegment)) {
469+
compareSegmentsByOffset(Parent.get(), Child->ParentSegment)) {
462470
Child->ParentSegment = Parent.get();
463471
}
464472
}
@@ -784,7 +792,8 @@ static uint64_t alignToAddr(uint64_t Offset, uint64_t Addr, uint64_t Align) {
784792

785793
// Orders segments such that if x = y->ParentSegment then y comes before x.
786794
static void OrderSegments(std::vector<Segment *> &Segments) {
787-
std::stable_sort(std::begin(Segments), std::end(Segments), compareSegments);
795+
std::stable_sort(std::begin(Segments), std::end(Segments),
796+
compareSegmentsByOffset);
788797
}
789798

790799
// This function finds a consistent layout for a list of segments starting from
@@ -793,7 +802,7 @@ static void OrderSegments(std::vector<Segment *> &Segments) {
793802
static uint64_t LayoutSegments(std::vector<Segment *> &Segments,
794803
uint64_t Offset) {
795804
assert(std::is_sorted(std::begin(Segments), std::end(Segments),
796-
compareSegments));
805+
compareSegmentsByOffset));
797806
// The only way a segment should move is if a section was between two
798807
// segments and that section was removed. If that section isn't in a segment
799808
// then it's acceptable, but not ideal, to simply move it to after the
@@ -947,14 +956,29 @@ template <class ELFT> void BinaryObject<ELFT>::finalize() {
947956
OrderedSegments.push_back(Section->ParentSegment);
948957
}
949958
}
950-
OrderSegments(OrderedSegments);
959+
960+
// For binary output, we're going to use physical addresses instead of
961+
// virtual addresses, since a binary output is used for cases like ROM
962+
// loading and physical addresses are intended for ROM loading.
963+
// However, if no segment has a physical address, we'll fallback to using
964+
// virtual addresses for all.
965+
if (std::all_of(std::begin(OrderedSegments), std::end(OrderedSegments),
966+
[](const Segment *Segment) { return Segment->PAddr == 0; }))
967+
for (const auto &Segment : OrderedSegments)
968+
Segment->PAddr = Segment->VAddr;
969+
970+
std::stable_sort(std::begin(OrderedSegments), std::end(OrderedSegments),
971+
compareSegmentsByPAddr);
972+
951973
// Because we add a ParentSegment for each section we might have duplicate
952974
// segments in OrderedSegments. If there were duplicates then LayoutSegments
953975
// would do very strange things.
954976
auto End =
955977
std::unique(std::begin(OrderedSegments), std::end(OrderedSegments));
956978
OrderedSegments.erase(End, std::end(OrderedSegments));
957979

980+
uint64_t Offset = 0;
981+
958982
// Modify the first segment so that there is no gap at the start. This allows
959983
// our layout algorithm to proceed as expected while not out writing out the
960984
// gap at the start.
@@ -963,19 +987,18 @@ template <class ELFT> void BinaryObject<ELFT>::finalize() {
963987
auto Sec = Seg->firstSection();
964988
auto Diff = Sec->OriginalOffset - Seg->OriginalOffset;
965989
Seg->OriginalOffset += Diff;
966-
// The size needs to be shrunk as well
990+
// The size needs to be shrunk as well.
967991
Seg->FileSize -= Diff;
968-
Seg->MemSize -= Diff;
969-
// The VAddr needs to be adjusted so that the alignment is correct as well
970-
Seg->VAddr += Diff;
971-
Seg->PAddr = Seg->VAddr;
972-
// We don't want this to be shifted by alignment so we need to set the
973-
// alignment to zero.
974-
Seg->Align = 0;
992+
// The PAddr needs to be increased to remove the gap before the first
993+
// section.
994+
Seg->PAddr += Diff;
995+
uint64_t LowestPAddr = Seg->PAddr;
996+
for (auto &Segment : OrderedSegments) {
997+
Segment->Offset = Segment->PAddr - LowestPAddr;
998+
Offset = std::max(Offset, Segment->Offset + Segment->FileSize);
999+
}
9751000
}
9761001

977-
uint64_t Offset = LayoutSegments(OrderedSegments, 0);
978-
9791002
// TODO: generalize LayoutSections to take a range. Pass a special range
9801003
// constructed from an iterator that skips values for which a predicate does
9811004
// not hold. Then pass such a range to LayoutSections instead of constructing

0 commit comments

Comments
 (0)