[llvm] r362818 - llvm-objcopy: Implement --extract-partition and --extract-main-partition.

Peter Collingbourne via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 7 10:57:48 PDT 2019


Author: pcc
Date: Fri Jun  7 10:57:48 2019
New Revision: 362818

URL: http://llvm.org/viewvc/llvm-project?rev=362818&view=rev
Log:
llvm-objcopy: Implement --extract-partition and --extract-main-partition.

This implements the functionality described in
https://lld.llvm.org/Partitions.html. It works as follows:

- Reads the section headers using the ELF header at file offset 0;
- If extracting a loadable partition:
  - Finds the section containing the required partition ELF header by looking it up in the section table;
  - Reads the ELF and program headers from the section.
- If extracting the main partition:
  - Reads the ELF and program headers from file offset 0.
- Filters the section table according to which sections are in the program headers that it read:
  - If ParentSegment != nullptr or section is not SHF_ALLOC, then it goes in.
  - Sections containing partition ELF headers or program headers are excluded as there are no headers for these in ordinary ELF files.

Differential Revision: https://reviews.llvm.org/D62364

Added:
    llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/partitions.elf   (with props)
    llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/partitions.elf.test
    llvm/trunk/test/tools/llvm-objcopy/ELF/partitions.test
Modified:
    llvm/trunk/include/llvm/BinaryFormat/ELF.h
    llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp
    llvm/trunk/tools/llvm-objcopy/CopyConfig.h
    llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
    llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp
    llvm/trunk/tools/llvm-objcopy/ELF/Object.h
    llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td

Modified: llvm/trunk/include/llvm/BinaryFormat/ELF.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/BinaryFormat/ELF.h?rev=362818&r1=362817&r2=362818&view=diff
==============================================================================
--- llvm/trunk/include/llvm/BinaryFormat/ELF.h (original)
+++ llvm/trunk/include/llvm/BinaryFormat/ELF.h Fri Jun  7 10:57:48 2019
@@ -843,6 +843,8 @@ enum : unsigned {
                                         // 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.

Added: llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/partitions.elf
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/partitions.elf?rev=362818&view=auto
==============================================================================
Binary file - no diff available.

Propchange: llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/partitions.elf
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/partitions.elf.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/partitions.elf.test?rev=362818&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/partitions.elf.test (added)
+++ llvm/trunk/test/tools/llvm-objcopy/ELF/Inputs/partitions.elf.test Fri Jun  7 10:57:48 2019
@@ -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,"", at llvm_sympart
+.asciz "part1"
+.quad g1
+
+.section .llvm_sympart.g2,"", at llvm_sympart
+.asciz "part2"
+.quad g2
+
+.section .text0,"ax", at progbits
+.globl _start
+_start:
+ret
+
+.section .bss1,"aw", at nobits
+.globl g1
+g1:
+.zero 8
+
+.section .bss2,"aw", at nobits
+.globl g2
+g2:
+.zero 16

Added: llvm/trunk/test/tools/llvm-objcopy/ELF/partitions.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/ELF/partitions.test?rev=362818&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/ELF/partitions.test (added)
+++ llvm/trunk/test/tools/llvm-objcopy/ELF/partitions.test Fri Jun  7 10:57:48 2019
@@ -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

Modified: llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp?rev=362818&r1=362817&r2=362818&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp Fri Jun  7 10:57:48 2019
@@ -519,6 +519,8 @@ Expected<DriverConfig> parseObjcopyOptio
   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 @@ Expected<DriverConfig> parseObjcopyOptio
   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 @@ Expected<DriverConfig> parseObjcopyOptio
         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);
 }

