Index: test/tools/llvm-objcopy/marker-segment.test =================================================================== --- test/tools/llvm-objcopy/marker-segment.test +++ test/tools/llvm-objcopy/marker-segment.test @@ -0,0 +1,109 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy %t %t2 +# RUN: llvm-readobj -program-headers %t2 | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_ARM +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x1000 + AddressAlign: 0x0000000000001000 + Content: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Address: 0x2000 + AddressAlign: 0x0000000000001000 + Content: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + - Name: .xdata + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + - Name: .after + Type: SHT_NOBITS + Flags: [ SHF_ALLOC ] + Size: 64 +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: 0x2000 + Align: 0x1000 + Sections: + - Section: .data + - Type: 0x6474e551 # GNU_STACK + Flags: [ PF_R, PF_W ] + VAddr: 0x0000 + PAddr: 0x0000 + Align: 0x0000 + - Type: PT_LOAD + Flags: [ PF_R ] + Sections: + - Section: .xdata + - Section: .after + +#CHECK: ProgramHeaders [ +#CHECK-NEXT: ProgramHeader { +#CHECK-NEXT: Type: PT_LOAD +#CHECK-NEXT: Offset: 0x1000 +#CHECK-NEXT: VirtualAddress: 0x1000 +#CHECK-NEXT: PhysicalAddress: 0x1000 +#CHECK-NEXT: FileSize: 16 +#CHECK-NEXT: MemSize: 16 +#CHECK-NEXT: Flags [ +#CHECK-NEXT: PF_R +#CHECK-NEXT: PF_X +#CHECK-NEXT: ] +#CHECK-NEXT: Alignment: 4096 +#CHECK-NEXT: } +#CHECK-NEXT: ProgramHeader { +#CHECK-NEXT: Type: PT_LOAD +#CHECK-NEXT: Offset: 0x2000 +#CHECK-NEXT: VirtualAddress: 0x2000 +#CHECK-NEXT: PhysicalAddress: 0x2000 +#CHECK-NEXT: FileSize: 16 +#CHECK-NEXT: MemSize: 16 +#CHECK-NEXT: Flags [ +#CHECK-NEXT: PF_R +#CHECK-NEXT: PF_W +#CHECK-NEXT: ] +#CHECK-NEXT: Alignment: 4096 +#CHECK-NEXT: } +#CHECK-NEXT: ProgramHeader { +#CHECK-NEXT: Type: PT_GNU_STACK +#CHECK-NEXT: Offset: 0x0 +#CHECK-NEXT: VirtualAddress: 0x0 +#CHECK-NEXT: PhysicalAddress: 0x0 +#CHECK-NEXT: FileSize: 0 +#CHECK-NEXT: MemSize: 0 +#CHECK-NEXT: Flags [ +#CHECK-NEXT: PF_R +#CHECK-NEXT: PF_W +#CHECK-NEXT: ] +#CHECK-NEXT: Alignment: 0 +#CHECK-NEXT: } +#CHECK-NEXT: ProgramHeader { +#CHECK-NEXT: Type: PT_LOAD +#CHECK-NEXT: Offset: 0x2010 +#CHECK-NEXT: VirtualAddress: 0x0 +#CHECK-NEXT: PhysicalAddress: 0x0 +#CHECK-NEXT: FileSize: 0 +#CHECK-NEXT: MemSize: 64 +#CHECK-NEXT: Flags [ +#CHECK-NEXT: PF_R +#CHECK-NEXT: ] +#CHECK-NEXT: Alignment: 1 +#CHECK-NEXT: } +#CHECK-NEXT:] Index: tools/llvm-objcopy/Object.h =================================================================== --- tools/llvm-objcopy/Object.h +++ tools/llvm-objcopy/Object.h @@ -237,7 +237,12 @@ uint64_t OriginalOffset; Segment *ParentSegment = nullptr; + // These segments are created to ensure the correct layout of the target ELF, + // but are not present in the resulting file. + bool DummySegment = false; + Segment(ArrayRef Data) : Contents(Data) {} + Segment() : DummySegment(true) {} const SectionBase *firstSection() const { if (!Sections.empty()) @@ -512,6 +517,7 @@ template class ELFBuilder { private: using Elf_Shdr = typename ELFT::Shdr; + using Elf_Ehdr = typename ELFT::Ehdr; const ELFFile &ElfFile; Object &Obj; @@ -579,6 +585,11 @@ Range segments() { return make_pointee_range(Segments); } ConstRange segments() const { return make_pointee_range(Segments); } + size_t countFileSegments() { + return std::count_if(Segments.begin(), Segments.end(), + [](const SegPtr &Seg) { return !Seg->DummySegment; }); + } + void removeSections(std::function ToRemove); template T &addSection(Ts &&... Args) { auto Sec = llvm::make_unique(std::forward(Args)...); @@ -590,6 +601,10 @@ Segments.emplace_back(llvm::make_unique(Data)); return *Segments.back(); } + Segment &addDummySegment() { + Segments.emplace_back(llvm::make_unique()); + return *Segments.back(); + } }; } // end namespace llvm Index: tools/llvm-objcopy/Object.cpp =================================================================== --- tools/llvm-objcopy/Object.cpp +++ tools/llvm-objcopy/Object.cpp @@ -458,6 +458,8 @@ template void ELFBuilder::readProgramHeaders() { uint32_t Index = 0; + bool IsHeaderInMemory = false; + uint64_t PageAlign = 0; for (const auto &Phdr : unwrapOrError(ElfFile.program_headers())) { ArrayRef Data{ElfFile.base() + Phdr.p_offset, (size_t)Phdr.p_filesz}; @@ -472,6 +474,20 @@ Seg.MemSize = Phdr.p_memsz; Seg.Align = Phdr.p_align; Seg.Index = Index++; + + // ELF header may be mentioned in program headers by a dedicated segment + // (PT_PHDR), or by a loadable segment with a zero file offset. + if (Seg.Type == PT_PHDR || + (Seg.Type == PT_LOAD && Seg.Offset == 0 && Seg.FileSize > 0)) + IsHeaderInMemory = true; + + // Different segments may have different alignment, but the spec defines + // 0 and 1 alignment as no alignment, and anything higher should be page + // aligned at least. + if (Seg.Type == PT_LOAD && Seg.Align > 1 && + (Seg.Align < PageAlign || PageAlign == 0)) + PageAlign = Seg.Align; + for (auto &Section : Obj.sections()) { if (sectionWithinSegment(Section, Seg)) { Seg.addSection(&Section); @@ -482,6 +498,26 @@ } } } + + if (!IsHeaderInMemory) { + // Each ELF has to begin with a header, so we create a dummy segment + // to protect ourselves from writing to this area. + Segment &ElfHeader = Obj.addDummySegment(); + ElfHeader.Type = PT_LOAD; + ElfHeader.Flags = 0; + ElfHeader.OriginalOffset = 0; + ElfHeader.Offset = 0; + ElfHeader.VAddr = 0; + ElfHeader.PAddr = 0; + if (PageAlign > sizeof(Elf_Ehdr)) + ElfHeader.FileSize = PageAlign; + else + ElfHeader.FileSize = sizeof(Elf_Ehdr); + ElfHeader.MemSize = 0; + ElfHeader.Align = 0; + ElfHeader.Index = Index++; + } + // Now we do an O(n^2) loop through the segments in order to match up // segments. for (auto &Child : Obj.segments()) { @@ -743,7 +779,7 @@ Ehdr.e_flags = Obj.Flags; Ehdr.e_ehsize = sizeof(Elf_Ehdr); Ehdr.e_phentsize = sizeof(Elf_Phdr); - Ehdr.e_phnum = size(Obj.segments()); + Ehdr.e_phnum = Obj.countFileSegments(); Ehdr.e_shentsize = sizeof(Elf_Shdr); if (WriteSectionHeaders) { Ehdr.e_shoff = Obj.SHOffset; @@ -757,8 +793,10 @@ } template void ELFWriter::writePhdrs() { - for (auto &Seg : Obj.segments()) - writePhdr(Seg); + for (auto &Seg : Obj.segments()) { + if (!Seg.DummySegment) + writePhdr(Seg); + } } template void ELFWriter::writeShdrs() {