diff options
-rw-r--r-- | lld/include/lld/Core/DefinedAtom.h | 1 | ||||
-rw-r--r-- | lld/include/lld/ReaderWriter/MachOLinkingContext.h | 6 | ||||
-rw-r--r-- | lld/lib/Core/DefinedAtom.cpp | 1 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/MachO/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp | 10 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp | 58 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/MachO/MachOPasses.h | 1 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/MachO/ObjCPass.cpp | 126 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp | 2 | ||||
-rw-r--r-- | lld/test/mach-o/objc-image-info-pass-output.yaml | 30 |
10 files changed, 204 insertions, 32 deletions
diff --git a/lld/include/lld/Core/DefinedAtom.h b/lld/include/lld/Core/DefinedAtom.h index e4d4488ccdc..47891b9b474 100644 --- a/lld/include/lld/Core/DefinedAtom.h +++ b/lld/include/lld/Core/DefinedAtom.h @@ -134,6 +134,7 @@ public: typeCStringPtr, // pointer to UTF8 C string [Darwin] typeObjCClassPtr, // pointer to ObjC class [Darwin] typeObjC2CategoryList, // pointers to ObjC category [Darwin] + typeObjCImageInfo, // pointer to ObjC class [Darwin] typeDTraceDOF, // runtime data for Dtrace [Darwin] typeInterposingTuples, // tuples of interposing info for dyld [Darwin] typeTempLTO, // temporary atom for bitcode reader diff --git a/lld/include/lld/ReaderWriter/MachOLinkingContext.h b/lld/include/lld/ReaderWriter/MachOLinkingContext.h index 32a03fb790c..c1c9f6b8dc9 100644 --- a/lld/include/lld/ReaderWriter/MachOLinkingContext.h +++ b/lld/include/lld/ReaderWriter/MachOLinkingContext.h @@ -154,7 +154,8 @@ public: void setBaseAddress(uint64_t baseAddress) { _baseAddress = baseAddress; } ObjCConstraint objcConstraint() const { return _objcConstraint; } - void setObjcConstraint(ObjCConstraint v) { _objcConstraint = v; } + + uint32_t swiftVersion() const { return _swiftVersion; } /// \brief Checks whether a given path on the filesystem exists. /// @@ -310,6 +311,9 @@ public: /// Pass to add shims switching between thumb and arm mode. bool needsShimPass() const; + /// Pass to add objc image info and optimized objc data. + bool needsObjCPass() const; + /// Magic symbol name stubs will need to help lazy bind. StringRef binderSymbolName() const; diff --git a/lld/lib/Core/DefinedAtom.cpp b/lld/lib/Core/DefinedAtom.cpp index f1d308088ed..71d0f67ad40 100644 --- a/lld/lib/Core/DefinedAtom.cpp +++ b/lld/lib/Core/DefinedAtom.cpp @@ -43,6 +43,7 @@ DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) { case typeProcessedUnwindInfo: case typeRONote: case typeNoAlloc: + case typeObjCImageInfo: return permR__; case typeData: diff --git a/lld/lib/ReaderWriter/MachO/CMakeLists.txt b/lld/lib/ReaderWriter/MachO/CMakeLists.txt index a389ca51ddf..c4587a24118 100644 --- a/lld/lib/ReaderWriter/MachO/CMakeLists.txt +++ b/lld/lib/ReaderWriter/MachO/CMakeLists.txt @@ -13,6 +13,7 @@ add_lld_library(lldMachO MachONormalizedFileFromAtoms.cpp MachONormalizedFileToAtoms.cpp MachONormalizedFileYAML.cpp + ObjCPass.cpp ShimPass.cpp StubsPass.cpp TLVPass.cpp diff --git a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp index 38c73d7a6be..ff788fd32bf 100644 --- a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp @@ -326,6 +326,11 @@ bool MachOLinkingContext::needsCompactUnwindPass() const { } } +bool MachOLinkingContext::needsObjCPass() const { + // ObjC pass is only needed if any of the inputs were ObjC. + return _objcConstraint != objc_unknown; +} + bool MachOLinkingContext::needsShimPass() const { // Shim pass only used in final executables. if (_outputMachOType == MH_OBJECT) @@ -590,6 +595,10 @@ bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) { } void MachOLinkingContext::addPasses(PassManager &pm) { + // objc pass should be before layout pass. Otherwise test cases may contain + // no atoms which confuses the layout pass. + if (needsObjCPass()) + mach_o::addObjCPass(pm, *this); mach_o::addLayoutPass(pm, *this); if (needsStubsPass()) mach_o::addStubsPass(pm, *this); @@ -1060,6 +1069,7 @@ std::error_code MachOLinkingContext::handleLoadedFile(File &file) { // Swift versions are different. return make_dynamic_error_code("different swift versions"); } + return std::error_code(); } diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp index 44e22ab6491..32ad88fe396 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp @@ -88,6 +88,7 @@ const MachORelocatableSectionToAtomType sectsToAtomType[] = { ENTRY("__DATA", "__thread_data", S_THREAD_LOCAL_REGULAR, typeTLVInitialData), ENTRY("__DATA", "__thread_bss", S_THREAD_LOCAL_ZEROFILL, typeTLVInitialZeroFill), + ENTRY("__DATA", "__objc_imageinfo", S_REGULAR, typeObjCImageInfo), ENTRY("", "", S_INTERPOSING, typeInterposingTuples), ENTRY("__LD", "__compact_unwind", S_REGULAR, typeCompactUnwindInfo), @@ -867,52 +868,35 @@ std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile, return ehFrameErr; } -std::error_code parseObjCImageInfo(const NormalizedFile &normalizedFile, +std::error_code parseObjCImageInfo(const Section §, + const NormalizedFile &normalizedFile, MachOFile &file) { - const Section *imageInfoSection = nullptr; - for (auto §ion : normalizedFile.sections) { - if (section.segmentName == "__OBJC" && - section.sectionName == "__image_info") { - imageInfoSection = §ion; - break; - } - if (section.segmentName == "__DATA" && - section.sectionName == "__objc_imageinfo") { - imageInfoSection = §ion; - break; - } - } - - // No image info section so nothing to do. - if (!imageInfoSection) - return std::error_code(); - // struct objc_image_info { // uint32_t version; // initially 0 // uint32_t flags; // }; - ArrayRef<uint8_t> content = imageInfoSection->content; + ArrayRef<uint8_t> content = sect.content; if (content.size() != 8) - return make_dynamic_error_code(imageInfoSection->segmentName + "/" + - imageInfoSection->sectionName + + return make_dynamic_error_code(sect.segmentName + "/" + + sect.sectionName + " in file " + file.path() + " should be 8 bytes in size"); const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch); uint32_t version = read32(content.data(), isBig); if (version) - return make_dynamic_error_code(imageInfoSection->segmentName + "/" + - imageInfoSection->sectionName + + return make_dynamic_error_code(sect.segmentName + "/" + + sect.sectionName + " in file " + file.path() + " should have version=0"); uint32_t flags = read32(content.data() + 4, isBig); if (flags & (MachOLinkingContext::objc_supports_gc | MachOLinkingContext::objc_gc_only)) - return make_dynamic_error_code(imageInfoSection->segmentName + "/" + - imageInfoSection->sectionName + + return make_dynamic_error_code(sect.segmentName + "/" + + sect.sectionName + " in file " + file.path() + " uses GC. This is not supported"); @@ -951,6 +935,11 @@ dylibToAtoms(const NormalizedFile &normalizedFile, StringRef path, namespace normalized { +static bool isObjCImageInfo(const Section §) { + return (sect.segmentName == "__OBJC" && sect.sectionName == "__image_info") || + (sect.segmentName == "__DATA" && sect.sectionName == "__objc_imageinfo"); +} + std::error_code normalizedObjectToAtoms(MachOFile *file, const NormalizedFile &normalizedFile, @@ -964,6 +953,18 @@ normalizedObjectToAtoms(MachOFile *file, DEBUG(llvm::dbgs() << "Creating atoms: "; sect.dump()); if (isDebugInfoSection(sect)) continue; + + + // If the file contains an objc_image_info struct, then we should parse the + // ObjC flags and Swift version. + if (isObjCImageInfo(sect)) { + if (std::error_code ec = parseObjCImageInfo(sect, normalizedFile, *file)) + return ec; + // We then skip adding atoms for this section as we use the ObjCPass to + // re-emit this data after it has been aggregated for all files. + continue; + } + bool customSectionName; DefinedAtom::ContentType atomType = atomTypeFromSection(sect, customSectionName); @@ -1007,11 +1008,6 @@ normalizedObjectToAtoms(MachOFile *file, if (std::error_code ec = addEHFrameReferences(normalizedFile, *file, *handler)) return ec; - // If the file contains an objc_image_info struct, then we should parse the - // ObjC flags and Swift version. - if (std::error_code ec = parseObjCImageInfo(normalizedFile, *file)) - return ec; - // Process mach-o data-in-code regions array. That information is encoded in // atoms as References at each transition point. unsigned nextIndex = 0; diff --git a/lld/lib/ReaderWriter/MachO/MachOPasses.h b/lld/lib/ReaderWriter/MachO/MachOPasses.h index a73785418d5..cd01d4aa2c9 100644 --- a/lld/lib/ReaderWriter/MachO/MachOPasses.h +++ b/lld/lib/ReaderWriter/MachO/MachOPasses.h @@ -21,6 +21,7 @@ void addStubsPass(PassManager &pm, const MachOLinkingContext &ctx); void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx); void addTLVPass(PassManager &pm, const MachOLinkingContext &ctx); void addCompactUnwindPass(PassManager &pm, const MachOLinkingContext &ctx); +void addObjCPass(PassManager &pm, const MachOLinkingContext &ctx); void addShimPass(PassManager &pm, const MachOLinkingContext &ctx); } // namespace mach_o diff --git a/lld/lib/ReaderWriter/MachO/ObjCPass.cpp b/lld/lib/ReaderWriter/MachO/ObjCPass.cpp new file mode 100644 index 00000000000..023019111a8 --- /dev/null +++ b/lld/lib/ReaderWriter/MachO/ObjCPass.cpp @@ -0,0 +1,126 @@ +//===- lib/ReaderWriter/MachO/ObjCPass.cpp -------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//===----------------------------------------------------------------------===// + +#include "ArchHandler.h" +#include "File.h" +#include "MachOPasses.h" +#include "lld/Core/DefinedAtom.h" +#include "lld/Core/File.h" +#include "lld/Core/LLVM.h" +#include "lld/Core/Reference.h" +#include "lld/Core/Simple.h" +#include "lld/ReaderWriter/MachOLinkingContext.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" + +namespace lld { +namespace mach_o { + +// +// ObjC Image Info Atom created by the ObjC pass. +// +class ObjCImageInfoAtom : public SimpleDefinedAtom { +public: + ObjCImageInfoAtom(const File &file, + MachOLinkingContext::ObjCConstraint objCConstraint, + uint32_t swiftVersion) + : SimpleDefinedAtom(file) { + + Data.info.version = 0; + + switch (objCConstraint) { + case MachOLinkingContext::objc_unknown: + llvm_unreachable("Shouldn't run the objc pass without a constraint"); + case MachOLinkingContext::objc_supports_gc: + case MachOLinkingContext::objc_gc_only: + llvm_unreachable("GC is not supported"); + case MachOLinkingContext::objc_retainReleaseForSimulator: + // The retain/release for simulator flag is already the correct + // encoded value for the data so just set it here. + Data.info.flags = (uint32_t)objCConstraint; + break; + case MachOLinkingContext::objc_retainRelease: + // We don't need to encode this flag, so just leave the flags as 0. + Data.info.flags = 0; + break; + } + + Data.info.flags |= (swiftVersion << 8); + } + + ContentType contentType() const override { + return DefinedAtom::typeObjCImageInfo; + } + + Alignment alignment() const override { + return 4; + } + + uint64_t size() const override { + return 8; + } + + ContentPermissions permissions() const override { + return DefinedAtom::permR__; + } + + ArrayRef<uint8_t> rawContent() const override { + return llvm::makeArrayRef(Data.bytes, size()); + } + +private: + + struct objc_image_info { + uint32_t version; + uint32_t flags; + }; + + union { + objc_image_info info; + uint8_t bytes[8]; + } Data; +}; + +class ObjCPass : public Pass { +public: + ObjCPass(const MachOLinkingContext &context) + : _ctx(context), + _file("<mach-o objc pass>") { + _file.setOrdinal(_ctx.getNextOrdinalAndIncrement()); + } + + std::error_code perform(SimpleFile &mergedFile) override { + // Add the image info. + mergedFile.addAtom(*getImageInfo()); + + return std::error_code(); + } + +private: + + const DefinedAtom* getImageInfo() { + return new (_file.allocator()) ObjCImageInfoAtom(_file, + _ctx.objcConstraint(), + _ctx.swiftVersion()); + } + + const MachOLinkingContext &_ctx; + MachOFile _file; +}; + + + +void addObjCPass(PassManager &pm, const MachOLinkingContext &ctx) { + pm.add(llvm::make_unique<ObjCPass>(ctx)); +} + +} // end namespace mach_o +} // end namespace lld diff --git a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp index 4478feeffb4..3e4f51882c6 100644 --- a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp +++ b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp @@ -418,6 +418,8 @@ template <> struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> { DefinedAtom::typeObjCClassPtr); io.enumCase(value, "objc-category-list", DefinedAtom::typeObjC2CategoryList); + io.enumCase(value, "objc-image-info", + DefinedAtom::typeObjCImageInfo); io.enumCase(value, "objc-class1", DefinedAtom::typeObjC1Class); io.enumCase(value, "dtraceDOF", DefinedAtom::typeDTraceDOF); io.enumCase(value, "interposing-tuples", diff --git a/lld/test/mach-o/objc-image-info-pass-output.yaml b/lld/test/mach-o/objc-image-info-pass-output.yaml new file mode 100644 index 00000000000..7fc95a84632 --- /dev/null +++ b/lld/test/mach-o/objc-image-info-pass-output.yaml @@ -0,0 +1,30 @@ +# RUN: lld -flavor darwin -ios_simulator_version_min 5.0 -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s + +# Make sure that we have an objc image info in the output. It should have +# been generated by the objc pass. + +--- !mach-o +arch: x86_64 +file-type: MH_OBJECT +flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ] +compat-version: 0.0 +current-version: 0.0 +has-UUID: false +OS: unknown +sections: + - segment: __DATA + section: __objc_imageinfo + type: S_REGULAR + attributes: [ S_ATTR_NO_DEAD_STRIP ] + address: 0x0000000000000100 + content: [ 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00 ] +... + +# CHECK: --- !native +# CHECK: path: '<linker-internal>' +# CHECK: defined-atoms: +# CHECK: - scope: hidden +# CHECK: type: objc-image-info +# CHECK: content: [ 00, 00, 00, 00, 20, 02, 00, 00 ] +# CHECK: alignment: 4 +# CHECK: ...
\ No newline at end of file |