1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
   3  * Copyright (c) 2010-2011 Apple Inc. All rights reserved. 
   5  * @APPLE_LICENSE_HEADER_START@ 
   7  * This file contains Original Code and/or Modifications of Original Code 
   8  * as defined in and that are subject to the Apple Public Source License 
   9  * Version 2.0 (the 'License'). You may not use this file except in 
  10  * compliance with the License. Please obtain a copy of the License at 
  11  * http://www.opensource.apple.com/apsl/ and read it before using this 
  14  * The Original Code and all software distributed under the License are 
  15  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  16  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  17  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  18  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  19  * Please see the License for the specific language governing rights and 
  20  * limitations under the License. 
  22  * @APPLE_LICENSE_HEADER_END@ 
  30 #include <mach/machine.h> 
  36 #include "Architectures.hpp" 
  37 #include "MachOFileAbstraction.hpp" 
  48 struct objc_image_info  
{ 
  49         uint32_t        version
;        // initially 0 
  53 #define OBJC_IMAGE_SUPPORTS_GC                                          (1<<1) 
  54 #define OBJC_IMAGE_REQUIRES_GC                                          (1<<2) 
  55 #define OBJC_IMAGE_OPTIMIZED_BY_DYLD                            (1<<3) 
  56 #define OBJC_IMAGE_SUPPORTS_COMPACTION                          (1<<4) 
  57 #define OBJC_IMAGE_IS_SIMULATED                                         (1<<5) 
  58 #define OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES        (1<<6) 
  63 // This class is the 8 byte section containing ObjC flags 
  66 class ObjCImageInfoAtom 
: public ld::Atom 
{ 
  68                                                                                         ObjCImageInfoAtom(bool abi2
, bool hasCategoryClassProperties
, uint8_t swiftVersion
); 
  70         virtual const ld::File
*                                 file() const                                    { return NULL
; } 
  71         virtual const char*                                             name() const                                    { return "objc image info"; } 
  72         virtual uint64_t                                                size() const                                    { return sizeof(objc_image_info
); } 
  73         virtual uint64_t                                                objectAddress() const                   { return 0; } 
  74         virtual void                                                    setScope(Scope
)                                 { } 
  75         virtual void                                                    copyRawContent(uint8_t buffer
[]) const { 
  76                 memcpy(buffer
, &_content
, sizeof(objc_image_info
)); 
  80         objc_image_info                                                 _content
; 
  82         static ld::Section                                              _s_sectionABI1
; 
  83         static ld::Section                                              _s_sectionABI2
; 
  86 template <typename A
> ld::Section ObjCImageInfoAtom
<A
>::_s_sectionABI1("__OBJC", "__image_info", ld::Section::typeUnclassified
); 
  87 template <typename A
> ld::Section ObjCImageInfoAtom
<A
>::_s_sectionABI2("__DATA", "__objc_imageinfo", ld::Section::typeUnclassified
); 
  91 ObjCImageInfoAtom
<A
>::ObjCImageInfoAtom(bool abi2
, bool hasCategoryClassProperties
, uint8_t swiftVersion
) 
  92         : ld::Atom(abi2 
? _s_sectionABI2 
: _s_sectionABI1
, ld::Atom::definitionRegular
, ld::Atom::combineNever
, 
  93                                                         ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,  
  94                                                         symbolTableNotIn
, false, false, false, ld::Atom::Alignment(2)) 
  98         if ( hasCategoryClassProperties 
) { 
  99                 value 
|= OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES
; 
 102         // provide swift language version in final binary for runtime to inspect 
 103         value 
|= (swiftVersion 
<< 8); 
 105         _content
.version 
= 0; 
 106         A::P::E::set32(_content
.flags
, value
); 
 112 // This class is for a new Atom which is an ObjC method list created by merging method lists from categories 
 114 template <typename A
> 
 115 class MethodListAtom 
: public ld::Atom 
{ 
 117                                                                                         MethodListAtom(ld::Internal
& state
, const ld::Atom
* baseMethodList
, bool meta
,  
 118                                                                                                                         const std::vector
<const ld::Atom
*>* categories
,  
 119                                                                                                                         std::set
<const ld::Atom
*>& deadAtoms
); 
 121         virtual const ld::File
*                                 file() const                                    { return _file
; } 
 122         virtual const char*                                             name() const                                    { return "objc merged method list"; } 
 123         virtual uint64_t                                                size() const                                    { return _methodCount
*3*sizeof(pint_t
) + 8; } 
 124         virtual uint64_t                                                objectAddress() const                   { return 0; } 
 125         virtual void                                                    setScope(Scope
)                                 { } 
 126         virtual void                                                    copyRawContent(uint8_t buffer
[]) const { 
 127                 bzero(buffer
, size()); 
 128                 A::P::E::set32(*((uint32_t*)(&buffer
[0])), 3*sizeof(pint_t
)); // entry size 
 129                 A::P::E::set32(*((uint32_t*)(&buffer
[4])), _methodCount
); 
 131         virtual ld::Fixup::iterator                             
fixupsBegin() const     { return (ld::Fixup
*)&_fixups
[0]; } 
 132         virtual ld::Fixup::iterator                             
fixupsEnd()     const   { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; } 
 135         typedef typename 
A::P::uint_t                   pint_t
; 
 137         const ld::File
*                                                 _file
; 
 138         unsigned int                                                    _methodCount
; 
 139         std::vector
<ld::Fixup
>                                  _fixups
; 
 141         static ld::Section                                              _s_section
; 
 144 template <typename A
>  
 145 ld::Section MethodListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
); 
 149 // This class is for a new Atom which is an ObjC protocol list created by merging protocol lists from categories 
 151 template <typename A
> 
 152 class ProtocolListAtom 
: public ld::Atom 
{ 
 154                                                                                         ProtocolListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,  
 155                                                                                                                         const std::vector
<const ld::Atom
*>* categories
,  
 156                                                                                                                         std::set
<const ld::Atom
*>& deadAtoms
); 
 158         virtual const ld::File
*                                 file() const                                    { return _file
; } 
 159         virtual const char*                                             name() const                                    { return "objc merged protocol list"; } 
 160         virtual uint64_t                                                size() const                                    { return (_protocolCount
+1)*sizeof(pint_t
); } 
 161         virtual uint64_t                                                objectAddress() const                   { return 0; } 
 162         virtual void                                                    setScope(Scope
)                                 { } 
 163         virtual void                                                    copyRawContent(uint8_t buffer
[]) const { 
 164                 bzero(buffer
, size()); 
 165                 A::P::setP(*((pint_t
*)(buffer
)), _protocolCount
); 
 167         virtual ld::Fixup::iterator                             
fixupsBegin() const     { return (ld::Fixup
*)&_fixups
[0]; } 
 168         virtual ld::Fixup::iterator                             
fixupsEnd()     const   { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; } 
 171         typedef typename 
A::P::uint_t                   pint_t
; 
 173         const ld::File
*                                                 _file
; 
 174         unsigned int                                                    _protocolCount
; 
 175         std::vector
<ld::Fixup
>                                  _fixups
; 
 177         static ld::Section                                              _s_section
; 
 180 template <typename A
>  
 181 ld::Section ProtocolListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
); 
 186 // This class is for a new Atom which is an ObjC property list created by merging property lists from categories 
 188 template <typename A
> 
 189 class PropertyListAtom 
: public ld::Atom 
{ 
 191         enum class PropertyKind 
{ ClassProperties
, InstanceProperties 
}; 
 193                                                                                         PropertyListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,  
 194                                                                                                          const std::vector
<const ld::Atom
*>* categories
,  
 195                                                                                                          std::set
<const ld::Atom
*>& deadAtoms
,  
 198         virtual const ld::File
*                                 file() const                                    { return _file
; } 
 199         virtual const char*                                             name() const                                    { return "objc merged property list"; } 
 200         virtual uint64_t                                                size() const                                    { return _propertyCount
*2*sizeof(pint_t
) + 8; } 
 201         virtual uint64_t                                                objectAddress() const                   { return 0; } 
 202         virtual void                                                    setScope(Scope
)                                 { } 
 203         virtual void                                                    copyRawContent(uint8_t buffer
[]) const { 
 204                 bzero(buffer
, size()); 
 205                 A::P::E::set32(((uint32_t*)(buffer
))[0], 2*sizeof(pint_t
)); // sizeof(objc_property) 
 206                 A::P::E::set32(((uint32_t*)(buffer
))[1], _propertyCount
); 
 208         virtual ld::Fixup::iterator                             
fixupsBegin() const     { return (ld::Fixup
*)&_fixups
[0]; } 
 209         virtual ld::Fixup::iterator                             
fixupsEnd()     const   { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; } 
 212         typedef typename 
A::P::uint_t                   pint_t
; 
 214         const ld::File
*                                                 _file
; 
 215         unsigned int                                                    _propertyCount
; 
 216         std::vector
<ld::Fixup
>                                  _fixups
; 
 218         static ld::Section                                              _s_section
; 
 221 template <typename A
>  
 222 ld::Section PropertyListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
); 
 229 // This class is used to create an Atom that replaces an atom from a .o file that holds a class_ro_t. 
 230 // It is needed because there is no way to add Fixups to an existing atom. 
 232 template <typename A
> 
 233 class ClassROOverlayAtom 
: public ld::Atom 
{ 
 235                                                                                         ClassROOverlayAtom(const ld::Atom
* classROAtom
); 
 237         // overrides of ld::Atom 
 238         virtual const ld::File
*                         file() const            { return _atom
->file(); } 
 239         virtual const char*                                     name() const            { return _atom
->name(); } 
 240         virtual uint64_t                                        size() const            { return _atom
->size(); } 
 241         virtual uint64_t                                        objectAddress() const { return _atom
->objectAddress(); } 
 242         virtual void                                            copyRawContent(uint8_t buffer
[]) const  
 243                                                                                                                         { _atom
->copyRawContent(buffer
); } 
 244         virtual const uint8_t*                          rawContentPointer() const  
 245                                                                                                                         { return _atom
->rawContentPointer(); } 
 246         virtual unsigned long                           contentHash(const class ld::IndirectBindingTable
& ibt
) const  
 247                                                                                                                         { return _atom
->contentHash(ibt
); } 
 248         virtual bool                                            canCoalesceWith(const ld::Atom
& rhs
, const class ld::IndirectBindingTable
& ibt
) const  
 249                                                                                                                         { return _atom
->canCoalesceWith(rhs
,ibt
); } 
 251         virtual ld::Fixup::iterator                     
fixupsBegin() const     { return (ld::Fixup
*)&_fixups
[0]; } 
 252         virtual ld::Fixup::iterator                     
fixupsEnd()     const   { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; } 
 254         void                                                            addProtocolListFixup(); 
 255         void                                                            addPropertyListFixup(); 
 256         void                                                            addMethodListFixup(); 
 259         typedef typename 
A::P::uint_t                   pint_t
; 
 261         void addFixupAtOffset(uint32_t offset
); 
 263         const ld::Atom
*                                                 _atom
; 
 264         std::vector
<ld::Fixup
>                                  _fixups
; 
 267 template <typename A
> 
 268 ClassROOverlayAtom
<A
>::ClassROOverlayAtom(const ld::Atom
* classROAtom
) 
 269         : ld::Atom(classROAtom
->section(), ld::Atom::definitionRegular
, ld::Atom::combineNever
, 
 270                         ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,  
 271                         classROAtom
->symbolTableInclusion(), false, false, false, classROAtom
->alignment()), 
 274         // ensure all attributes are same as original 
 275         this->setAttributesFromAtom(*classROAtom
); 
 277         // copy fixups from orginal atom 
 278         for (ld::Fixup::iterator fit
=classROAtom
->fixupsBegin(); fit 
!= classROAtom
->fixupsEnd(); ++fit
) { 
 279                 ld::Fixup fixup 
= *fit
; 
 280                 _fixups
.push_back(fixup
); 
 286 // Base class for reading and updating existing ObjC atoms from .o files 
 288 template <typename A
> 
 291         static const ld::Atom
*  getPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
, unsigned int offset
, bool* hasAddend
=NULL
); 
 292         static void                             setPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
,  
 293                                                                                                 unsigned int offset
, const ld::Atom
* newAtom
); 
 294         typedef typename 
A::P::uint_t                   pint_t
; 
 297 template <typename A
> 
 298 const ld::Atom
* ObjCData
<A
>::getPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
, unsigned int offset
, bool* hasAddend
) 
 300         const ld::Atom
* target 
= NULL
; 
 301         if ( hasAddend 
!= NULL 
) 
 303         for (ld::Fixup::iterator fit
=contentAtom
->fixupsBegin(); fit 
!= contentAtom
->fixupsEnd(); ++fit
) { 
 304                 if ( (fit
->offsetInAtom 
== offset
) && (fit
->kind 
!= ld::Fixup::kindNoneFollowOn
) ) { 
 305                         switch ( fit
->binding 
) { 
 306                                 case ld::Fixup::bindingsIndirectlyBound
: 
 307                                         target 
= state
.indirectBindingTable
[fit
->u
.bindingIndex
]; 
 309                                 case ld::Fixup::bindingDirectlyBound
: 
 310                                         target 
=  fit
->u
.target
; 
 312                                 case ld::Fixup::bindingNone
: 
 313                                         if ( fit
->kind 
== ld::Fixup::kindAddAddend 
) { 
 314                                                 if ( hasAddend 
!= NULL 
) 
 326 template <typename A
> 
 327 void ObjCData
<A
>::setPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
,  
 328                                                                                                                 unsigned int offset
, const ld::Atom
* newAtom
) 
 330         for (ld::Fixup::iterator fit
=contentAtom
->fixupsBegin(); fit 
!= contentAtom
->fixupsEnd(); ++fit
) { 
 331                 if ( fit
->offsetInAtom 
== offset 
) { 
 332                         switch ( fit
->binding 
) { 
 333                                 case ld::Fixup::bindingsIndirectlyBound
: 
 334                                         state
.indirectBindingTable
[fit
->u
.bindingIndex
] = newAtom
; 
 336                                 case ld::Fixup::bindingDirectlyBound
: 
 337                                         fit
->u
.target 
= newAtom
; 
 344         assert(0 && "could not update method list"); 
 350 // Helper class for reading and updating existing ObjC category atoms from .o files 
 352 template <typename A
> 
 353 class Category 
: public ObjCData
<A
> { 
 355         static const ld::Atom
*  getClass(ld::Internal
& state
, const ld::Atom
* contentAtom
, bool& hasAddend
); 
 356         static const ld::Atom
*  getInstanceMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
); 
 357         static const ld::Atom
*  getClassMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
); 
 358         static const ld::Atom
*  getProtocols(ld::Internal
& state
, const ld::Atom
* contentAtom
); 
 359         static const ld::Atom
*  getInstanceProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
); 
 360         static const ld::Atom
*  getClassProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
); 
 361         static uint32_t         size() { return 6*sizeof(pint_t
); } 
 363         typedef typename 
A::P::uint_t                   pint_t
; 
 367 template <typename A
> 
 368 const ld::Atom
* Category
<A
>::getClass(ld::Internal
& state
, const ld::Atom
* contentAtom
, bool& hasAddend
) 
 370         return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, sizeof(pint_t
), &hasAddend
); // category_t.cls 
 373 template <typename A
> 
 374 const ld::Atom
* Category
<A
>::getInstanceMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
) 
 376         return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 2*sizeof(pint_t
)); // category_t.instanceMethods 
 379 template <typename A
> 
 380 const ld::Atom
* Category
<A
>::getClassMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
) 
 382         return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 3*sizeof(pint_t
)); // category_t.classMethods 
 385 template <typename A
> 
 386 const ld::Atom
* Category
<A
>::getProtocols(ld::Internal
& state
, const ld::Atom
* contentAtom
) 
 388         return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 4*sizeof(pint_t
)); // category_t.protocols 
 391 template <typename A
> 
 392 const ld::Atom
* Category
<A
>::getInstanceProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
) 
 394         return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 5*sizeof(pint_t
)); // category_t.instanceProperties 
 397 template <typename A
