From 08d6a7bfef5ab69a9c85512727b26d0b6d3d9d55 Mon Sep 17 00:00:00 2001 From: Tim Northover Date: Mon, 30 Jun 2014 09:49:30 +0000 Subject: [PATCH] MachO: calculate segment offsets in final MachO files properly. Because of how we were calculating fileOffset and fileSize for segments, most ended up at a single offset in a finalised MachO file. This meant the data often didn't even get written in the final object, let alone where it would be useful. llvm-svn: 212030 --- .../MachO/MachONormalizedFileBinaryWriter.cpp | 22 ++++++++--- lld/test/mach-o/exe-offsets.yaml | 44 ++++++++++++++++++++++ 2 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 lld/test/mach-o/exe-offsets.yaml diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp index a593f07..2f61607 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp @@ -142,6 +142,7 @@ private: struct SegExtraInfo { uint32_t fileOffset; + uint32_t fileSize; std::vector sections; }; typedef std::map SegMap; @@ -423,23 +424,32 @@ void MachOFileLayout::buildFileOffsets() { DEBUG_WITH_TYPE("MachOFileLayout", llvm::dbgs() << "buildFileOffsets()\n"); for (const Segment &sg : _file.segments) { - // FIXME: 4096 should be inferred from segments in normalized file. - _segInfo[&sg].fileOffset = llvm::RoundUpToAlignment(fileOffset, 4096); + _segInfo[&sg].fileOffset = fileOffset; if ((_seg1addr == INT64_MAX) && sg.access) _seg1addr = sg.address; DEBUG_WITH_TYPE("MachOFileLayout", llvm::dbgs() << " segment=" << sg.name << ", fileOffset=" << _segInfo[&sg].fileOffset << "\n"); + + uint32_t segFileSize = 0; for (const Section *s : _segInfo[&sg].sections) { - fileOffset = s->address - sg.address + _segInfo[&sg].fileOffset; - _sectInfo[s].fileOffset = fileOffset; + uint32_t sectOffset = s->address - sg.address; + uint32_t sectFileSize = + s->type == llvm::MachO::S_ZEROFILL ? 0 : s->content.size(); + segFileSize = std::max(segFileSize, sectOffset + sectFileSize); + + _sectInfo[s].fileOffset = _segInfo[&sg].fileOffset + sectOffset; DEBUG_WITH_TYPE("MachOFileLayout", llvm::dbgs() << " section=" << s->sectionName << ", fileOffset=" << fileOffset << "\n"); } + + // FIXME: 4096 should be inferred from segments in normalized file. + _segInfo[&sg].fileSize = llvm::RoundUpToAlignment(segFileSize, 4096); + fileOffset = llvm::RoundUpToAlignment(fileOffset + segFileSize, 4096); _addressOfLinkEdit = sg.address + sg.size; } - _startOfLinkEdit = llvm::RoundUpToAlignment(fileOffset, 4096); + _startOfLinkEdit = fileOffset; } @@ -537,7 +547,7 @@ std::error_code MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) { cmd->vmaddr = seg.address; cmd->vmsize = seg.size; cmd->fileoff = segInfo.fileOffset; - cmd->filesize = seg.access ? seg.size : Hex64(0); + cmd->filesize = segInfo.fileSize; cmd->maxprot = seg.access; cmd->initprot = seg.access; cmd->nsects = segInfo.sections.size(); diff --git a/lld/test/mach-o/exe-offsets.yaml b/lld/test/mach-o/exe-offsets.yaml new file mode 100644 index 0000000..12f0815 --- /dev/null +++ b/lld/test/mach-o/exe-offsets.yaml @@ -0,0 +1,44 @@ +# RUN: lld -flavor darwin -arch x86_64 %s -o %t -e start +# RUN: llvm-readobj -sections %t | FileCheck %s + +# Make sure data gets put at offset + +--- !native +defined-atoms: + - name: start + scope: global + content: [ 90 ] + + - name: _s1 + type: data + content: [ 31, 32, 33, 34 ] + + - name: _s2 + type: zero-fill + size: 8192 + + - name: _s3 + type: zero-fill + size: 100 + + - name: _s4 + type: data + content: [ 01 ] + +# CHECK-LABEL: Section { +# CHECK: Name: __text +# CHECK: Segment: __TEXT +# CHECK: Size: 0x1 +# CHECK: Offset: 0 + +# CHECK-LABEL: Section { +# CHECK: Name: __data +# CHECK: Segment: __DATA +# CHECK: Size: 0x5 +# CHECK: Offset: 4096 + +# CHECK-LABEL: Section { +# CHECK: Name: ___bss +# CHECK: Segment: __DATA +# CHECK: Size: 0x0 +# CHECK: Offset: 4101 -- 2.7.4