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