diff --git a/lld/include/lld/Core/DefinedAtom.h b/lld/include/lld/Core/DefinedAtom.h index 6c6d1f9ef9b6..e4d4488ccdca 100644 --- a/lld/include/lld/Core/DefinedAtom.h +++ b/lld/include/lld/Core/DefinedAtom.h @@ -151,6 +151,7 @@ public: typeNoAlloc, // Identifies non allocatable sections [ELF] typeGroupComdat, // Identifies a section group [ELF, COFF] typeGnuLinkOnce, // Identifies a gnu.linkonce section [ELF] + typeSectCreate, // Created via the -sectcreate option [Darwin] }; // Permission bits for atoms and segments. The order of these values are diff --git a/lld/include/lld/ReaderWriter/MachOLinkingContext.h b/lld/include/lld/ReaderWriter/MachOLinkingContext.h index a3459693c7d6..dc44d3f303f8 100644 --- a/lld/include/lld/ReaderWriter/MachOLinkingContext.h +++ b/lld/include/lld/ReaderWriter/MachOLinkingContext.h @@ -27,6 +27,7 @@ namespace mach_o { class ArchHandler; class MachODylibFile; class MachOFile; +class SectCreateFile; } class MachOLinkingContext : public LinkingContext { @@ -272,6 +273,10 @@ public: /// Add section alignment constraint on final layout. void addSectionAlignment(StringRef seg, StringRef sect, uint16_t align); + /// \brief Add a section based on a command-line sectcreate option. + void addSectCreateSection(StringRef seg, StringRef sect, + std::unique_ptr content); + /// Returns true if specified section had alignment constraints. bool sectionAligned(StringRef seg, StringRef sect, uint16_t &align) const; @@ -416,6 +421,7 @@ private: llvm::StringMap> _orderFiles; unsigned _orderFileEntries; File *_flatNamespaceFile; + mach_o::SectCreateFile *_sectCreateFile = nullptr; }; } // end namespace lld diff --git a/lld/lib/Core/DefinedAtom.cpp b/lld/lib/Core/DefinedAtom.cpp index b3f81ca65a91..f1d308088ed4 100644 --- a/lld/lib/Core/DefinedAtom.cpp +++ b/lld/lib/Core/DefinedAtom.cpp @@ -76,6 +76,7 @@ DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) { case typeGnuLinkOnce: case typeUnknown: case typeTempLTO: + case typeSectCreate: return permUnknown; } llvm_unreachable("unknown content type"); diff --git a/lld/lib/Driver/DarwinLdDriver.cpp b/lld/lib/Driver/DarwinLdDriver.cpp index 40a5a7174aa9..cf018934e32a 100644 --- a/lld/lib/Driver/DarwinLdDriver.cpp +++ b/lld/lib/Driver/DarwinLdDriver.cpp @@ -822,7 +822,7 @@ bool DarwinLdDriver::parse(llvm::ArrayRef args, } } - // Handle input files + // Handle input files and sectcreate. for (auto &arg : parsedArgs) { bool upward; ErrorOr resolvedPath = StringRef(); @@ -876,6 +876,22 @@ bool DarwinLdDriver::parse(llvm::ArrayRef args, return false; } break; + case OPT_sectcreate: { + const char* seg = arg->getValue(0); + const char* sect = arg->getValue(1); + const char* fileName = arg->getValue(2); + + ErrorOr> contentOrErr = + MemoryBuffer::getFile(fileName); + + if (!contentOrErr) { + diagnostics << "error: can't open -sectcreate file " << fileName << "\n"; + return false; + } + + ctx.addSectCreateSection(seg, sect, std::move(*contentOrErr)); + } + break; } } diff --git a/lld/lib/Driver/DarwinLdOptions.td b/lld/lib/Driver/DarwinLdOptions.td index 6631ee9527b7..cbf6ac1d4a4b 100644 --- a/lld/lib/Driver/DarwinLdOptions.td +++ b/lld/lib/Driver/DarwinLdOptions.td @@ -177,7 +177,10 @@ def arch : Separate<["-"], "arch">, HelpText<"Architecture to link">; def sectalign : MultiArg<["-"], "sectalign", 3>, MetaVarName<" ">, - HelpText<"alignment for segment/section">; + HelpText<"Alignment for segment/section">; +def sectcreate : MultiArg<["-"], "sectcreate", 3>, + MetaVarName<" ">, + HelpText<"Create section / from contents of ">; def image_base : Separate<["-"], "image_base">; def seg1addr : Separate<["-"], "seg1addr">, Alias; def demangle : Flag<["-"], "demangle">, diff --git a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp index 4031eb8840ad..1c97c5a39d3f 100644 --- a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp @@ -13,6 +13,7 @@ #include "FlatNamespaceFile.h" #include "MachONormalizedFile.h" #include "MachOPasses.h" +#include "SectCreateFile.h" #include "lld/Core/ArchiveLibraryFile.h" #include "lld/Core/PassManager.h" #include "lld/Core/Reader.h" @@ -749,6 +750,20 @@ void MachOLinkingContext::addSectionAlignment(StringRef seg, StringRef sect, _sectAligns.push_back(entry); } +void MachOLinkingContext::addSectCreateSection( + StringRef seg, StringRef sect, + std::unique_ptr content) { + + if (!_sectCreateFile) { + auto sectCreateFile = llvm::make_unique(); + _sectCreateFile = sectCreateFile.get(); + getNodes().push_back(llvm::make_unique(std::move(sectCreateFile))); + } + + assert(_sectCreateFile && "sectcreate file does not exist."); + _sectCreateFile->addSection(seg, sect, std::move(content)); +} + bool MachOLinkingContext::sectionAligned(StringRef seg, StringRef sect, uint16_t &align) const { for (const SectionAlign &entry : _sectAligns) { diff --git a/lld/lib/ReaderWriter/MachO/SectCreateFile.h b/lld/lib/ReaderWriter/MachO/SectCreateFile.h new file mode 100644 index 000000000000..ea16e69ab3cc --- /dev/null +++ b/lld/lib/ReaderWriter/MachO/SectCreateFile.h @@ -0,0 +1,94 @@ +//===---- lib/ReaderWriter/MachO/SectCreateFile.h ---------------*- c++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_MACHO_SECTCREATE_FILE_H +#define LLD_READER_WRITER_MACHO_SECTCREATE_FILE_H + +#include "lld/Core/DefinedAtom.h" +#include "lld/Core/Simple.h" +#include "lld/ReaderWriter/MachOLinkingContext.h" + +namespace lld { +namespace mach_o { + +// +// A FlateNamespaceFile instance may be added as a resolution source of last +// resort, depending on how -flat_namespace and -undefined are set. +// +class SectCreateFile : public File { +public: + + class SectCreateAtom : public SimpleDefinedAtom { + public: + SectCreateAtom(const File &file, StringRef segName, StringRef sectName, + std::unique_ptr content) + : SimpleDefinedAtom(file), + _combinedName((segName + "/" + sectName).str()), + _content(std::move(content)) {} + + uint64_t size() const override { return _content->getBufferSize(); } + + Scope scope() const override { return scopeGlobal; } + + ContentType contentType() const override { return typeSectCreate; } + + SectionChoice sectionChoice() const override { return sectionCustomRequired; } + + StringRef customSectionName() const override { return _combinedName; } + + DeadStripKind deadStrip() const override { return deadStripNever; } + + ArrayRef rawContent() const override { + const uint8_t *data = + reinterpret_cast(_content->getBufferStart()); + return ArrayRef(data, _content->getBufferSize()); + } + + StringRef segmentName() const { return _segName; } + StringRef sectionName() const { return _sectName; } + + private: + std::string _combinedName; + StringRef _segName; + StringRef _sectName; + std::unique_ptr _content; + }; + + SectCreateFile() : File("sectcreate", kindObject) {} + + void addSection(StringRef seg, StringRef sect, + std::unique_ptr content) { + _definedAtoms.push_back( + new (allocator()) SectCreateAtom(*this, seg, sect, std::move(content))); + } + + const AtomVector &defined() const { + return _definedAtoms; + } + + const AtomVector &undefined() const { + return _noUndefinedAtoms; + } + + const AtomVector &sharedLibrary() const { + return _noSharedLibraryAtoms; + } + + const AtomVector &absolute() const { + return _noAbsoluteAtoms; + } + +private: + AtomVector _definedAtoms; +}; + +} // namespace mach_o +} // namespace lld + +#endif // LLD_READER_WRITER_MACHO_SECTCREATE_FILE_H diff --git a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp index 182439ed07aa..78c6797b713f 100644 --- a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp +++ b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp @@ -437,6 +437,7 @@ template <> struct ScalarEnumerationTraits { io.enumCase(value, "no-alloc", DefinedAtom::typeNoAlloc); io.enumCase(value, "group-comdat", DefinedAtom::typeGroupComdat); io.enumCase(value, "gnu-linkonce", DefinedAtom::typeGnuLinkOnce); + io.enumCase(value, "sectcreate", DefinedAtom::typeSectCreate); } }; diff --git a/lld/test/mach-o/Inputs/hw.raw_bytes b/lld/test/mach-o/Inputs/hw.raw_bytes new file mode 100644 index 000000000000..ce013625030b --- /dev/null +++ b/lld/test/mach-o/Inputs/hw.raw_bytes @@ -0,0 +1 @@ +hello diff --git a/lld/test/mach-o/sectcreate.yaml b/lld/test/mach-o/sectcreate.yaml new file mode 100644 index 000000000000..51c59dc5f3d4 --- /dev/null +++ b/lld/test/mach-o/sectcreate.yaml @@ -0,0 +1,12 @@ +# RUN: lld -flavor darwin -r -arch x86_64 -o %t -sectcreate __DATA __data \ +# RUN: %p/Inputs/hw.raw_bytes -print_atoms | FileCheck %s + +# CHECK: --- !native +# CHECK: path: '' +# CHECK: defined-atoms: +# CHECK: - scope: global +# CHECK: type: sectcreate +# CHECK: content: [ 68, 65, 6C, 6C, 6F, 0A ] +# CHECK: section-choice: custom-required +# CHECK: section-name: __DATA/__data +# CHECK: dead-strip: never