> 
 398 const ld::Atom
* Category
<A
>::getClassProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
) 
 400         // Only specially-marked files have this field. 
 401         if ( const ld::relocatable::File
* objFile 
= dynamic_cast<const ld::relocatable::File
*>(contentAtom
->file()) ) { 
 402                 if ( objFile
->objcHasCategoryClassPropertiesField() ) { 
 403                         return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 6*sizeof(pint_t
)); // category_t.classProperties 
 410 template <typename A
> 
 411 class MethodList 
: public ObjCData
<A
> { 
 413         static uint32_t count(ld::Internal
& state
, const ld::Atom
* methodListAtom
) { 
 414                 const uint32_t* methodListData 
= (uint32_t*)(methodListAtom
->rawContentPointer()); 
 415                 return A::P::E::get32(methodListData
[1]); // method_list_t.count 
 419 template <typename A
> 
 420 class ProtocolList 
: public ObjCData
<A
> { 
 422         static uint32_t count(ld::Internal
& state
, const ld::Atom
* protocolListAtom
)  { 
 423                 pint_t
* protocolListData 
= (pint_t
*)(protocolListAtom
->rawContentPointer()); 
 424                 return A::P::getP(*protocolListData
); // protocol_list_t.count 
 427         typedef typename 
A::P::uint_t   pint_t
; 
 430 template <typename A
> 
 431 class PropertyList 
: public ObjCData
<A
> { 
 433         static uint32_t count(ld::Internal
& state
, const ld::Atom
* protocolListAtom
)  { 
 434                 uint32_t* protocolListData 
= (uint32_t*)(protocolListAtom
->rawContentPointer()); 
 435                 return A::P::E::get32(protocolListData
[1]); // property_list_t.count 
 438         typedef typename 
A::P::uint_t   pint_t
; 
 444 // Helper class for reading and updating existing ObjC class atoms from .o files 
 446 template <typename A
> 
 447 class Class 
: public ObjCData
<A
> { 
 449         static const ld::Atom
*  getMetaClass(ld::Internal
& state
, const ld::Atom
* classAtom
); 
 450         static const ld::Atom
*  getInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
); 
 451         static const ld::Atom
*  getInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
); 
 452         static const ld::Atom
*  getInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
); 
 453         static const ld::Atom
*  getClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
); 
 454         static const ld::Atom
*  getClassPropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
); 
 455         static const ld::Atom
*  setInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,  
 456                                                                                                 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
); 
 457         static const ld::Atom
*  setInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,  
 458                                                                                                 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
); 
 459         static const ld::Atom
*  setInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,  
 460                                                                                                 const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
); 
 461         static const ld::Atom
