Index: llvm/trunk/include/llvm/BinaryFormat/ELF.h =================================================================== --- llvm/trunk/include/llvm/BinaryFormat/ELF.h +++ llvm/trunk/include/llvm/BinaryFormat/ELF.h @@ -843,6 +843,8 @@ // for safe ICF. SHT_LLVM_DEPENDENT_LIBRARIES = 0x6fff4c04, // LLVM Dependent Library Specifiers. SHT_LLVM_SYMPART = 0x6fff4c05, // Symbol partition specification. + SHT_LLVM_PART_EHDR = 0x6fff4c06, // ELF header for loadable partition. + SHT_LLVM_PART_PHDR = 0x6fff4c07, // Phdrs for loadable partition. // Android's experimental support for SHT_RELR sections. // https://android.googlesource.com/platform/bionic/+/b7feec74547f84559a1467aca02708ff61346d2a/libc/include/elf.h#512 SHT_ANDROID_RELR = 0x6fffff00, // Relocation entries; only offsets. Index: llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/partitions.elf.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/partitions.elf.test +++ llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/partitions.elf.test @@ -0,0 +1,28 @@ +// partitions.elf was generated by running this test in lld: + +// REQUIRES: x86 +// RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux +// RUN: ld.lld %t.o -o %t --export-dynamic --gc-sections + +.section .llvm_sympart.g1,"",@llvm_sympart +.asciz "part1" +.quad g1 + +.section .llvm_sympart.g2,"",@llvm_sympart +.asciz "part2" +.quad g2 + +.section .text0,"ax",@progbits +.globl _start +_start: +ret + +.section .bss1,"aw",@nobits +.globl g1 +g1: +.zero 8 + +.section .bss2,"aw",@nobits +.globl g2 +g2: +.zero 16 Index: llvm/trunk/test/tools/llvm-objcopy/ELF/partitions.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/ELF/partitions.test +++ llvm/trunk/test/tools/llvm-objcopy/ELF/partitions.test @@ -0,0 +1,187 @@ +partitions.elf is a file containing a main partition and two loadable +partitions "part1" and "part2" (see https://lld.llvm.org/Partitions.html +for a description of partitions). This file tests that extracting the main +and loadable partitions produces a file with the correct headers and sections. + +RUN: llvm-objcopy --extract-main-partition %p/Inputs/partitions.elf %t1 +RUN: llvm-objcopy --extract-partition=part1 %p/Inputs/partitions.elf %t2 +RUN: llvm-objcopy --extract-partition=part2 %p/Inputs/partitions.elf %t3 + +RUN: llvm-readelf --headers --sections --symbols %t1 | FileCheck --check-prefix=MAIN %s +RUN: llvm-readelf --headers --sections --symbols %t2 | FileCheck --check-prefix=PART1 %s +RUN: llvm-readelf --headers --sections --symbols %t3 | FileCheck --check-prefix=PART2 %s + +MAIN: ELF Header: +MAIN-NEXT: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 +MAIN-NEXT: Class: ELF64 +MAIN-NEXT: Data: 2's complement, little endian +MAIN-NEXT: Version: 1 (current) +MAIN-NEXT: OS/ABI: UNIX - System V +MAIN-NEXT: ABI Version: 0x0 +MAIN-NEXT: Type: EXEC (Executable file) +MAIN-NEXT: Machine: Advanced Micro Devices X86-64 +MAIN-NEXT: Version: 0x1 +MAIN-NEXT: Entry point address: 0x201000 +MAIN-NEXT: Start of program headers: 64 (bytes into file) +MAIN-NEXT: Start of section headers: 12488 (bytes into file) +MAIN-NEXT: Flags: 0x0 +MAIN-NEXT: Size of this header: 64 (bytes) +MAIN-NEXT: Size of program headers: 56 (bytes) +MAIN-NEXT: Number of program headers: 8 +MAIN-NEXT: Size of section headers: 64 (bytes) +MAIN-NEXT: Number of section headers: 13 +MAIN-NEXT: Section header string table index: 11 + +MAIN: Section Headers: +MAIN-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +MAIN-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 +MAIN-NEXT: [ 1] .dynsym DYNSYM 0000000000200200 000200 000030 18 A 4 1 8 +MAIN-NEXT: [ 2] .gnu.hash GNU_HASH 0000000000200230 000230 000020 00 A 1 0 8 +MAIN-NEXT: [ 3] .hash HASH 0000000000200250 000250 000018 04 A 1 0 4 +MAIN-NEXT: [ 4] .dynstr STRTAB 0000000000200268 000268 000014 00 A 0 0 1 +MAIN-NEXT: [ 5] .rodata PROGBITS 000000000020027c 00027c 000018 00 A 0 0 4 +MAIN-NEXT: [ 6] .text0 PROGBITS 0000000000201000 001000 000001 00 AX 0 0 1 +MAIN-NEXT: [ 7] .dynamic DYNAMIC 0000000000202000 002000 000080 10 WA 4 0 8 +MAIN-NEXT: [ 8] .part.end NOBITS 0000000000209000 003000 001000 00 WA 0 0 1 +MAIN-NEXT: [ 9] .comment PROGBITS 0000000000000000 003000 000008 01 MS 0 0 1 +MAIN-NEXT: [10] .symtab SYMTAB 0000000000000000 003008 000048 18 12 2 8 +MAIN-NEXT: [11] .shstrtab STRTAB 0000000000000000 003050 000060 00 0 0 1 +MAIN-NEXT: [12] .strtab STRTAB 0000000000000000 0030b0 000011 00 0 0 1 + +MAIN: Symbol table '.dynsym' contains 2 entries: +MAIN-NEXT: Num: Value Size Type Bind Vis Ndx Name +MAIN-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND +MAIN-NEXT: 1: 0000000000201000 0 NOTYPE GLOBAL DEFAULT 6 _start + +MAIN: Symbol table '.symtab' contains 3 entries: +MAIN-NEXT: Num: Value Size Type Bind Vis Ndx Name +MAIN-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND +MAIN-NEXT: 1: 0000000000202000 0 NOTYPE LOCAL HIDDEN 7 _DYNAMIC +MAIN-NEXT: 2: 0000000000201000 0 NOTYPE GLOBAL DEFAULT 6 _start + +MAIN: Program Headers: +MAIN-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +MAIN-NEXT: PHDR 0x000040 0x0000000000200040 0x0000000000200040 0x0001c0 0x0001c0 R 0x8 +MAIN-NEXT: LOAD 0x000000 0x0000000000200000 0x0000000000200000 0x000294 0x000294 R 0x1000 +MAIN-NEXT: LOAD 0x001000 0x0000000000201000 0x0000000000201000 0x000001 0x000001 R E 0x1000 +MAIN-NEXT: LOAD 0x002000 0x0000000000202000 0x0000000000202000 0x000080 0x000080 RW 0x1000 +MAIN-NEXT: LOAD 0x003000 0x0000000000209000 0x0000000000209000 0x000000 0x001000 RW 0x1000 +MAIN-NEXT: DYNAMIC 0x002000 0x0000000000202000 0x0000000000202000 0x000080 0x000080 RW 0x8 +MAIN-NEXT: GNU_RELRO 0x002000 0x0000000000202000 0x0000000000202000 0x000080 0x001000 R 0x1 +MAIN-NEXT: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x0 + +PART1: ELF Header: +PART1-NEXT: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 +PART1-NEXT: Class: ELF64 +PART1-NEXT: Data: 2's complement, little endian +PART1-NEXT: Version: 1 (current) +PART1-NEXT: OS/ABI: UNIX - System V +PART1-NEXT: ABI Version: 0x0 +PART1-NEXT: Type: DYN (Shared object file) +PART1-NEXT: Machine: Advanced Micro Devices X86-64 +PART1-NEXT: Version: 0x1 +PART1-NEXT: Entry point address: 0x0 +PART1-NEXT: Start of program headers: 64 (bytes into file) +PART1-NEXT: Start of section headers: 8336 (bytes into file) +PART1-NEXT: Flags: 0x0 +PART1-NEXT: Size of this header: 64 (bytes) +PART1-NEXT: Size of program headers: 56 (bytes) +PART1-NEXT: Number of program headers: 7 +PART1-NEXT: Size of section headers: 64 (bytes) +PART1-NEXT: Number of section headers: 11 +PART1-NEXT: Section header string table index: 9 + +PART1: Section Headers: +PART1-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +PART1-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 +PART1-NEXT: [ 1] .dynsym DYNSYM 00000000002031c8 0001c8 000030 18 A 4 1 8 +PART1-NEXT: [ 2] .gnu.hash GNU_HASH 00000000002031f8 0001f8 000020 00 A 1 0 8 +PART1-NEXT: [ 3] .hash HASH 0000000000203218 000218 000018 04 A 1 0 4 +PART1-NEXT: [ 4] .dynstr STRTAB 0000000000203230 000230 00000a 00 A 0 0 1 +PART1-NEXT: [ 5] .dynamic DYNAMIC 0000000000204000 001000 000090 10 WA 4 0 8 +PART1-NEXT: [ 6] .bss1 NOBITS 0000000000205000 002000 000008 00 WA 0 0 1 +PART1-NEXT: [ 7] .comment PROGBITS 0000000000000000 002000 000008 01 MS 0 0 1 +PART1-NEXT: [ 8] .symtab SYMTAB 0000000000000000 002008 000030 18 10 1 8 +PART1-NEXT: [ 9] .shstrtab STRTAB 0000000000000000 002038 00004d 00 0 0 1 +PART1-NEXT: [10] .strtab STRTAB 0000000000000000 002085 000004 00 0 0 1 + +PART1: Symbol table '.dynsym' contains 2 entries: +PART1-NEXT: Num: Value Size Type Bind Vis Ndx Name +PART1-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND +PART1-NEXT: 1: 0000000000205000 0 NOTYPE GLOBAL DEFAULT 15 g1 + +PART1: Symbol table '.symtab' contains 2 entries: +PART1-NEXT: Num: Value Size Type Bind Vis Ndx Name +PART1-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND +PART1-NEXT: 1: 0000000000205000 0 NOTYPE GLOBAL DEFAULT 6 g1 + +PART1: Program Headers: +PART1-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +PART1-NEXT: PHDR 0x000040 0x0000000000203040 0x0000000000203040 0x000188 0x000188 R 0x1 +PART1-NEXT: LOAD 0x000000 0x0000000000203000 0x0000000000203000 0x00023a 0x00023a R 0x1000 +PART1-NEXT: LOAD 0x001000 0x0000000000204000 0x0000000000204000 0x000090 0x000090 RW 0x1000 +PART1-NEXT: LOAD 0x002000 0x0000000000205000 0x0000000000205000 0x000000 0x000008 RW 0x1000 +PART1-NEXT: DYNAMIC 0x001000 0x0000000000204000 0x0000000000204000 0x000090 0x000090 RW 0x8 +PART1-NEXT: GNU_RELRO 0x001000 0x0000000000204000 0x0000000000204000 0x000090 0x001000 R 0x1 +PART1-NEXT: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x0 + +PART2: ELF Header: +PART2-NEXT: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 +PART2-NEXT: Class: ELF64 +PART2-NEXT: Data: 2's complement, little endian +PART2-NEXT: Version: 1 (current) +PART2-NEXT: OS/ABI: UNIX - System V +PART2-NEXT: ABI Version: 0x0 +PART2-NEXT: Type: DYN (Shared object file) +PART2-NEXT: Machine: Advanced Micro Devices X86-64 +PART2-NEXT: Version: 0x1 +PART2-NEXT: Entry point address: 0x0 +PART2-NEXT: Start of program headers: 64 (bytes into file) +PART2-NEXT: Start of section headers: 8336 (bytes into file) +PART2-NEXT: Flags: 0x0 +PART2-NEXT: Size of this header: 64 (bytes) +PART2-NEXT: Size of program headers: 56 (bytes) +PART2-NEXT: Number of program headers: 7 +PART2-NEXT: Size of section headers: 64 (bytes) +PART2-NEXT: Number of section headers: 11 +PART2-NEXT: Section header string table index: 9 + +PART2: Section Headers: +PART2-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +PART2-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 +PART2-NEXT: [ 1] .dynsym DYNSYM 00000000002061c8 0001c8 000030 18 A 4 1 8 +PART2-NEXT: [ 2] .gnu.hash GNU_HASH 00000000002061f8 0001f8 000020 00 A 1 0 8 +PART2-NEXT: [ 3] .hash HASH 0000000000206218 000218 000018 04 A 1 0 4 +PART2-NEXT: [ 4] .dynstr STRTAB 0000000000206230 000230 00000a 00 A 0 0 1 +PART2-NEXT: [ 5] .dynamic DYNAMIC 0000000000207000 001000 000090 10 WA 4 0 8 +PART2-NEXT: [ 6] .bss2 NOBITS 0000000000208000 002000 000010 00 WA 0 0 1 +PART2-NEXT: [ 7] .comment PROGBITS 0000000000000000 002000 000008 01 MS 0 0 1 +PART2-NEXT: [ 8] .symtab SYMTAB 0000000000000000 002008 000030 18 10 1 8 +PART2-NEXT: [ 9] .shstrtab STRTAB 0000000000000000 002038 00004d 00 0 0 1 +PART2-NEXT: [10] .strtab STRTAB 0000000000000000 002085 000004 00 0 0 1 + +PART2: Symbol table '.dynsym' contains 2 entries: +PART2-NEXT: Num: Value Size Type Bind Vis Ndx Name +PART2-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND +PART2-NEXT: 1: 0000000000208000 0 NOTYPE GLOBAL DEFAULT 23 g2 + +PART2: Symbol table '.symtab' contains 2 entries: +PART2-NEXT: Num: Value Size Type Bind Vis Ndx Name +PART2-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND +PART2-NEXT: 1: 0000000000208000 0 NOTYPE GLOBAL DEFAULT 6 g2 + +PART2: Program Headers: +PART2-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +PART2-NEXT: PHDR 0x000040 0x0000000000206040 0x0000000000206040 0x000188 0x000188 R 0x1 +PART2-NEXT: LOAD 0x000000 0x0000000000206000 0x0000000000206000 0x00023a 0x00023a R 0x1000 +PART2-NEXT: LOAD 0x001000 0x0000000000207000 0x0000000000207000 0x000090 0x000090 RW 0x1000 +PART2-NEXT: LOAD 0x002000 0x0000000000208000 0x0000000000208000 0x000000 0x000010 RW 0x1000 +PART2-NEXT: DYNAMIC 0x001000 0x0000000000207000 0x0000000000207000 0x000090 0x000090 RW 0x8 +PART2-NEXT: GNU_RELRO 0x001000 0x0000000000207000 0x0000000000207000 0x000090 0x001000 R 0x1 +PART2-NEXT: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x0 + +RUN: not llvm-objcopy --extract-partition=part3 %p/Inputs/partitions.elf %t4 2>&1 | FileCheck --check-prefix=ERROR1 %s +ERROR1: error: could not find partition named 'part3' + +RUN: not llvm-objcopy --extract-main-partition --extract-partition=part2 %p/Inputs/partitions.elf %t4 2>&1 | FileCheck --check-prefix=ERROR2 %s +ERROR2: error: cannot specify --extract-partition together with --extract-main-partition Index: llvm/trunk/tools/llvm-objcopy/CopyConfig.h =================================================================== --- llvm/trunk/tools/llvm-objcopy/CopyConfig.h +++ llvm/trunk/tools/llvm-objcopy/CopyConfig.h @@ -120,6 +120,7 @@ StringRef BuildIdLinkDir; Optional BuildIdLinkInput; Optional BuildIdLinkOutput; + Optional ExtractPartition; StringRef SplitDWO; StringRef SymbolsPrefix; StringRef AllocSectionsPrefix; @@ -155,6 +156,7 @@ bool AllowBrokenLinks = false; bool DeterministicArchives = true; bool ExtractDWO = false; + bool ExtractMainPartition = false; bool KeepFileSymbols = false; bool LocalizeHidden = false; bool OnlyKeepDebug = false; Index: llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp =================================================================== --- llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp +++ llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp @@ -519,6 +519,8 @@ Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols); Config.AllocSectionsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_alloc_sections); + if (auto Arg = InputArgs.getLastArg(OBJCOPY_extract_partition)) + Config.ExtractPartition = Arg->getValue(); for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) { if (!StringRef(Arg->getValue()).contains('=')) @@ -593,6 +595,8 @@ Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc); Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded); Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo); + Config.ExtractMainPartition = + InputArgs.hasArg(OBJCOPY_extract_main_partition); Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden); Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken); if (InputArgs.hasArg(OBJCOPY_discard_all, OBJCOPY_discard_locals)) @@ -697,6 +701,11 @@ errc::invalid_argument, "LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress"); + if (Config.ExtractPartition && Config.ExtractMainPartition) + return createStringError(errc::invalid_argument, + "cannot specify --extract-partition together with " + "--extract-main-partition"); + DC.CopyConfigs.push_back(std::move(Config)); return std::move(DC); } Index: llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp =================================================================== --- llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -507,6 +507,16 @@ return (Sec.Flags & SHF_ALLOC) == 0; }; + if (Config.ExtractPartition || Config.ExtractMainPartition) { + RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { + if (RemovePred(Sec)) + return true; + if (Sec.Type == SHT_LLVM_PART_EHDR || Sec.Type == SHT_LLVM_PART_PHDR) + return true; + return (Sec.Flags & SHF_ALLOC) != 0 && !Sec.ParentSegment; + }; + } + // Explicit copies: if (!Config.OnlySection.empty()) { RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) { @@ -747,7 +757,7 @@ Error executeObjcopyOnBinary(const CopyConfig &Config, object::ELFObjectFileBase &In, Buffer &Out) { - ELFReader Reader(&In); + ELFReader Reader(&In, Config.ExtractPartition); std::unique_ptr Obj = Reader.create(); // Prefer OutputArch (-O) if set, otherwise infer it from the input. const ElfType OutputElfType = Index: llvm/trunk/tools/llvm-objcopy/ELF/Object.h =================================================================== --- llvm/trunk/tools/llvm-objcopy/ELF/Object.h +++ llvm/trunk/tools/llvm-objcopy/ELF/Object.h @@ -889,17 +889,23 @@ const ELFFile &ElfFile; Object &Obj; + uint64_t EhdrOffset = 0; + Optional ExtractPartition; void setParentSegment(Segment &Child); - void readProgramHeaders(); + void readProgramHeaders(const ELFFile &HeadersFile); void initGroupSection(GroupSection *GroupSec); void initSymbolTable(SymbolTableSection *SymTab); void readSectionHeaders(); + void readSections(); + void findEhdrOffset(); SectionBase &makeSection(const Elf_Shdr &Shdr); public: - ELFBuilder(const ELFObjectFile &ElfObj, Object &Obj) - : ElfFile(*ElfObj.getELFFile()), Obj(Obj) {} + ELFBuilder(const ELFObjectFile &ElfObj, Object &Obj, + Optional ExtractPartition) + : ElfFile(*ElfObj.getELFFile()), Obj(Obj), + ExtractPartition(ExtractPartition) {} void build(); }; @@ -916,10 +922,12 @@ class ELFReader : public Reader { Binary *Bin; + Optional ExtractPartition; public: std::unique_ptr create() const override; - explicit ELFReader(Binary *B) : Bin(B) {} + explicit ELFReader(Binary *B, Optional ExtractPartition) + : Bin(B), ExtractPartition(ExtractPartition) {} }; class Object { Index: llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp =================================================================== --- llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp +++ llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp @@ -1101,21 +1101,36 @@ } } -template void ELFBuilder::readProgramHeaders() { +template void ELFBuilder::findEhdrOffset() { + if (!ExtractPartition) + return; + + for (const SectionBase &Section : Obj.sections()) { + if (Section.Type == SHT_LLVM_PART_EHDR && + Section.Name == *ExtractPartition) { + EhdrOffset = Section.Offset; + return; + } + } + error("could not find partition named '" + *ExtractPartition + "'"); +} + +template +void ELFBuilder::readProgramHeaders(const ELFFile &HeadersFile) { uint32_t Index = 0; - for (const auto &Phdr : unwrapOrError(ElfFile.program_headers())) { - if (Phdr.p_offset + Phdr.p_filesz > ElfFile.getBufSize()) + for (const auto &Phdr : unwrapOrError(HeadersFile.program_headers())) { + if (Phdr.p_offset + Phdr.p_filesz > HeadersFile.getBufSize()) error("program header with offset 0x" + Twine::utohexstr(Phdr.p_offset) + " and file size 0x" + Twine::utohexstr(Phdr.p_filesz) + " goes past the end of the file"); - ArrayRef Data{ElfFile.base() + Phdr.p_offset, + ArrayRef Data{HeadersFile.base() + Phdr.p_offset, (size_t)Phdr.p_filesz}; Segment &Seg = Obj.addSegment(Data); Seg.Type = Phdr.p_type; Seg.Flags = Phdr.p_flags; - Seg.OriginalOffset = Phdr.p_offset; - Seg.Offset = Phdr.p_offset; + Seg.OriginalOffset = Phdr.p_offset + EhdrOffset; + Seg.Offset = Phdr.p_offset + EhdrOffset; Seg.VAddr = Phdr.p_vaddr; Seg.PAddr = Phdr.p_paddr; Seg.FileSize = Phdr.p_filesz; @@ -1135,8 +1150,9 @@ auto &ElfHdr = Obj.ElfHdrSegment; ElfHdr.Index = Index++; + ElfHdr.OriginalOffset = ElfHdr.Offset = EhdrOffset; - const auto &Ehdr = *ElfFile.getHeader(); + const auto &Ehdr = *HeadersFile.getHeader(); auto &PrHdr = Obj.ProgramHdrSegment; PrHdr.Type = PT_PHDR; PrHdr.Flags = 0; @@ -1144,7 +1160,7 @@ // Whereas this works automatically for ElfHdr, here OriginalOffset is // always non-zero and to ensure the equation we assign the same value to // VAddr as well. - PrHdr.OriginalOffset = PrHdr.Offset = PrHdr.VAddr = Ehdr.e_phoff; + PrHdr.OriginalOffset = PrHdr.Offset = PrHdr.VAddr = EhdrOffset + Ehdr.e_phoff; PrHdr.PAddr = 0; PrHdr.FileSize = PrHdr.MemSize = Ehdr.e_phentsize * Ehdr.e_phnum; // The spec requires us to naturally align all the fields. @@ -1363,7 +1379,9 @@ ArrayRef(ElfFile.base() + Shdr.sh_offset, (Shdr.sh_type == SHT_NOBITS) ? 0 : Shdr.sh_size); } +} +template void ELFBuilder::readSections() { // If a section index table exists we'll need to initialize it before we // initialize the symbol table because the symbol table might need to // reference it. @@ -1397,11 +1415,34 @@ initGroupSection(GroupSec); } } + + uint32_t ShstrIndex = ElfFile.getHeader()->e_shstrndx; + if (ShstrIndex == SHN_XINDEX) + ShstrIndex = unwrapOrError(ElfFile.getSection(0))->sh_link; + + if (ShstrIndex == SHN_UNDEF) + Obj.HadShdrs = false; + else + Obj.SectionNames = + Obj.sections().template getSectionOfType( + ShstrIndex, + "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " + + " is invalid", + "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " + + " is not a string table"); } template void ELFBuilder::build() { - const auto &Ehdr = *ElfFile.getHeader(); + readSectionHeaders(); + findEhdrOffset(); + + // The ELFFile whose ELF headers and program headers are copied into the + // output file. Normally the same as ElfFile, but if we're extracting a + // loadable partition it will point to the partition's headers. + ELFFile HeadersFile = unwrapOrError(ELFFile::create(toStringRef( + {ElfFile.base() + EhdrOffset, ElfFile.getBufSize() - EhdrOffset}))); + auto &Ehdr = *HeadersFile.getHeader(); Obj.OSABI = Ehdr.e_ident[EI_OSABI]; Obj.ABIVersion = Ehdr.e_ident[EI_ABIVERSION]; Obj.Type = Ehdr.e_type; @@ -1410,23 +1451,8 @@ Obj.Entry = Ehdr.e_entry; Obj.Flags = Ehdr.e_flags; - readSectionHeaders(); - readProgramHeaders(); - - uint32_t ShstrIndex = Ehdr.e_shstrndx; - if (ShstrIndex == SHN_XINDEX) - ShstrIndex = unwrapOrError(ElfFile.getSection(0))->sh_link; - - if (ShstrIndex == SHN_UNDEF) - Obj.HadShdrs = false; - else - Obj.SectionNames = - Obj.sections().template getSectionOfType( - ShstrIndex, - "e_shstrndx field value " + Twine(Ehdr.e_shstrndx) + - " in elf header is invalid", - "e_shstrndx field value " + Twine(Ehdr.e_shstrndx) + - " in elf header is not a string table"); + readSections(); + readProgramHeaders(HeadersFile); } Writer::~Writer() {} @@ -1440,19 +1466,19 @@ std::unique_ptr ELFReader::create() const { auto Obj = llvm::make_unique(); if (auto *O = dyn_cast>(Bin)) { - ELFBuilder Builder(*O, *Obj); + ELFBuilder Builder(*O, *Obj, ExtractPartition); Builder.build(); return Obj; } else if (auto *O = dyn_cast>(Bin)) { - ELFBuilder Builder(*O, *Obj); + ELFBuilder Builder(*O, *Obj, ExtractPartition); Builder.build(); return Obj; } else if (auto *O = dyn_cast>(Bin)) { - ELFBuilder Builder(*O, *Obj); + ELFBuilder Builder(*O, *Obj, ExtractPartition); Builder.build(); return Obj; } else if (auto *O = dyn_cast>(Bin)) { - ELFBuilder Builder(*O, *Obj); + ELFBuilder Builder(*O, *Obj, ExtractPartition); Builder.build(); return Obj; } @@ -1732,7 +1758,6 @@ Segment &ElfHdr = Obj.ElfHdrSegment; ElfHdr.Type = PT_PHDR; ElfHdr.Flags = 0; - ElfHdr.OriginalOffset = ElfHdr.Offset = 0; ElfHdr.VAddr = 0; ElfHdr.PAddr = 0; ElfHdr.FileSize = ElfHdr.MemSize = sizeof(Elf_Ehdr); Index: llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td =================================================================== --- llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td +++ llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td @@ -145,6 +145,13 @@ HelpText< "Remove all sections that are not DWARF .dwo sections from file">; +defm extract_partition + : Eq<"extract-partition", "Extract named partition from input file">, + MetaVarName<"name">; +def extract_main_partition + : Flag<["--"], "extract-main-partition">, + HelpText<"Extract main partition from the input file">; + def localize_hidden : Flag<["--"], "localize-hidden">, HelpText<