Index: lib/ReaderWriter/MachO/ObjCPass.cpp =================================================================== --- lib/ReaderWriter/MachO/ObjCPass.cpp +++ lib/ReaderWriter/MachO/ObjCPass.cpp @@ -11,6 +11,7 @@ #include "ArchHandler.h" #include "File.h" +#include "MachONormalizedFileBinaryUtils.h" #include "MachOPasses.h" #include "lld/Core/DefinedAtom.h" #include "lld/Core/File.h" @@ -89,6 +90,66 @@ } Data; }; +/// +/// ObjC Method List Atom created by the ObjC pass. +/// +/// struct _method_list_t { +/// uint32_t SizeOfMethod = sizeof(method_t); +/// uint32_t NumMethods; +/// method_t Methods[NumMethods]; +/// } +/// +class ObjCMethodListAtom : public MachODefinedCustomSectionAtom { +public: + ObjCMethodListAtom(const File &file, + StringRef classAtomName, + unsigned methodCount, + const MachOLinkingContext &ctx, + llvm::BumpPtrAllocator &allocator) + : MachODefinedCustomSectionAtom(file, getAtomName(classAtomName, allocator), + Scope::scopeGlobal, + DefinedAtom::typeObjCMethodList, + Merge::mergeNo, + false /* thumb */, true /* noDeadStrip */, + getBuffer(methodCount, ctx, allocator), + "__DATA/__objc_const", 8) { + + bool isBig = MachOLinkingContext::isBigEndian(ctx.arch()); + uint8_t *BufferData = const_cast(rawContent().data()); + normalized::write32(BufferData, getMethodSize(ctx), isBig); + normalized::write32(BufferData + 4, methodCount, isBig); + bzero(BufferData + 8, size() - 8); + } + + ContentPermissions permissions() const override { + return DefinedAtom::permR__; + } + +private: + /// Constructs a buffer for a method list with the given number of methods. + static ArrayRef getBuffer(unsigned methodCount, + const MachOLinkingContext &ctx, + llvm::BumpPtrAllocator &allocator) { + unsigned BufferSize = 8 + (getMethodSize(ctx) * methodCount); + uint8_t *BufferData = (uint8_t*)allocator.Allocate(BufferSize, 8); + return llvm::makeArrayRef(BufferData, BufferSize); + } + + static StringRef getAtomName(StringRef classAtomName, + llvm::BumpPtrAllocator &allocator) { + SmallString<128> name; + name += "l_"; + name += classAtomName; + name += "_objc_merged_method_list"; + return name.str().copy(allocator); + } + + static unsigned getMethodSize(const MachOLinkingContext &ctx) { + // A single method is exactly 3 pointers in size + return 3 * (ctx.is64Bit() ? 8 : 4); + } +}; + class ObjCPass : public Pass { public: ObjCPass(const MachOLinkingContext &context) @@ -101,6 +162,10 @@ // Add the image info. mergedFile.addAtom(*getImageInfo()); + if (_ctx.mergeObjCCategories()) + if (auto EC = optimizeCategories(mergedFile)) + return EC; + return std::error_code(); } @@ -112,11 +177,513 @@ _ctx.swiftVersion()); } + std::error_code optimizeCategories(SimpleFile &mergedFile); + const MachOLinkingContext &_ctx; MachOFile _file; }; +/// Provides accessors to an in memory category atom. +/// +/// struct category_t { +/// ptr_t name; +/// ptr_t class; +/// ptr_t instance methods; +/// ptr_t class methods; +/// ptr_t protocols; +/// ptr_t instance properties; +/// } +class Category { +public: + Category(const DefinedAtom *atom, MachOLinkingContext::Arch arch) + : AtomAndIs64Bit(atom, MachOLinkingContext::is64Bit(arch)) { + } + + /// Verifies that the category is correct. Otherwise returns an error. + std::error_code verify() const { + // Categories are 6 pointers. Make sure the size reflects that. + const DefinedAtom *atom = AtomAndIs64Bit.getPointer(); + if (atom->size() != (6 * (is64Bit() ? 8 : 4))) + return make_dynamic_error_code("ObjC category size must be 6 pointers"); + return std::error_code(); + } + + ErrorOr getClass() const { + auto ErrorOrAtom = getReferenceAtOffset(1 * (is64Bit() ? 8 : 4)); + if (!ErrorOrAtom) + return ErrorOrAtom.getError(); + if (auto *atom = ErrorOrAtom.get()) { + if (auto *definedAtom = dyn_cast(atom)) + return definedAtom; + return make_dynamic_error_code("ObjC atom must be defined"); + } + return nullptr; + } + + ErrorOr getInstanceMethods() const { + auto ErrorOrAtom = getReferenceAtOffset(2 * (is64Bit() ? 8 : 4)); + if (!ErrorOrAtom) + return ErrorOrAtom.getError(); + if (auto *atom = ErrorOrAtom.get()) { + if (auto *definedAtom = dyn_cast(atom)) + return definedAtom; + return make_dynamic_error_code("ObjC atom must be defined"); + } + return nullptr; + } + + bool hasInstanceMethods() const { + return hasReferenceAtOffset(2 * (is64Bit() ? 8 : 4)); + } + +private: + + ErrorOr getReferenceAtOffset(unsigned Offset) const { + const DefinedAtom *atom = AtomAndIs64Bit.getPointer(); + for (const Reference *ref : *atom) { + if (ref->offsetInAtom() != Offset) + continue; + if (ref->addend()) + return make_dynamic_error_code("ObjC category field" + " addend is not supported"); + return ref->target(); + } + return nullptr; + } + + bool hasReferenceAtOffset(unsigned Offset) const { + const DefinedAtom *atom = AtomAndIs64Bit.getPointer(); + for (const Reference *ref : *atom) + if (ref->offsetInAtom() == Offset) + return true; + return false; + } + + bool is64Bit() const { + return AtomAndIs64Bit.getInt(); + } + + llvm::PointerIntPair AtomAndIs64Bit; +}; + +/// Provides accessors to an in memory class atom. +/// +/// struct _class_t { +/// struct _class_t *isa; +/// struct _class_t * const superclass; +/// void *cache; +/// IMP *vtable; +/// struct class_ro_t *ro; +/// } +class Class { +public: + Class(const DefinedAtom *atom, MachOLinkingContext::Arch arch) + : AtomAndIs64Bit(atom, MachOLinkingContext::is64Bit(arch)) { + } + /// Verifies that the class is correct. Otherwise returns an error. + std::error_code verify() const { + // classes are 5 pointers. Make sure the size reflects that. + const DefinedAtom *atom = AtomAndIs64Bit.getPointer(); + if (atom->size() != (5 * (is64Bit() ? 8 : 4))) + return make_dynamic_error_code("ObjC class size must be 6 pointers"); + return std::error_code(); + } + + ErrorOr getData() const { + auto ErrorOrAtom = getReferenceAtOffset(4 * (is64Bit() ? 8 : 4)); + if (!ErrorOrAtom) + return ErrorOrAtom.getError(); + if (auto *atom = ErrorOrAtom.get()) { + if (auto *definedAtom = dyn_cast(atom)) + return definedAtom; + return make_dynamic_error_code("ObjC atom must be defined"); + } + return nullptr; + } + + ErrorOr getReferenceAtOffset(unsigned Offset) const { + const DefinedAtom *atom = AtomAndIs64Bit.getPointer(); + for (const Reference *ref : *atom) { + if (ref->offsetInAtom() != Offset) + continue; + if (ref->addend()) + return make_dynamic_error_code("ObjC class field" + " addend is not supported"); + return ref->target(); + } + return make_dynamic_error_code("Could not find Objc class field"); + } + +private: + + bool is64Bit() const { + return AtomAndIs64Bit.getInt(); + } + + llvm::PointerIntPair AtomAndIs64Bit; +}; + +/// Provides accessors to an in memory class RO data atom. +/// +/// struct _class_ro_t { +/// uint32_t const flags; +/// uint32_t const instanceStart; +/// uint32_t const instanceSize; +/// uint32_t const reserved; // only when building for 64bit targets +/// const uint8_t * const ivarLayout; +/// const char *const name; +/// const struct _method_list_t * const baseMethods; +/// const struct _protocol_list_t *const baseProtocols; +/// const struct _ivar_list_t *const ivars; +/// const uint8_t * const weakIvarLayout; +/// const struct _prop_list_t * const properties; +/// } +/// +class ClassROData { +public: + ClassROData(const DefinedAtom *atom, MachOLinkingContext::Arch arch) + : AtomAndIs64Bit(atom, MachOLinkingContext::is64Bit(arch)) { + } + + /// Verifies that the RO data is correct. Otherwise returns an error. + std::error_code verify() const { + // There are 7 pointers of data after the header. Verify that this is the + // case. + const DefinedAtom *atom = AtomAndIs64Bit.getPointer(); + if (atom->size() != (getHeaderSizeInBytes() + (7 * (is64Bit() ? 8 : 4)))) + return make_dynamic_error_code("ObjC RO data size in incorrect"); + return std::error_code(); + } + + unsigned offsetOfBaseMethods() const { + return getHeaderSizeInBytes() + 2 * (is64Bit() ? 8 : 4); + } + + ErrorOr getBaseMethods() const { + auto ErrorOrAtom = getReferenceAtOffset(offsetOfBaseMethods()); + if (!ErrorOrAtom) + return ErrorOrAtom.getError(); + if (auto *atom = ErrorOrAtom.get()) { + if (auto *definedAtom = dyn_cast(atom)) + return definedAtom; + return make_dynamic_error_code("ObjC atom must be defined"); + } + return nullptr; + } + + /// Looks up a reference at 'Offset' bytes after the header. + ErrorOr getReferenceAtOffset(unsigned Offset) const { + const DefinedAtom *atom = AtomAndIs64Bit.getPointer(); + for (const Reference *ref : *atom) { + if (ref->offsetInAtom() != Offset) + continue; + if (ref->addend()) + return make_dynamic_error_code("ObjC RO data field" + " addend is not supported"); + return ref->target(); + } + return nullptr; + } + +private: + + bool is64Bit() const { + return AtomAndIs64Bit.getInt(); + } + + /// On 32-bit targets, the header is 3 uint32_t's, while on 64-bit targets + /// we have 4 uint32_t's. Return the size in bytes of the header here. + unsigned getHeaderSizeInBytes() const { + return is64Bit() ? 16 : 12; + } + + llvm::PointerIntPair AtomAndIs64Bit; +}; + +/// Provides accessors to an in memory class method list atom. +/// +/// struct _method_list_t { +/// uint32_t SizeOfMethod = sizeof(method_t); +/// uint32_t NumMethods; +/// method_t Methods[NumMethods]; +/// } +/// +class MethodList { +public: + MethodList(const DefinedAtom *atom, MachOLinkingContext::Arch arch) + : atom(atom), is64Bit(MachOLinkingContext::is64Bit(arch)), + isBig(MachOLinkingContext::isBigEndian(arch)) { + } + + /// Verifies that the method list is correct. Otherwise returns an error. + std::error_code initAndverify() { + if (atom->size() < 8) + return make_dynamic_error_code("Method list requries size and count"); + + const uint8_t *atomData = atom->rawContent().data(); + methodSize = normalized::read32(atomData, isBig); + methodCount = normalized::read32(atomData + 4, isBig); + + if (methodSize != (3 * (is64Bit ? 8 : 4))) + return make_dynamic_error_code("ObjC method is the wrong size"); + + if (atom->size() != (8 + (methodSize * methodCount))) + return make_dynamic_error_code("ObjC method list size in incorrect"); + return std::error_code(); + } + + ErrorOr getReferenceAtOffset(unsigned Offset) const { + for (const Reference *ref : *atom) { + if (ref->offsetInAtom() != Offset) + continue; + if (ref->addend()) + return make_dynamic_error_code("ObjC method list field" + " addend is not supported"); + return ref->target(); + } + return nullptr; + } + + unsigned getMethodCount() const { + return methodCount; + } + + unsigned getMethodSize() const { + return methodSize; + } + +private: + + /// On 32-bit targets, the header is 3 uint32_t's, while on 64-bit targets + /// we have 4 uint32_t's. Return the size in bytes of the header here. + unsigned getHeaderSizeInBytes() const { + return is64Bit ? 16 : 12; + } + + const DefinedAtom *atom; + unsigned methodSize; + unsigned methodCount; + bool is64Bit; + bool isBig; +}; + +/// Returns a new method list atom. This merges all of the methods in the +/// given class method list, with all of the method lists from the categories. +static ErrorOr +getMethodListAtom(StringRef classAtomName, + const DefinedAtom *baseMethodsAtom, + ArrayRef categories, + const MachOLinkingContext &context, + llvm::BumpPtrAllocator &allocator) { + MachOLinkingContext::Arch arch = context.arch(); + + unsigned methodCount = 0; + const File *file = nullptr; + + // First work out how many methods we have and which file the new atom + // should be in. + auto processMethodList = + [&](const DefinedAtom *methodListAtom)->std::error_code { + if (!file) + file = &methodListAtom->file(); + MethodList methodList(methodListAtom, arch); + auto EC = methodList.initAndverify(); + if (EC) + return EC; + methodCount += methodList.getMethodCount(); + // TODO: We should delete the method list atom once we are done with it. + return std::error_code(); + }; + + if (baseMethodsAtom) + if (auto EC = processMethodList(baseMethodsAtom)) + return EC; + + for (const Category &category : categories) { + auto ErrorOrMethods = category.getInstanceMethods(); + if (ErrorOrMethods.getError()) + return ErrorOrMethods; + auto *methodListAtom = ErrorOrMethods.get(); + if (!methodListAtom) + continue; + if (auto EC = processMethodList(methodListAtom)) + return EC; + } + + // Now create an atom to hold our method list. + auto *newMethodListAtom = new (allocator) ObjCMethodListAtom(*file, + classAtomName, + methodCount, + context, + allocator); + + // Finally, add fixups for all of the methods in the lists. + unsigned slide = 0; + auto addFixups = [&](const DefinedAtom *methodListAtom) { + MethodList methodList(methodListAtom, arch); + auto EC = methodList.initAndverify(); + assert(!EC && "Method list error should have been caught earlier"); + for (const Reference *ref : *methodListAtom) + newMethodListAtom->addReference(ref->kindNamespace(), + ref->kindArch(), + ref->kindValue(), + ref->offsetInAtom() + slide, + ref->target(), + ref->addend()); + + slide += methodList.getMethodSize() * methodList.getMethodCount(); + }; + + // We add these in reverse, to match the objc runtime. + for (const Category &category : llvm::reverse(categories)) { + auto *methodListAtom = category.getInstanceMethods().get(); + if (methodListAtom) + addFixups(methodListAtom); + } + + // And the base class method list comes last, if at all. + if (baseMethodsAtom) + addFixups(baseMethodsAtom); + + return newMethodListAtom; +} + +static void addOrReplaceFixup(const DefinedAtom *atom, + uint64_t OffsetInAtom, + const DefinedAtom *newTarget, + mach_o::ArchHandler &handler) { + for (const Reference *ref : *atom) { + if (ref->offsetInAtom() != OffsetInAtom) + continue; + auto *mutableRef = const_cast(ref); + mutableRef->setTarget(newTarget); + mutableRef->setKindValue(handler.pointerKind()); + return; + } + // Couldn't find a reference, so add a new one. + auto *mutableAtom = const_cast(atom); + mutableAtom->addReference(Reference::KindNamespace::mach_o, + handler.kindArch(), handler.pointerKind(), + OffsetInAtom, newTarget, 0); +} + +std::error_code ObjCPass::optimizeCategories(SimpleFile &mergedFile) { + // Map from class atoms to the category atoms which point to them. + llvm::DenseMap> classToCategories; + + // Keep track of the order in which we add classes to the map + std::vector classOrder; + + // Keep track of the atoms we can now delete + std::set deadAtoms; + + // Find all of the classes referenced in the category list, and map from + // classes to all of the categories which reference them + for (const DefinedAtom *atom : mergedFile.defined()) { + if (atom->contentType() != DefinedAtom::typeObjC2CategoryList) + continue; + const DefinedAtom *categoryListAtom = cast(atom); + + // Category lists are atomized. They should only contain a single reference + // to a category. + assert((++categoryListAtom->begin()) == categoryListAtom->end() && + "Category lists should be atomized to a single reference"); + const Reference *ref = *categoryListAtom->begin(); + const DefinedAtom* categoryAtom = dyn_cast(ref->target()); + + // TODO: We need to ignore categories in the __objc_nlcatlist section. + + if (!categoryAtom) + return make_dynamic_error_code("ObjC category must be defined"); + + Category category(categoryAtom, _ctx.arch()); + if (auto EC = category.verify()) + return EC; + + // Get the class this category points to. + const DefinedAtom *classAtom = nullptr; + if (auto ErrorOrClassAtom = category.getClass()) + classAtom = ErrorOrClassAtom.get(); + else + return ErrorOrClassAtom.getError(); + + // TODO: Check for aliasing classes. + + // Keep track of this class, as well as the reference from the category + // back to the class. + auto PosAndInserted = classToCategories.insert({ classAtom, { }}); + if (PosAndInserted.second) + classOrder.push_back(classAtom); + PosAndInserted.first->second.push_back(category); + + // Delete this category list atom as we've now processed this element. + deadAtoms.insert(categoryListAtom); + + // TODO: We can also delete the category atom once we've verified that its + // not in the nlcatlist. + } + + if (classOrder.empty()) + return std::error_code(); + + std::unique_ptr handler + = ArchHandler::create(_ctx.arch()); + + // Walk the classes and merge in any new methods/protocols/etc from the + // categories. + for (auto *classAtom : classOrder) { + ArrayRef categories = classToCategories[classAtom]; + assert(!categories.empty() && "Must have categories"); + + Class cls(classAtom, _ctx.arch()); + if (auto EC = cls.verify()) + return EC; + + // Get the data atom from the class. This data contains pointers to the + // method list and other lists we need to merge. + auto ErrorOrDataAtom = cls.getData(); + if (!ErrorOrDataAtom) + return ErrorOrDataAtom.getError(); + + const DefinedAtom *dataAtom = ErrorOrDataAtom.get(); + + ClassROData data(dataAtom, _ctx.arch()); + if (auto EC = data.verify()) + return EC; + + // Merge in instance methods from the categories. + const DefinedAtom *newInstanceMethods = nullptr; + if (llvm::any_of(categories, + [](Category cat) { return cat.hasInstanceMethods(); })) { + auto ErrorOrBaseMethodsAtom = data.getBaseMethods(); + if (!ErrorOrBaseMethodsAtom) + return ErrorOrBaseMethodsAtom.getError(); + + const DefinedAtom *baseMethodsAtom = ErrorOrBaseMethodsAtom.get(); + auto ErrorOrAtom = getMethodListAtom(classAtom->name(), + baseMethodsAtom, categories, + _ctx, _file.allocator()); + if (!ErrorOrAtom) + return ErrorOrAtom.getError(); + newInstanceMethods = ErrorOrAtom.get(); + + mergedFile.addAtom(*newInstanceMethods); + } + + // Patch the class RO data with the new lists. + if (newInstanceMethods) + addOrReplaceFixup(dataAtom, data.offsetOfBaseMethods(), + newInstanceMethods, *handler); + } + + // Delete any atoms we don't need any more. + mergedFile.removeDefinedAtomsIf([&deadAtoms](const DefinedAtom *atom) { + return deadAtoms.count(atom); + }); + + return std::error_code(); +} void addObjCPass(PassManager &pm, const MachOLinkingContext &ctx) { pm.add(llvm::make_unique(ctx)); Index: test/mach-o/objc-method-list-merge.yaml =================================================================== --- /dev/null +++ test/mach-o/objc-method-list-merge.yaml @@ -0,0 +1,771 @@ +# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t1 -no_objc_category_merging | FileCheck %s --check-prefix=NO_OPT +# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %t1 -o %t2 -no_objc_category_merging | FileCheck %s --check-prefix=NO_OPT +# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t3 | FileCheck %s --check-prefix=OPT +# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %t3 -o %t4 | FileCheck %s --check-prefix=OPT + + +--- !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: __TEXT + section: __text + type: S_REGULAR + attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ] + alignment: 16 + address: 0x0000000000000000 + content: [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x89, 0x7D, 0xF8, + 0x48, 0x89, 0x75, 0xF0, 0x5D, 0xC3, 0x66, 0x90, + 0x55, 0x48, 0x89, 0xE5, 0x48, 0x89, 0x7D, 0xF8, + 0x48, 0x89, 0x75, 0xF0, 0x5D, 0xC3, 0x66, 0x90, + 0x55, 0x48, 0x89, 0xE5, 0x48, 0x89, 0x7D, 0xF8, + 0x48, 0x89, 0x75, 0xF0, 0x5D, 0xC3, 0x66, 0x90, + 0x55, 0x48, 0x89, 0xE5, 0x48, 0x89, 0x7D, 0xF8, + 0x48, 0x89, 0x75, 0xF0, 0x5D, 0xC3 ] + - segment: __DATA + section: __objc_data + type: S_REGULAR + attributes: [ ] + alignment: 8 + address: 0x0000000000000040 + content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] + relocations: + - offset: 0x000000E8 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 16 + - offset: 0x000000D8 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 23 + - offset: 0x000000D0 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 17 + - offset: 0x000000C8 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 22 + - offset: 0x000000C0 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 15 + - offset: 0x000000B0 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 23 + - offset: 0x000000A8 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 20 + - offset: 0x000000A0 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 20 + - offset: 0x00000098 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 11 + - offset: 0x00000088 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 23 + - offset: 0x00000080 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 18 + - offset: 0x00000078 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 21 + - offset: 0x00000070 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 10 + - offset: 0x00000060 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 23 + - offset: 0x00000050 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 21 + - offset: 0x00000048 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 5 + - offset: 0x00000038 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 23 + - offset: 0x00000030 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 17 + - offset: 0x00000028 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 20 + - offset: 0x00000020 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 4 + - offset: 0x00000010 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 23 + - offset: 0x00000000 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 20 + - segment: __TEXT + section: __objc_classname + type: S_CSTRING_LITERALS + attributes: [ ] + address: 0x0000000000000130 + content: [ 0x41, 0x00, 0x43, 0x61, 0x74, 0x00, 0x42, 0x00, + 0x43, 0x00 ] + - segment: __TEXT + section: __objc_methname + type: S_CSTRING_LITERALS + attributes: [ ] + address: 0x000000000000013A + content: [ 0x6C, 0x6F, 0x61, 0x64, 0x00 ] + - segment: __TEXT + section: __objc_methtype + type: S_CSTRING_LITERALS + attributes: [ ] + address: 0x000000000000013F + content: [ 0x76, 0x31, 0x36, 0x40, 0x30, 0x3A, 0x38, 0x00 ] + - segment: __DATA + section: __objc_const + type: S_REGULAR + attributes: [ ] + alignment: 8 + address: 0x0000000000000148 + content: [ 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x3A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x3A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x3A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x3A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] + relocations: + - offset: 0x00000260 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 3 + - offset: 0x00000218 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 3 + - offset: 0x000001E0 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 13 + - offset: 0x000001D8 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 18 + - offset: 0x000001D0 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 3 + - offset: 0x000001C8 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 3 + - offset: 0x000001C0 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 5 + - offset: 0x000001B8 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 4 + - offset: 0x00000188 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 12 + - offset: 0x00000180 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 3 + - offset: 0x00000160 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 2 + - offset: 0x00000158 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 5 + - offset: 0x00000150 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 4 + - offset: 0x00000118 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 3 + - offset: 0x000000E8 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 7 + - offset: 0x000000D8 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 8 + - offset: 0x000000D0 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 3 + - offset: 0x000000C8 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 1 + - offset: 0x000000C0 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 5 + - offset: 0x000000B8 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 4 + - offset: 0x00000080 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 3 + - offset: 0x00000040 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 6 + - offset: 0x00000038 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 3 + - offset: 0x00000018 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 0 + - offset: 0x00000010 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 5 + - offset: 0x00000008 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 4 + - segment: __DATA + section: __objc_classlist + type: S_REGULAR + attributes: [ S_ATTR_NO_DEAD_STRIP ] + alignment: 8 + address: 0x00000000000003D8 + content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] + relocations: + - offset: 0x00000010 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 19 + - offset: 0x00000008 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 18 + - offset: 0x00000000 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 17 + - segment: __DATA + section: __objc_nlclslist + type: S_REGULAR + attributes: [ S_ATTR_NO_DEAD_STRIP ] + alignment: 8 + address: 0x00000000000003F0 + content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] + relocations: + - offset: 0x00000000 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 17 + - segment: __DATA + section: __objc_catlist + type: S_REGULAR + attributes: [ S_ATTR_NO_DEAD_STRIP ] + alignment: 8 + address: 0x00000000000003F8 + content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] + relocations: + - offset: 0x00000008 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 14 + - offset: 0x00000000 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 9 + - segment: __DATA + section: __objc_nlcatlist + type: S_REGULAR + attributes: [ S_ATTR_NO_DEAD_STRIP ] + alignment: 8 + address: 0x0000000000000408 + content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] + relocations: + - offset: 0x00000000 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 9 + - segment: __DATA + section: __objc_imageinfo + type: S_REGULAR + attributes: [ S_ATTR_NO_DEAD_STRIP ] + address: 0x0000000000000410 + content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] + - segment: __LD + section: __compact_unwind + type: S_REGULAR + attributes: [ ] + alignment: 8 + address: 0x0000000000000418 + content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] + relocations: + - offset: 0x00000060 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 1 + - offset: 0x00000040 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 1 + - offset: 0x00000020 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 1 + - offset: 0x00000000 + type: X86_64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 1 +local-symbols: + - name: '+[A load]' + type: N_SECT + sect: 1 + value: 0x0000000000000000 + - name: '+[A(Cat) load]' + type: N_SECT + sect: 1 + value: 0x0000000000000010 + - name: '-[B load]' + type: N_SECT + sect: 1 + value: 0x0000000000000020 + - name: '-[B(Cat) load]' + type: N_SECT + sect: 1 + value: 0x0000000000000030 + - name: 'l_OBJC_CLASS_RO_$_A' + type: N_SECT + sect: 6 + value: 0x00000000000001B0 + - name: 'l_OBJC_METACLASS_RO_$_A' + type: N_SECT + sect: 6 + value: 0x0000000000000168 + - name: 'l_OBJC_$_CLASS_METHODS_A' + type: N_SECT + sect: 6 + value: 0x0000000000000148 + - name: 'l_OBJC_$_CATEGORY_CLASS_METHODS_A_$_Cat' + type: N_SECT + sect: 6 + value: 0x00000000000001F8 + - name: _CLASS_A_ALIAS + type: N_SECT + sect: 2 + desc: [ N_NO_DEAD_STRIP ] + value: 0x0000000000000040 + - name: 'l_OBJC_$_CATEGORY_A_$_Cat' + type: N_SECT + sect: 6 + value: 0x0000000000000218 + - name: 'l_OBJC_CLASS_RO_$_B' + type: N_SECT + sect: 6 + value: 0x00000000000002B0 + - name: 'l_OBJC_METACLASS_RO_$_B' + type: N_SECT + sect: 6 + value: 0x0000000000000248 + - name: 'l_OBJC_$_INSTANCE_METHODS_B' + type: N_SECT + sect: 6 + value: 0x0000000000000290 + - name: 'l_OBJC_$_CATEGORY_INSTANCE_METHODS_B_$_Cat' + type: N_SECT + sect: 6 + value: 0x00000000000002F8 + - name: 'l_OBJC_$_CATEGORY_B_$_Cat' + type: N_SECT + sect: 6 + value: 0x0000000000000318 + - name: 'l_OBJC_METACLASS_RO_$_C' + type: N_SECT + sect: 6 + value: 0x0000000000000348 + - name: 'l_OBJC_CLASS_RO_$_C' + type: N_SECT + sect: 6 + value: 0x0000000000000390 +global-symbols: + - name: '_OBJC_CLASS_$_A' + type: N_SECT + scope: [ N_EXT ] + sect: 2 + value: 0x0000000000000040 + - name: '_OBJC_CLASS_$_B' + type: N_SECT + scope: [ N_EXT ] + sect: 2 + value: 0x0000000000000090 + - name: '_OBJC_CLASS_$_C' + type: N_SECT + scope: [ N_EXT ] + sect: 2 + value: 0x0000000000000108 + - name: '_OBJC_METACLASS_$_A' + type: N_SECT + scope: [ N_EXT ] + sect: 2 + value: 0x0000000000000068 + - name: '_OBJC_METACLASS_$_B' + type: N_SECT + scope: [ N_EXT ] + sect: 2 + value: 0x00000000000000B8 + - name: '_OBJC_METACLASS_$_C' + type: N_SECT + scope: [ N_EXT ] + sect: 2 + value: 0x00000000000000E0 +undefined-symbols: + - name: __objc_empty_cache + type: N_UNDF + scope: [ N_EXT ] + value: 0x0000000000000000 +page-size: 0x00000000 +... + +# NO_OPT: - type: objc-category-list +# NO_OPT: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ] +# NO_OPT: merge: by-content +# NO_OPT: alignment: 8 +# NO_OPT: references: +# NO_OPT: - kind: pointer64 +# NO_OPT: offset: 0 +# NO_OPT: target: 'l_OBJC_$_CATEGORY_A_$_Cat' +# NO_OPT: - type: objc-category-list +# NO_OPT: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ] +# NO_OPT: merge: by-content +# NO_OPT: alignment: 8 +# NO_OPT: references: +# NO_OPT: - kind: pointer64 +# NO_OPT: offset: 0 +# NO_OPT: target: 'l_OBJC_$_CATEGORY_B_$_Cat' + +# Make sure that the class RO data for B points to the new method list. + + +# OPT-DAG: - name: 'l__OBJC_CLASS_$_B_objc_merged_method_list' +# OPT: scope: global +# OPT-NEXT: type: {{objc-method-list|unknown}} +# OPT-NEXT: content: [ 18, 00, 00, 00, 02, 00, 00, 00, {{..}}, {{..}}, {{..}}, {{..}}, +# OPT-NEXT: {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, +# OPT-NEXT: {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, +# OPT-NEXT: {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, +# OPT-NEXT: {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}} ] +# OPT-NEXT: alignment: 8 +# OPT-NEXT: section-choice: custom-required +# OPT-NEXT: section-name: __DATA/__objc_const +# OPT-NEXT: dead-strip: never +# OPT-NEXT: references: +# OPT-NEXT: - kind: pointer64Anon +# OPT-NEXT: offset: 8 +# OPT-NEXT: target: L{{[0-9]*}} +# OPT-NEXT: - kind: pointer64Anon +# OPT-NEXT: offset: 16 +# OPT-NEXT: target: L{{[0-9]*}} +# OPT-NEXT: - kind: pointer64 +# OPT-NEXT: offset: 24 +# OPT-NEXT: target: '-[B(Cat) load]' +# OPT-NEXT: - kind: pointer64Anon +# OPT-NEXT: offset: 32 +# OPT-NEXT: target: L{{[0-9]*}} +# OPT-NEXT: - kind: pointer64Anon +# OPT-NEXT: offset: 40 +# OPT-NEXT: target: L{{[0-9]*}} +# OPT-NEXT: - kind: pointer64 +# OPT-NEXT: offset: 48 +# OPT-NEXT: target: '-[B load]' + +# OPT-DAG: - name: 'l_OBJC_CLASS_RO_$_B' +# OPT: type: unknown +# OPT-NEXT: content: [ 02, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, +# OPT-NEXT: 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, +# OPT-NEXT: {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, +# OPT-NEXT: {{..}}, {{..}}, {{..}}, {{..}}, 00, 00, 00, 00, 00, 00, 00, 00, +# OPT-NEXT: 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, +# OPT-NEXT: 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 ] +# OPT-NEXT: alignment: 8 +# OPT-NEXT: section-choice: custom-required +# OPT-NEXT: section-name: __DATA/__objc_const +# OPT-NEXT: references: +# OPT-NEXT: - kind: pointer64Anon +# OPT-NEXT: offset: 24 +# OPT-NEXT: target: L{{[0-9]*}} +# OPT-NEXT: - kind: pointer64 +# OPT-NEXT: offset: 32 +# OPT-NEXT: target: 'l__OBJC_CLASS_$_B_objc_merged_method_list'