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(ld::File::ObjcConstraint objcConstraint
,
69 bool compaction
, bool abi2
, bool hasCategoryClassProperties
, uint8_t swiftVersion
);
71 virtual const ld::File
* file() const { return NULL
; }
72 virtual const char* name() const { return "objc image info"; }
73 virtual uint64_t size() const { return sizeof(objc_image_info
); }
74 virtual uint64_t objectAddress() const { return 0; }
75 virtual void setScope(Scope
) { }
76 virtual void copyRawContent(uint8_t buffer
[]) const {
77 memcpy(buffer
, &_content
, sizeof(objc_image_info
));
81 objc_image_info _content
;
83 static ld::Section _s_sectionABI1
;
84 static ld::Section _s_sectionABI2
;
87 template <typename A
> ld::Section ObjCImageInfoAtom
<A
>::_s_sectionABI1("__OBJC", "__image_info", ld::Section::typeUnclassified
);
88 template <typename A
> ld::Section ObjCImageInfoAtom
<A
>::_s_sectionABI2("__DATA", "__objc_imageinfo", ld::Section::typeUnclassified
);
92 ObjCImageInfoAtom
<A
>::ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint
, bool compaction
,
93 bool abi2
, bool hasCategoryClassProperties
, uint8_t swiftVersion
)
94 : ld::Atom(abi2
? _s_sectionABI2
: _s_sectionABI1
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
95 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
96 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(2))
100 switch ( objcConstraint
) {
101 case ld::File::objcConstraintNone
:
102 case ld::File::objcConstraintRetainRelease
:
104 warning("ignoring -objc_gc_compaction because code not compiled for ObjC garbage collection");
106 case ld::File::objcConstraintRetainReleaseOrGC
:
107 value
|= OBJC_IMAGE_SUPPORTS_GC
;
109 value
|= OBJC_IMAGE_SUPPORTS_COMPACTION
;
111 case ld::File::objcConstraintGC
:
112 value
|= OBJC_IMAGE_SUPPORTS_GC
| OBJC_IMAGE_REQUIRES_GC
;
114 value
|= OBJC_IMAGE_SUPPORTS_COMPACTION
;
116 case ld::File::objcConstraintRetainReleaseForSimulator
:
117 value
|= OBJC_IMAGE_IS_SIMULATED
;
121 if ( hasCategoryClassProperties
) {
122 value
|= OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES
;
125 // provide swift language version in final binary for runtime to inspect
126 value
|= (swiftVersion
<< 8);
128 _content
.version
= 0;
129 A::P::E::set32(_content
.flags
, value
);
135 // This class is for a new Atom which is an ObjC method list created by merging method lists from categories
137 template <typename A
>
138 class MethodListAtom
: public ld::Atom
{
140 MethodListAtom(ld::Internal
& state
, const ld::Atom
* baseMethodList
, bool meta
,
141 const std::vector
<const ld::Atom
*>* categories
,
142 std::set
<const ld::Atom
*>& deadAtoms
);
144 virtual const ld::File
* file() const { return _file
; }
145 virtual const char* name() const { return "objc merged method list"; }
146 virtual uint64_t size() const { return _methodCount
*3*sizeof(pint_t
) + 8; }
147 virtual uint64_t objectAddress() const { return 0; }
148 virtual void setScope(Scope
) { }
149 virtual void copyRawContent(uint8_t buffer
[]) const {
150 bzero(buffer
, size());
151 A::P::E::set32(*((uint32_t*)(&buffer
[0])), 3*sizeof(pint_t
)); // entry size
152 A::P::E::set32(*((uint32_t*)(&buffer
[4])), _methodCount
);
154 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
155 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
158 typedef typename
A::P::uint_t pint_t
;
160 const ld::File
* _file
;
161 unsigned int _methodCount
;
162 std::vector
<ld::Fixup
> _fixups
;
164 static ld::Section _s_section
;
167 template <typename A
>
168 ld::Section MethodListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
172 // This class is for a new Atom which is an ObjC protocol list created by merging protocol lists from categories
174 template <typename A
>
175 class ProtocolListAtom
: public ld::Atom
{
177 ProtocolListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
178 const std::vector
<const ld::Atom
*>* categories
,
179 std::set
<const ld::Atom
*>& deadAtoms
);
181 virtual const ld::File
* file() const { return _file
; }
182 virtual const char* name() const { return "objc merged protocol list"; }
183 virtual uint64_t size() const { return (_protocolCount
+1)*sizeof(pint_t
); }
184 virtual uint64_t objectAddress() const { return 0; }
185 virtual void setScope(Scope
) { }
186 virtual void copyRawContent(uint8_t buffer
[]) const {
187 bzero(buffer
, size());
188 A::P::setP(*((pint_t
*)(buffer
)), _protocolCount
);
190 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
191 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
194 typedef typename
A::P::uint_t pint_t
;
196 const ld::File
* _file
;
197 unsigned int _protocolCount
;
198 std::vector
<ld::Fixup
> _fixups
;
200 static ld::Section _s_section
;
203 template <typename A
>
204 ld::Section ProtocolListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
209 // This class is for a new Atom which is an ObjC property list created by merging property lists from categories
211 template <typename A
>
212 class PropertyListAtom
: public ld::Atom
{
214 enum class PropertyKind
{ ClassProperties
, InstanceProperties
};
216 PropertyListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
217 const std::vector
<const ld::Atom
*>* categories
,
218 std::set
<const ld::Atom
*>& deadAtoms
,
221 virtual const ld::File
* file() const { return _file
; }
222 virtual const char* name() const { return "objc merged property list"; }
223 virtual uint64_t size() const { return _propertyCount
*2*sizeof(pint_t
) + 8; }
224 virtual uint64_t objectAddress() const { return 0; }
225 virtual void setScope(Scope
) { }
226 virtual void copyRawContent(uint8_t buffer
[]) const {
227 bzero(buffer
, size());
228 A::P::E::set32(((uint32_t*)(buffer
))[0], 2*sizeof(pint_t
)); // sizeof(objc_property)
229 A::P::E::set32(((uint32_t*)(buffer
))[1], _propertyCount
);
231 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
232 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
235 typedef typename
A::P::uint_t pint_t
;
237 const ld::File
* _file
;
238 unsigned int _propertyCount
;
239 std::vector
<ld::Fixup
> _fixups
;
241 static ld::Section _s_section
;
244 template <typename A
>
245 ld::Section PropertyListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
252 // This class is used to create an Atom that replaces an atom from a .o file that holds a class_ro_t.
253 // It is needed because there is no way to add Fixups to an existing atom.
255 template <typename A
>
256 class ClassROOverlayAtom
: public ld::Atom
{
258 ClassROOverlayAtom(const ld::Atom
* classROAtom
);
260 // overrides of ld::Atom
261 virtual const ld::File
* file() const { return _atom
->file(); }
262 virtual const char* name() const { return _atom
->name(); }
263 virtual uint64_t size() const { return _atom
->size(); }
264 virtual uint64_t objectAddress() const { return _atom
->objectAddress(); }
265 virtual void copyRawContent(uint8_t buffer
[]) const
266 { _atom
->copyRawContent(buffer
); }
267 virtual const uint8_t* rawContentPointer() const
268 { return _atom
->rawContentPointer(); }
269 virtual unsigned long contentHash(const class ld::IndirectBindingTable
& ibt
) const
270 { return _atom
->contentHash(ibt
); }
271 virtual bool canCoalesceWith(const ld::Atom
& rhs
, const class ld::IndirectBindingTable
& ibt
) const
272 { return _atom
->canCoalesceWith(rhs
,ibt
); }
274 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
275 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
277 void addProtocolListFixup();
278 void addPropertyListFixup();
279 void addMethodListFixup();
282 typedef typename
A::P::uint_t pint_t
;
284 void addFixupAtOffset(uint32_t offset
);
286 const ld::Atom
* _atom
;
287 std::vector
<ld::Fixup
> _fixups
;
290 template <typename A
>
291 ClassROOverlayAtom
<A
>::ClassROOverlayAtom(const ld::Atom
* classROAtom
)
292 : ld::Atom(classROAtom
->section(), ld::Atom::definitionRegular
, ld::Atom::combineNever
,
293 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
294 classROAtom
->symbolTableInclusion(), false, false, false, classROAtom
->alignment()),
297 // ensure all attributes are same as original
298 this->setAttributesFromAtom(*classROAtom
);
300 // copy fixups from orginal atom
301 for (ld::Fixup::iterator fit
=classROAtom
->fixupsBegin(); fit
!= classROAtom
->fixupsEnd(); ++fit
) {
302 ld::Fixup fixup
= *fit
;
303 _fixups
.push_back(fixup
);
309 // Base class for reading and updating existing ObjC atoms from .o files
311 template <typename A
>
314 static const ld::Atom
* getPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
, unsigned int offset
, bool* hasAddend
=NULL
);
315 static void setPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
,
316 unsigned int offset
, const ld::Atom
* newAtom
);
317 typedef typename
A::P::uint_t pint_t
;
320 template <typename A
>
321 const ld::Atom
* ObjCData
<A
>::getPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
, unsigned int offset
, bool* hasAddend
)
323 const ld::Atom
* target
= NULL
;
324 if ( hasAddend
!= NULL
)
326 for (ld::Fixup::iterator fit
=contentAtom
->fixupsBegin(); fit
!= contentAtom
->fixupsEnd(); ++fit
) {
327 if ( (fit
->offsetInAtom
== offset
) && (fit
->kind
!= ld::Fixup::kindNoneFollowOn
) ) {
328 switch ( fit
->binding
) {
329 case ld::Fixup::bindingsIndirectlyBound
:
330 target
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
332 case ld::Fixup::bindingDirectlyBound
:
333 target
= fit
->u
.target
;
335 case ld::Fixup::bindingNone
:
336 if ( fit
->kind
== ld::Fixup::kindAddAddend
) {
337 if ( hasAddend
!= NULL
)
349 template <typename A
>
350 void ObjCData
<A
>::setPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
,
351 unsigned int offset
, const ld::Atom
* newAtom
)
353 for (ld::Fixup::iterator fit
=contentAtom
->fixupsBegin(); fit
!= contentAtom
->fixupsEnd(); ++fit
) {
354 if ( fit
->offsetInAtom
== offset
) {
355 switch ( fit
->binding
) {
356 case ld::Fixup::bindingsIndirectlyBound
:
357 state
.indirectBindingTable
[fit
->u
.bindingIndex
] = newAtom
;
359 case ld::Fixup::bindingDirectlyBound
:
360 fit
->u
.target
= newAtom
;
367 assert(0 && "could not update method list");
373 // Helper class for reading and updating existing ObjC category atoms from .o files
375 template <typename A
>
376 class Category
: public ObjCData
<A
> {
378 static const ld::Atom
* getClass(ld::Internal
& state
, const ld::Atom
* contentAtom
, bool& hasAddend
);
379 static const ld::Atom
* getInstanceMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
);
380 static const ld::Atom
* getClassMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
);
381 static const ld::Atom
* getProtocols(ld::Internal
& state
, const ld::Atom
* contentAtom
);
382 static const ld::Atom
* getInstanceProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
);
383 static const ld::Atom
* getClassProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
);
384 static uint32_t size() { return 6*sizeof(pint_t
); }
386 typedef typename
A::P::uint_t pint_t
;
390 template <typename A
>
391 const ld::Atom
* Category
<A
>::getClass(ld::Internal
& state
, const ld::Atom
* contentAtom
, bool& hasAddend
)
393 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, sizeof(pint_t
), &hasAddend
); // category_t.cls
396 template <typename A
>
397 const ld::Atom
* Category
<A
>::getInstanceMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
)
399 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 2*sizeof(pint_t
)); // category_t.instanceMethods
402 template <typename A
>
403 const ld::Atom
* Category
<A
>::getClassMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
)
405 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 3*sizeof(pint_t
)); // category_t.classMethods
408 template <typename A
>
409 const ld::Atom
* Category
<A
>::getProtocols(ld::Internal
& state
, const ld::Atom
* contentAtom
)
411 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 4*sizeof(pint_t
)); // category_t.protocols
414 template <typename A
>
415 const ld::Atom
* Category
<A
>::getInstanceProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
)
417 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 5*sizeof(pint_t
)); // category_t.instanceProperties
420 template <typename A
>
421 const ld::Atom
* Category
<A
>::getClassProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
)
423 // Only specially-marked files have this field.
424 if (!contentAtom
->file()->objcHasCategoryClassPropertiesField()) return NULL
;
426 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 6*sizeof(pint_t
)); // category_t.classProperties
430 template <typename A
>
431 class MethodList
: public ObjCData
<A
> {
433 static uint32_t count(ld::Internal
& state
, const ld::Atom
* methodListAtom
) {
434 const uint32_t* methodListData
= (uint32_t*)(methodListAtom
->rawContentPointer());
435 return A::P::E::get32(methodListData
[1]); // method_list_t.count
439 template <typename A
>
440 class ProtocolList
: public ObjCData
<A
> {
442 static uint32_t count(ld::Internal
& state
, const ld::Atom
* protocolListAtom
) {
443 pint_t
* protocolListData
= (pint_t
*)(protocolListAtom
->rawContentPointer());
444 return A::P::getP(*protocolListData
); // protocol_list_t.count
447 typedef typename
A::P::uint_t pint_t
;
450 template <typename A
>
451 class PropertyList
: public ObjCData
<A
> {
453 static uint32_t count(ld::Internal
& state
, const ld::Atom
* protocolListAtom
) {
454 uint32_t* protocolListData
= (uint32_t*)(protocolListAtom
->rawContentPointer());
455 return A::P::E::get32(protocolListData
[1]); // property_list_t.count
458 typedef typename
A::P::uint_t pint_t
;
464 // Helper class for reading and updating existing ObjC class atoms from .o files
466 template <typename A
>
467 class Class
: public ObjCData
<A
> {
469 static const ld::Atom
* getMetaClass(ld::Internal
& state
, const ld::Atom
* classAtom
);
470 static const ld::Atom
* getInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
);
471 static const ld::Atom
* getInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
);
472 static const ld::Atom
* getInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
);
473 static const ld::Atom
* getClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
);
474 static const ld::Atom
* getClassPropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
);
475 static const ld::Atom
* setInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
476 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
477 static const ld::Atom
* setInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
478 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
479 static const ld::Atom
* setInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,
480 const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
481 static const ld::Atom
* setClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
482 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
483 static const ld::Atom
* setClassProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
484 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
485 static const ld::Atom
* setClassPropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,
486 const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
487 static uint32_t size() { return sizeof(Content
); }
490 friend class ClassROOverlayAtom
<A
>;
492 typedef typename
A::P::uint_t pint_t
;
494 static const ld::Atom
* getROData(ld::Internal
& state
, const ld::Atom
* classAtom
);
506 uint32_t instanceStart
;
507 // Note there is 4-bytes of alignment padding between instanceSize
508 // and ivarLayout on 64-bit archs, but no padding on 32-bit archs.
509 // This union is a way to model that.
511 uint32_t instanceSize
;
517 pint_t baseProtocols
;
519 pint_t weakIvarLayout
;
520 pint_t baseProperties
;
524 #define GET_FIELD(state, classAtom, field) \
525 ObjCData<A>::getPointerInContent(state, classAtom, offsetof(Content, field))
526 #define SET_FIELD(state, classAtom, field, valueAtom) \
527 ObjCData<A>::setPointerInContent(state, classAtom, offsetof(Content, field), valueAtom)
529 #define GET_RO_FIELD(state, classAtom, field) \
530 ObjCData<A>::getPointerInContent(state, getROData(state, classAtom), offsetof(ROContent, field))
531 #define SET_RO_FIELD(state, classROAtom, field, valueAtom) \
532 ObjCData<A>::setPointerInContent(state, getROData(state, classAtom), offsetof(ROContent, field), valueAtom)
534 template <typename A
>
535 const ld::Atom
* Class
<A
>::getMetaClass(ld::Internal
& state
, const ld::Atom
* classAtom
)
537 const ld::Atom
* metaClassAtom
= GET_FIELD(state
, classAtom
, isa
);
538 assert(metaClassAtom
!= NULL
);
539 return metaClassAtom
;
542 template <typename A
>
543 const ld::Atom
* Class
<A
>::getROData(ld::Internal
& state
, const ld::Atom
* classAtom
)
545 const ld::Atom
* classROAtom
= GET_FIELD(state
, classAtom
, data
);
546 assert(classROAtom
!= NULL
);
550 template <typename A
>
551 const ld::Atom
* Class
<A
>::getInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
)
553 return GET_RO_FIELD(state
, classAtom
, baseMethods
);
556 template <typename A
>
557 const ld::Atom
* Class
<A
>::getInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
)
559 return GET_RO_FIELD(state
, classAtom
, baseProtocols
);
562 template <typename A
>
563 const ld::Atom
* Class
<A
>::getInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
)
565 return GET_RO_FIELD(state
, classAtom
, baseProperties
);
568 template <typename A
>
569 const ld::Atom
* Class
<A
>::getClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
)
571 return Class
<A
>::getInstanceMethodList(state
, getMetaClass(state
, classAtom
));
574 template <typename A
>
575 const ld::Atom
* Class
<A
>::getClassPropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
)
577 return Class
<A
>::getInstancePropertyList(state
, getMetaClass(state
, classAtom
));
580 template <typename A
>
581 const ld::Atom
* Class
<A
>::setInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
582 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
584 // if the base class does not already have a method list, we need to create an overlay
585 if ( getInstanceMethodList(state
, classAtom
) == NULL
) {
586 const ld::Atom
* oldROAtom
= getROData(state
, classAtom
);
587 deadAtoms
.insert(oldROAtom
);
588 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(oldROAtom
);
589 //fprintf(stderr, "replace class RO atom %p with %p for method list in class atom %s\n", classROAtom, overlay, classAtom->name());
590 overlay
->addMethodListFixup();
591 SET_FIELD(state
, classAtom
, data
, overlay
);
592 SET_RO_FIELD(state
, classAtom
, baseMethods
, methodListAtom
);
595 SET_RO_FIELD(state
, classAtom
, baseMethods
, methodListAtom
);
596 return NULL
; // means classRO atom was not replaced
599 template <typename A
>
600 const ld::Atom
* Class
<A
>::setInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
601 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
603 // if the base class does not already have a protocol list, we need to create an overlay
604 if ( getInstanceProtocolList(state
, classAtom
) == NULL
) {
605 const ld::Atom
* oldROAtom
= getROData(state
, classAtom
);
606 deadAtoms
.insert(oldROAtom
);
607 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(oldROAtom
);
608 //fprintf(stderr, "replace class RO atom %p with %p for protocol list in class atom %s\n", classROAtom, overlay, classAtom->name());
609 overlay
->addProtocolListFixup();
610 SET_FIELD(state
, classAtom
, data
, overlay
);
611 SET_RO_FIELD(state
, classAtom
, baseProtocols
, protocolListAtom
);
614 //fprintf(stderr, "set class RO atom %p protocol list in class atom %s\n", classROAtom, classAtom->name());
615 SET_RO_FIELD(state
, classAtom
, baseProtocols
, protocolListAtom
);
616 return NULL
; // means classRO atom was not replaced
619 template <typename A
>
620 const ld::Atom
* Class
<A
>::setClassProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
621 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
623 // meta class also points to same protocol list as class
624 const ld::Atom
* metaClassAtom
= getMetaClass(state
, classAtom
);
625 //fprintf(stderr, "setClassProtocolList(), classAtom=%p %s, metaClass=%p %s\n", classAtom, classAtom->name(), metaClassAtom, metaClassAtom->name());
626 return setInstanceProtocolList(state
, metaClassAtom
, protocolListAtom
, deadAtoms
);
631 template <typename A
>
632 const ld::Atom
* Class
<A
>::setInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,
633 const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
635 // if the base class does not already have a property list, we need to create an overlay
636 if ( getInstancePropertyList(state
, classAtom
) == NULL
) {
637 const ld::Atom
* oldROAtom
= getROData(state
, classAtom
);
638 deadAtoms
.insert(oldROAtom
);
639 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(oldROAtom
);
640 //fprintf(stderr, "replace class RO atom %p with %p for property list in class atom %s\n", classROAtom, overlay, classAtom->name());
641 overlay
->addPropertyListFixup();
642 SET_FIELD(state
, classAtom
, data
, overlay
);
643 SET_RO_FIELD(state
, classAtom
, baseProperties
, propertyListAtom
);
646 SET_RO_FIELD(state
, classAtom
, baseProperties
, propertyListAtom
);
647 return NULL
; // means classRO atom was not replaced
650 template <typename A
>
651 const ld::Atom
* Class
<A
>::setClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
652 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
654 // class methods is just instance methods of metaClass
655 return setInstanceMethodList(state
, getMetaClass(state
, classAtom
), methodListAtom
, deadAtoms
);
658 template <typename A
>
659 const ld::Atom
* Class
<A
>::setClassPropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,
660 const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
662 // class properties is just instance properties of metaClass
663 return setInstancePropertyList(state
, getMetaClass(state
, classAtom
), propertyListAtom
, deadAtoms
);
672 template <typename P
>
673 ld::Fixup::Kind
pointerFixupKind();
676 ld::Fixup::Kind pointerFixupKind
<Pointer32
<BigEndian
>>() {
677 return ld::Fixup::kindStoreTargetAddressBigEndian32
;
680 ld::Fixup::Kind pointerFixupKind
<Pointer64
<BigEndian
>>() {
681 return ld::Fixup::kindStoreTargetAddressBigEndian64
;
684 ld::Fixup::Kind pointerFixupKind
<Pointer32
<LittleEndian
>>() {
685 return ld::Fixup::kindStoreTargetAddressLittleEndian32
;
688 ld::Fixup::Kind pointerFixupKind
<Pointer64
<LittleEndian
>>() {
689 return ld::Fixup::kindStoreTargetAddressLittleEndian64
;
692 template <typename A
>
693 void ClassROOverlayAtom
<A
>::addFixupAtOffset(uint32_t offset
)
695 const ld::Atom
* targetAtom
= this; // temporary
696 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, pointerFixupKind
<typename
A::P
>(), targetAtom
));
700 template <typename A
>
701 void ClassROOverlayAtom
<A
>::addMethodListFixup()
703 addFixupAtOffset(offsetof(typename Class
<A
>::ROContent
, baseMethods
));
706 template <typename A
>
707 void ClassROOverlayAtom
<A
>::addProtocolListFixup()
709 addFixupAtOffset(offsetof(typename Class
<A
>::ROContent
, baseProtocols
));
712 template <typename A
>
713 void ClassROOverlayAtom
<A
>::addPropertyListFixup()
715 addFixupAtOffset(offsetof(typename Class
<A
>::ROContent
, baseProperties
));
722 // Encapsulates merging of ObjC categories
724 template <typename A
>
725 class OptimizeCategories
{
727 static void doit(const Options
& opts
, ld::Internal
& state
);
728 static bool hasInstanceMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
729 static bool hasClassMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
730 static bool hasProtocols(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
731 static bool hasInstanceProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
732 static bool hasClassProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
734 static unsigned int class_ro_baseMethods_offset();
736 typedef typename
A::P::uint_t pint_t
;
741 template <typename A
>
742 bool OptimizeCategories
<A
>::hasInstanceMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
744 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
745 const ld::Atom
* categoryAtom
= *it
;
746 const ld::Atom
* methodList
= Category
<A
>::getInstanceMethods(state
, categoryAtom
);
747 if ( methodList
!= NULL
) {
748 if ( MethodList
<A
>::count(state
, methodList
) > 0 )
756 template <typename A
>
757 bool OptimizeCategories
<A
>::hasClassMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
759 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
760 const ld::Atom
* categoryAtom
= *it
;
761 const ld::Atom
* methodList
= Category
<A
>::getClassMethods(state
, categoryAtom
);
762 if ( methodList
!= NULL
) {
763 if ( MethodList
<A
>::count(state
, methodList
) > 0 )
770 template <typename A
>
771 bool OptimizeCategories
<A
>::hasProtocols(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
773 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
774 const ld::Atom
* categoryAtom
= *it
;
775 const ld::Atom
* protocolListAtom
= Category
<A
>::getProtocols(state
, categoryAtom
);
776 if ( protocolListAtom
!= NULL
) {
777 if ( ProtocolList
<A
>::count(state
, protocolListAtom
) > 0 ) {
786 template <typename A
>
787 bool OptimizeCategories
<A
>::hasInstanceProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
789 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
790 const ld::Atom
* categoryAtom
= *it
;
791 const ld::Atom
* propertyListAtom
= Category
<A
>::getInstanceProperties(state
, categoryAtom
);
792 if ( propertyListAtom
!= NULL
) {
793 if ( PropertyList
<A
>::count(state
, propertyListAtom
) > 0 )
801 template <typename A
>
802 bool OptimizeCategories
<A
>::hasClassProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
804 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
805 const ld::Atom
* categoryAtom
= *it
;
806 const ld::Atom
* propertyListAtom
= Category
<A
>::getClassProperties(state
, categoryAtom
);
807 if ( propertyListAtom
!= NULL
) {
808 if ( PropertyList
<A
>::count(state
, propertyListAtom
) > 0 )
816 static const ld::Atom
* fixClassAliases(const ld::Atom
* classAtom
)
818 if ( (classAtom
->size() != 0) || (classAtom
->definition() == ld::Atom::definitionProxy
) )
821 for (ld::Fixup::iterator fit
=classAtom
->fixupsBegin(); fit
!= classAtom
->fixupsEnd(); ++fit
) {
822 if ( fit
->kind
== ld::Fixup::kindNoneFollowOn
) {
823 assert(fit
->offsetInAtom
== 0);
824 assert(fit
->binding
== ld::Fixup::bindingDirectlyBound
);
825 return fit
->u
.target
;
833 // Helper for std::remove_if
835 class OptimizedAway
{
837 OptimizedAway(const std::set
<const ld::Atom
*>& oa
) : _dead(oa
) {}
838 bool operator()(const ld::Atom
* atom
) const {
839 return ( _dead
.count(atom
) != 0 );
842 const std::set
<const ld::Atom
*>& _dead
;
847 bool operator()(const Atom
* left
, const Atom
* right
)
849 // sort by file ordinal, then object address, then zero size, then symbol name
850 // only file based atoms are supported (file() != NULL)
851 if (left
==right
) return false;
852 const File
*leftf
= left
->file();
853 const File
*rightf
= right
->file();
855 if (leftf
== rightf
) {
856 if (left
->objectAddress() != right
->objectAddress()) {
857 return left
->objectAddress() < right
->objectAddress();
859 // for atoms in the same file with the same address, zero sized
860 // atoms must sort before nonzero sized atoms
861 if ((left
->size() == 0 && right
->size() > 0) || (left
->size() > 0 && right
->size() == 0))
862 return left
->size() < right
->size();
863 return strcmp(left
->name(), right
->name());
866 return (leftf
->ordinal() < rightf
->ordinal());
870 static void sortAtomVector(std::vector
<const Atom
*> &atoms
) {
871 std::sort(atoms
.begin(), atoms
.end(), AtomSorter());
875 template <typename A
>
876 void OptimizeCategories
<A
>::doit(const Options
& opts
, ld::Internal
& state
)
878 // first find all categories referenced by __objc_nlcatlist section
879 std::set
<const ld::Atom
*> nlcatListAtoms
;
880 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
881 ld::Internal::FinalSection
* sect
= *sit
;
882 if ( (strcmp(sect
->sectionName(), "__objc_nlcatlist") == 0) && (strncmp(sect
->segmentName(), "__DATA", 6) == 0) ) {
883 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
884 const ld::Atom
* categoryListElementAtom
= *ait
;
885 for (unsigned int offset
=0; offset
< categoryListElementAtom
->size(); offset
+= sizeof(pint_t
)) {
886 const ld::Atom
* categoryAtom
= ObjCData
<A
>::getPointerInContent(state
, categoryListElementAtom
, offset
);
887 //fprintf(stderr, "offset=%d, cat=%p %s\n", offset, categoryAtom, categoryAtom->name());
888 assert(categoryAtom
!= NULL
);
889 nlcatListAtoms
.insert(categoryAtom
);
895 // build map of all classes in this image that have categories on them
896 typedef std::map
<const ld::Atom
*, std::vector
<const ld::Atom
*>*> CatMap
;
897 CatMap classToCategories
;
898 std::vector
<const ld::Atom
*> classOrder
;
899 std::set
<const ld::Atom
*> deadAtoms
;
900 ld::Internal::FinalSection
* methodListSection
= NULL
;
901 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
902 ld::Internal::FinalSection
* sect
= *sit
;
903 if ( sect
->type() == ld::Section::typeObjC2CategoryList
) {
904 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
905 const ld::Atom
* categoryListElementAtom
= *ait
;
907 const ld::Atom
* categoryAtom
= ObjCData
<A
>::getPointerInContent(state
, categoryListElementAtom
, 0, &hasAddend
);
908 if ( hasAddend
|| (categoryAtom
->symbolTableInclusion() == ld::Atom::symbolTableNotIn
)) {
909 //<rdar://problem/8309530> gcc-4.0 uses 'L' labels on categories which disables this optimization
910 //warning("__objc_catlist element does not point to start of category");
913 assert(categoryAtom
!= NULL
);
914 assert(categoryAtom
->size() >= Category
<A
>::size());
915 // ignore categories also in __objc_nlcatlist
916 if ( nlcatListAtoms
.count(categoryAtom
) != 0 )
918 const ld::Atom
* categoryOnClassAtom
= fixClassAliases(Category
<A
>::getClass(state
, categoryAtom
, hasAddend
));
919 assert(categoryOnClassAtom
!= NULL
);
920 // only look at classes defined in this image
921 if ( categoryOnClassAtom
->definition() != ld::Atom::definitionProxy
) {
922 // <rdar://problem/16107696> for now, back off optimization on new style classes
923 if ( hasAddend
!= 0 )
925 // <rdar://problem/17249777> don't apply categories to swift classes
926 if ( categoryOnClassAtom
->hasFixupsOfKind(ld::Fixup::kindNoneGroupSubordinate
) )
929 CatMap::iterator pos
= classToCategories
.find(categoryOnClassAtom
);
930 if ( pos
== classToCategories
.end() ) {
931 classToCategories
[categoryOnClassAtom
] = new std::vector
<const ld::Atom
*>();
932 classOrder
.push_back(categoryOnClassAtom
);
934 classToCategories
[categoryOnClassAtom
]->push_back(categoryAtom
);
935 // mark category atom and catlist atom as dead
936 deadAtoms
.insert(categoryAtom
);
937 deadAtoms
.insert(categoryListElementAtom
);
941 // record method list section
942 if ( (strcmp(sect
->sectionName(), "__objc_const") == 0) && (strncmp(sect
->segmentName(), "__DATA", 6) == 0) )
943 methodListSection
= sect
;
946 // if found some categories
947 if ( classToCategories
.size() != 0 ) {
948 assert(methodListSection
!= NULL
);
949 sortAtomVector(classOrder
);
950 // alter each class definition to have new method list which includes all category methods
951 for (std::vector
<const ld::Atom
*>::iterator it
= classOrder
.begin(); it
!= classOrder
.end(); it
++) {
952 const ld::Atom
* classAtom
= *it
;
953 const std::vector
<const ld::Atom
*>* categories
= classToCategories
[classAtom
];
954 assert(categories
->size() != 0);
955 // if any category adds instance methods, generate new merged method list, and replace
956 if ( OptimizeCategories
<A
>::hasInstanceMethods(state
, categories
) ) {
957 const ld::Atom
* baseInstanceMethodListAtom
= Class
<A
>::getInstanceMethodList(state
, classAtom
);
958 const ld::Atom
* newInstanceMethodListAtom
= new MethodListAtom
<A
>(state
, baseInstanceMethodListAtom
, false, categories
, deadAtoms
);
959 const ld::Atom
* newClassRO
= Class
<A
>::setInstanceMethodList(state
, classAtom
, newInstanceMethodListAtom
, deadAtoms
);
960 // add new method list to final sections
961 methodListSection
->atoms
.push_back(newInstanceMethodListAtom
);
962 state
.atomToSection
[newInstanceMethodListAtom
] = methodListSection
;
963 if ( newClassRO
!= NULL
) {
964 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
965 methodListSection
->atoms
.push_back(newClassRO
);
966 state
.atomToSection
[newClassRO
] = methodListSection
;
969 // if any category adds class methods, generate new merged method list, and replace
970 if ( OptimizeCategories
<A
>::hasClassMethods(state
, categories
) ) {
971 const ld::Atom
* baseClassMethodListAtom
= Class
<A
>::getClassMethodList(state
, classAtom
);
972 const ld::Atom
* newClassMethodListAtom
= new MethodListAtom
<A
>(state
, baseClassMethodListAtom
, true, categories
, deadAtoms
);
973 const ld::Atom
* newClassRO
= Class
<A
>::setClassMethodList(state
, classAtom
, newClassMethodListAtom
, deadAtoms
);
974 // add new method list to final sections
975 methodListSection
->atoms
.push_back(newClassMethodListAtom
);
976 state
.atomToSection
[newClassMethodListAtom
] = methodListSection
;
977 if ( newClassRO
!= NULL
) {
978 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
979 methodListSection
->atoms
.push_back(newClassRO
);
980 state
.atomToSection
[newClassRO
] = methodListSection
;
983 // if any category adds protocols, generate new merged protocol list, and replace
984 if ( OptimizeCategories
<A
>::hasProtocols(state
, categories
) ) {
985 const ld::Atom
* baseProtocolListAtom
= Class
<A
>::getInstanceProtocolList(state
, classAtom
);
986 const ld::Atom
* newProtocolListAtom
= new ProtocolListAtom
<A
>(state
, baseProtocolListAtom
, categories
, deadAtoms
);
987 const ld::Atom
* newClassRO
= Class
<A
>::setInstanceProtocolList(state
, classAtom
, newProtocolListAtom
, deadAtoms
);
988 const ld::Atom
* newMetaClassRO
= Class
<A
>::setClassProtocolList(state
, classAtom
, newProtocolListAtom
, deadAtoms
);
989 // add new protocol list to final sections
990 methodListSection
->atoms
.push_back(newProtocolListAtom
);
991 state
.atomToSection
[newProtocolListAtom
] = methodListSection
;
992 if ( newClassRO
!= NULL
) {
993 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
994 methodListSection
->atoms
.push_back(newClassRO
);
995 state
.atomToSection
[newClassRO
] = methodListSection
;
997 if ( newMetaClassRO
!= NULL
) {
998 assert(strcmp(newMetaClassRO
->section().sectionName(), "__objc_const") == 0);
999 methodListSection
->atoms
.push_back(newMetaClassRO
);
1000 state
.atomToSection
[newMetaClassRO
] = methodListSection
;
1003 // if any category adds instance properties, generate new merged property list, and replace
1004 if ( OptimizeCategories
<A
>::hasInstanceProperties(state
, categories
) ) {
1005 const ld::Atom
* basePropertyListAtom
= Class
<A
>::getInstancePropertyList(state
, classAtom
);
1006 const ld::Atom
* newPropertyListAtom
= new PropertyListAtom
<A
>(state
, basePropertyListAtom
, categories
, deadAtoms
, PropertyListAtom
<A
>::PropertyKind::InstanceProperties
);
1007 const ld::Atom
* newClassRO
= Class
<A
>::setInstancePropertyList(state
, classAtom
, newPropertyListAtom
, deadAtoms
);
1008 // add new property list to final sections
1009 methodListSection
->atoms
.push_back(newPropertyListAtom
);
1010 state
.atomToSection
[newPropertyListAtom
] = methodListSection
;
1011 if ( newClassRO
!= NULL
) {
1012 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
1013 methodListSection
->atoms
.push_back(newClassRO
);
1014 state
.atomToSection
[newClassRO
] = methodListSection
;
1017 // if any category adds class properties, generate new merged property list, and replace
1018 if ( OptimizeCategories
<A
>::hasClassProperties(state
, categories
) ) {
1019 const ld::Atom
* basePropertyListAtom
= Class
<A
>::getClassPropertyList(state
, classAtom
);
1020 const ld::Atom
* newPropertyListAtom
= new PropertyListAtom
<A
>(state
, basePropertyListAtom
, categories
, deadAtoms
, PropertyListAtom
<A
>::PropertyKind::ClassProperties
);
1021 const ld::Atom
* newClassRO
= Class
<A
>::setClassPropertyList(state
, classAtom
, newPropertyListAtom
, deadAtoms
);
1022 // add new property list to final sections
1023 methodListSection
->atoms
.push_back(newPropertyListAtom
);
1024 state
.atomToSection
[newPropertyListAtom
] = methodListSection
;
1025 if ( newClassRO
!= NULL
) {
1026 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
1027 methodListSection
->atoms
.push_back(newClassRO
);
1028 state
.atomToSection
[newClassRO
] = methodListSection
;
1033 // remove dead atoms
1034 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
1035 ld::Internal::FinalSection
* sect
= *sit
;
1036 sect
->atoms
.erase(std::remove_if(sect
->atoms
.begin(), sect
->atoms
.end(), OptimizedAway(deadAtoms
)), sect
->atoms
.end());
1043 template <typename A
>
1044 MethodListAtom
<A
>::MethodListAtom(ld::Internal
& state
, const ld::Atom
* baseMethodList
, bool meta
,
1045 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
1046 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
1047 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
1048 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _methodCount(0)
1050 unsigned int fixupCount
= 0;
1051 std::set
<const ld::Atom
*> baseMethodListMethodNameAtoms
;
1052 // if base class has method list, then associate new method list with file defining class
1053 if ( baseMethodList
!= NULL
) {
1054 _file
= baseMethodList
->file();
1055 // calculate total size of merge method lists
1056 _methodCount
= MethodList
<A
>::count(state
, baseMethodList
);
1057 deadAtoms
.insert(baseMethodList
);
1058 fixupCount
= baseMethodList
->fixupsEnd() - baseMethodList
->fixupsBegin();
1059 for (ld::Fixup::iterator fit
=baseMethodList
->fixupsBegin(); fit
!= baseMethodList
->fixupsEnd(); ++fit
) {
1060 if ( (fit
->offsetInAtom
- 8) % (3*sizeof(pint_t
)) == 0 ) {
1061 assert(fit
->binding
== ld::Fixup::bindingsIndirectlyBound
&& "malformed method list");
1062 const ld::Atom
* target
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
1063 assert(target
->contentType() == ld::Atom::typeCString
&& "malformed method list");
1064 baseMethodListMethodNameAtoms
.insert(target
);
1068 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
1069 const ld::Atom
* categoryMethodListAtom
;
1071 categoryMethodListAtom
= Category
<A
>::getClassMethods(state
, *ait
);
1073 categoryMethodListAtom
= Category
<A
>::getInstanceMethods(state
, *ait
);
1074 if ( categoryMethodListAtom
!= NULL
) {
1075 _methodCount
+= MethodList
<A
>::count(state
, categoryMethodListAtom
);
1076 fixupCount
+= (categoryMethodListAtom
->fixupsEnd() - categoryMethodListAtom
->fixupsBegin());
1077 deadAtoms
.insert(categoryMethodListAtom
);
1078 // if base class did not have method list, associate new method list with file the defined category
1079 if ( _file
== NULL
)
1080 _file
= categoryMethodListAtom
->file();
1083 //if ( baseMethodList != NULL )
1084 // fprintf(stderr, "total merged method count=%u for baseMethodList=%s\n", _methodCount, baseMethodList->name());
1086 // fprintf(stderr, "total merged method count=%u\n", _methodCount);
1087 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
1089 // copy fixups and adjust offsets (in reverse order to simulator objc runtime)
1090 _fixups
.reserve(fixupCount
);
1092 std::set
<const ld::Atom
*> categoryMethodNameAtoms
;
1093 for (std::vector
<const ld::Atom
*>::const_reverse_iterator rit
=categories
->rbegin(); rit
!= categories
->rend(); ++rit
) {
1094 const ld::Atom
* categoryMethodListAtom
;
1096 categoryMethodListAtom
= Category
<A
>::getClassMethods(state
, *rit
);
1098 categoryMethodListAtom
= Category
<A
>::getInstanceMethods(state
, *rit
);
1099 if ( categoryMethodListAtom
!= NULL
) {
1100 for (ld::Fixup::iterator fit
=categoryMethodListAtom
->fixupsBegin(); fit
!= categoryMethodListAtom
->fixupsEnd(); ++fit
) {
1101 ld::Fixup fixup
= *fit
;
1102 fixup
.offsetInAtom
+= slide
;
1103 _fixups
.push_back(fixup
);
1104 if ( (fixup
.offsetInAtom
- 8) % (3*sizeof(pint_t
)) == 0 ) {
1105 // <rdar://problem/8642343> warning when a method is overridden in a category in the same link unit
1106 assert(fixup
.binding
== ld::Fixup::bindingsIndirectlyBound
&& "malformed category method list");
1107 const ld::Atom
* target
= state
.indirectBindingTable
[fixup
.u
.bindingIndex
];
1108 assert(target
->contentType() == ld::Atom::typeCString
&& "malformed method list");
1109 // this objc pass happens after cstrings are coalesced, so we can just compare the atom addres instead of its content
1110 if ( baseMethodListMethodNameAtoms
.count(target
) != 0 ) {
1111 warning("%s method '%s' in category from %s overrides method from class in %s",
1112 (meta
? "meta" : "instance"), target
->rawContentPointer(),
1113 categoryMethodListAtom
->safeFilePath(), baseMethodList
->safeFilePath() );
1115 if ( categoryMethodNameAtoms
.count(target
) != 0 ) {
1116 warning("%s method '%s' in category from %s conflicts with same method from another category",
1117 (meta
? "meta" : "instance"), target
->rawContentPointer(),
1118 categoryMethodListAtom
->safeFilePath());
1120 categoryMethodNameAtoms
.insert(target
);
1123 slide
+= 3*sizeof(pint_t
) * MethodList
<A
>::count(state
, categoryMethodListAtom
);
1126 // add method list from base class last
1127 if ( baseMethodList
!= NULL
) {
1128 for (ld::Fixup::iterator fit
=baseMethodList
->fixupsBegin(); fit
!= baseMethodList
->fixupsEnd(); ++fit
) {
1129 ld::Fixup fixup
= *fit
;
1130 fixup
.offsetInAtom
+= slide
;
1131 _fixups
.push_back(fixup
);
1137 template <typename A
>
1138 ProtocolListAtom
<A
>::ProtocolListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
1139 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
1140 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
1141 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
1142 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _protocolCount(0)
1144 unsigned int fixupCount
= 0;
1145 if ( baseProtocolList
!= NULL
) {
1146 // if base class has protocol list, then associate new protocol list with file defining class
1147 _file
= baseProtocolList
->file();
1148 // calculate total size of merged protocol list
1149 _protocolCount
= ProtocolList
<A
>::count(state
, baseProtocolList
);
1150 deadAtoms
.insert(baseProtocolList
);
1151 fixupCount
= baseProtocolList
->fixupsEnd() - baseProtocolList
->fixupsBegin();
1153 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
1154 const ld::Atom
* categoryProtocolListAtom
= Category
<A
>::getProtocols(state
, *ait
);
1155 if ( categoryProtocolListAtom
!= NULL
) {
1156 _protocolCount
+= ProtocolList
<A
>::count(state
, categoryProtocolListAtom
);
1157 fixupCount
+= (categoryProtocolListAtom
->fixupsEnd() - categoryProtocolListAtom
->fixupsBegin());
1158 deadAtoms
.insert(categoryProtocolListAtom
);
1159 // if base class did not have protocol list, associate new protocol list with file the defined category
1160 if ( _file
== NULL
)
1161 _file
= categoryProtocolListAtom
->file();
1164 //fprintf(stderr, "total merged protocol count=%u\n", _protocolCount);
1165 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
1167 // copy fixups and adjust offsets
1168 _fixups
.reserve(fixupCount
);
1170 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
1171 const ld::Atom
* categoryProtocolListAtom
= Category
<A
>::getProtocols(state
, *it
);
1172 if ( categoryProtocolListAtom
!= NULL
) {
1173 for (ld::Fixup::iterator fit
=categoryProtocolListAtom
->fixupsBegin(); fit
!= categoryProtocolListAtom
->fixupsEnd(); ++fit
) {
1174 ld::Fixup fixup
= *fit
;
1175 fixup
.offsetInAtom
+= slide
;
1176 _fixups
.push_back(fixup
);
1177 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
1178 // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
1180 slide
+= sizeof(pint_t
) * ProtocolList
<A
>::count(state
, categoryProtocolListAtom
);
1183 // add method list from base class last
1184 if ( baseProtocolList
!= NULL
) {
1185 for (ld::Fixup::iterator fit
=baseProtocolList
->fixupsBegin(); fit
!= baseProtocolList
->fixupsEnd(); ++fit
) {
1186 ld::Fixup fixup
= *fit
;
1187 fixup
.offsetInAtom
+= slide
;
1188 _fixups
.push_back(fixup
);
1194 template <typename A
>
1195 PropertyListAtom
<A
>::PropertyListAtom(ld::Internal
& state
, const ld::Atom
* basePropertyList
,
1196 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
, PropertyKind kind
)
1197 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
1198 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
1199 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _propertyCount(0)
1201 unsigned int fixupCount
= 0;
1202 if ( basePropertyList
!= NULL
) {
1203 // if base class has property list, then associate new property list with file defining class
1204 _file
= basePropertyList
->file();
1205 // calculate total size of merged property list
1206 _propertyCount
= PropertyList
<A
>::count(state
, basePropertyList
);
1207 deadAtoms
.insert(basePropertyList
);
1208 fixupCount
= basePropertyList
->fixupsEnd() - basePropertyList
->fixupsBegin();
1210 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
1211 const ld::Atom
* categoryPropertyListAtom
= kind
== PropertyKind::ClassProperties
? Category
<A
>::getClassProperties(state
, *ait
) : Category
<A
>::getInstanceProperties(state
, *ait
);
1212 if ( categoryPropertyListAtom
!= NULL
) {
1213 _propertyCount
+= PropertyList
<A
>::count(state
, categoryPropertyListAtom
);
1214 fixupCount
+= (categoryPropertyListAtom
->fixupsEnd() - categoryPropertyListAtom
->fixupsBegin());
1215 deadAtoms
.insert(categoryPropertyListAtom
);
1216 // if base class did not have property list, associate new property list with file the defined category
1217 if ( _file
== NULL
)
1218 _file
= categoryPropertyListAtom
->file();
1221 //fprintf(stderr, "total merged property count=%u\n", _propertyCount);
1222 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
1224 // copy fixups and adjust offsets
1225 _fixups
.reserve(fixupCount
);
1227 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
1228 const ld::Atom
* categoryPropertyListAtom
= kind
== PropertyKind::ClassProperties
? Category
<A
>::getClassProperties(state
, *it
) : Category
<A
>::getInstanceProperties(state
, *it
);
1229 if ( categoryPropertyListAtom
!= NULL
) {
1230 for (ld::Fixup::iterator fit
=categoryPropertyListAtom
->fixupsBegin(); fit
!= categoryPropertyListAtom
->fixupsEnd(); ++fit
) {
1231 ld::Fixup fixup
= *fit
;
1232 fixup
.offsetInAtom
+= slide
;
1233 _fixups
.push_back(fixup
);
1234 //fprintf(stderr, "offset=0x%08X, binding=%d\n", fixup.offsetInAtom, fixup.binding);
1235 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
1236 // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
1237 //else if ( fixup.binding == ld::Fixup::bindingsIndirectlyBound )
1238 // fprintf(stderr, "offset=0x%08X, indirect index=%u, name=%s\n", fixup.offsetInAtom, fixup.u.bindingIndex,
1239 // (char*)(state.indirectBindingTable[fixup.u.bindingIndex]->rawContentPointer()));
1241 slide
+= 2*sizeof(pint_t
) * PropertyList
<A
>::count(state
, categoryPropertyListAtom
);
1244 // add method list from base class last
1245 if ( basePropertyList
!= NULL
) {
1246 for (ld::Fixup::iterator fit
=basePropertyList
->fixupsBegin(); fit
!= basePropertyList
->fixupsEnd(); ++fit
) {
1247 ld::Fixup fixup
= *fit
;
1248 fixup
.offsetInAtom
+= slide
;
1249 _fixups
.push_back(fixup
);
1255 template <typename A
>
1256 void scanCategories(ld::Internal
& state
,
1257 bool& haveCategoriesWithNonNullClassProperties
,
1258 bool& haveCategoriesWithoutClassPropertyStorage
)
1260 haveCategoriesWithNonNullClassProperties
= false;
1261 haveCategoriesWithoutClassPropertyStorage
= false;
1263 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
1264 ld::Internal::FinalSection
* sect
= *sit
;
1265 if ( sect
->type() == ld::Section::typeObjC2CategoryList
) {
1266 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
1267 const ld::Atom
* categoryListElementAtom
= *ait
;
1269 const ld::Atom
* categoryAtom
= ObjCData
<A
>::getPointerInContent(state
, categoryListElementAtom
, 0, &hasAddend
);
1271 if (Category
<A
>::getClassProperties(state
, categoryAtom
)) {
1272 haveCategoriesWithNonNullClassProperties
= true;
1273 // fprintf(stderr, "category in file %s has non-null class properties\n", categoryAtom->safeFilePath());
1276 if (!categoryAtom
->file()->objcHasCategoryClassPropertiesField()) {
1277 haveCategoriesWithoutClassPropertyStorage
= true;
1278 // fprintf(stderr, "category in file %s has no storage for class properties\n", categoryAtom->safeFilePath());
1286 template <typename A
, bool isObjC2
>
1287 void doPass(const Options
& opts
, ld::Internal
& state
)
1289 // Do nothing if the output has no ObjC content.
1290 if ( state
.objcObjectConstraint
== ld::File::objcConstraintNone
) {
1294 // verify dylibs are GC compatible with object files
1295 if ( state
.objcObjectConstraint
!= state
.objcDylibConstraint
) {
1296 if ( (state
.objcDylibConstraint
== ld::File::objcConstraintRetainRelease
)
1297 && (state
.objcObjectConstraint
== ld::File::objcConstraintGC
) ) {
1298 throw "Linked dylibs built for retain/release but object files built for GC-only";
1300 else if ( (state
.objcDylibConstraint
== ld::File::objcConstraintGC
)
1301 && (state
.objcObjectConstraint
== ld::File::objcConstraintRetainRelease
) ) {
1302 throw "Linked dylibs built for GC-only but object files built for retain/release";
1306 if ( opts
.objcCategoryMerging() ) {
1307 // optimize classes defined in this linkage unit by merging in categories also in this linkage unit
1308 OptimizeCategories
<A
>::doit(opts
, state
);
1311 // Search for surviving categories that have a non-null class properties field.
1312 // Search for surviving categories that do not have storage for the class properties field.
1313 bool haveCategoriesWithNonNullClassProperties
;
1314 bool haveCategoriesWithoutClassPropertyStorage
;
1315 scanCategories
<A
>(state
, haveCategoriesWithNonNullClassProperties
, haveCategoriesWithoutClassPropertyStorage
);
1317 // Complain about mismatched category ABI.
1318 // These can't be combined into a single linkage unit because there is only one size indicator for all categories in the file.
1319 // If there is a mismatch then we don't set the HasCategoryClassProperties bit in the output file,
1320 // which has at runtime causes any class property metadata that was present to be ignored.
1321 if (haveCategoriesWithNonNullClassProperties
&& haveCategoriesWithoutClassPropertyStorage
) {
1322 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.");
1325 // add image info atom
1326 // The HasCategoryClassProperties bit is set as often as possible.
1327 state
.addAtom(*new ObjCImageInfoAtom
<A
>(state
.objcObjectConstraint
, opts
.objcGcCompaction(), isObjC2
,
1328 !haveCategoriesWithoutClassPropertyStorage
, state
.swiftVersion
));
1332 void doPass(const Options
& opts
, ld::Internal
& state
)
1334 switch ( opts
.architecture() ) {
1335 #if SUPPORT_ARCH_x86_64
1336 case CPU_TYPE_X86_64
:
1337 doPass
<x86_64
, true>(opts
, state
);
1340 #if SUPPORT_ARCH_i386
1342 if (opts
.objCABIVersion2POverride()) {
1343 doPass
<x86
, true>(opts
, state
);
1345 doPass
<x86
, false>(opts
, state
);
1349 #if SUPPORT_ARCH_arm_any
1351 doPass
<arm
, true>(opts
, state
);
1354 #if SUPPORT_ARCH_arm64
1355 case CPU_TYPE_ARM64
:
1356 doPass
<arm64
, true>(opts
, state
);
1360 assert(0 && "unknown objc arch");
1366 } // namespace passes