[lld] r214268 - [mach-o] Add support for -sectalign option
Nick Kledzik
kledzik at apple.com
Tue Jul 29 17:58:06 PDT 2014
Author: kledzik
Date: Tue Jul 29 19:58:06 2014
New Revision: 214268
URL: http://llvm.org/viewvc/llvm-project?rev=214268&view=rev
Log:
[mach-o] Add support for -sectalign option
The -sectalign option is used to increase the alignment required for a section.
It required some reworking of how the __TEXT segment is laid out because that
segment also contains the mach_header and load commands. And the size of load
commands depend on the number of segments, sections, and dependent dylibs used.
Using this option will simplify some future test cases because the final
address of code can be pinned down, making tests of its content easier.
Added:
lld/trunk/test/mach-o/sectalign.yaml
Modified:
lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
lld/trunk/lib/Driver/DarwinLdDriver.cpp
lld/trunk/lib/Driver/DarwinLdOptions.td
lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
Modified: lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h?rev=214268&r1=214267&r2=214268&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h Tue Jul 29 19:58:06 2014
@@ -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
Modified: lld/trunk/lib/Driver/DarwinLdDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/DarwinLdDriver.cpp?rev=214268&r1=214267&r2=214268&view=diff
==============================================================================
--- lld/trunk/lib/Driver/DarwinLdDriver.cpp (original)
+++ lld/trunk/lib/Driver/DarwinLdDriver.cpp Tue Jul 29 19:58:06 2014
@@ -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, con
}
}
+ // 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());
Modified: lld/trunk/lib/Driver/DarwinLdOptions.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/DarwinLdOptions.td?rev=214268&r1=214267&r2=214268&view=diff
==============================================================================
--- lld/trunk/lib/Driver/DarwinLdOptions.td (original)
+++ lld/trunk/lib/Driver/DarwinLdOptions.td Tue Jul 29 19:58:06 2014
@@ -92,6 +92,9 @@ def path_exists : Separate<["-"], "path_
// 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">;
Modified: lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp?rev=214268&r1=214267&r2=214268&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp Tue Jul 29 19:58:06 2014
@@ -422,4 +422,24 @@ ArchHandler &MachOLinkingContext::archHa
}
+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
Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp?rev=214268&r1=214267&r2=214268&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp Tue Jul 29 19:58:06 2014
@@ -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(u
}
+size_t MachOFileLayout::headerAndLoadCommandsSize() const {
+ return _endOfLoadCommands;
+}
MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp?rev=214268&r1=214267&r2=214268&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp Tue Jul 29 19:58:06 2014
@@ -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
}
// 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(Defin
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
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(Segme
// __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(S
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(S
}
-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(NormalizedFil
}
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
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*>
(§ionContent[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 &
}
}
+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 &ato
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);
Added: lld/trunk/test/mach-o/sectalign.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/sectalign.yaml?rev=214268&view=auto
==============================================================================
--- lld/trunk/test/mach-o/sectalign.yaml (added)
+++ lld/trunk/test/mach-o/sectalign.yaml Tue Jul 29 19:58:06 2014
@@ -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
+
More information about the llvm-commits
mailing list