*  setClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,  
 462                                                                                                 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
); 
 463         static const ld::Atom
*  setClassProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,  
 464                                                                                                 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
); 
 465         static const ld::Atom
*  setClassPropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,  
 466                                                                                                 const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
); 
 467         static uint32_t         size() { return sizeof(Content
); } 
 470         friend class ClassROOverlayAtom
<A
>; 
 472         typedef typename 
A::P::uint_t                   pint_t
; 
 474         static const ld::Atom
*  getROData(ld::Internal
& state
, const ld::Atom
* classAtom
); 
 486                 uint32_t instanceStart
; 
 487                 // Note there is 4-bytes of alignment padding between instanceSize  
 488                 // and ivarLayout on 64-bit archs, but no padding on 32-bit archs. 
 489                 // This union is a way to model that. 
 491                         uint32_t instanceSize
; 
 497                 pint_t baseProtocols
; 
 499                 pint_t weakIvarLayout
; 
 500                 pint_t baseProperties
; 
 504 #define GET_FIELD(state, classAtom, field) \ 
 505         ObjCData<A>::getPointerInContent(state, classAtom, offsetof(Content, field)) 
 506 #define SET_FIELD(state, classAtom, field, valueAtom) \ 
 507         ObjCData<A>::setPointerInContent(state, classAtom, offsetof(Content, field), valueAtom) 
 509 #define GET_RO_FIELD(state, classAtom, field) \ 
 510         ObjCData<A>::getPointerInContent(state, getROData(state, classAtom), offsetof(ROContent, field)) 
 511 #define SET_RO_FIELD(state, classROAtom, field, valueAtom) \ 
 512         ObjCData<A>::setPointerInContent(state, getROData(state, classAtom), offsetof(ROContent, field), valueAtom) 
 514 template <typename A
> 
 515 const ld::Atom
* Class
<A
>::getMetaClass(ld::Internal
& state
, const ld::Atom
* classAtom
) 
 517     const ld::Atom
* metaClassAtom 
= GET_FIELD(state
, classAtom
, isa
); 
 518     assert(metaClassAtom 
!= NULL
); 
 519     return metaClassAtom
; 
 522 template <typename A
> 
 523 const ld::Atom
* Class
<A
>::getROData(ld::Internal
& state
, const ld::Atom
* classAtom
) 
 525     const ld::Atom
* classROAtom 
= GET_FIELD(state
, classAtom
, data
); 
 526     assert(classROAtom 
!= NULL
); 
 530 template <typename A
> 
 531 const ld::Atom
* Class
<A
>::getInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
) 
 533         return GET_RO_FIELD(state
, classAtom
, baseMethods
); 
 536 template <typename A
> 
 537 const ld::Atom
* Class
<A
>::getInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
) 
 539         return GET_RO_FIELD(state
, classAtom
, baseProtocols
); 
 542 template <typename A
> 
 543 const ld::Atom
* Class
<A
>::getInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
) 
 545         return GET_RO_FIELD(state
, classAtom
, baseProperties
); 
 548 template <typename A
> 
 549 const ld::Atom
* Class
<A
>::getClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
) 
 551         return Class
<A
>::getInstanceMethodList(state
, getMetaClass(state
, classAtom
)); 
 554 template <typename A
> 
 555 const ld::Atom
* Class
<A
>::getClassPropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
) 
 557     return Class
<A
>::getInstancePropertyList(state
, getMetaClass(state
, classAtom
)); 
 560 template <typename A
> 
 561 const ld::Atom
* Class
<A
>::setInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,  
 562                                                                                                 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
) 
 564         // if the base class does not already have a method list, we need to create an overlay 
 565         if ( getInstanceMethodList(state
, classAtom
) == NULL 
) { 
 566                 const ld::Atom
* oldROAtom 
= getROData(state
, classAtom
); 
 567                 deadAtoms
.insert(oldROAtom
); 
 568                 ClassROOverlayAtom
<A
>* overlay 
= new ClassROOverlayAtom
<A
>(oldROAtom
); 
 569                 //fprintf(stderr, "replace class RO atom %p with %p for method list in class atom %s\n", classROAtom, overlay, classAtom->name()); 
 570                 overlay
->addMethodListFixup(); 
 571                 SET_FIELD(state
, classAtom
, data
, overlay
); 
 572                 SET_RO_FIELD(state
, classAtom
, baseMethods
, methodListAtom
); 
 575         SET_RO_FIELD(state
, classAtom
, baseMethods
, methodListAtom
); 
 576         return NULL
; // means classRO atom was not replaced 
 579 template <typename A
> 
 580 const ld::Atom
* Class
<A
>::setInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,  
 581                                                                         const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
) 
 583         // if the base class does not already have a protocol list, we need to create an overlay 
 584         if ( getInstanceProtocolList(state
, classAtom
) == NULL 
) { 
 585                 const ld::Atom
* oldROAtom 
= getROData(state
, classAtom
); 
 586                 deadAtoms
.insert(oldROAtom
); 
 587                 ClassROOverlayAtom
<A
>* overlay 
= new ClassROOverlayAtom
<A
>(oldROAtom
); 
 588                 //fprintf(stderr, "replace class RO atom %p with %p for protocol list in class atom %s\n", classROAtom, overlay, classAtom->name()); 
 589                 overlay
->addProtocolListFixup(); 
 590                 SET_FIELD(state
, classAtom
, data
, overlay
); 
 591                 SET_RO_FIELD(state
, classAtom
, baseProtocols
, protocolListAtom
); 
 594         //fprintf(stderr, "set class RO atom %p protocol list in class atom %s\n", classROAtom, classAtom->name()); 
 595         SET_RO_FIELD(state
, classAtom
, baseProtocols
, protocolListAtom
); 
 596         return NULL
;  // means classRO atom was not replaced 
 599 template <typename A
> 
 600 const ld::Atom
* Class
<A
>::setClassProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,  
 601                                                                         const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
) 
 603         // meta class also points to same protocol list as class 
 604         const ld::Atom
