Index: test/tools/llvm-objcopy/binary-no-paddr.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/binary-no-paddr.test @@ -0,0 +1,42 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy -O binary %t %t2 +# RUN: od -t x2 -v %t2 | FileCheck %s +# RUN: wc -c < %t2 | FileCheck %s --check-prefix=SIZE + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x1000 + AddressAlign: 0x0000000000001000 + Content: "c3c3c3c3" + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Address: 0x1004 + AddressAlign: 0x0000000000000004 + Content: "3232" +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_X, PF_R ] + VAddr: 0x1000 + PAddr: 0x0000 + Align: 0x1000 + Sections: + - Section: .text + - Type: PT_LOAD + Flags: [ PF_R, PF_W ] + VAddr: 0x1004 + PAddr: 0x0000 + Align: 0x1000 + Sections: + - Section: .data + +# CHECK: 0000000 c3c3 c3c3 3232 +# SIZE: 6 Index: test/tools/llvm-objcopy/binary-paddr.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/binary-paddr.test @@ -0,0 +1,42 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy -O binary %t %t2 +# RUN: od -t x2 -v %t2 | FileCheck %s +# RUN: wc -c < %t2 | FileCheck %s --check-prefix=SIZE + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x1000 + AddressAlign: 0x0000000000001000 + Content: "c3c3c3c3" + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Address: 0x2000 + AddressAlign: 0x0000000000000004 + Content: "3232" +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_X, PF_R ] + VAddr: 0x1000 + PAddr: 0x1000 + Align: 0x1000 + Sections: + - Section: .text + - Type: PT_LOAD + Flags: [ PF_R, PF_W ] + VAddr: 0x2000 + PAddr: 0x1008 + Align: 0x1000 + Sections: + - Section: .data + +# CHECK: 0000000 c3c3 c3c3 0000 0000 3232 +# SIZE: 10 Index: test/tools/llvm-objcopy/binary-segment-layout.test =================================================================== --- test/tools/llvm-objcopy/binary-segment-layout.test +++ test/tools/llvm-objcopy/binary-segment-layout.test @@ -14,24 +14,25 @@ Type: SHT_PROGBITS Flags: [ SHF_ALLOC, SHF_EXECINSTR ] AddressAlign: 0x0000000000001000 + Address: 0x00 Content: "c3c3c3c3" - Name: .data Type: SHT_PROGBITS Flags: [ SHF_ALLOC, SHF_EXECINSTR ] - AddressAlign: 0x0000000000001000 + AddressAlign: 0x0000000000000008 + Address: 0x08 Content: "3232" ProgramHeaders: - Type: PT_LOAD Flags: [ PF_X, PF_R ] + VAddr: 0x00 Sections: - Section: .text - Type: PT_LOAD Flags: [ PF_R ] + VAddr: 0x08 Sections: - Section: .data -# CHECK: 0000000 c3c3 c3c3 0000 0000 0000 0000 0000 0000 -# CHECK-NEXT: 0000020 0000 0000 0000 0000 0000 0000 0000 0000 -# CHECK-NEXT: * -# CHECK-NEXT: 0010000 3232 -# SIZE: 4098 +# CHECK: 0000000 c3c3 c3c3 0000 0000 3232 +# SIZE: 10 Index: test/tools/llvm-objcopy/two-seg-remove-end.test =================================================================== --- test/tools/llvm-objcopy/two-seg-remove-end.test +++ test/tools/llvm-objcopy/two-seg-remove-end.test @@ -48,8 +48,8 @@ - Section: .text2 - Type: PT_LOAD Flags: [ PF_R ] - VAddr: 0x1000 - PAddr: 0x1000 + VAddr: 0x3000 + PAddr: 0x3000 Sections: - Section: .text3 - Section: .text4 Index: test/tools/llvm-objcopy/two-seg-remove-first.test =================================================================== --- test/tools/llvm-objcopy/two-seg-remove-first.test +++ test/tools/llvm-objcopy/two-seg-remove-first.test @@ -48,8 +48,8 @@ - Section: .text2 - Type: PT_LOAD Flags: [ PF_R ] - VAddr: 0x1000 - PAddr: 0x1000 + VAddr: 0x3000 + PAddr: 0x3000 Sections: - Section: .text3 - Section: .text4 Index: test/tools/llvm-objcopy/two-seg-remove-third-sec.test =================================================================== --- test/tools/llvm-objcopy/two-seg-remove-third-sec.test +++ test/tools/llvm-objcopy/two-seg-remove-third-sec.test @@ -48,8 +48,8 @@ - Section: .text2 - Type: PT_LOAD Flags: [ PF_R ] - VAddr: 0x1000 - PAddr: 0x1000 + VAddr: 0x3000 + PAddr: 0x3000 Sections: - Section: .text3 - Section: .text4 Index: tools/llvm-objcopy/Object.cpp =================================================================== --- tools/llvm-objcopy/Object.cpp +++ tools/llvm-objcopy/Object.cpp @@ -409,7 +409,7 @@ 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 // that has a parent segment. if (A->OriginalOffset < B->OriginalOffset) @@ -419,6 +419,14 @@ 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 void Object::readProgramHeaders(const ELFFile &ElfFile) { uint32_t Index = 0; @@ -456,9 +464,9 @@ if (&Child != &Parent && segmentOverlapsSegment(*Child, *Parent)) { // We want a canonical "most parental" segment but this requires // inspecting the ParentSegment. - if (compareSegments(Parent.get(), Child.get())) + if (compareSegmentsByOffset(Parent.get(), Child.get())) if (Child->ParentSegment == nullptr || - compareSegments(Parent.get(), Child->ParentSegment)) { + compareSegmentsByOffset(Parent.get(), Child->ParentSegment)) { Child->ParentSegment = Parent.get(); } } @@ -784,7 +792,8 @@ // Orders segments such that if x = y->ParentSegment then y comes before x. static void OrderSegments(std::vector &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 @@ -793,7 +802,7 @@ static uint64_t LayoutSegments(std::vector &Segments, uint64_t Offset) { 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 // 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 @@ -947,7 +956,22 @@ 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 // segments in OrderedSegments. If there were duplicates then LayoutSegments // would do very strange things. @@ -955,6 +979,8 @@ std::unique(std::begin(OrderedSegments), 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 // our layout algorithm to proceed as expected while not out writing out the // gap at the start. @@ -965,17 +991,15 @@ Seg->OriginalOffset += Diff; // The size needs to be shrunk as well Seg->FileSize -= Diff; - Seg->MemSize -= Diff; - // The VAddr needs to be adjusted so that the alignment is correct as well - Seg->VAddr += Diff; - Seg->PAddr = Seg->VAddr; - // We don't want this to be shifted by alignment so we need to set the - // alignment to zero. - Seg->Align = 0; + // The PAddr needs to be increased to remove the gap + Seg->PAddr += Diff; + uint64_t LowestPAddr = Seg->PAddr; + for (auto &Segment : OrderedSegments) { + Segment->Offset = Segment->PAddr - LowestPAddr; + 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 // constructed from an iterator that skips values for which a predicate does // not hold. Then pass such a range to LayoutSections instead of constructing