[llvm] r369301 - Recommit "[llvm-objcopy][MachO] Implement a layout algorithm for executables"

Seiya Nuta via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 19 14:12:02 PDT 2019


Author: seiya
Date: Mon Aug 19 14:12:02 2019
New Revision: 369301

URL: http://llvm.org/viewvc/llvm-project?rev=369301&view=rev
Log:
Recommit "[llvm-objcopy][MachO] Implement a layout algorithm for executables"

Summary: The layout algorithm for relocatable objects and for executable are somewhat different. This patch implements the latter one based on the algorithm in LLD (MachOFileLayout).

Reviewers: alexshap, rupprecht, jhenderson

Reviewed By: alexshap

Subscribers: jakehehrlich, abrachet, llvm-commits

Tags: #llvm

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

Added:
    llvm/trunk/test/tools/llvm-objcopy/MachO/basic-executable-copy.test
Modified:
    llvm/trunk/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp

Added: llvm/trunk/test/tools/llvm-objcopy/MachO/basic-executable-copy.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/MachO/basic-executable-copy.test?rev=369301&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/MachO/basic-executable-copy.test (added)
+++ llvm/trunk/test/tools/llvm-objcopy/MachO/basic-executable-copy.test Mon Aug 19 14:12:02 2019
@@ -0,0 +1,291 @@
+## This test verifies that llvm-objcopy copies an executable properly. It
+## uses llvm-readobj instead of cmp because some parts of the object
+## (e.g., the string table) are not identical; the output file is correct but
+## some offsets differ from the input file.
+# RUN: yaml2obj %s > %t
+# RUN: llvm-objcopy %t %t2
+# RUN: llvm-readobj --file-headers --sections %t2 | FileCheck %s
+
+--- !mach-o
+FileHeader:
+  magic:           0xFEEDFACF
+  cputype:         0x01000007
+  cpusubtype:      0x80000003
+  filetype:        0x00000002
+  ncmds:           15
+  sizeofcmds:      976
+  flags:           0x00200085
+  reserved:        0x00000000
+LoadCommands:
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         72
+    segname:         __PAGEZERO
+    vmaddr:          0
+    vmsize:          4294967296
+    fileoff:         0
+    filesize:        0
+    maxprot:         0
+    initprot:        0
+    nsects:          0
+    flags:           0
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         232
+    segname:         __TEXT
+    vmaddr:          4294967296
+    vmsize:          4096
+    fileoff:         0
+    filesize:        4096
+    maxprot:         7
+    initprot:        5
+    nsects:          2
+    flags:           0
+    Sections:
+      - sectname:        __text
+        segname:         __TEXT
+        addr:            0x0000000100000F70
+        size:            58
+        offset:          0x00000F70
+        align:           4
+        reloff:          0x00000000
+        nreloc:          0
+        flags:           0x80000400
+        reserved1:       0x00000000
+        reserved2:       0x00000000
+        reserved3:       0x00000000
+      - sectname:        __unwind_info
+        segname:         __TEXT
+        addr:            0x0000000100000FAC
+        size:            72
+        offset:          0x00000FAC
+        align:           2
+        reloff:          0x00000000
+        nreloc:          0
+        flags:           0x00000000
+        reserved1:       0x00000000
+        reserved2:       0x00000000
+        reserved3:       0x00000000
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         232
+    segname:         __DATA
+    vmaddr:          4294971392
+    vmsize:          4096
+    fileoff:         4096
+    filesize:        4096
+    maxprot:         7
+    initprot:        3
+    nsects:          2
+    flags:           0
+    Sections:
+      - sectname:        __data
+        segname:         __DATA
+        addr:            0x0000000100001000
+        size:            4
+        offset:          0x00001000
+        align:           2
+        reloff:          0x00000000
+        nreloc:          0
+        flags:           0x00000000
+        reserved1:       0x00000000
+        reserved2:       0x00000000
+        reserved3:       0x00000000
+      - sectname:        __common
+        segname:         __DATA
+        addr:            0x0000000100001004
+        size:            4
+        offset:          0x00000000
+        align:           2
+        reloff:          0x00000000
+        nreloc:          0
+        flags:           0x00000001
+        reserved1:       0x00000000
+        reserved2:       0x00000000
+        reserved3:       0x00000000
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         72
+    segname:         __LINKEDIT
+    vmaddr:          4294975488
+    vmsize:          4096
+    fileoff:         8192
+    filesize:        232
+    maxprot:         7
+    initprot:        1
+    nsects:          0
+    flags:           0
+  - cmd:             LC_DYLD_INFO_ONLY
+    cmdsize:         48
+    rebase_off:      0
+    rebase_size:     0
+    bind_off:        0
+    bind_size:       0
+    weak_bind_off:   0
+    weak_bind_size:  0
+    lazy_bind_off:   0
+    lazy_bind_size:  0
+    export_off:      8192
+    export_size:     72
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          8272
+    nsyms:           6
+    stroff:          8368
+    strsize:         56
+  - cmd:             LC_DYSYMTAB
+    cmdsize:         80
+    ilocalsym:       0
+    nlocalsym:       0
+    iextdefsym:      0
+    nextdefsym:      5
+    iundefsym:       5
+    nundefsym:       1
+    tocoff:          0
+    ntoc:            0
+    modtaboff:       0
+    nmodtab:         0
+    extrefsymoff:    0
+    nextrefsyms:     0
+    indirectsymoff:  0
+    nindirectsyms:   0
+    extreloff:       0
+    nextrel:         0
+    locreloff:       0
+    nlocrel:         0
+  - cmd:             LC_LOAD_DYLINKER
+    cmdsize:         32
+    name:            12
+    PayloadString:   '/usr/lib/dyld'
+    ZeroPadBytes:    7
+  - cmd:             LC_UUID
+    cmdsize:         24
+    uuid:            B6EE4FB7-4E1E-3C7A-80D3-CFBD89DBC0FE
+  - cmd:             LC_BUILD_VERSION
+    cmdsize:         32
+    platform:        1
+    minos:           658944
+    sdk:             658944
+    ntools:          1
+    Tools:
+      - tool:            3
+        version:         29491968
+  - cmd:             LC_SOURCE_VERSION
+    cmdsize:         16
+    version:         0
+  - cmd:             LC_MAIN
+    cmdsize:         24
+    entryoff:        3984
+    stacksize:       0
+  - cmd:             LC_LOAD_DYLIB
+    cmdsize:         56
+    dylib:
+      name:            24
+      timestamp:       2
+      current_version: 82115073
+      compatibility_version: 65536
+    PayloadString:   '/usr/lib/libSystem.B.dylib'
+    ZeroPadBytes:    6
+  - cmd:             LC_FUNCTION_STARTS
+    cmdsize:         16
+    dataoff:         8264
+    datasize:        8
+  - cmd:             LC_DATA_IN_CODE
+    cmdsize:         16
+    dataoff:         8272
+    datasize:        0
+LinkEditData:
+  ExportTrie:
+    TerminalSize:    0
+    NodeOffset:      0
+    Name:            ''
+    Flags:           0x0000000000000000
+    Address:         0x0000000000000000
+    Other:           0x0000000000000000
+    ImportName:      ''
+    Children:
+      - TerminalSize:    0
+        NodeOffset:      5
+        Name:            _
+        Flags:           0x0000000000000000
+        Address:         0x0000000000000000
+        Other:           0x0000000000000000
+        ImportName:      ''
+        Children:
+          - TerminalSize:    2
+            NodeOffset:      44
+            Name:            _mh_execute_header
+            Flags:           0x0000000000000000
+            Address:         0x0000000000000000
+            Other:           0x0000000000000000
+            ImportName:      ''
+          - TerminalSize:    3
+            NodeOffset:      48
+            Name:            foo
+            Flags:           0x0000000000000000
+            Address:         0x0000000000000F70
+            Other:           0x0000000000000000
+            ImportName:      ''
+          - TerminalSize:    3
+            NodeOffset:      53
+            Name:            main
+            Flags:           0x0000000000000000
+            Address:         0x0000000000000F90
+            Other:           0x0000000000000000
+            ImportName:      ''
+          - TerminalSize:    3
+            NodeOffset:      58
+            Name:            b
+            Flags:           0x0000000000000000
+            Address:         0x0000000000001000
+            Other:           0x0000000000000000
+            ImportName:      ''
+          - TerminalSize:    3
+            NodeOffset:      63
+            Name:            a
+            Flags:           0x0000000000000000
+            Address:         0x0000000000001004
+            Other:           0x0000000000000000
+            ImportName:      ''
+  NameList:
+    - n_strx:          2
+      n_type:          0x0F
+      n_sect:          1
+      n_desc:          16
+      n_value:         4294967296
+    - n_strx:          22
+      n_type:          0x0F
+      n_sect:          4
+      n_desc:          0
+      n_value:         4294971396
+    - n_strx:          25
+      n_type:          0x0F
+      n_sect:          3
+      n_desc:          0
+      n_value:         4294971392
+    - n_strx:          28
+      n_type:          0x0F
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294971248
+    - n_strx:          33
+      n_type:          0x0F
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294971280
+    - n_strx:          39
+      n_type:          0x01
+      n_sect:          0
+      n_desc:          256
+      n_value:         0
+  StringTable:
+    - ' '
+    - __mh_execute_header
+    - _a
+    - _b
+    - _foo
+    - _main
+    - dyld_stub_binder
+...
+
+# CHECK: FileType: Executable (0x2)
+# CHECK: Name: __text
+# CHECK: Name: __unwind_info
+# CHECK: Name: __data
+# CHECK: Name: __common

