Index: test/tools/llvm-objcopy/ELF/adjacent-segments.test =================================================================== --- test/tools/llvm-objcopy/ELF/adjacent-segments.test +++ test/tools/llvm-objcopy/ELF/adjacent-segments.test @@ -15,20 +15,30 @@ - Name: .text Type: SHT_PROGBITS Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x1000 AddressAlign: 0x1000 Size: 24 - Name: .text2 Type: SHT_PROGBITS Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x1020 AddressAlign: 0x10 Size: 16 ProgramHeaders: - Type: PT_LOAD Flags: [ PF_X, PF_R ] + Offset: 0x1000 + VAddr: 0x1000 + PAddr: 0x1000 + Align: 0x1000 Sections: - Section: .text - Type: PT_LOAD Flags: [ PF_X, PF_R ] + Offset: 0x1020 + VAddr: 0x2020 + PAddr: 0x2020 + Align: 0x1000 Sections: - Section: .text2 @@ -36,8 +46,8 @@ #CHECK-NEXT: ProgramHeader { #CHECK-NEXT: Type: PT_LOAD (0x1) #CHECK-NEXT: Offset: 0x1000 -#CHECK-NEXT: VirtualAddress: 0x0 -#CHECK-NEXT: PhysicalAddress: 0x0 +#CHECK-NEXT: VirtualAddress: 0x1000 +#CHECK-NEXT: PhysicalAddress: 0x1000 #CHECK-NEXT: FileSize: 24 #CHECK-NEXT: MemSize: 24 #CHECK-NEXT: Flags [ (0x5) @@ -49,14 +59,14 @@ #CHECK-NEXT: ProgramHeader { #CHECK-NEXT: Type: PT_LOAD (0x1) #CHECK-NEXT: Offset: 0x1020 -#CHECK-NEXT: VirtualAddress: 0x0 -#CHECK-NEXT: PhysicalAddress: 0x0 +#CHECK-NEXT: VirtualAddress: 0x2020 +#CHECK-NEXT: PhysicalAddress: 0x2020 #CHECK-NEXT: FileSize: 16 #CHECK-NEXT: MemSize: 16 #CHECK-NEXT: Flags [ (0x5) #CHECK-NEXT: PF_R (0x4) #CHECK-NEXT: PF_X (0x1) #CHECK-NEXT: ] -#CHECK-NEXT: Alignment: 16 +#CHECK-NEXT: Alignment: 4096 #CHECK-NEXT: } #CHECK-NEXT:] Index: test/tools/llvm-objcopy/ELF/basic-only-keep-debug.test =================================================================== --- test/tools/llvm-objcopy/ELF/basic-only-keep-debug.test +++ /dev/null @@ -1,22 +0,0 @@ -# NOTE: This test is only intended to be valid as long as --only-keep-debug is -# implemented as a NOP. This test should fail when that changes and you -# will need to update this test. - -# RUN: yaml2obj %s > %t -# RUN: llvm-objcopy %t %t2 -# RUN: llvm-objcopy --only-keep-debug %t %t3 -# RUN: cmp %t2 %t3 -# RUN: llvm-strip --only-keep-debug --no-strip-all %t -o %t4 -# RUN: cmp %t2 %t4 - -!ELF -FileHeader: - Class: ELFCLASS64 - Data: ELFDATA2LSB - Type: ET_EXEC - Machine: EM_X86_64 -Sections: - - Name: .text - Type: SHT_PROGBITS - Flags: [ SHF_ALLOC, SHF_EXECINSTR ] - Content: "DEADBEEF" Index: test/tools/llvm-objcopy/ELF/marker-segment.test =================================================================== --- test/tools/llvm-objcopy/ELF/marker-segment.test +++ test/tools/llvm-objcopy/ELF/marker-segment.test @@ -27,6 +27,7 @@ - Name: .after Type: SHT_NOBITS Flags: [ SHF_ALLOC ] + Address: 0x2010 Size: 64 ProgramHeaders: - Type: PT_LOAD Index: test/tools/llvm-objcopy/ELF/only-keep-debug.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/ELF/only-keep-debug.test @@ -0,0 +1,96 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy --only-keep-debug %t %t.dbg +# RUN: llvm-readelf -S -l -x .note -x .debug_abbrev -x .debug_frame -x .debug_info %t.dbg | FileCheck %s + +## Check that SHT_NOTE and .debug* are kept, but others are changed to SHT_NOBITS. +## SHT_NOBITS sections do not occupy space in the output. + +# CHECK: .note NOTE 00000000000003e0 0003e0 000001 00 A 0 0 0 +# CHECK-NEXT: .text NOBITS 00000000000003e1 0003e1 000001 00 AX 0 0 0 +# CHECK-NEXT: .tdata NOBITS 0000000000001400 000400 000007 00 WAT 0 0 128 +# CHECK-NEXT: .bss NOBITS 0000000000001420 0003e1 00003f 00 WA 0 0 32 +# CHECK-NEXT: .debug_abbrev PROGBITS 0000000000000000 0003e1 000001 00 0 0 0 +# CHECK-NEXT: .debug_frame PROGBITS 0000000000000000 0003e8 000001 00 0 0 8 +# CHECK-NEXT: .debug_info PROGBITS 0000000000000000 0003e9 000001 00 0 0 0 +# CHECK-NEXT: .shstrtab STRTAB 0000000000000000 0003ea 00004a 00 0 0 1 + +# CHECK: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +# CHECK-NEXT: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0003e2 0x0003e2 R E 0x1000 +# CHECK-NEXT: LOAD 0x000400 0x0000000000001400 0x0000000000000000 0x000000 0x00005f RW 0x1000 +# CHECK-NEXT: TLS 0x000400 0x0000000000001400 0x0000000000000000 0x000000 0x000007 RW 0x80 +# CHECK-NEXT: NOTE 0x0003e0 0x00000000000003e0 0x0000000000000000 0x000001 0x000001 0x1 + +## Contents of SHT_NOTE and .debug* are kept. + +# CHECK: Hex dump of section '.note': +# CHECK-NEXT: 0x000003e0 01 +# CHECK: Hex dump of section '.debug_abbrev': +# CHECK-NEXT: 0x00000000 02 +# CHECK: Hex dump of section '.debug_frame': +# CHECK-NEXT: 0x00000000 03 +# CHECK: Hex dump of section '.debug_info': +# CHECK-NEXT: 0x00000000 04 + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .note + Type: SHT_NOTE + Flags: [ SHF_ALLOC ] + Address: 0x3e0 # Ensure Address=Offset + Content: 01 + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x3e1 # Ensure Address=Offset + Content: c3 + - Name: .tdata + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_WRITE, SHF_TLS ] + Address: 0x1400 # Ensure Address=0x1000+Offset + AddressAlign: 128 + Size: 7 + - Name: .bss + Type: SHT_NOBITS + Flags: [ SHF_ALLOC, SHF_WRITE ] + Address: 0x1420 # Ensure Address=0x1000+Offset + AddressAlign: 32 + Size: 63 + - Name: .debug_abbrev + Type: SHT_PROGBITS + Content: 02 + - Name: .debug_frame + Type: SHT_PROGBITS + AddressAlign: 8 + Content: 03 + - Name: .debug_info + Type: SHT_PROGBITS + Content: 04 +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_R, PF_X ] + Offset: 0 + Align: 4096 + Sections: + - Section: .note + - Section: .text + - Type: PT_LOAD + Flags: [ PF_R, PF_W ] + VAddr: 0x1400 # Ensure Offset=VAddr (mod Align) if Offset changes + Align: 4096 + Sections: + - Section: .tdata + - Section: .bss + - Type: PT_TLS + Flags: [ PF_R, PF_W ] + VAddr: 0x1400 # Ensure Offset=VAddr (mod Align) if Offset changes + Sections: + - Section: .tdata + - Type: PT_NOTE + VAddr: 0x3e0 + Sections: + - Section: .note Index: test/tools/llvm-objcopy/ELF/remove-section-in-segment.test =================================================================== --- test/tools/llvm-objcopy/ELF/remove-section-in-segment.test +++ test/tools/llvm-objcopy/ELF/remove-section-in-segment.test @@ -15,14 +15,14 @@ # RUN: od -t x1 -N 16 -j 120 %t.nonalloc | FileCheck %s --check-prefix=NONALLOC-BYTES # NONALLOC-SHDRS-NOT: non_alloc -# NONALLOC-BYTES: 11 22 33 44 00 00 00 00 +# NONALLOC-BYTES: 11 22 33 44 00 73 68 66 5f 61 6c 6c 6f 63 00 2e # RUN: llvm-objcopy --remove-section shf_alloc %t %t.alloc # RUN: llvm-readelf --sections %t.alloc | FileCheck %s --check-prefix=ALLOC-SHDRS # RUN: od -t x1 -N 16 -j 120 %t.alloc | FileCheck %s --check-prefix=ALLOC-BYTES # ALLOC-SHDRS-NOT: shf_alloc -# ALLOC-BYTES: 00 00 00 00 55 66 77 88 +# ALLOC-BYTES: 55 66 77 88 00 6e 6f 6e 5f 61 6c 6c 6f 63 00 2e --- !ELF FileHeader: Index: test/tools/llvm-objcopy/ELF/segment-shift.test =================================================================== --- test/tools/llvm-objcopy/ELF/segment-shift.test +++ test/tools/llvm-objcopy/ELF/segment-shift.test @@ -56,7 +56,7 @@ # CHECK-NEXT: } # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_LOAD (0x1) -# CHECK-NEXT: Offset: 0x2000 +# CHECK-NEXT: Offset: 0x3000 # CHECK-NEXT: VirtualAddress: 0x3000 # CHECK-NEXT: PhysicalAddress: 0x3000 # CHECK-NEXT: FileSize: 4096 Index: test/tools/llvm-objcopy/ELF/segment-test-remove-section.test =================================================================== --- test/tools/llvm-objcopy/ELF/segment-test-remove-section.test +++ test/tools/llvm-objcopy/ELF/segment-test-remove-section.test @@ -7,7 +7,6 @@ # RUN: yaml2obj %s -o %t # RUN: llvm-objcopy -R .text2 %t %t2 # RUN: llvm-readobj --file-headers --program-headers --sections %t2 | FileCheck %s -# RUN: od -t x1 -j 8192 -N 4 %t2 | FileCheck %s --check-prefix=DATA !ELF FileHeader: @@ -43,9 +42,6 @@ - Section: .text2 - Section: .text3 -# Make sure that when we remove a section we overwrite it with zeros -# DATA: {{^[^[:blank:]]+}} 00 00 00 00 - #CHECK: SectionHeaderCount: 4 # CHECK: Sections [ Index: test/tools/llvm-objcopy/ELF/triple-overlap.test =================================================================== --- test/tools/llvm-objcopy/ELF/triple-overlap.test +++ test/tools/llvm-objcopy/ELF/triple-overlap.test @@ -17,42 +17,50 @@ - Name: .text Type: SHT_PROGBITS Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x1000 AddressAlign: 0x1000 Size: 4096 - Name: .text2 Type: SHT_PROGBITS Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x2000 AddressAlign: 0x1000 Size: 4096 - Name: .text3 Type: SHT_PROGBITS Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x3000 AddressAlign: 0x1000 Size: 4096 - Name: .text4 Type: SHT_PROGBITS Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x4000 AddressAlign: 0x1000 Size: 4096 - Name: .text5 Type: SHT_PROGBITS Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x5000 AddressAlign: 0x1000 Size: 4096 ProgramHeaders: - Type: PT_LOAD Flags: [ PF_X, PF_R ] + VAddr: 0x4000 Sections: - Section: .text4 - Section: .text5 - Type: PT_LOAD Flags: [ PF_X, PF_R ] + VAddr: 0x3000 Sections: - Section: .text3 - Section: .text4 - Section: .text5 - Type: PT_LOAD Flags: [ PF_X, PF_R ] + VAddr: 0x1000 Sections: - Section: .text - Section: .text2 @@ -61,6 +69,7 @@ - Section: .text5 - Type: PT_LOAD Flags: [ PF_X, PF_R ] + VAddr: 0x2000 Sections: - Section: .text2 - Section: .text3 @@ -71,7 +80,7 @@ #CHECK-NEXT: ProgramHeader { #CHECK-NEXT: Type: PT_LOAD (0x1) #CHECK-NEXT: Offset: 0x4000 -#CHECK-NEXT: VirtualAddress: 0x0 +#CHECK-NEXT: VirtualAddress: 0x4000 #CHECK-NEXT: PhysicalAddress: 0x0 #CHECK-NEXT: FileSize: 8192 #CHECK-NEXT: MemSize: 8192 @@ -84,7 +93,7 @@ #CHECK-NEXT: ProgramHeader { #CHECK-NEXT: Type: PT_LOAD (0x1) #CHECK-NEXT: Offset: 0x3000 -#CHECK-NEXT: VirtualAddress: 0x0 +#CHECK-NEXT: VirtualAddress: 0x3000 #CHECK-NEXT: PhysicalAddress: 0x0 #CHECK-NEXT: FileSize: 12288 #CHECK-NEXT: MemSize: 12288 @@ -97,7 +106,7 @@ #CHECK-NEXT: ProgramHeader { #CHECK-NEXT: Type: PT_LOAD (0x1) #CHECK-NEXT: Offset: 0x1000 -#CHECK-NEXT: VirtualAddress: 0x0 +#CHECK-NEXT: VirtualAddress: 0x1000 #CHECK-NEXT: PhysicalAddress: 0x0 #CHECK-NEXT: FileSize: 20480 #CHECK-NEXT: MemSize: 20480 @@ -110,7 +119,7 @@ #CHECK-NEXT: ProgramHeader { #CHECK-NEXT: Type: PT_LOAD (0x1) #CHECK-NEXT: Offset: 0x2000 -#CHECK-NEXT: VirtualAddress: 0x0 +#CHECK-NEXT: VirtualAddress: 0x2000 #CHECK-NEXT: PhysicalAddress: 0x0 #CHECK-NEXT: FileSize: 16384 #CHECK-NEXT: MemSize: 16384 Index: tools/llvm-objcopy/ELF/ELFObjcopy.cpp =================================================================== --- tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -134,19 +134,21 @@ Object &Obj, Buffer &Buf, ElfType OutputElfType) { // Depending on the initial ELFT and OutputFormat we need a different Writer. + bool ExtractPartition = + Config.ExtractPartition || Config.ExtractMainPartition; switch (OutputElfType) { case ELFT_ELF32LE: - return std::make_unique>(Obj, Buf, - !Config.StripSections); + return std::make_unique>(Obj, Buf, !Config.StripSections, + ExtractPartition); case ELFT_ELF64LE: - return std::make_unique>(Obj, Buf, - !Config.StripSections); + return std::make_unique>(Obj, Buf, !Config.StripSections, + ExtractPartition); case ELFT_ELF32BE: - return std::make_unique>(Obj, Buf, - !Config.StripSections); + return std::make_unique>(Obj, Buf, !Config.StripSections, + ExtractPartition); case ELFT_ELF64BE: - return std::make_unique>(Obj, Buf, - !Config.StripSections); + return std::make_unique>(Obj, Buf, !Config.StripSections, + ExtractPartition); } llvm_unreachable("Invalid output format"); } @@ -565,6 +567,11 @@ }; } + if (Config.OnlyKeepDebug) + for (auto &Sec : Obj.sections()) + if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE) + Sec.Type = SHT_NOBITS; + if (Config.CompressionType != DebugCompressionType::None) replaceDebugSections(Obj, RemovePred, isCompressable, [&Config, &Obj](const SectionBase *S) { Index: tools/llvm-objcopy/ELF/Object.h =================================================================== --- tools/llvm-objcopy/ELF/Object.h +++ tools/llvm-objcopy/ELF/Object.h @@ -341,10 +341,11 @@ public: virtual ~ELFWriter() {} bool WriteSectionHeaders; + bool ExtractPartition; Error finalize() override; Error write() override; - ELFWriter(Object &Obj, Buffer &Buf, bool WSH); + ELFWriter(Object &Obj, Buffer &Buf, bool WSH, bool ExtractPartition); }; class BinaryWriter : public Writer { @@ -432,8 +433,6 @@ } }; - std::set Sections; - public: uint32_t Type; uint32_t Flags; @@ -448,6 +447,7 @@ uint64_t OriginalOffset; Segment *ParentSegment = nullptr; ArrayRef Contents; + std::set Sections; explicit Segment(ArrayRef Data) : Contents(Data) {} Segment() {} Index: tools/llvm-objcopy/ELF/Object.cpp =================================================================== --- tools/llvm-objcopy/ELF/Object.cpp +++ tools/llvm-objcopy/ELF/Object.cpp @@ -1760,35 +1760,27 @@ template void ELFWriter::writeSectionData() { for (SectionBase &Sec : Obj.sections()) - // Segments are responsible for writing their contents, so only write the - // section data if the section is not in a segment. Note that this renders - // sections in segments effectively immutable. - if (Sec.ParentSegment == nullptr) + // Only write the section data if the section is not in a segment or the + // section is not SHF_ALLOC. Segments are responsible for writing contents + // for SHF_ALLOC. If a non-ALLOC section in a segment is removed, its place + // may be taken by subsequent non-ALLOC sections. + if (Sec.ParentSegment == nullptr || !(Sec.Flags & SHF_ALLOC)) Sec.accept(*SecWriter); } template void ELFWriter::writeSegmentData() { for (Segment &Seg : Obj.segments()) { - uint8_t *B = Buf.getBufferStart() + Seg.Offset; - assert(Seg.FileSize == Seg.getContents().size() && - "Segment size must match contents size"); - std::memcpy(B, Seg.getContents().data(), Seg.FileSize); - } - - // Iterate over removed sections and overwrite their old data with zeroes. - for (auto &Sec : Obj.removedSections()) { - Segment *Parent = Sec.ParentSegment; - if (Parent == nullptr || Sec.Type == SHT_NOBITS || Sec.Size == 0) - continue; - uint64_t Offset = - Sec.OriginalOffset - Parent->OriginalOffset + Parent->Offset; - std::memset(Buf.getBufferStart() + Offset, 0, Sec.Size); + size_t Size = std::min(Seg.FileSize, Seg.getContents().size()); + std::memcpy(Buf.getBufferStart() + Seg.Offset, Seg.getContents().data(), + Size); } } template -ELFWriter::ELFWriter(Object &Obj, Buffer &Buf, bool WSH) - : Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs) {} +ELFWriter::ELFWriter(Object &Obj, Buffer &Buf, bool WSH, + bool ExtractPartition) + : Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs), + ExtractPartition(ExtractPartition) {} Error Object::removeSections(bool AllowBrokenLinks, std::function ToRemove) { @@ -1868,11 +1860,9 @@ llvm::stable_sort(Segments, compareSegmentsByOffset); } -// 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 -// returns an Offset one past the end of the last segment. -static uint64_t layoutSegments(std::vector &Segments, - uint64_t Offset) { +// TODO Unify this function and layoutSegments. +static uint64_t layoutSegmentsForPartition(std::vector &Segments, + uint64_t Offset) { assert(std::is_sorted(std::begin(Segments), std::end(Segments), compareSegmentsByOffset)); // The only way a segment should move is if a section was between two @@ -1905,7 +1895,7 @@ // sections had a ParentSegment or an offset one past the last section if there // was a section that didn't have a ParentSegment. template -static uint64_t layoutSections(Range Sections, uint64_t Offset) { +static uint64_t layoutBinarySections(Range Sections, uint64_t Offset) { // Now the offset of every segment has been set we can assign the offsets // of each section. For sections that are covered by a segment we should use // the segment's original offset and the section's original offset to compute @@ -1929,6 +1919,85 @@ return Offset; } +// 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 +// returns an Offset one past the end of the last segment. +static uint64_t layoutSegments(std::vector &Segments, + uint64_t HdrOffset) { + uint64_t MaxOffset = 0; + for (Segment *Seg : Segments) { + if (Seg->Type == PT_PHDR) + continue; + uint64_t Offset = Seg->Offset; + if (const SectionBase *Sec = Seg->firstSection()) + Offset = Sec->Offset; + + uint64_t FileSize = 0; + for (const SectionBase *Sec : Seg->Sections) { + uint64_t Size = Sec->Type == SHT_NOBITS ? 0 : Sec->Size; + if (Sec->Offset + Size > Offset) + FileSize = std::max(FileSize, Sec->Offset + Size - Offset); + } + + // If the segment includes EHDR or PHDR, don't make it smaller than the + // headers. + uint64_t OrigFileEnd = Seg->Offset + Seg->FileSize; + if (Seg->Offset <= HdrOffset && HdrOffset <= OrigFileEnd) { + FileSize += Offset - Seg->Offset; + Offset = Seg->Offset; + FileSize = std::max(FileSize, OrigFileEnd - Offset); + } + + Seg->Offset = Offset; + Seg->FileSize = FileSize; + MaxOffset = std::max(MaxOffset, Offset + FileSize); + } + return MaxOffset; +} + +static uint64_t layoutSections(Object &Obj, uint64_t Off, + uint64_t MaxPageSize) { + uint32_t Index = 1; + uint64_t NewOff; + for (auto &Sec : Obj.sections()) { + Sec.Index = Index++; + + auto *FirstSec = Sec.ParentSegment && Sec.ParentSegment->Type == PT_LOAD + ? Sec.ParentSegment->firstSection() + : nullptr; + + // The first section in a PT_LOAD has to have congruent offset and address + // modulo the maximum page size. + if (FirstSec && FirstSec == &Sec) + NewOff = alignTo(Off, MaxPageSize, Sec.Addr); + else + NewOff = Off; + + // sh_offset is not significant for SHT_NOBITS sections, but the congruence + // rule must be followed if it is the first section in a PT_LOAD. Do not + // advance Off. + if (Sec.Type == SHT_NOBITS) { + Sec.Offset = NewOff; + continue; + } + + if (!FirstSec) + NewOff = Sec.Align ? alignTo(Off, Sec.Align) : Off; + else if (FirstSec != &Sec) { + // The offset is relative to the first section in the PT_LOAD segment. Use + // sh_offset for non-SHF_ALLOC sections. + if (Sec.Type & SHF_ALLOC) + NewOff = Sec.Addr - FirstSec->Addr + FirstSec->Offset; + else + NewOff = + Sec.OriginalOffset - FirstSec->OriginalOffset + FirstSec->Offset; + } + Sec.Offset = NewOff; + Off = NewOff + Sec.Size; + } + return Off; +} + template void ELFWriter::initEhdrSegment() { Segment &ElfHdr = Obj.ElfHdrSegment; ElfHdr.Type = PT_PHDR; @@ -1949,12 +2018,26 @@ OrderedSegments.push_back(&Obj.ElfHdrSegment); OrderedSegments.push_back(&Obj.ProgramHdrSegment); orderSegments(OrderedSegments); - // Offset is used as the start offset of the first segment to be laid out. - // Since the ELF Header (ElfHdrSegment) must be at the start of the file, - // we start at offset 0. - uint64_t Offset = 0; - Offset = layoutSegments(OrderedSegments, Offset); - Offset = layoutSections(Obj.sections(), Offset); + + uint64_t Offset; + if (ExtractPartition) { + // Offset is used as the start offset of the first segment to be laid out. + // Since the ELF Header (ElfHdrSegment) must be at the start of the file, + // we start at offset 0. + Offset = layoutSegmentsForPartition(OrderedSegments, 0); + Offset = layoutBinarySections(Obj.sections(), Offset); + } else { + // Assume the alignment of a PT_LOAD segment is max-page-size. + uint64_t MaxPageSize = 1; + for (const Segment *Seg : OrderedSegments) + if (Seg->Type == PT_LOAD) + MaxPageSize = std::max(MaxPageSize, Seg->Align); + + uint64_t HdrOffset = + sizeof(Elf_Ehdr) + llvm::size(Obj.segments()) * sizeof(Elf_Phdr); + Offset = layoutSections(Obj, HdrOffset, MaxPageSize); + Offset = std::max(Offset, layoutSegments(OrderedSegments, HdrOffset)); + } // If we need to write the section header table out then we need to align the // Offset so that SHOffset is valid. if (WriteSectionHeaders) @@ -2175,7 +2258,7 @@ for (SectionBase &Section : Obj.sections()) if (Section.Flags & SHF_ALLOC) AllocatedSections.push_back(&Section); - layoutSections(make_pointee_range(AllocatedSections), Offset); + layoutBinarySections(make_pointee_range(AllocatedSections), Offset); // Now that every section has been laid out we just need to compute the total // file size. This might not be the same as the offset returned by