diff options
| author | Seiya Nuta <nuta@seiya.me> | 2019-08-19 21:12:02 +0000 | 
|---|---|---|
| committer | Seiya Nuta <nuta@seiya.me> | 2019-08-19 21:12:02 +0000 | 
| commit | 12bd490427d7d19425ba1a7e5c55c3b22d8aa61d (patch) | |
| tree | af42d04d463fb5ffcd0f5f2a7ae4c1c91f94fa1e | |
| parent | 55ccd16354d90a70e890f4a79b9bfd20186b3c5f (diff) | |
| download | bcm5719-llvm-12bd490427d7d19425ba1a7e5c55c3b22d8aa61d.tar.gz bcm5719-llvm-12bd490427d7d19425ba1a7e5c55c3b22d8aa61d.zip  | |
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
llvm-svn: 369301
| -rw-r--r-- | llvm/test/tools/llvm-objcopy/MachO/basic-executable-copy.test | 291 | ||||
| -rw-r--r-- | llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp | 66 | 
2 files changed, 337 insertions, 20 deletions
diff --git a/llvm/test/tools/llvm-objcopy/MachO/basic-executable-copy.test b/llvm/test/tools/llvm-objcopy/MachO/basic-executable-copy.test new file mode 100644 index 00000000000..85eebad2870 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/MachO/basic-executable-copy.test @@ -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 diff --git a/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp b/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp index b06a622aed7..9f4e4fc4fdb 100644 --- a/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp @@ -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(MachO::macho_load_command &MLC) {  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::layoutSegments() {      }      // 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;  | 