Modified: llvm/trunk/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp?rev=369301&r1=369300&r2=369301&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp Mon Aug 19 14:12:02 2019
@@ -17,7 +17,7 @@ namespace macho {
 uint32_t MachOLayoutBuilder::computeSizeOfCmds() const {
   uint32_t Size = 0;
   for (const auto &LC : O.LoadCommands) {
-    auto &MLC = LC.MachOLoadCommand;
+    const MachO::macho_load_command &MLC = LC.MachOLoadCommand;
     auto cmd = MLC.load_command_data.cmd;
     switch (cmd) {
     case MachO::LC_SEGMENT:
@@ -101,20 +101,25 @@ void MachOLayoutBuilder::updateDySymTab(
 uint64_t MachOLayoutBuilder::layoutSegments() {
   auto HeaderSize =
       Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
-  auto Offset = HeaderSize + O.Header.SizeOfCmds;
-
-  // Lay out sections.
+  const bool IsObjectFile =
+      O.Header.FileType == MachO::HeaderFileType::MH_OBJECT;
+  uint64_t Offset = IsObjectFile ? (HeaderSize + O.Header.SizeOfCmds) : 0;
   for (auto &LC : O.LoadCommands) {
-    uint64_t FileOff = Offset;
     auto &MLC = LC.MachOLoadCommand;
     StringRef Segname;
+    uint64_t SegmentVmAddr;
+    uint64_t SegmentVmSize;
     switch (MLC.load_command_data.cmd) {
     case MachO::LC_SEGMENT:
+      SegmentVmAddr = MLC.segment_command_data.vmaddr;
+      SegmentVmSize = MLC.segment_command_data.vmsize;
       Segname = StringRef(MLC.segment_command_data.segname,
                           strnlen(MLC.segment_command_data.segname,
                                   sizeof(MLC.segment_command_data.segname)));
       break;
     case MachO::LC_SEGMENT_64:
+      SegmentVmAddr = MLC.segment_command_64_data.vmaddr;
+      SegmentVmSize = MLC.segment_command_64_data.vmsize;
       Segname = StringRef(MLC.segment_command_64_data.segname,
                           strnlen(MLC.segment_command_64_data.segname,
                                   sizeof(MLC.segment_command_64_data.segname)));
@@ -131,43 +136,64 @@ uint64_t MachOLayoutBuilder::layoutSegme
     }
 
     // Update file offsets and sizes of sections.
+    uint64_t SegOffset = Offset;
+    uint64_t SegFileSize = 0;
     uint64_t VMSize = 0;
-    uint64_t FileOffsetInSegment = 0;
     for (auto &Sec : LC.Sections) {
-      if (!Sec.isVirtualSection()) {
-        auto FilePaddingSize =
-            OffsetToAlignment(FileOffsetInSegment, 1ull << Sec.Align);
-        Sec.Offset = Offset + FileOffsetInSegment + FilePaddingSize;
-        Sec.Size = Sec.Content.size();
-        FileOffsetInSegment += FilePaddingSize + Sec.Size;
+      if (IsObjectFile) {
+        if (Sec.isVirtualSection()) {
+          Sec.Offset = 0;
+        } else {
+          uint64_t PaddingSize = OffsetToAlignment(SegFileSize, 1 << Sec.Align);
+          Sec.Offset = SegOffset + SegFileSize + PaddingSize;
+          Sec.Size = Sec.Content.size();
+          SegFileSize += PaddingSize + Sec.Size;
+        }
+        VMSize = std::max(VMSize, Sec.Addr + Sec.Size);
+      } else {
+        if (Sec.isVirtualSection()) {
+          Sec.Offset = 0;
+          VMSize += Sec.Size;
+        } else {
+          uint32_t SectOffset = Sec.Addr - SegmentVmAddr;
+          Sec.Offset = SegOffset + SectOffset;
+          Sec.Size = Sec.Content.size();
+          SegFileSize = std::max(SegFileSize, SectOffset + Sec.Size);
+          VMSize = std::max(VMSize, SegFileSize);
+        }
       }
+    }
 
-      VMSize = std::max(VMSize, Sec.Addr + Sec.Size);
+    if (IsObjectFile) {
+      Offset += SegFileSize;
+    } else {
+      Offset = alignTo(Offset + SegFileSize, PageSize);
+      SegFileSize = alignTo(SegFileSize, PageSize);
+      // Use the original vmsize if the segment is __PAGEZERO.
+      VMSize =
+          Segname == "__PAGEZERO" ? SegmentVmSize : alignTo(VMSize, PageSize);
     }
 
-    // TODO: Handle the __PAGEZERO segment.
     switch (MLC.load_command_data.cmd) {
     case MachO::LC_SEGMENT:
       MLC.segment_command_data.cmdsize =
           sizeof(MachO::segment_command) +
           sizeof(MachO::section) * LC.Sections.size();
       MLC.segment_command_data.nsects = LC.Sections.size();
-      MLC.segment_command_data.fileoff = FileOff;
+      MLC.segment_command_data.fileoff = SegOffset;
       MLC.segment_command_data.vmsize = VMSize;
-      MLC.segment_command_data.filesize = FileOffsetInSegment;
+      MLC.segment_command_data.filesize = SegFileSize;
       break;
     case MachO::LC_SEGMENT_64:
       MLC.segment_command_64_data.cmdsize =
           sizeof(MachO::segment_command_64) +
           sizeof(MachO::section_64) * LC.Sections.size();
       MLC.segment_command_64_data.nsects = LC.Sections.size();
-      MLC.segment_command_64_data.fileoff = FileOff;
+      MLC.segment_command_64_data.fileoff = SegOffset;
       MLC.segment_command_64_data.vmsize = VMSize;
-      MLC.segment_command_64_data.filesize = FileOffsetInSegment;
+      MLC.segment_command_64_data.filesize = SegFileSize;
       break;
     }
-
-    Offset += FileOffsetInSegment;
   }
 
   return Offset;




More information about the llvm-commits mailing list