Index: test/tools/llvm-objcopy/basic-align-copy.test =================================================================== --- test/tools/llvm-objcopy/basic-align-copy.test +++ test/tools/llvm-objcopy/basic-align-copy.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 + 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/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: 0x1004 + Align: 0x1000 + Sections: + - Section: .data + +# CHECK: 0000000 c3c3 c3c3 3232 +# SIZE: 6 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 @@ -742,7 +742,7 @@ // an Offset. It assumes that Segments have been sorted by OrderSegments and // returns an Offset one past the end of the last segment. static uint64_t LayoutSegments(std::vector &Segments, - uint64_t Offset) { + uint64_t Offset, bool UsePAddr = false) { assert(std::is_sorted(std::begin(Segments), std::end(Segments), compareSegments)); // The only way a segment should move is if a section was between two @@ -750,6 +750,11 @@ // 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 // for alignment. + + if (Segments.empty()) + return Offset; + uint64_t LowestPAddr = Segments[0]->PAddr; + for (auto &Segment : Segments) { // We assume that segments have been ordered by OriginalOffset and Index // such that a parent segment will always come before a child segment in @@ -760,7 +765,10 @@ Segment->Offset = Parent->Offset + Segment->OriginalOffset - Parent->OriginalOffset; } else { - Offset = alignToAddr(Offset, Segment->VAddr, Segment->Align); + if (UsePAddr) + Offset = Segment->PAddr - LowestPAddr; + else + Offset = alignToAddr(Offset, Segment->VAddr, Segment->Align); Segment->Offset = Offset; } Offset = std::max(Offset, Segment->Offset + Segment->FileSize); @@ -906,6 +914,18 @@ std::unique(std::begin(OrderedSegments), std::end(OrderedSegments)); OrderedSegments.erase(End, std::end(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; + // 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. @@ -917,15 +937,15 @@ // 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 + // The VAddr and PAddr need to be adjusted so that the alignment is correct Seg->VAddr += Diff; - Seg->PAddr = Seg->VAddr; + Seg->PAddr += Diff; // We don't want this to be shifted by alignment so we need to set the // alignment to zero. Seg->Align = 0; } - uint64_t Offset = LayoutSegments(OrderedSegments, 0); + uint64_t Offset = LayoutSegments(OrderedSegments, 0, true); // TODO: generalize LayoutSections to take a range. Pass a special range // constructed from an iterator that skips values for which a predicate does