X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/b2fa67a80bc53211e4d1ea81f23e9f953ee1dd6c..e667b16e39593d19d0e25a8440a563eac3572653:/src/ld/passes/objc.cpp diff --git a/src/ld/passes/objc.cpp b/src/ld/passes/objc.cpp index b209b1d..2bbf54a 100644 --- a/src/ld/passes/objc.cpp +++ b/src/ld/passes/objc.cpp @@ -50,11 +50,11 @@ struct objc_image_info { uint32_t flags; }; -#define OBJC_IMAGE_IS_REPLACEMENT (1<<0) #define OBJC_IMAGE_SUPPORTS_GC (1<<1) #define OBJC_IMAGE_REQUIRES_GC (1<<2) #define OBJC_IMAGE_OPTIMIZED_BY_DYLD (1<<3) #define OBJC_IMAGE_SUPPORTS_COMPACTION (1<<4) +#define OBJC_IMAGE_IS_SIMULATED (1<<5) @@ -65,11 +65,9 @@ template class ObjCImageInfoAtom : public ld::Atom { public: ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint, - bool compaction, bool objcReplacementClasses, bool abi2); + bool compaction, bool abi2, uint8_t swiftVersion); virtual const ld::File* file() const { return NULL; } - virtual bool translationUnitSource(const char** dir, const char**) const - { return false; } virtual const char* name() const { return "objc image info"; } virtual uint64_t size() const { return sizeof(objc_image_info); } virtual uint64_t objectAddress() const { return 0; } @@ -91,15 +89,13 @@ template ld::Section ObjCImageInfoAtom::_s_sectionABI2("__DATA", template ObjCImageInfoAtom::ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint, bool compaction, - bool objcReplacementClasses, bool abi2) + bool abi2, uint8_t swiftVersion) : ld::Atom(abi2 ? _s_sectionABI2 : _s_sectionABI1, ld::Atom::definitionRegular, ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified, symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)) { uint32_t value = 0; - if ( objcReplacementClasses ) - value = OBJC_IMAGE_IS_REPLACEMENT; switch ( objcConstraint ) { case ld::File::objcConstraintNone: case ld::File::objcConstraintRetainRelease: @@ -116,8 +112,14 @@ ObjCImageInfoAtom::ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint, if ( compaction ) value |= OBJC_IMAGE_SUPPORTS_COMPACTION; break; + case ld::File::objcConstraintRetainReleaseForSimulator: + value |= OBJC_IMAGE_IS_SIMULATED; + break; } + // provide swift language version in final binary for runtime to inspect + value |= (swiftVersion << 8); + _content.version = 0; A::P::E::set32(_content.flags, value); } @@ -135,15 +137,13 @@ public: std::set& deadAtoms); virtual const ld::File* file() const { return _file; } - virtual bool translationUnitSource(const char** dir, const char**) const - { return false; } virtual const char* name() const { return "objc merged method list"; } virtual uint64_t size() const { return _methodCount*3*sizeof(pint_t) + 8; } virtual uint64_t objectAddress() const { return 0; } virtual void setScope(Scope) { } virtual void copyRawContent(uint8_t buffer[]) const { bzero(buffer, size()); - A::P::E::set32(*((uint32_t*)(&buffer[0])), 24); + A::P::E::set32(*((uint32_t*)(&buffer[0])), 3*sizeof(pint_t)); // entry size A::P::E::set32(*((uint32_t*)(&buffer[4])), _methodCount); } virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixups[0]; } @@ -174,8 +174,6 @@ public: std::set& deadAtoms); virtual const ld::File* file() const { return _file; } - virtual bool translationUnitSource(const char** dir, const char**) const - { return false; } virtual const char* name() const { return "objc merged protocol list"; } virtual uint64_t size() const { return (_protocolCount+1)*sizeof(pint_t); } virtual uint64_t objectAddress() const { return 0; } @@ -213,8 +211,6 @@ public: std::set& deadAtoms); virtual const ld::File* file() const { return _file; } - virtual bool translationUnitSource(const char** dir, const char**) const - { return false; } virtual const char* name() const { return "objc merged property list"; } virtual uint64_t size() const { return _propertyCount*2*sizeof(pint_t) + 8; } virtual uint64_t objectAddress() const { return 0; } @@ -255,8 +251,6 @@ public: // overrides of ld::Atom virtual const ld::File* file() const { return _atom->file(); } - virtual bool translationUnitSource(const char** dir, const char** nm) const - { return _atom->translationUnitSource(dir, nm); } virtual const char* name() const { return _atom->name(); } virtual uint64_t size() const { return _atom->size(); } virtual uint64_t objectAddress() const { return _atom->objectAddress(); } @@ -371,7 +365,7 @@ void ObjCData::setPointerInContent(ld::Internal& state, const ld::Atom* conte template class Category : public ObjCData { public: - static const ld::Atom* getClass(ld::Internal& state, const ld::Atom* contentAtom); + static const ld::Atom* getClass(ld::Internal& state, const ld::Atom* contentAtom, bool& hasAddend); static const ld::Atom* getInstanceMethods(ld::Internal& state, const ld::Atom* contentAtom); static const ld::Atom* getClassMethods(ld::Internal& state, const ld::Atom* contentAtom); static const ld::Atom* getProtocols(ld::Internal& state, const ld::Atom* contentAtom); @@ -383,9 +377,9 @@ private: template -const ld::Atom* Category::getClass(ld::Internal& state, const ld::Atom* contentAtom) +const ld::Atom* Category::getClass(ld::Internal& state, const ld::Atom* contentAtom, bool& hasAddend) { - return ObjCData::getPointerInContent(state, contentAtom, sizeof(pint_t)); // category_t.cls + return ObjCData::getPointerInContent(state, contentAtom, sizeof(pint_t), &hasAddend); // category_t.cls } template @@ -775,6 +769,35 @@ private: const std::set& _dead; }; + struct AtomSorter + { + bool operator()(const Atom* left, const Atom* right) + { + // sort by file ordinal, then object address, then zero size, then symbol name + // only file based atoms are supported (file() != NULL) + if (left==right) return false; + const File *leftf = left->file(); + const File *rightf = right->file(); + + if (leftf == rightf) { + if (left->objectAddress() != right->objectAddress()) { + return left->objectAddress() < right->objectAddress(); + } else { + // for atoms in the same file with the same address, zero sized + // atoms must sort before nonzero sized atoms + if ((left->size() == 0 && right->size() > 0) || (left->size() > 0 && right->size() == 0)) + return left->size() < right->size(); + return strcmp(left->name(), right->name()); + } + } + return (leftf->ordinal() < rightf->ordinal()); + } + }; + + static void sortAtomVector(std::vector &atoms) { + std::sort(atoms.begin(), atoms.end(), AtomSorter()); + } + template void OptimizeCategories::doit(const Options& opts, ld::Internal& state) { @@ -798,6 +821,7 @@ void OptimizeCategories::doit(const Options& opts, ld::Internal& state) // build map of all classes in this image that have categories on them typedef std::map*> CatMap; CatMap classToCategories; + std::vector classOrder; std::set deadAtoms; ld::Internal::FinalSection* methodListSection = NULL; for (std::vector::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) { @@ -813,17 +837,25 @@ void OptimizeCategories::doit(const Options& opts, ld::Internal& state) continue; } assert(categoryAtom != NULL); - assert(categoryAtom->size() == Category::size()); + assert(categoryAtom->size() >= Category::size()); // ignore categories also in __objc_nlcatlist if ( nlcatListAtoms.count(categoryAtom) != 0 ) continue; - const ld::Atom* categoryOnClassAtom = Category::getClass(state, categoryAtom); + const ld::Atom* categoryOnClassAtom = Category::getClass(state, categoryAtom, hasAddend); assert(categoryOnClassAtom != NULL); + // only look at classes defined in this image if ( categoryOnClassAtom->definition() != ld::Atom::definitionProxy ) { - // only look at classes defined in this image + // for now, back off optimization on new style classes + if ( hasAddend != 0 ) + continue; + // don't apply categories to swift classes + if ( categoryOnClassAtom->hasFixupsOfKind(ld::Fixup::kindNoneGroupSubordinate) ) + continue; + CatMap::iterator pos = classToCategories.find(categoryOnClassAtom); if ( pos == classToCategories.end() ) { classToCategories[categoryOnClassAtom] = new std::vector(); + classOrder.push_back(categoryOnClassAtom); } classToCategories[categoryOnClassAtom]->push_back(categoryAtom); // mark category atom and catlist atom as dead @@ -840,10 +872,11 @@ void OptimizeCategories::doit(const Options& opts, ld::Internal& state) // if found some categories if ( classToCategories.size() != 0 ) { assert(methodListSection != NULL); + sortAtomVector(classOrder); // alter each class definition to have new method list which includes all category methods - for (CatMap::iterator it=classToCategories.begin(); it != classToCategories.end(); ++it) { - const ld::Atom* classAtom = it->first; - const std::vector* categories = it->second; + for (std::vector::iterator it = classOrder.begin(); it != classOrder.end(); it++) { + const ld::Atom* classAtom = *it; + const std::vector* categories = classToCategories[classAtom]; assert(categories->size() != 0); // if any category adds instance methods, generate new merged method list, and replace if ( OptimizeCategories::hasInstanceMethods(state, categories) ) { @@ -1145,18 +1178,30 @@ void doPass(const Options& opts, ld::Internal& state) // add image info atom switch ( opts.architecture() ) { +#if SUPPORT_ARCH_x86_64 case CPU_TYPE_X86_64: state.addAtom(*new ObjCImageInfoAtom(state.objcObjectConstraint, compaction, - state.hasObjcReplacementClasses, true)); + true, state.swiftVersion)); break; +#endif +#if SUPPORT_ARCH_i386 case CPU_TYPE_I386: state.addAtom(*new ObjCImageInfoAtom(state.objcObjectConstraint, compaction, - state.hasObjcReplacementClasses, opts.objCABIVersion2POverride() ? true : false)); + opts.objCABIVersion2POverride() ? true : false, state.swiftVersion)); break; +#endif +#if SUPPORT_ARCH_arm_any case CPU_TYPE_ARM: state.addAtom(*new ObjCImageInfoAtom(state.objcObjectConstraint, compaction, - state.hasObjcReplacementClasses, true)); + true, state.swiftVersion)); break; +#endif +#if SUPPORT_ARCH_arm64 + case CPU_TYPE_ARM64: + state.addAtom(*new ObjCImageInfoAtom(state.objcObjectConstraint, compaction, + true, state.swiftVersion)); + break; +#endif default: assert(0 && "unknown objc arch"); } @@ -1165,18 +1210,27 @@ void doPass(const Options& opts, ld::Internal& state) if ( opts.objcCategoryMerging() ) { // optimize classes defined in this linkage unit by merging in categories also in this linkage unit switch ( opts.architecture() ) { +#if SUPPORT_ARCH_x86_64 case CPU_TYPE_X86_64: OptimizeCategories::doit(opts, state); break; +#endif +#if SUPPORT_ARCH_i386 case CPU_TYPE_I386: - // disable optimization until fully tested - //if ( opts.objCABIVersion2POverride() ) - // OptimizeCategories::doit(opts, state); + if ( opts.objCABIVersion2POverride() ) + OptimizeCategories::doit(opts, state); break; +#endif +#if SUPPORT_ARCH_arm_any case CPU_TYPE_ARM: - // disable optimization until fully tested - //OptimizeCategories::doit(opts, state); + OptimizeCategories::doit(opts, state); + break; +#endif +#if SUPPORT_ARCH_arm64 + case CPU_TYPE_ARM64: + // disabled until tested break; +#endif default: assert(0 && "unknown objc arch"); }