summaryrefslogtreecommitdiffstats
path: root/lld
diff options
context:
space:
mode:
Diffstat (limited to 'lld')
-rw-r--r--lld/include/lld/ReaderWriter/MachOLinkingContext.h13
-rw-r--r--lld/lib/Driver/DarwinLdDriver.cpp25
-rw-r--r--lld/lib/Driver/DarwinLdOptions.td3
-rw-r--r--lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp20
-rw-r--r--lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp8
-rw-r--r--lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp134
-rw-r--r--lld/test/mach-o/sectalign.yaml79
7 files changed, 237 insertions, 45 deletions
diff --git a/lld/include/lld/ReaderWriter/MachOLinkingContext.h b/lld/include/lld/ReaderWriter/MachOLinkingContext.h
index 82c782147ed..fe13aab7dbc 100644
--- a/lld/include/lld/ReaderWriter/MachOLinkingContext.h
+++ b/lld/include/lld/ReaderWriter/MachOLinkingContext.h
@@ -166,6 +166,12 @@ public:
_existingPaths.insert(path);
}
+ /// Add section alignment constraint on final layout.
+ void addSectionAlignment(StringRef seg, StringRef sect, uint8_t align2);
+
+ /// Returns true if specified section had alignment constraints.
+ bool sectionAligned(StringRef seg, StringRef sect, uint8_t &align2) const;
+
StringRef dyldPath() const { return "/usr/lib/dyld"; }
/// Stub creation Pass should be run.
@@ -201,6 +207,12 @@ private:
uint32_t cpusubtype;
};
+ struct SectionAlign {
+ StringRef segmentName;
+ StringRef sectionName;
+ uint8_t align2;
+ };
+
static ArchInfo _s_archInfos[];
std::set<StringRef> _existingPaths; // For testing only.
@@ -222,6 +234,7 @@ private:
StringRef _bundleLoader;
mutable std::unique_ptr<mach_o::ArchHandler> _archHandler;
mutable std::unique_ptr<Writer> _writer;
+ std::vector<SectionAlign> _sectAligns;
};
} // end namespace lld
diff --git a/lld/lib/Driver/DarwinLdDriver.cpp b/lld/lib/Driver/DarwinLdDriver.cpp
index 64a7fd42d8c..45035cd48c3 100644
--- a/lld/lib/Driver/DarwinLdDriver.cpp
+++ b/lld/lib/Driver/DarwinLdDriver.cpp
@@ -23,6 +23,7 @@
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MachO.h"
#include "llvm/Support/ManagedStatic.h"
@@ -254,6 +255,30 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
}
}
+ // Handle -sectalign segname sectname align
+ for (auto &alignArg : parsedArgs->filtered(OPT_sectalign)) {
+ const char* segName = alignArg->getValue(0);
+ const char* sectName = alignArg->getValue(1);
+ const char* alignStr = alignArg->getValue(2);
+ if ((alignStr[0] == '0') && (alignStr[1] == 'x'))
+ alignStr += 2;
+ unsigned long long alignValue;
+ if (llvm::getAsUnsignedInteger(alignStr, 16, alignValue)) {
+ diagnostics << "error: -sectalign alignment value '"
+ << alignStr << "' not a valid number\n";
+ return false;
+ }
+ uint8_t align2 = llvm::countTrailingZeros(alignValue);
+ if ( (unsigned long)(1 << align2) != alignValue ) {
+ diagnostics << "warning: alignment for '-sectalign "
+ << segName << " " << sectName
+ << llvm::format(" 0x%llX", alignValue)
+ << "' is not a power of two, using "
+ << llvm::format("0x%08X", (1 << align2)) << "\n";
+ }
+ ctx.addSectionAlignment(segName, sectName, align2);
+ }
+
// Handle -mllvm
for (auto &llvmArg : parsedArgs->filtered(OPT_mllvm)) {
ctx.appendLLVMOption(llvmArg->getValue());
diff --git a/lld/lib/Driver/DarwinLdOptions.td b/lld/lib/Driver/DarwinLdOptions.td
index 7aa67773e17..45eaa88b695 100644
--- a/lld/lib/Driver/DarwinLdOptions.td
+++ b/lld/lib/Driver/DarwinLdOptions.td
@@ -92,6 +92,9 @@ def path_exists : Separate<["-"], "path_exists">,
// general options
def output : Separate<["-"], "o">, HelpText<"Output file path">;
def arch : Separate<["-"], "arch">, HelpText<"Architecture to link">;
+def sectalign : MultiArg<["-"], "sectalign", 3>,
+ HelpText<"alignment for segment/section">;
+
// extras
def help : Flag<["-"], "help">;
diff --git a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
index c05772b6054..5fa74d14564 100644
--- a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
+++ b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
@@ -422,4 +422,24 @@ ArchHandler &MachOLinkingContext::archHandler() const {
}
+void MachOLinkingContext::addSectionAlignment(StringRef seg, StringRef sect,
+ uint8_t align2) {
+ SectionAlign entry;
+ entry.segmentName = seg;
+ entry.sectionName = sect;
+ entry.align2 = align2;
+ _sectAligns.push_back(entry);
+}
+
+bool MachOLinkingContext::sectionAligned(StringRef seg, StringRef sect,
+ uint8_t &align2) const {
+ for (const SectionAlign &entry : _sectAligns) {
+ if (seg.equals(entry.segmentName) && sect.equals(entry.sectionName)) {
+ align2 = entry.align2;
+ return true;
+ }
+ }
+ return false;
+}
+
} // end namespace lld
diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
index fc90e8b34cb..5d9f46dd582 100644
--- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
+++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
@@ -58,6 +58,9 @@ public:
/// Returns the final file size as computed in the constructor.
size_t size() const;
+ // Returns size of the mach_header and load commands.
+ size_t headerAndLoadCommandsSize() const;
+
/// Writes the normalized file as a binary mach-o file to the specified
/// path. This does not have a stream interface because the generated
/// file may need the 'x' bit set.
@@ -200,7 +203,7 @@ private:
size_t headerAndLoadCommandsSize(const NormalizedFile &file) {
MachOFileLayout layout(file);
- return layout.size();
+ return layout.headerAndLoadCommandsSize();
}
StringRef MachOFileLayout::dyldPath() {
@@ -212,6 +215,9 @@ uint32_t MachOFileLayout::pointerAlign(uint32_t value) {
}
+size_t MachOFileLayout::headerAndLoadCommandsSize() const {
+ return _endOfLoadCommands;
+}
MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
index e181a212de3..9f8fa42847a 100644
--- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
+++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
@@ -51,7 +51,8 @@ struct AtomInfo {
};
struct SectionInfo {
- SectionInfo(StringRef seg, StringRef sect, SectionType type, uint32_t attr=0);
+ SectionInfo(StringRef seg, StringRef sect, SectionType type,
+ const MachOLinkingContext &ctxt, uint32_t attr=0);
StringRef segmentName;
StringRef sectionName;
@@ -65,10 +66,15 @@ struct SectionInfo {
uint32_t finalSectionIndex;
};
-SectionInfo::SectionInfo(StringRef sg, StringRef sct, SectionType t, uint32_t a)
- : segmentName(sg), sectionName(sct), type(t), attributes(a),
+SectionInfo::SectionInfo(StringRef sg, StringRef sct, SectionType t,
+ const MachOLinkingContext &ctxt, uint32_t attrs)
+ : segmentName(sg), sectionName(sct), type(t), attributes(attrs),
address(0), size(0), alignment(0),
normalizedSectionIndex(0), finalSectionIndex(0) {
+ uint8_t align;
+ if (ctxt.sectionAligned(segmentName, sectionName, align)) {
+ alignment = align;
+ }
}
struct SegmentInfo {
@@ -79,10 +85,11 @@ struct SegmentInfo {
uint64_t size;
uint32_t access;
std::vector<SectionInfo*> sections;
+ uint32_t normalizedSegmentIndex;
};
SegmentInfo::SegmentInfo(StringRef n)
- : name(n), address(0), size(0), access(0) {
+ : name(n), address(0), size(0), access(0), normalizedSegmentIndex(0) {
}
@@ -93,10 +100,11 @@ public:
void assignAtomsToSections(const lld::File &atomFile);
void organizeSections();
- void assignAddressesToSections();
+ void assignAddressesToSections(const NormalizedFile &file);
uint32_t fileFlags();
void copySegmentInfo(NormalizedFile &file);
- void copySections(NormalizedFile &file);
+ void copySectionInfo(NormalizedFile &file);
+ void updateSectionInfo(NormalizedFile &file);
void buildAtomToAddressMap();
void addSymbols(const lld::File &atomFile, NormalizedFile &file);
void addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file);
@@ -105,6 +113,7 @@ public:
void buildDataInCodeArray(const lld::File &, NormalizedFile &file);
void addDependentDylibs(const lld::File &, NormalizedFile &file);
void copyEntryPointAddress(NormalizedFile &file);
+ void copySectionContent(NormalizedFile &file);
private:
typedef std::map<DefinedAtom::ContentType, SectionInfo*> TypeToSection;
@@ -119,7 +128,7 @@ private:
void appendAtom(SectionInfo *sect, const DefinedAtom *atom);
SegmentInfo *segmentForName(StringRef segName);
void layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr);
- void layoutSectionsInTextSegment(SegmentInfo *seg, uint64_t &addr);
+ void layoutSectionsInTextSegment(size_t, SegmentInfo *, uint64_t &);
void copySectionContent(SectionInfo *si, ContentBytes &content);
uint8_t scopeBits(const DefinedAtom* atom);
uint16_t descBits(const DefinedAtom* atom);
@@ -180,7 +189,8 @@ SectionInfo *Util::getRelocatableSection(DefinedAtom::ContentType type) {
}
// Otherwise allocate new SectionInfo object.
SectionInfo *sect = new (_allocator) SectionInfo(segmentName, sectionName,
- sectionType, sectionAttrs);
+ sectionType, _context,
+ sectionAttrs);
_sectionInfos.push_back(sect);
_sectionMap[type] = sect;
return sect;
@@ -255,6 +265,7 @@ SectionInfo *Util::getFinalSection(DefinedAtom::ContentType atomType) {
SectionInfo *sect = new (_allocator) SectionInfo(p.segmentName,
p.sectionName,
p.sectionType,
+ _context,
sectionAttrs);
_sectionInfos.push_back(sect);
_sectionMap[atomType] = sect;
@@ -290,7 +301,7 @@ SectionInfo *Util::sectionForAtom(const DefinedAtom *atom) {
StringRef segName = customName.slice(0, seperatorIndex);
StringRef sectName = customName.drop_front(seperatorIndex + 1);
SectionInfo *sect = new (_allocator) SectionInfo(segName, sectName,
- S_REGULAR);
+ S_REGULAR, _context);
_customSections.push_back(sect);
_sectionInfos.push_back(sect);
return sect;
@@ -402,11 +413,13 @@ void Util::organizeSections() {
}
// Record final section indexes.
+ uint32_t segmentIndex = 0;
uint32_t sectionIndex = 1;
for (SegmentInfo *seg : _segmentInfos) {
- for (SectionInfo *sect : seg->sections) {
- sect->finalSectionIndex = sectionIndex++;
- }
+ seg->normalizedSegmentIndex = segmentIndex++;
+ for (SectionInfo *sect : seg->sections) {
+ sect->finalSectionIndex = sectionIndex++;
+ }
}
}
@@ -428,7 +441,8 @@ void Util::layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr) {
// __TEXT segment lays out backwards so padding is at front after load commands.
-void Util::layoutSectionsInTextSegment(SegmentInfo *seg, uint64_t &addr) {
+void Util::layoutSectionsInTextSegment(size_t hlcSize, SegmentInfo *seg,
+ uint64_t &addr) {
seg->address = addr;
// Walks sections starting at end to calculate padding for start.
int64_t taddr = 0;
@@ -437,11 +451,11 @@ void Util::layoutSectionsInTextSegment(SegmentInfo *seg, uint64_t &addr) {
taddr -= sect->size;
taddr = taddr & (0 - (1 << sect->alignment));
}
- int64_t padding = taddr;
+ int64_t padding = taddr - hlcSize;
while (padding < 0)
padding += _context.pageSize();
// Start assigning section address starting at padded offset.
- addr += padding;
+ addr += (padding + hlcSize);
for (SectionInfo *sect : seg->sections) {
sect->address = alignTo(addr, sect->alignment);
addr = sect->address + sect->size;
@@ -450,7 +464,8 @@ void Util::layoutSectionsInTextSegment(SegmentInfo *seg, uint64_t &addr) {
}
-void Util::assignAddressesToSections() {
+void Util::assignAddressesToSections(const NormalizedFile &file) {
+ size_t hlcSize = headerAndLoadCommandsSize(file);
uint64_t address = 0; // FIXME
if (_context.outputMachOType() != llvm::MachO::MH_OBJECT) {
for (SegmentInfo *seg : _segmentInfos) {
@@ -459,7 +474,7 @@ void Util::assignAddressesToSections() {
address += seg->size;
}
else if (seg->name.equals("__TEXT"))
- layoutSectionsInTextSegment(seg, address);
+ layoutSectionsInTextSegment(hlcSize, seg, address);
else
layoutSectionsInSegment(seg, address);
@@ -510,16 +525,7 @@ void Util::copySegmentInfo(NormalizedFile &file) {
}
void Util::appendSection(SectionInfo *si, NormalizedFile &file) {
- const bool rMode = (_context.outputMachOType() == llvm::MachO::MH_OBJECT);
-
- // Utility function for ArchHandler to find address of atom in output file.
- auto addrForAtom = [&] (const Atom &atom) -> uint64_t {
- auto pos = _atomToAddress.find(&atom);
- assert(pos != _atomToAddress.end());
- return pos->second;
- };
-
- // Add new empty section to end of file.sections.
+ // Add new empty section to end of file.sections.
Section temp;
file.sections.push_back(std::move(temp));
Section* normSect = &file.sections.back();
@@ -532,19 +538,35 @@ void Util::appendSection(SectionInfo *si, NormalizedFile &file) {
normSect->alignment = si->alignment;
// Record where normalized section is.
si->normalizedSectionIndex = file.sections.size()-1;
- // Copy content from atoms to content buffer for section.
- if (si->type == llvm::MachO::S_ZEROFILL)
- return;
- uint8_t *sectionContent = file.ownedAllocations.Allocate<uint8_t>(si->size);
- normSect->content = llvm::makeArrayRef(sectionContent, si->size);
- for (AtomInfo &ai : si->atomsAndOffsets) {
- uint8_t *atomContent = reinterpret_cast<uint8_t*>
+}
+
+void Util::copySectionContent(NormalizedFile &file) {
+ const bool r = (_context.outputMachOType() == llvm::MachO::MH_OBJECT);
+
+ // Utility function for ArchHandler to find address of atom in output file.
+ auto addrForAtom = [&] (const Atom &atom) -> uint64_t {
+ auto pos = _atomToAddress.find(&atom);
+ assert(pos != _atomToAddress.end());
+ return pos->second;
+ };
+
+ for (SectionInfo *si : _sectionInfos) {
+ if (si->type == llvm::MachO::S_ZEROFILL)
+ continue;
+ // Copy content from atoms to content buffer for section.
+ uint8_t *sectionContent = file.ownedAllocations.Allocate<uint8_t>(si->size);
+ Section *normSect = &file.sections[si->normalizedSectionIndex];
+ normSect->content = llvm::makeArrayRef(sectionContent, si->size);
+ for (AtomInfo &ai : si->atomsAndOffsets) {
+ uint8_t *atomContent = reinterpret_cast<uint8_t*>
(&sectionContent[ai.offsetInSection]);
- _archHandler.generateAtomContent(*ai.atom, rMode, addrForAtom, atomContent);
+ _archHandler.generateAtomContent(*ai.atom, r, addrForAtom, atomContent);
+ }
}
}
-void Util::copySections(NormalizedFile &file) {
+
+void Util::copySectionInfo(NormalizedFile &file) {
file.sections.reserve(_sectionInfos.size());
// For final linked images, write sections grouped by segment.
if (_context.outputMachOType() != llvm::MachO::MH_OBJECT) {
@@ -561,6 +583,28 @@ void Util::copySections(NormalizedFile &file) {
}
}
+void Util::updateSectionInfo(NormalizedFile &file) {
+ file.sections.reserve(_sectionInfos.size());
+ if (_context.outputMachOType() != llvm::MachO::MH_OBJECT) {
+ // For final linked images, sections grouped by segment.
+ for (SegmentInfo *sgi : _segmentInfos) {
+ Segment *normSeg = &file.segments[sgi->normalizedSegmentIndex];
+ normSeg->address = sgi->address;
+ normSeg->size = sgi->size;
+ for (SectionInfo *si : sgi->sections) {
+ Section *normSect = &file.sections[si->normalizedSectionIndex];
+ normSect->address = si->address;
+ }
+ }
+ } else {
+ // Object files write sections in default order.
+ for (SectionInfo *si : _sectionInfos) {
+ Section *normSect = &file.sections[si->normalizedSectionIndex];
+ normSect->address = si->address;
+ }
+ }
+}
+
void Util::copyEntryPointAddress(NormalizedFile &nFile) {
if (_context.outputTypeHasEntry()) {
if (_archHandler.isThumbFunction(*_entryAtom))
@@ -1020,18 +1064,20 @@ normalizedFromAtoms(const lld::File &atomFile,
Util util(context);
util.assignAtomsToSections(atomFile);
util.organizeSections();
- util.assignAddressesToSections();
- util.buildAtomToAddressMap();
std::unique_ptr<NormalizedFile> f(new NormalizedFile());
NormalizedFile &normFile = *f.get();
- f->arch = context.arch();
- f->fileType = context.outputMachOType();
- f->flags = util.fileFlags();
- f->installName = context.installName();
- util.copySegmentInfo(normFile);
- util.copySections(normFile);
+ normFile.arch = context.arch();
+ normFile.fileType = context.outputMachOType();
+ normFile.flags = util.fileFlags();
+ normFile.installName = context.installName();
util.addDependentDylibs(atomFile, normFile);
+ util.copySegmentInfo(normFile);
+ util.copySectionInfo(normFile);
+ util.assignAddressesToSections(normFile);
+ util.buildAtomToAddressMap();
+ util.updateSectionInfo(normFile);
+ util.copySectionContent(normFile);
util.addSymbols(atomFile, normFile);
util.addIndirectSymbols(atomFile, normFile);
util.addRebaseAndBindingInfo(atomFile, normFile);
diff --git a/lld/test/mach-o/sectalign.yaml b/lld/test/mach-o/sectalign.yaml
new file mode 100644
index 00000000000..7e2ad97ef4e
--- /dev/null
+++ b/lld/test/mach-o/sectalign.yaml
@@ -0,0 +1,79 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -dylib \
+# RUN: -sectalign __DATA __custom 0x800 -sectalign __TEXT __text 0x400 -o %t \
+# RUN: && llvm-readobj -sections %t | FileCheck %s
+#
+# Test -sectalign option on __text and a custom section.
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x8B, 0x05, 0x00, 0x00,
+ 0x00, 0x00, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00,
+ 0x5D, 0xC3 ]
+ relocations:
+ - offset: 0x0000000C
+ type: X86_64_RELOC_SIGNED
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 1
+ - offset: 0x00000006
+ type: X86_64_RELOC_SIGNED
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 2
+ - segment: __DATA
+ section: __data
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 2
+ address: 0x0000000000000014
+ content: [ 0x0A, 0x00, 0x00, 0x00 ]
+ - segment: __DATA
+ section: __custom
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 2
+ address: 0x0000000000000018
+ content: [ 0x0A, 0x00, 0x00, 0x00 ]
+global-symbols:
+ - name: _a
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 2
+ value: 0x0000000000000014
+ - name: _b
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 3
+ value: 0x0000000000000018
+ - name: _get
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+
+...
+
+
+# CHECK: Name: __text (5F 5F 74 65 78 74 00 00 00 00 00 00 00 00 00 00)
+# CHECK: Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00)
+# CHECK: Address: 0xC00
+
+# CHECK: Name: __data (5F 5F 64 61 74 61 00 00 00 00 00 00 00 00 00 00)
+# CHECK: Segment: __DATA (5F 5F 44 41 54 41 00 00 00 00 00 00 00 00 00 00)
+# CHECK: Address: 0x1000
+
+# CHECK: Name: __custom (5F 5F 63 75 73 74 6F 6D 00 00 00 00 00 00 00 00)
+# CHECK: Segment: __DATA (5F 5F 44 41 54 41 00 00 00 00 00 00 00 00 00 00)
+# CHECK: Address: 0x1800
+
OpenPOWER on IntegriCloud