* metaClassAtom 
= getMetaClass(state
, classAtom
); 
 605         //fprintf(stderr, "setClassProtocolList(), classAtom=%p %s, metaClass=%p %s\n", classAtom, classAtom->name(), metaClassAtom, metaClassAtom->name()); 
 606         return setInstanceProtocolList(state
, metaClassAtom
, protocolListAtom
, deadAtoms
); 
 611 template <typename A
> 
 612 const ld::Atom
*  Class
<A
>::setInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,  
 613                                                                                                 const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
) 
 615         // if the base class does not already have a property list, we need to create an overlay 
 616         if ( getInstancePropertyList(state
, classAtom
) == NULL 
) { 
 617                 const ld::Atom
* oldROAtom 
= getROData(state
, classAtom
); 
 618                 deadAtoms
.insert(oldROAtom
); 
 619                 ClassROOverlayAtom
<A
>* overlay 
= new ClassROOverlayAtom
<A
>(oldROAtom
); 
 620                 //fprintf(stderr, "replace class RO atom %p with %p for property list in class atom %s\n", classROAtom, overlay, classAtom->name()); 
 621                 overlay
->addPropertyListFixup(); 
 622                 SET_FIELD(state
, classAtom
, data
, overlay
); 
 623                 SET_RO_FIELD(state
, classAtom
, baseProperties
, propertyListAtom
); 
 626         SET_RO_FIELD(state
, classAtom
, baseProperties
, propertyListAtom
); 
 627         return NULL
;  // means classRO atom was not replaced 
 630 template <typename A
> 
 631 const ld::Atom
* Class
<A
>::setClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,  
 632                                                                                         const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
) 
 634         // class methods is just instance methods of metaClass 
 635         return setInstanceMethodList(state
, getMetaClass(state
, classAtom
), methodListAtom
, deadAtoms
); 
 638 template <typename A
> 
 639 const ld::Atom
* Class
<A
>::setClassPropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,  
 640                                                                                         const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
) 
 642         // class properties is just instance properties of metaClass 
 643         return setInstancePropertyList(state
, getMetaClass(state
, classAtom
), propertyListAtom
, deadAtoms
); 
 652 template <typename P
> 
 653 ld::Fixup::Kind 
pointerFixupKind(); 
 656 ld::Fixup::Kind pointerFixupKind
<Pointer32
<BigEndian
>>() {  
 657         return ld::Fixup::kindStoreTargetAddressBigEndian32
;  
 660 ld::Fixup::Kind pointerFixupKind
<Pointer64
<BigEndian
>>() {  
 661         return ld::Fixup::kindStoreTargetAddressBigEndian64
;  
 664 ld::Fixup::Kind pointerFixupKind
<Pointer32
<LittleEndian
>>() {  
 665         return ld::Fixup::kindStoreTargetAddressLittleEndian32
;  
 668 ld::Fixup::Kind pointerFixupKind
<Pointer64
<LittleEndian
>>() {  
 669         return ld::Fixup::kindStoreTargetAddressLittleEndian64
;  
 672 template <typename A
> 
 673 void ClassROOverlayAtom
<A
>::addFixupAtOffset(uint32_t offset
) 
 675         const ld::Atom
* targetAtom 
= this; // temporary 
 676         _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, pointerFixupKind
<typename 
A::P
>(), targetAtom
)); 
 680 template <typename A
> 
 681 void ClassROOverlayAtom
<A
>::addMethodListFixup() 
 683         addFixupAtOffset(offsetof(typename Class
<A
>::ROContent
, baseMethods
)); 
 686 template <typename A
> 
 687 void ClassROOverlayAtom
<A
>::addProtocolListFixup() 
 689         addFixupAtOffset(offsetof(typename Class
<A
>::ROContent
, baseProtocols
)); 
 692 template <typename A
> 
 693 void ClassROOverlayAtom
<A
>::addPropertyListFixup() 
 695         addFixupAtOffset(offsetof(typename Class
<A
>::ROContent
, baseProperties
)); 
 702 // Encapsulates merging of ObjC categories 
 704 template <typename A
> 
 705 class OptimizeCategories 
{ 
 707         static void                             doit(const Options
& opts
, ld::Internal
& state
); 
 708         static bool                             hasInstanceMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
); 
 709         static bool                             hasClassMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
); 
 710         static bool                             hasProtocols(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
); 
 711         static bool                             hasInstanceProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
); 
 712         static bool                             hasClassProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
); 
 714         static unsigned int             class_ro_baseMethods_offset(); 
 716         typedef typename 
A::P::uint_t                   pint_t
; 
 721 template <typename A
> 
 722 bool OptimizeCategories
<A
>::hasInstanceMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
) 
 724         for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it 
