summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/include/lld/Core/DefinedAtom.h1
-rw-r--r--lld/include/lld/ReaderWriter/MachOLinkingContext.h6
-rw-r--r--lld/lib/Core/DefinedAtom.cpp1
-rw-r--r--lld/lib/ReaderWriter/MachO/CMakeLists.txt1
-rw-r--r--lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp10
-rw-r--r--lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp58
-rw-r--r--lld/lib/ReaderWriter/MachO/MachOPasses.h1
-rw-r--r--lld/lib/ReaderWriter/MachO/ObjCPass.cpp126
-rw-r--r--lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp2
-rw-r--r--lld/test/mach-o/objc-image-info-pass-output.yaml30
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 &sect,
+ const NormalizedFile &normalizedFile,
MachOFile &file) {
- const Section *imageInfoSection = nullptr;
- for (auto &section : normalizedFile.sections) {
- if (section.segmentName == "__OBJC" &&
- section.sectionName == "__image_info") {
- imageInfoSection = &section;
- break;
- }
- if (section.segmentName == "__DATA" &&
- section.sectionName == "__objc_imageinfo") {
- imageInfoSection = &section;
- 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 &sect) {
+ 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
OpenPOWER on IntegriCloud