1 //===- lib/ReaderWriter/MachO/ObjCPass.cpp -------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 //===----------------------------------------------------------------------===// 10 11 #include "ArchHandler.h" 12 #include "File.h" 13 #include "MachONormalizedFileBinaryUtils.h" 14 #include "MachOPasses.h" 15 #include "lld/Common/LLVM.h" 16 #include "lld/Core/DefinedAtom.h" 17 #include "lld/Core/File.h" 18 #include "lld/Core/Reference.h" 19 #include "lld/Core/Simple.h" 20 #include "lld/ReaderWriter/MachOLinkingContext.h" 21 #include "llvm/ADT/DenseMap.h" 22 #include "llvm/ADT/STLExtras.h" 23 24 namespace lld { 25 namespace mach_o { 26 27 /// 28 /// ObjC Image Info Atom created by the ObjC pass. 29 /// 30 class ObjCImageInfoAtom : public SimpleDefinedAtom { 31 public: 32 ObjCImageInfoAtom(const File &file, bool isBig, 33 MachOLinkingContext::ObjCConstraint objCConstraint, 34 uint32_t swiftVersion) 35 : SimpleDefinedAtom(file) { 36 37 Data.info.version = 0; 38 39 switch (objCConstraint) { 40 case MachOLinkingContext::objc_unknown: 41 llvm_unreachable("Shouldn't run the objc pass without a constraint"); 42 case MachOLinkingContext::objc_supports_gc: 43 case MachOLinkingContext::objc_gc_only: 44 llvm_unreachable("GC is not supported"); 45 case MachOLinkingContext::objc_retainReleaseForSimulator: 46 // The retain/release for simulator flag is already the correct 47 // encoded value for the data so just set it here. 48 Data.info.flags = (uint32_t)objCConstraint; 49 break; 50 case MachOLinkingContext::objc_retainRelease: 51 // We don't need to encode this flag, so just leave the flags as 0. 52 Data.info.flags = 0; 53 break; 54 } 55 56 Data.info.flags |= (swiftVersion << 8); 57 58 normalized::write32(Data.bytes + 4, Data.info.flags, isBig); 59 } 60 61 ~ObjCImageInfoAtom() override = default; 62 63 ContentType contentType() const override { 64 return DefinedAtom::typeObjCImageInfo; 65 } 66 67 Alignment alignment() const override { 68 return 4; 69 } 70 71 uint64_t size() const override { 72 return 8; 73 } 74 75 ContentPermissions permissions() const override { 76 return DefinedAtom::permR__; 77 } 78 79 ArrayRef<uint8_t> rawContent() const override { 80 return llvm::makeArrayRef(Data.bytes, size()); 81 } 82 83 private: 84 85 struct objc_image_info { 86 uint32_t version; 87 uint32_t flags; 88 }; 89 90 union { 91 objc_image_info info; 92 uint8_t bytes[8]; 93 } Data; 94 }; 95 96 class ObjCPass : public Pass { 97 public: 98 ObjCPass(const MachOLinkingContext &context) 99 : _ctx(context), 100 _file(*_ctx.make_file<MachOFile>("<mach-o objc pass>")) { 101 _file.setOrdinal(_ctx.getNextOrdinalAndIncrement()); 102 } 103 104 llvm::Error perform(SimpleFile &mergedFile) override { 105 // Add the image info. 106 mergedFile.addAtom(*getImageInfo()); 107 108 return llvm::Error::success(); 109 } 110 111 private: 112 113 const DefinedAtom* getImageInfo() { 114 bool IsBig = MachOLinkingContext::isBigEndian(_ctx.arch()); 115 return new (_file.allocator()) ObjCImageInfoAtom(_file, IsBig, 116 _ctx.objcConstraint(), 117 _ctx.swiftVersion()); 118 } 119 120 const MachOLinkingContext &_ctx; 121 MachOFile &_file; 122 }; 123 124 125 126 void addObjCPass(PassManager &pm, const MachOLinkingContext &ctx) { 127 pm.add(llvm::make_unique<ObjCPass>(ctx)); 128 } 129 130 } // end namespace mach_o 131 } // end namespace lld 132