Modified: llvm/trunk/tools/llvm-objcopy/CopyConfig.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/CopyConfig.h?rev=362818&r1=362817&r2=362818&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/CopyConfig.h (original)
+++ llvm/trunk/tools/llvm-objcopy/CopyConfig.h Fri Jun  7 10:57:48 2019
@@ -120,6 +120,7 @@ struct CopyConfig {
   StringRef BuildIdLinkDir;
   Optional<StringRef> BuildIdLinkInput;
   Optional<StringRef> BuildIdLinkOutput;
+  Optional<StringRef> ExtractPartition;
   StringRef SplitDWO;
   StringRef SymbolsPrefix;
   StringRef AllocSectionsPrefix;
@@ -155,6 +156,7 @@ struct CopyConfig {
   bool AllowBrokenLinks = false;
   bool DeterministicArchives = true;
   bool ExtractDWO = false;
+  bool ExtractMainPartition = false;
   bool KeepFileSymbols = false;
   bool LocalizeHidden = false;
   bool OnlyKeepDebug = false;

Modified: llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp?rev=362818&r1=362817&r2=362818&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/ELF/ELFObjcopy.cpp Fri Jun  7 10:57:48 2019
@@ -507,6 +507,16 @@ static Error replaceAndRemoveSections(co
       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 executeObjcopyOnRawBinary(const Co
 
 Error executeObjcopyOnBinary(const CopyConfig &Config,
                              object::ELFObjectFileBase &In, Buffer &Out) {
-  ELFReader Reader(&In);
+  ELFReader Reader(&In, Config.ExtractPartition);
   std::unique_ptr<Object> Obj = Reader.create();
   // Prefer OutputArch (-O<format>) if set, otherwise infer it from the input.
   const ElfType OutputElfType =

Modified: llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp?rev=362818&r1=362817&r2=362818&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/ELF/Object.cpp Fri Jun  7 10:57:48 2019
@@ -1101,21 +1101,36 @@ template <class ELFT> void ELFBuilder<EL
   }
 }
 
-template <class ELFT> void ELFBuilder<ELFT>::readProgramHeaders() {
+template <class ELFT> void ELFBuilder<ELFT>::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 <class ELFT>
+void ELFBuilder<ELFT>::readProgramHeaders(const ELFFile<ELFT> &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<uint8_t> Data{ElfFile.base() + Phdr.p_offset,
+    ArrayRef<uint8_t> 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 @@ template <class ELFT> void ELFBuilder<EL
 
   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 @@ template <class ELFT> void ELFBuilder<EL
   // 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 @@ template <class ELFT> void ELFBuilder<EL
         ArrayRef<uint8_t>(ElfFile.base() + Shdr.sh_offset,
                           (Shdr.sh_type == SHT_NOBITS) ? 0 : Shdr.sh_size);
   }
+}
 
+template <class ELFT> void ELFBuilder<ELFT>::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 @@ template <class ELFT> void ELFBuilder<EL
       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<StringTableSection>(
+            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 <class ELFT> void ELFBuilder<ELFT>::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<ELFT> HeadersFile = unwrapOrError(ELFFile<ELFT>::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 @@ template <class ELFT> void ELFBuilder<EL
   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<StringTableSection>(
-            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<Object> BinaryReader::cr
 std::unique_ptr<Object> ELFReader::create() const {
   auto Obj = llvm::make_unique<Object>();
   if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) {
-    ELFBuilder<ELF32LE> Builder(*O, *Obj);
+    ELFBuilder<ELF32LE> Builder(*O, *Obj, ExtractPartition);
     Builder.build();
     return Obj;
   } else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Bin)) {
-    ELFBuilder<ELF64LE> Builder(*O, *Obj);
+    ELFBuilder<ELF64LE> Builder(*O, *Obj, ExtractPartition);
     Builder.build();
     return Obj;
   } else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Bin)) {
-    ELFBuilder<ELF32BE> Builder(*O, *Obj);
+    ELFBuilder<ELF32BE> Builder(*O, *Obj, ExtractPartition);
     Builder.build();
     return Obj;
   } else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Bin)) {
-    ELFBuilder<ELF64BE> Builder(*O, *Obj);
+    ELFBuilder<ELF64BE> Builder(*O, *Obj, ExtractPartition);
     Builder.build();
     return Obj;
   }
@@ -1732,7 +1758,6 @@ template <class ELFT> void ELFWriter<ELF
   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);

Modified: llvm/trunk/tools/llvm-objcopy/ELF/Object.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ELF/Object.h?rev=362818&r1=362817&r2=362818&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/ELF/Object.h (original)
+++ llvm/trunk/tools/llvm-objcopy/ELF/Object.h Fri Jun  7 10:57:48 2019
@@ -889,17 +889,23 @@ private:
 
   const ELFFile<ELFT> &ElfFile;
   Object &Obj;
+  uint64_t EhdrOffset = 0;
+  Optional<StringRef> ExtractPartition;
 
   void setParentSegment(Segment &Child);
-  void readProgramHeaders();
+  void readProgramHeaders(const ELFFile<ELFT> &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<ELFT> &ElfObj, Object &Obj)
-      : ElfFile(*ElfObj.getELFFile()), Obj(Obj) {}
+  ELFBuilder(const ELFObjectFile<ELFT> &ElfObj, Object &Obj,
+             Optional<StringRef> ExtractPartition)
+      : ElfFile(*ElfObj.getELFFile()), Obj(Obj),
+        ExtractPartition(ExtractPartition) {}
 
   void build();
 };
@@ -916,10 +922,12 @@ public:
 
 class ELFReader : public Reader {
   Binary *Bin;
+  Optional<StringRef> ExtractPartition;
 
 public:
   std::unique_ptr<Object> create() const override;
-  explicit ELFReader(Binary *B) : Bin(B) {}
+  explicit ELFReader(Binary *B, Optional<StringRef> ExtractPartition)
+      : Bin(B), ExtractPartition(ExtractPartition) {}
 };
 
 class Object {

Modified: llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td?rev=362818&r1=362817&r2=362818&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td (original)
+++ llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td Fri Jun  7 10:57:48 2019
@@ -145,6 +145,13 @@ def extract_dwo
       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<




More information about the llvm-commits mailing list