!= categories
->end(); ++it
) { 
 725                 const ld::Atom
* categoryAtom 
= *it
; 
 726                 const ld::Atom
* methodList 
= Category
<A
>::getInstanceMethods(state
, categoryAtom
); 
 727                 if ( methodList 
!= NULL 
) { 
 728                         if ( MethodList
<A
>::count(state
, methodList
) > 0 ) 
 736 template <typename A
> 
 737 bool OptimizeCategories
<A
>::hasClassMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
) 
 739         for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it 
!= categories
->end(); ++it
) { 
 740                 const ld::Atom
* categoryAtom 
= *it
; 
 741                 const ld::Atom
* methodList 
= Category
<A
>::getClassMethods(state
, categoryAtom
); 
 742                 if ( methodList 
!= NULL 
) { 
 743                         if ( MethodList
<A
>::count(state
, methodList
) > 0 ) 
 750 template <typename A
> 
 751 bool OptimizeCategories
<A
>::hasProtocols(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
) 
 753         for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it 
!= categories
->end(); ++it
) { 
 754                 const ld::Atom
* categoryAtom 
= *it
; 
 755                 const ld::Atom
* protocolListAtom 
= Category
<A
>::getProtocols(state
, categoryAtom
); 
 756                 if ( protocolListAtom 
!= NULL 
) { 
 757                         if ( ProtocolList
<A
>::count(state
, protocolListAtom
) > 0 ) {     
 766 template <typename A
> 
 767 bool OptimizeCategories
<A
>::hasInstanceProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
) 
 769         for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it 
!= categories
->end(); ++it
) { 
 770                 const ld::Atom
* categoryAtom 
= *it
; 
 771                 const ld::Atom
* propertyListAtom 
= Category
<A
>::getInstanceProperties(state
, categoryAtom
); 
 772                 if ( propertyListAtom 
!= NULL 
) { 
 773                         if ( PropertyList
<A
>::count(state
, propertyListAtom
) > 0 ) 
 781 template <typename A
> 
 782 bool OptimizeCategories
<A
>::hasClassProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
) 
 784         for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it 
!= categories
->end(); ++it
) { 
 785                 const ld::Atom
* categoryAtom 
= *it
; 
 786                 const ld::Atom
* propertyListAtom 
= Category
<A
>::getClassProperties(state
, categoryAtom
); 
 787                 if ( propertyListAtom 
!= NULL 
) { 
 788                         if ( PropertyList
<A
>::count(state
, propertyListAtom
) > 0 ) 
 796 static const ld::Atom
* fixClassAliases(const ld::Atom
* classAtom
) 
 798         if ( (classAtom
->size() != 0) || (classAtom
->definition() == ld::Atom::definitionProxy
) ) 
 801         for (ld::Fixup::iterator fit
=classAtom
->fixupsBegin(); fit 
!= classAtom
->fixupsEnd(); ++fit
) { 
 802                 if ( fit
->kind 
== ld::Fixup::kindNoneFollowOn 
) { 
 803                         assert(fit
->offsetInAtom 
== 0); 
 804                         assert(fit
->binding 
== ld::Fixup::bindingDirectlyBound
); 
 805                         return fit
->u
.target
; 
 813 // Helper for std::remove_if 
 815 class OptimizedAway 
{ 
 817         OptimizedAway(const std::set
<const ld::Atom
*>& oa
) : _dead(oa
) {} 
 818         bool operator()(const ld::Atom
* atom
) const { 
 819                 return ( _dead
.count(atom
) != 0 ); 
 822         const std::set
<const ld::Atom
*>& _dead
; 
 827                 bool operator()(const Atom
* left
, const Atom
* right
) 
 829                         // sort by file ordinal, then object address, then zero size, then symbol name 
 830                         // only file based atoms are supported (file() != NULL) 
 831                         if (left
==right
) return false; 
 832                         const File 
*leftf 
= left
->file(); 
 833                         const File 
*rightf 
= right
->file(); 
 835                         if (leftf 
== rightf
) { 
 836                                 if (left
->objectAddress() != right
->objectAddress()) { 
 837                                         return left
->objectAddress() < right
->objectAddress(); 
 839                                         // for atoms in the same file with the same address, zero sized 
 840                                         // atoms must sort before nonzero sized atoms 
 841                                         if ((left
->size() == 0 && right
->size() > 0) || (left
->size() > 0 && right
->size() == 0)) 
 842                                                 return left
->size() < right
->size(); 
 843                                         return strcmp(left
->name(), right
->name()); 
 846                         return  (leftf
->ordinal() < rightf
->ordinal()); 
 850         static void sortAtomVector(std::vector
<const Atom
*> &atoms
) { 
 851                 std::sort(atoms
.begin(), atoms
.end(), AtomSorter()); 
 855 template <typename A
> 
 856 void OptimizeCategories
<A
>::doit(const Options
& opts
, ld::Internal
& state
) 
 858         // first find all categories referenced by __objc_nlcatlist section 
 859         std::set
<const ld::Atom
*> nlcatListAtoms
; 
 860         for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit 
!= state
.sections
.end(); ++sit
) { 
 861                 ld::Internal::FinalSection
* sect 
= *sit
; 
 862                 if ( (strcmp(sect
->sectionName(), "__objc_nlcatlist") == 0) && (strncmp(sect
->segmentName(), "__DATA", 6) == 0) ) { 
 863                         for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait 
!= sect
->atoms
.end(); ++ait
) { 
 864                                 const ld::Atom
* categoryListElementAtom 
= *ait
; 
 865                                 for (unsigned int offset
=0; offset 
< categoryListElementAtom
->size(); offset 
+= sizeof(pint_t
)) { 
 866                                         const ld::Atom
* categoryAtom 
= ObjCData
<A
>::getPointerInContent(state
, categoryListElementAtom
, offset
); 
 867                                         //fprintf(stderr, "offset=%d, cat=%p %s\n", offset, categoryAtom, categoryAtom->name()); 
 868                                         assert(categoryAtom 
!= NULL
); 
 869                                         nlcatListAtoms
.insert(categoryAtom
); 
 875         // build map of all classes in this image that have categories on them 
 876         typedef std::map
<const ld::Atom
*, std::vector
<const ld::Atom
*>*> CatMap
; 
 877         CatMap classToCategories
; 
 878         std::vector
<const ld::Atom
*> classOrder
; 
 879         std::set
<const ld::Atom
*> deadAtoms
; 
 880         ld::Internal::FinalSection
* methodListSection 
= NULL
; 
 881         for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit 
!= state
.sections
.end(); ++sit
) { 
 882                 ld::Internal::FinalSection
* sect 
= *sit
; 
 883                 if ( sect
->type() == ld::Section::typeObjC2CategoryList 
) { 
 884                         for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait 
!= sect
->atoms
.end(); ++ait
) { 
 885                                 const ld::Atom
* categoryListElementAtom 
= *ait
; 
 887                                 const ld::Atom
* categoryAtom 
= ObjCData
<A
>::getPointerInContent(state
, categoryListElementAtom
, 0, &hasAddend
); 
 888                                 if ( hasAddend 
|| (categoryAtom
->symbolTableInclusion() ==  ld::Atom::symbolTableNotIn
)) { 
 889                                         //<rdar://problem/8309530> gcc-4.0 uses 'L' labels on categories which disables this optimization 
 890                                         //warning("__objc_catlist element does not point to start of category"); 
 893                                 assert(categoryAtom 
!= NULL
); 
 894                                 assert(categoryAtom
->size() >= Category
<A
>::size()); 
 895                                 // ignore categories also in __objc_nlcatlist 
 896                                 if ( nlcatListAtoms
.count(categoryAtom
) != 0 ) 
 898                                 const ld::Atom
* categoryOnClassAtom 
= fixClassAliases(Category
<A
>::getClass(state
, categoryAtom
, hasAddend
)); 
 899                                 assert(categoryOnClassAtom 
!= NULL
); 
 900                                 // only look at classes defined in this image 
 901                                 if ( categoryOnClassAtom
->definition() != ld::Atom::definitionProxy 
) { 
 902                                         // <rdar://problem/16107696> for now, back off optimization on new style classes 
 903                                         if ( hasAddend 
!= 0 ) 
 905                                         // <rdar://problem/17249777> don't apply categories to swift classes 
 906                                         if ( categoryOnClassAtom
->hasFixupsOfKind(ld::Fixup::kindNoneGroupSubordinate
) ) 
 909                                         CatMap::iterator pos 
= classToCategories
.find(categoryOnClassAtom
); 
 910                                         if ( pos 
== classToCategories
.end() ) { 
 911                                                 classToCategories
[categoryOnClassAtom
] = new std::vector
<const ld::Atom
*>(); 
 912                                                 classOrder
.push_back(categoryOnClassAtom
); 
 914                                         classToCategories
[categoryOnClassAtom
]->push_back(categoryAtom
); 
 915                                         // mark category atom and catlist atom as dead 
 916                                         deadAtoms
.insert(categoryAtom
); 
 917                                         deadAtoms
.insert(categoryListElementAtom
); 
 921                 // record method list section 
 922                 if ( (strcmp(sect
->sectionName(), "__objc_const") == 0) && (strncmp(sect
->segmentName(), "__DATA", 6) == 0) ) 
 923                         methodListSection 
= sect
; 
 926         // if found some categories 
 927         if ( classToCategories
.size() != 0 ) { 
 928                 assert(methodListSection 
!= NULL
); 
 929                 sortAtomVector(classOrder
); 
 930                 // alter each class definition to have new method list which includes all category methods 
 931                 for (std::vector
<const ld::Atom
*>::iterator it 
= classOrder
.begin(); it 
!= classOrder
.end(); it
++) { 
 932                         const ld::Atom
* classAtom 
= *it
; 
 933                         const std::vector
<const ld::Atom
*>* categories 
= classToCategories
[classAtom
]; 
 934                         assert(categories
->size() != 0); 
 935                         // if any category adds instance methods, generate new merged method list, and replace 
 936                         if ( OptimizeCategories
<A
>::hasInstanceMethods(state
, categories
) ) {  
 937                                 const ld::Atom
* baseInstanceMethodListAtom 
= Class
<A
>::getInstanceMethodList(state
, classAtom
);  
 938                                 const ld::Atom
* newInstanceMethodListAtom 
= new MethodListAtom
<A
>(state
, baseInstanceMethodListAtom
, false, categories
, deadAtoms
); 
 939                                 const ld::Atom
* newClassRO 
= Class
<A
>::setInstanceMethodList(state
, classAtom
, newInstanceMethodListAtom
, deadAtoms
); 
 940                                 // add new method list to final sections 
 941                                 methodListSection
->atoms
.push_back(newInstanceMethodListAtom
); 
 942                                 state
.atomToSection
[newInstanceMethodListAtom
] = methodListSection
; 
 943                                 if ( newClassRO 
!= NULL 
) { 
 944                                         assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0); 
 945                                         methodListSection
->atoms
.push_back(newClassRO
); 
 946                                         state
.atomToSection
[newClassRO
] = methodListSection
; 
 949                         // if any category adds class methods, generate new merged method list, and replace 
 950                         if ( OptimizeCategories
<A
>::hasClassMethods(state
, categories
) ) {  
 951                                 const ld::Atom
* baseClassMethodListAtom 
= Class
<A
>::getClassMethodList(state
, classAtom
);  
 952                                 const ld::Atom
* newClassMethodListAtom 
= new MethodListAtom
<A
>(state
, baseClassMethodListAtom
, true, categories
, deadAtoms
); 
 953                                 const ld::Atom
* newClassRO 
= Class
<A
>::setClassMethodList(state
, classAtom
, newClassMethodListAtom
, deadAtoms
); 
 954                                 // add new method list to final sections 
 955                                 methodListSection
->atoms
.push_back(newClassMethodListAtom
); 
 956                                 state
.atomToSection
[newClassMethodListAtom
] = methodListSection
; 
 957                                 if ( newClassRO 
!= NULL 
) { 
 958                                         assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0); 
 959                                         methodListSection
->atoms
.push_back(newClassRO
); 
 960                                         state
.atomToSection
[newClassRO
] = methodListSection
; 
 963                         // if any category adds protocols, generate new merged protocol list, and replace 
 964                         if ( OptimizeCategories
<A
>::hasProtocols(state
, categories
) ) {  
 965                                 const ld::Atom
* baseProtocolListAtom 
= Class
<A
>::getInstanceProtocolList(state
, classAtom
);  
 966                                 const ld::Atom
* newProtocolListAtom 
= new ProtocolListAtom
<A
>(state
, baseProtocolListAtom
, categories
, deadAtoms
); 
 967                                 const ld::Atom
* newClassRO 
= Class
<A
>::setInstanceProtocolList(state
, classAtom
, newProtocolListAtom
, deadAtoms
); 
 968                                 const ld::Atom
* newMetaClassRO 
= Class
<A
>::setClassProtocolList(state
, classAtom
, newProtocolListAtom
, deadAtoms
); 
 969                                 // add new protocol list to final sections 
 970                                 methodListSection
->atoms
.push_back(newProtocolListAtom
); 
 971                                 state
.atomToSection
[newProtocolListAtom
] = methodListSection
; 
 972                                 if ( newClassRO 
!= NULL 
) { 
 973                                         assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0); 
 974                                         methodListSection
->atoms
.push_back(newClassRO
); 
 975                                         state
.atomToSection
[newClassRO
] = methodListSection
; 
 977                                 if ( newMetaClassRO 
!= NULL 
) { 
 978                                         assert(strcmp(newMetaClassRO
->section().sectionName(), "__objc_const") == 0); 
 979                                         methodListSection
->atoms
.push_back(newMetaClassRO
); 
 980                                         state
.atomToSection
[newMetaClassRO
] = methodListSection
; 
 983                         // if any category adds instance properties, generate new merged property list, and replace 
 984                         if ( OptimizeCategories
<A
>::hasInstanceProperties(state
, categories
) ) {  
 985                                 const ld::Atom
* basePropertyListAtom 
= Class
<A
>::getInstancePropertyList(state
, classAtom
);  
 986                                 const ld::Atom
* newPropertyListAtom 
= new PropertyListAtom
<A
>(state
, basePropertyListAtom
, categories
, deadAtoms
, PropertyListAtom
<A
>::PropertyKind::InstanceProperties
); 
 987                                 const ld::Atom
* newClassRO 
= Class
<A
>::setInstancePropertyList(state
, classAtom
, newPropertyListAtom
, deadAtoms
); 
 988                                 // add new property list to final sections 
 989                                 methodListSection
->atoms
.push_back(newPropertyListAtom
); 
 990                                 state
.atomToSection
[newPropertyListAtom
] = methodListSection
; 
 991                                 if ( newClassRO 
!= NULL 
) { 
 992                                         assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0); 
 993                                         methodListSection
->atoms
.push_back(newClassRO
); 
 994                                         state
.atomToSection
[newClassRO
] = methodListSection
; 
 997                         // if any category adds class properties, generate new merged property list, and replace 
 998                         if ( OptimizeCategories
<A
>::hasClassProperties(state
, categories
) ) {  
 999                                 const ld::Atom
* basePropertyListAtom 
= Class
<A
>::getClassPropertyList(state
, classAtom
);  
1000                                 const ld::Atom
* newPropertyListAtom 
= new PropertyListAtom
<A
>(state
, basePropertyListAtom
, categories
, deadAtoms
, PropertyListAtom
<A
>::PropertyKind::ClassProperties
); 
1001                                 const ld::Atom
* newClassRO 
= Class
<A
>::setClassPropertyList(state
, classAtom
, newPropertyListAtom
, deadAtoms
); 
1002                                 // add new property list to final sections 
1003                                 methodListSection
->atoms
.push_back(newPropertyListAtom
); 
1004                                 state
.atomToSection
[newPropertyListAtom
] = methodListSection
; 
1005                                 if ( newClassRO 
!= NULL 
) { 
1006                                         assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0); 
1007                                         methodListSection
->atoms
.push_back(newClassRO
); 
1008                                         state
.atomToSection
[newClassRO
] = methodListSection
; 
1013                 // remove dead atoms 
1014                 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit 
!= state
.sections
.end(); ++sit
) { 
1015                         ld::Internal::FinalSection
* sect 
= *sit
; 
1016                         sect
->atoms
.erase(std::remove_if(sect
->atoms
.begin(), sect
->atoms
.end(), OptimizedAway(deadAtoms
)), sect
->atoms
.end()); 
1023 template <typename A
>  
1024 MethodListAtom
<A
>::MethodListAtom(ld::Internal
& state
, const ld::Atom
* baseMethodList
, bool meta
,  
1025                                                                         const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
) 
1026   : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
, 
1027                         ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,  
1028                         symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _methodCount(0)  
1030         unsigned int fixupCount 
= 0; 
1031         std::set
<const ld::Atom
*> baseMethodListMethodNameAtoms
; 
1032         // if base class has method list, then associate new method list with file defining class 
1033         if ( baseMethodList 
!= NULL 
) { 
1034                 _file 
= baseMethodList
->file(); 
1035                 // calculate total size of merge method lists 
1036                 _methodCount 
= MethodList
<A
>::count(state
, baseMethodList
); 
1037                 deadAtoms
.insert(baseMethodList
); 
1038                 fixupCount 
= baseMethodList
->fixupsEnd() - baseMethodList
->fixupsBegin(); 
1039                 for (ld::Fixup::iterator fit
=baseMethodList
->fixupsBegin(); fit 
!= baseMethodList
->fixupsEnd(); ++fit
) { 
1040                         if ( (fit
->offsetInAtom 
- 8) % (3*sizeof(pint_t
)) == 0 ) { 
1041                                 assert(fit
->binding 
== ld::Fixup::bindingsIndirectlyBound 
&& "malformed method list"); 
1042                                 const ld::Atom
* target 
= state
.indirectBindingTable
[fit
->u
.bindingIndex
]; 
1043                                 assert(target
->contentType() == ld::Atom::typeCString 
&& "malformed method list"); 
1044                                 baseMethodListMethodNameAtoms
.insert(target
); 
1048         for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait 
!= categories
->end(); ++ait
) { 
1049                 const ld::Atom
* categoryMethodListAtom
; 
1051                         categoryMethodListAtom 
= Category
<A
>::getClassMethods(state
, *ait
); 
1053                         categoryMethodListAtom 
= Category
<A
>::getInstanceMethods(state
, *ait
); 
1054                 if ( categoryMethodListAtom 
!= NULL 
) { 
1055                         _methodCount 
+= MethodList
<A
>::count(state
, categoryMethodListAtom
); 
1056                         fixupCount 
+= (categoryMethodListAtom
->fixupsEnd() - categoryMethodListAtom
->fixupsBegin()); 
1057                         deadAtoms
.insert(categoryMethodListAtom
); 
1058                         // if base class did not have method list, associate new method list with file the defined category 
1059                         if ( _file 
== NULL 
) 
1060                                 _file 
= categoryMethodListAtom
->file(); 
1063         //if ( baseMethodList != NULL ) 
1064         //      fprintf(stderr, "total merged method count=%u for baseMethodList=%s\n", _methodCount, baseMethodList->name()); 
1066         //      fprintf(stderr, "total merged method count=%u\n", _methodCount); 
1067         //fprintf(stderr, "total merged fixup count=%u\n", fixupCount); 
1069         // copy fixups and adjust offsets (in reverse order to simulator objc runtime) 
1070         _fixups
.reserve(fixupCount
); 
1072         std::set
<const ld::Atom
*> categoryMethodNameAtoms
; 
1073         for (std::vector
<const ld::Atom
*>::const_reverse_iterator rit
=categories
->rbegin(); rit 
!= categories
->rend(); ++rit
) { 
1074                 const ld::Atom
* categoryMethodListAtom
; 
1076                         categoryMethodListAtom 
= Category
<A
>::getClassMethods(state
, *rit
); 
1078                         categoryMethodListAtom 
= Category
<A
>::getInstanceMethods(state
, *rit
); 
1079                 if ( categoryMethodListAtom 
!= NULL 
) { 
1080                         for (ld::Fixup::iterator fit
=categoryMethodListAtom
->fixupsBegin(); fit 
!= categoryMethodListAtom
->fixupsEnd(); ++fit
) { 
1081                                 ld::Fixup fixup 
= *fit
; 
1082                                 fixup
.offsetInAtom 
+= slide
; 
1083                                 _fixups
.push_back(fixup
); 
1084                                 if ( (fixup
.offsetInAtom 
- 8) % (3*sizeof(pint_t
)) == 0 ) { 
1085                                         // <rdar://problem/8642343> warning when a method is overridden in a category in the same link unit 
1086                                         assert(fixup
.binding 
== ld::Fixup::bindingsIndirectlyBound 
&& "malformed category method list"); 
1087                                         const ld::Atom
* target 
= state
.indirectBindingTable
[fixup
.u
.bindingIndex
]; 
1088                                         assert(target
->contentType() == ld::Atom::typeCString 
&& "malformed method list"); 
1089                                         // this objc pass happens after cstrings are coalesced, so we can just compare the atom addres instead of its content 
1090                                         if ( baseMethodListMethodNameAtoms
.count(target
) != 0 ) { 
1091                                                 warning("%s method '%s' in category from %s overrides method from class in %s",  
1092                                                         (meta 
? "meta" : "instance"), target
->rawContentPointer(), 
1093                                                         categoryMethodListAtom
->safeFilePath(), baseMethodList
->safeFilePath() ); 
1095                                         if ( categoryMethodNameAtoms
.count(target
) != 0 ) { 
1096                                                 warning("%s method '%s' in category from %s conflicts with same method from another category",  
1097                                                         (meta 
? "meta" : "instance"), target
->rawContentPointer(), 
1098                                                         categoryMethodListAtom
->safeFilePath()); 
1100                                         categoryMethodNameAtoms
.insert(target
); 
1103                         slide 
+= 3*sizeof(pint_t
) * MethodList
<A
>::count(state
, categoryMethodListAtom
); 
1106         // add method list from base class last 
1107         if ( baseMethodList 
!= NULL 
) { 
1108                 for (ld::Fixup::iterator fit
=baseMethodList
->fixupsBegin(); fit 
!= baseMethodList
->fixupsEnd(); ++fit
) { 
1109                         ld::Fixup fixup 
= *fit
; 
1110                         fixup
.offsetInAtom 
+= slide
; 
1111                         _fixups
.push_back(fixup
); 
1117 template <typename A
>  
1118 ProtocolListAtom
<A
>::ProtocolListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,  
1119                                                                         const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
) 
1120   : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
, 
1121                         ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,  
1122                         symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _protocolCount(0)  
1124         unsigned int fixupCount 
= 0; 
1125         if ( baseProtocolList 
!= NULL 
) { 
1126                 // if base class has protocol list, then associate new protocol list with file defining class 
1127                 _file 
= baseProtocolList
->file(); 
1128                 // calculate total size of merged protocol list 
1129                 _protocolCount 
= ProtocolList
<A
>::count(state
, baseProtocolList
); 
1130                 deadAtoms
.insert(baseProtocolList
); 
1131                 fixupCount 
= baseProtocolList
->fixupsEnd() - baseProtocolList
->fixupsBegin(); 
1133         for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait 
!= categories
->end(); ++ait
) { 
1134                 const ld::Atom
* categoryProtocolListAtom 
= Category
<A
>::getProtocols(state
, *ait
); 
1135                 if ( categoryProtocolListAtom 
!= NULL 
) { 
1136                         _protocolCount 
+= ProtocolList
<A
>::count(state
, categoryProtocolListAtom
); 
1137                         fixupCount 
+= (categoryProtocolListAtom
->fixupsEnd() - categoryProtocolListAtom
->fixupsBegin()); 
1138                         deadAtoms
.insert(categoryProtocolListAtom
); 
1139                         // if base class did not have protocol list, associate new protocol list with file the defined category 
1140                         if ( _file 
== NULL 
) 
1141                                 _file 
= categoryProtocolListAtom
->file(); 
1144         //fprintf(stderr, "total merged protocol count=%u\n", _protocolCount); 
1145         //fprintf(stderr, "total merged fixup count=%u\n", fixupCount); 
1147         // copy fixups and adjust offsets  
1148         _fixups
.reserve(fixupCount
); 
1150         for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it 
!= categories
->end(); ++it
) { 
1151                 const ld::Atom
* categoryProtocolListAtom 
= Category
<A
>::getProtocols(state
, *it
); 
1152                 if ( categoryProtocolListAtom 
!= NULL 
) { 
1153                         for (ld::Fixup::iterator fit
=categoryProtocolListAtom
->fixupsBegin(); fit 
!= categoryProtocolListAtom
->fixupsEnd(); ++fit
) { 
1154                                 ld::Fixup fixup 
= *fit
; 
1155                                 fixup
.offsetInAtom 
+= slide
; 
1156                                 _fixups
.push_back(fixup
); 
1157                                 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound ) 
1158                                 //      fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name()); 
1160                         slide 
+= sizeof(pint_t
) * ProtocolList
<A
>::count(state
, categoryProtocolListAtom
); 
1163         // add method list from base class last 
1164         if ( baseProtocolList 
!= NULL 
) { 
1165                 for (ld::Fixup::iterator fit
=baseProtocolList
->fixupsBegin(); fit 
!= baseProtocolList
->fixupsEnd(); ++fit
) { 
1166                         ld::Fixup fixup 
= *fit
; 
1167                         fixup
.offsetInAtom 
+= slide
; 
1168                         _fixups
.push_back(fixup
); 
1174 template <typename A
>  
1175 PropertyListAtom
<A
>::PropertyListAtom(ld::Internal
& state
, const ld::Atom
* basePropertyList
,  
1176                                       const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
, PropertyKind kind
) 
1177   : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
, 
1178                         ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,  
1179                         symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _propertyCount(0)  
1181         unsigned int fixupCount 
= 0; 
1182         if ( basePropertyList 
!= NULL 
) { 
1183                 // if base class has property list, then associate new property list with file defining class 
1184                 _file 
= basePropertyList
->file(); 
1185                 // calculate total size of merged property list 
1186                 _propertyCount 
= PropertyList
<A
>::count(state
, basePropertyList
); 
1187                 deadAtoms
.insert(basePropertyList
); 
1188                 fixupCount 
= basePropertyList
->fixupsEnd() - basePropertyList
->fixupsBegin(); 
1190         for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait 
!= categories
->end(); ++ait
) { 
1191                 const ld::Atom
* categoryPropertyListAtom 
= kind 
== PropertyKind::ClassProperties 
? Category
<A
>::getClassProperties(state
, *ait
) : Category
<A
>::getInstanceProperties(state
, *ait
); 
1192                 if ( categoryPropertyListAtom 
!= NULL 
) { 
1193                         _propertyCount 
+= PropertyList
<A
>::count(state
, categoryPropertyListAtom
); 
1194                         fixupCount 
+= (categoryPropertyListAtom
->fixupsEnd() - categoryPropertyListAtom
->fixupsBegin()); 
1195                         deadAtoms
.insert(categoryPropertyListAtom
); 
1196                         // if base class did not have property list, associate new property list with file the defined category 
1197                         if ( _file 
== NULL 
) 
1198                                 _file 
= categoryPropertyListAtom
->file(); 
1201         //fprintf(stderr, "total merged property count=%u\n", _propertyCount); 
1202         //fprintf(stderr, "total merged fixup count=%u\n", fixupCount); 
1204         // copy fixups and adjust offsets  
1205         _fixups
.reserve(fixupCount
); 
1207         for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it 
!= categories
->end(); ++it
) { 
1208                 const ld::Atom
* categoryPropertyListAtom 
= kind 
== PropertyKind::ClassProperties 
? Category
<A
>::getClassProperties(state
, *it
) : Category
<A
>::getInstanceProperties(state
, *it
); 
1209                 if ( categoryPropertyListAtom 
!= NULL 
) { 
1210                         for (ld::Fixup::iterator fit
=categoryPropertyListAtom
->fixupsBegin(); fit 
!= categoryPropertyListAtom
->fixupsEnd(); ++fit
) { 
1211                                 ld::Fixup fixup 
= *fit
; 
1212                                 fixup
.offsetInAtom 
+= slide
; 
1213                                 _fixups
.push_back(fixup
); 
1214                                 //fprintf(stderr, "offset=0x%08X, binding=%d\n", fixup.offsetInAtom, fixup.binding); 
1215                                 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound ) 
1216                                 //      fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name()); 
1217                                 //else if ( fixup.binding == ld::Fixup::bindingsIndirectlyBound ) 
1218                                 //      fprintf(stderr, "offset=0x%08X, indirect index=%u, name=%s\n", fixup.offsetInAtom, fixup.u.bindingIndex,  
1219                                 //                      (char*)(state.indirectBindingTable[fixup.u.bindingIndex]->rawContentPointer())); 
1221                         slide 
+= 2*sizeof(pint_t
) * PropertyList
<A
>::count(state
, categoryPropertyListAtom
); 
1224         // add method list from base class last 
1225         if ( basePropertyList 
!= NULL 
) { 
1226                 for (ld::Fixup::iterator fit
=basePropertyList
->fixupsBegin(); fit 
!= basePropertyList
->fixupsEnd(); ++fit
) { 
1227                         ld::Fixup fixup 
= *fit
; 
1228                         fixup
.offsetInAtom 
+= slide
; 
1229                         _fixups
.push_back(fixup
); 
1235 template <typename A
> 
1236 void scanCategories(ld::Internal
& state
,  
1237                                         bool& haveCategoriesWithNonNullClassProperties
,  
1238                                         bool& haveCategoriesWithoutClassPropertyStorage
) 
1240         haveCategoriesWithNonNullClassProperties 
= false; 
1241         haveCategoriesWithoutClassPropertyStorage 
= false; 
1243         for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit 
!= state
.sections
.end(); ++sit
) { 
1244                 ld::Internal::FinalSection
* sect 
= *sit
; 
1245                 if ( sect
->type() == ld::Section::typeObjC2CategoryList 
) { 
1246                         for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait 
!= sect
->atoms
.end(); ++ait
) { 
1247                                 const ld::Atom
* categoryListElementAtom 
= *ait
; 
1249                                 const ld::Atom
* categoryAtom 
= ObjCData
<A
>::getPointerInContent(state
, categoryListElementAtom
, 0, &hasAddend
); 
1251                                 if (Category
<A
>::getClassProperties(state
, categoryAtom
)) { 
1252                                         haveCategoriesWithNonNullClassProperties 
= true; 
1253                                         // fprintf(stderr, "category in file %s has non-null class properties\n", categoryAtom->safeFilePath()); 
1256                                 if ( const ld::relocatable::File
* objFile 
= dynamic_cast<const ld::relocatable::File
*>(categoryAtom
->file()) ) { 
1257                                         if ( !objFile
->objcHasCategoryClassPropertiesField() ) { 
1258                                                 haveCategoriesWithoutClassPropertyStorage 
= true; 
1259                                                 // fprintf(stderr, "category in file %s has no storage for class properties\n", categoryAtom->safeFilePath()); 
1268 template <typename A
, bool isObjC2
> 
1269 void doPass(const Options
& opts
, ld::Internal
& state
) 
1271         // Do nothing if the output has no ObjC content. 
1272         if ( !state
.hasObjC 
) { 
1276         if ( opts
.objcCategoryMerging() ) { 
1277                 // optimize classes defined in this linkage unit by merging in categories also in this linkage unit 
1278                 OptimizeCategories
<A
>::doit(opts
, state
); 
1281         // Search for surviving categories that have a non-null class properties field. 
1282         // Search for surviving categories that do not have storage for the class properties field. 
1283         bool haveCategoriesWithNonNullClassProperties
; 
1284         bool haveCategoriesWithoutClassPropertyStorage
; 
1285         scanCategories
<A
>(state
, haveCategoriesWithNonNullClassProperties
, haveCategoriesWithoutClassPropertyStorage
); 
1287         // Complain about mismatched category ABI. 
1288         // These can't be combined into a single linkage unit because there is only one size indicator for all categories in the file. 
1289         // If there is a mismatch then we don't set the HasCategoryClassProperties bit in the output file,  
1290         // which has at runtime causes any class property metadata that was present to be ignored. 
1291         if (haveCategoriesWithNonNullClassProperties  
&&  haveCategoriesWithoutClassPropertyStorage
) { 
1292                 warning("Some object files have incompatible Objective-C category definitions. Some category metadata may be lost. All files containing Objective-C categories should be built using the same compiler."); 
1295         // add image info atom 
1296         // The HasCategoryClassProperties bit is set as often as possible. 
1297         state
.addAtom(*new ObjCImageInfoAtom
<A
>(isObjC2
, !haveCategoriesWithoutClassPropertyStorage
, state
.swiftVersion
)); 
1301 void doPass(const Options
& opts
, ld::Internal
& state
) 
1303         switch ( opts
.architecture() ) { 
1304 #if SUPPORT_ARCH_x86_64 
1305                 case CPU_TYPE_X86_64
: 
1306                         doPass
<x86_64
, true>(opts
, state
); 
1309 #if SUPPORT_ARCH_i386 
1311                         if (opts
.objCABIVersion2POverride()) { 
1312                                 doPass
<x86
, true>(opts
, state
); 
1314                                 doPass
<x86
, false>(opts
, state
); 
1318 #if SUPPORT_ARCH_arm_any 
1320                         doPass
<arm
, true>(opts
, state
); 
1323 #if SUPPORT_ARCH_arm64 
1324                 case CPU_TYPE_ARM64
: 
1325 #if SUPPORT_ARCH_arm64e 
1326                         if (opts
.subArchitecture() == CPU_SUBTYPE_ARM64_E
) { 
1327                                 doPass
<arm64e
, true>(opts
, state
); 
1331                         doPass
<arm64
, true>(opts
, state
); 
1335                         assert(0 && "unknown objc arch"); 
1341 } // namespace passes