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)
62 // This class is the 8 byte section containing ObjC flags
65 class ObjCImageInfoAtom
: public ld::Atom
{
67 ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint
,
68 bool compaction
, bool abi2
, 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(ld::File::ObjcConstraint objcConstraint
, bool compaction
,
92 bool abi2
, uint8_t swiftVersion
)
93 : ld::Atom(abi2
? _s_sectionABI2
: _s_sectionABI1
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
94 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
95 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(2))
99 switch ( objcConstraint
) {
100 case ld::File::objcConstraintNone
:
101 case ld::File::objcConstraintRetainRelease
:
103 warning("ignoring -objc_gc_compaction because code not compiled for ObjC garbage collection");
105 case ld::File::objcConstraintRetainReleaseOrGC
:
106 value
|= OBJC_IMAGE_SUPPORTS_GC
;
108 value
|= OBJC_IMAGE_SUPPORTS_COMPACTION
;
110 case ld::File::objcConstraintGC
:
111 value
|= OBJC_IMAGE_SUPPORTS_GC
| OBJC_IMAGE_REQUIRES_GC
;
113 value
|= OBJC_IMAGE_SUPPORTS_COMPACTION
;
115 case ld::File::objcConstraintRetainReleaseForSimulator
:
116 value
|= OBJC_IMAGE_IS_SIMULATED
;
120 // provide swift language version in final binary for runtime to inspect
121 value
|= (swiftVersion
<< 8);
123 _content
.version
= 0;
124 A::P::E::set32(_content
.flags
, value
);
130 // This class is for a new Atom which is an ObjC method list created by merging method lists from categories
132 template <typename A
>
133 class MethodListAtom
: public ld::Atom
{
135 MethodListAtom(ld::Internal
& state
, const ld::Atom
* baseMethodList
, bool meta
,
136 const std::vector
<const ld::Atom
*>* categories
,
137 std::set
<const ld::Atom
*>& deadAtoms
);
139 virtual const ld::File
* file() const { return _file
; }
140 virtual const char* name() const { return "objc merged method list"; }
141 virtual uint64_t size() const { return _methodCount
*3*sizeof(pint_t
) + 8; }
142 virtual uint64_t objectAddress() const { return 0; }
143 virtual void setScope(Scope
) { }
144 virtual void copyRawContent(uint8_t buffer
[]) const {
145 bzero(buffer
, size());
146 A::P::E::set32(*((uint32_t*)(&buffer
[0])), 3*sizeof(pint_t
)); // entry size
147 A::P::E::set32(*((uint32_t*)(&buffer
[4])), _methodCount
);
149 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
150 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
153 typedef typename
A::P::uint_t pint_t
;
155 const ld::File
* _file
;
156 unsigned int _methodCount
;
157 std::vector
<ld::Fixup
> _fixups
;
159 static ld::Section _s_section
;
162 template <typename A
>
163 ld::Section MethodListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
167 // This class is for a new Atom which is an ObjC protocol list created by merging protocol lists from categories
169 template <typename A
>
170 class ProtocolListAtom
: public ld::Atom
{
172 ProtocolListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
173 const std::vector
<const ld::Atom
*>* categories
,
174 std::set
<const ld::Atom
*>& deadAtoms
);
176 virtual const ld::File
* file() const { return _file
; }
177 virtual const char* name() const { return "objc merged protocol list"; }
178 virtual uint64_t size() const { return (_protocolCount
+1)*sizeof(pint_t
); }
179 virtual uint64_t objectAddress() const { return 0; }
180 virtual void setScope(Scope
) { }
181 virtual void copyRawContent(uint8_t buffer
[]) const {
182 bzero(buffer
, size());
183 A::P::setP(*((pint_t
*)(buffer
)), _protocolCount
);
185 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
186 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
189 typedef typename
A::P::uint_t pint_t
;
191 const ld::File
* _file
;
192 unsigned int _protocolCount
;
193 std::vector
<ld::Fixup
> _fixups
;
195 static ld::Section _s_section
;
198 template <typename A
>
199 ld::Section ProtocolListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
204 // This class is for a new Atom which is an ObjC property list created by merging property lists from categories
206 template <typename A
>
207 class PropertyListAtom
: public ld::Atom
{
209 PropertyListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
210 const std::vector
<const ld::Atom
*>* categories
,
211 std::set
<const ld::Atom
*>& deadAtoms
);
213 virtual const ld::File
* file() const { return _file
; }
214 virtual const char* name() const { return "objc merged property list"; }
215 virtual uint64_t size() const { return _propertyCount
*2*sizeof(pint_t
) + 8; }
216 virtual uint64_t objectAddress() const { return 0; }
217 virtual void setScope(Scope
) { }
218 virtual void copyRawContent(uint8_t buffer
[]) const {
219 bzero(buffer
, size());
220 A::P::E::set32(((uint32_t*)(buffer
))[0], 2*sizeof(pint_t
)); // sizeof(objc_property)
221 A::P::E::set32(((uint32_t*)(buffer
))[1], _propertyCount
);
223 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
224 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
227 typedef typename
A::P::uint_t pint_t
;
229 const ld::File
* _file
;
230 unsigned int _propertyCount
;
231 std::vector
<ld::Fixup
> _fixups
;
233 static ld::Section _s_section
;
236 template <typename A
>
237 ld::Section PropertyListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
244 // This class is used to create an Atom that replaces an atom from a .o file that holds a class_ro_t.
245 // It is needed because there is no way to add Fixups to an existing atom.
247 template <typename A
>
248 class ClassROOverlayAtom
: public ld::Atom
{
250 ClassROOverlayAtom(const ld::Atom
* classROAtom
);
252 // overrides of ld::Atom
253 virtual const ld::File
* file() const { return _atom
->file(); }
254 virtual const char* name() const { return _atom
->name(); }
255 virtual uint64_t size() const { return _atom
->size(); }
256 virtual uint64_t objectAddress() const { return _atom
->objectAddress(); }
257 virtual void copyRawContent(uint8_t buffer
[]) const
258 { _atom
->copyRawContent(buffer
); }
259 virtual const uint8_t* rawContentPointer() const
260 { return _atom
->rawContentPointer(); }
261 virtual unsigned long contentHash(const class ld::IndirectBindingTable
& ibt
) const
262 { return _atom
->contentHash(ibt
); }
263 virtual bool canCoalesceWith(const ld::Atom
& rhs
, const class ld::IndirectBindingTable
& ibt
) const
264 { return _atom
->canCoalesceWith(rhs
,ibt
); }
266 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
267 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
269 void addProtocolListFixup();
270 void addPropertyListFixup();
271 void addMethodListFixup();
274 typedef typename
A::P::uint_t pint_t
;
276 const ld::Atom
* _atom
;
277 std::vector
<ld::Fixup
> _fixups
;
280 template <typename A
>
281 ClassROOverlayAtom
<A
>::ClassROOverlayAtom(const ld::Atom
* classROAtom
)
282 : ld::Atom(classROAtom
->section(), ld::Atom::definitionRegular
, ld::Atom::combineNever
,
283 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
284 classROAtom
->symbolTableInclusion(), false, false, false, classROAtom
->alignment()),
287 // ensure all attributes are same as original
288 this->setAttributesFromAtom(*classROAtom
);
290 // copy fixups from orginal atom
291 for (ld::Fixup::iterator fit
=classROAtom
->fixupsBegin(); fit
!= classROAtom
->fixupsEnd(); ++fit
) {
292 ld::Fixup fixup
= *fit
;
293 _fixups
.push_back(fixup
);
299 // Base class for reading and updating existing ObjC atoms from .o files
301 template <typename A
>
304 static const ld::Atom
* getPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
, unsigned int offset
, bool* hasAddend
=NULL
);
305 static void setPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
,
306 unsigned int offset
, const ld::Atom
* newAtom
);
307 typedef typename
A::P::uint_t pint_t
;
310 template <typename A
>
311 const ld::Atom
* ObjCData
<A
>::getPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
, unsigned int offset
, bool* hasAddend
)
313 const ld::Atom
* target
= NULL
;
314 if ( hasAddend
!= NULL
)
316 for (ld::Fixup::iterator fit
=contentAtom
->fixupsBegin(); fit
!= contentAtom
->fixupsEnd(); ++fit
) {
317 if ( fit
->offsetInAtom
== offset
) {
318 switch ( fit
->binding
) {
319 case ld::Fixup::bindingsIndirectlyBound
:
320 target
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
322 case ld::Fixup::bindingDirectlyBound
:
323 target
= fit
->u
.target
;
325 case ld::Fixup::bindingNone
:
326 if ( fit
->kind
== ld::Fixup::kindAddAddend
) {
327 if ( hasAddend
!= NULL
)
339 template <typename A
>
340 void ObjCData
<A
>::setPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
,
341 unsigned int offset
, const ld::Atom
* newAtom
)
343 for (ld::Fixup::iterator fit
=contentAtom
->fixupsBegin(); fit
!= contentAtom
->fixupsEnd(); ++fit
) {
344 if ( fit
->offsetInAtom
== offset
) {
345 switch ( fit
->binding
) {
346 case ld::Fixup::bindingsIndirectlyBound
:
347 state
.indirectBindingTable
[fit
->u
.bindingIndex
] = newAtom
;
349 case ld::Fixup::bindingDirectlyBound
:
350 fit
->u
.target
= newAtom
;
357 assert(0 && "could not update method list");
363 // Helper class for reading and updating existing ObjC category atoms from .o files
365 template <typename A
>
366 class Category
: public ObjCData
<A
> {
368 static const ld::Atom
* getClass(ld::Internal
& state
, const ld::Atom
* contentAtom
, bool& hasAddend
);
369 static const ld::Atom
* getInstanceMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
);
370 static const ld::Atom
* getClassMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
);
371 static const ld::Atom
* getProtocols(ld::Internal
& state
, const ld::Atom
* contentAtom
);
372 static const ld::Atom
* getProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
);
373 static uint32_t size() { return 6*sizeof(pint_t
); }
375 typedef typename
A::P::uint_t pint_t
;
379 template <typename A
>
380 const ld::Atom
* Category
<A
>::getClass(ld::Internal
& state
, const ld::Atom
* contentAtom
, bool& hasAddend
)
382 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, sizeof(pint_t
), &hasAddend
); // category_t.cls
385 template <typename A
>
386 const ld::Atom
* Category
<A
>::getInstanceMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
)
388 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 2*sizeof(pint_t
)); // category_t.instanceMethods
391 template <typename A
>
392 const ld::Atom
* Category
<A
>::getClassMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
)
394 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 3*sizeof(pint_t
)); // category_t.classMethods
397 template <typename A
>
398 const ld::Atom
* Category
<A
>::getProtocols(ld::Internal
& state
, const ld::Atom
* contentAtom
)
400 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 4*sizeof(pint_t
)); // category_t.protocols
403 template <typename A
>
404 const ld::Atom
* Category
<A
>::getProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
)
406 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 5*sizeof(pint_t
)); // category_t.instanceProperties
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
* getInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
);
450 static const ld::Atom
* getInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
);
451 static const ld::Atom
* getInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
);
452 static const ld::Atom
* getClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
);
453 static const ld::Atom
* setInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
454 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
455 static const ld::Atom
* setInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
456 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
457 static const ld::Atom
* setInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,
458 const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
459 static const ld::Atom
* setClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
460 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
461 static const ld::Atom
* setClassProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
462 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
463 static uint32_t size() { return 5*sizeof(pint_t
); }
464 static unsigned int class_ro_header_size();
466 typedef typename
A::P::uint_t pint_t
;
467 static const ld::Atom
* getROData(ld::Internal
& state
, const ld::Atom
* classAtom
);
470 template <> unsigned int Class
<x86_64
>::class_ro_header_size() { return 16; }
471 template <> unsigned int Class
<arm
>::class_ro_header_size() { return 12;}
472 template <> unsigned int Class
<x86
>::class_ro_header_size() { return 12; }
475 template <typename A
>
476 const ld::Atom
* Class
<A
>::getROData(ld::Internal
& state
, const ld::Atom
* classAtom
)
478 return ObjCData
<A
>::getPointerInContent(state
, classAtom
, 4*sizeof(pint_t
)); // class_t.data
482 template <typename A
>
483 const ld::Atom
* Class
<A
>::getInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
)
485 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
486 assert(classROAtom
!= NULL
);
487 return ObjCData
<A
>::getPointerInContent(state
, classROAtom
, class_ro_header_size() + 2*sizeof(pint_t
)); // class_ro_t.baseMethods
490 template <typename A
>
491 const ld::Atom
* Class
<A
>::getInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
)
493 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
494 assert(classROAtom
!= NULL
);
495 return ObjCData
<A
>::getPointerInContent(state
, classROAtom
, class_ro_header_size() + 3*sizeof(pint_t
)); // class_ro_t.baseProtocols
498 template <typename A
>
499 const ld::Atom
* Class
<A
>::getInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
)
501 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
502 assert(classROAtom
!= NULL
);
503 return ObjCData
<A
>::getPointerInContent(state
, classROAtom
, class_ro_header_size() + 6*sizeof(pint_t
)); // class_ro_t.baseProperties
506 template <typename A
>
507 const ld::Atom
* Class
<A
>::getClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
)
509 const ld::Atom
* metaClassAtom
= ObjCData
<A
>::getPointerInContent(state
, classAtom
, 0); // class_t.isa
510 assert(metaClassAtom
!= NULL
);
511 return Class
<A
>::getInstanceMethodList(state
, metaClassAtom
);
514 template <typename A
>
515 const ld::Atom
* Class
<A
>::setInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
516 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
518 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
519 assert(classROAtom
!= NULL
);
520 // if the base class does not already have a method list, we need to create an overlay
521 if ( getInstanceMethodList(state
, classAtom
) == NULL
) {
522 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(classROAtom
);
523 //fprintf(stderr, "replace class RO atom %p with %p for method list in class atom %s\n", classROAtom, overlay, classAtom->name());
524 overlay
->addMethodListFixup();
525 ObjCData
<A
>::setPointerInContent(state
, classAtom
, 4*sizeof(pint_t
), overlay
); // class_t.data
526 deadAtoms
.insert(classROAtom
);
527 ObjCData
<A
>::setPointerInContent(state
, overlay
, class_ro_header_size() + 2*sizeof(pint_t
), methodListAtom
); // class_ro_t.baseMethods
530 ObjCData
<A
>::setPointerInContent(state
, classROAtom
, class_ro_header_size() + 2*sizeof(pint_t
), methodListAtom
); // class_ro_t.baseMethods
531 return NULL
; // means classRO atom was not replaced
534 template <typename A
>
535 const ld::Atom
* Class
<A
>::setInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
536 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
538 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
539 assert(classROAtom
!= NULL
);
540 // if the base class does not already have a protocol list, we need to create an overlay
541 if ( getInstanceProtocolList(state
, classAtom
) == NULL
) {
542 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(classROAtom
);
543 //fprintf(stderr, "replace class RO atom %p with %p for protocol list in class atom %s\n", classROAtom, overlay, classAtom->name());
544 overlay
->addProtocolListFixup();
545 ObjCData
<A
>::setPointerInContent(state
, classAtom
, 4*sizeof(pint_t
), overlay
); // class_t.data
546 deadAtoms
.insert(classROAtom
);
547 ObjCData
<A
>::setPointerInContent(state
, overlay
, class_ro_header_size() + 3*sizeof(pint_t
), protocolListAtom
); // class_ro_t.baseProtocols
550 //fprintf(stderr, "set class RO atom %p protocol list in class atom %s\n", classROAtom, classAtom->name());
551 ObjCData
<A
>::setPointerInContent(state
, classROAtom
, class_ro_header_size() + 3*sizeof(pint_t
), protocolListAtom
); // class_ro_t.baseProtocols
552 return NULL
; // means classRO atom was not replaced
555 template <typename A
>
556 const ld::Atom
* Class
<A
>::setClassProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
557 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
559 // meta class also points to same protocol list as class
560 const ld::Atom
* metaClassAtom
= ObjCData
<A
>::getPointerInContent(state
, classAtom
, 0); // class_t.isa
561 //fprintf(stderr, "setClassProtocolList(), classAtom=%p %s, metaClass=%p %s\n", classAtom, classAtom->name(), metaClassAtom, metaClassAtom->name());
562 assert(metaClassAtom
!= NULL
);
563 return setInstanceProtocolList(state
, metaClassAtom
, protocolListAtom
, deadAtoms
);
568 template <typename A
>
569 const ld::Atom
* Class
<A
>::setInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,
570 const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
572 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
573 assert(classROAtom
!= NULL
);
574 // if the base class does not already have a property list, we need to create an overlay
575 if ( getInstancePropertyList(state
, classAtom
) == NULL
) {
576 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(classROAtom
);
577 //fprintf(stderr, "replace class RO atom %p with %p for property list in class atom %s\n", classROAtom, overlay, classAtom->name());
578 overlay
->addPropertyListFixup();
579 ObjCData
<A
>::setPointerInContent(state
, classAtom
, 4*sizeof(pint_t
), overlay
); // class_t.data
580 deadAtoms
.insert(classROAtom
);
581 ObjCData
<A
>::setPointerInContent(state
, overlay
, class_ro_header_size() + 6*sizeof(pint_t
), propertyListAtom
); // class_ro_t.baseProperties
584 ObjCData
<A
>::setPointerInContent(state
, classROAtom
, class_ro_header_size() + 6*sizeof(pint_t
), propertyListAtom
); // class_ro_t.baseProperties
585 return NULL
; // means classRO atom was not replaced
588 template <typename A
>
589 const ld::Atom
* Class
<A
>::setClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
590 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
592 // class methods is just instance methods of metaClass
593 const ld::Atom
* metaClassAtom
= ObjCData
<A
>::getPointerInContent(state
, classAtom
, 0); // class_t.isa
594 assert(metaClassAtom
!= NULL
);
595 return setInstanceMethodList(state
, metaClassAtom
, methodListAtom
, deadAtoms
);
601 void ClassROOverlayAtom
<x86_64
>::addMethodListFixup()
603 const ld::Atom
* targetAtom
= this; // temporary
604 uint32_t offset
= Class
<x86_64
>::class_ro_header_size() + 2*8; // class_ro_t.baseMethods
605 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian64
, targetAtom
));
609 void ClassROOverlayAtom
<arm
>::addMethodListFixup()
611 const ld::Atom
* targetAtom
= this; // temporary
612 uint32_t offset
= Class
<arm
>::class_ro_header_size() + 2*4; // class_ro_t.baseMethods
613 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
617 void ClassROOverlayAtom
<x86
>::addMethodListFixup()
619 const ld::Atom
* targetAtom
= this; // temporary
620 uint32_t offset
= Class
<x86
>::class_ro_header_size() + 2*4; // class_ro_t.baseMethods
621 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
627 void ClassROOverlayAtom
<x86_64
>::addProtocolListFixup()
629 const ld::Atom
* targetAtom
= this; // temporary
630 uint32_t offset
= Class
<x86_64
>::class_ro_header_size() + 3*8; // class_ro_t.baseProtocols
631 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian64
, targetAtom
));
635 void ClassROOverlayAtom
<arm
>::addProtocolListFixup()
637 const ld::Atom
* targetAtom
= this; // temporary
638 uint32_t offset
= Class
<arm
>::class_ro_header_size() + 3*4; // class_ro_t.baseProtocols
639 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
643 void ClassROOverlayAtom
<x86
>::addProtocolListFixup()
645 const ld::Atom
* targetAtom
= this; // temporary
646 uint32_t offset
= Class
<x86
>::class_ro_header_size() + 3*4; // class_ro_t.baseProtocols
647 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
652 void ClassROOverlayAtom
<x86_64
>::addPropertyListFixup()
654 const ld::Atom
* targetAtom
= this; // temporary
655 uint32_t offset
= Class
<x86_64
>::class_ro_header_size() + 6*8; // class_ro_t.baseProperties
656 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian64
, targetAtom
));
660 void ClassROOverlayAtom
<arm
>::addPropertyListFixup()
662 const ld::Atom
* targetAtom
= this; // temporary
663 uint32_t offset
= Class
<arm
>::class_ro_header_size() + 6*4; // class_ro_t.baseProperties
664 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
668 void ClassROOverlayAtom
<x86
>::addPropertyListFixup()
670 const ld::Atom
* targetAtom
= this; // temporary
671 uint32_t offset
= Class
<x86
>::class_ro_header_size() + 6*4; // class_ro_t.baseProperties
672 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
679 // Encapsulates merging of ObjC categories
681 template <typename A
>
682 class OptimizeCategories
{
684 static void doit(const Options
& opts
, ld::Internal
& state
);
685 static bool hasInstanceMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
686 static bool hasClassMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
687 static bool hasProtocols(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
688 static bool hasProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
691 static unsigned int class_ro_baseMethods_offset();
693 typedef typename
A::P::uint_t pint_t
;
698 template <typename A
>
699 bool OptimizeCategories
<A
>::hasInstanceMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
701 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
702 const ld::Atom
* categoryAtom
= *it
;
703 const ld::Atom
* methodList
= Category
<A
>::getInstanceMethods(state
, categoryAtom
);
704 if ( methodList
!= NULL
) {
705 if ( MethodList
<A
>::count(state
, methodList
) > 0 )
713 template <typename A
>
714 bool OptimizeCategories
<A
>::hasClassMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
716 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
717 const ld::Atom
* categoryAtom
= *it
;
718 const ld::Atom
* methodList
= Category
<A
>::getClassMethods(state
, categoryAtom
);
719 if ( methodList
!= NULL
) {
720 if ( MethodList
<A
>::count(state
, methodList
) > 0 )
727 template <typename A
>
728 bool OptimizeCategories
<A
>::hasProtocols(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
730 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
731 const ld::Atom
* categoryAtom
= *it
;
732 const ld::Atom
* protocolListAtom
= Category
<A
>::getProtocols(state
, categoryAtom
);
733 if ( protocolListAtom
!= NULL
) {
734 if ( ProtocolList
<A
>::count(state
, protocolListAtom
) > 0 ) {
743 template <typename A
>
744 bool OptimizeCategories
<A
>::hasProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
746 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
747 const ld::Atom
* categoryAtom
= *it
;
748 const ld::Atom
* propertyListAtom
= Category
<A
>::getProperties(state
, categoryAtom
);
749 if ( propertyListAtom
!= NULL
) {
750 if ( PropertyList
<A
>::count(state
, propertyListAtom
) > 0 )
760 // Helper for std::remove_if
762 class OptimizedAway
{
764 OptimizedAway(const std::set
<const ld::Atom
*>& oa
) : _dead(oa
) {}
765 bool operator()(const ld::Atom
* atom
) const {
766 return ( _dead
.count(atom
) != 0 );
769 const std::set
<const ld::Atom
*>& _dead
;
774 bool operator()(const Atom
* left
, const Atom
* right
)
776 // sort by file ordinal, then object address, then zero size, then symbol name
777 // only file based atoms are supported (file() != NULL)
778 if (left
==right
) return false;
779 const File
*leftf
= left
->file();
780 const File
*rightf
= right
->file();
782 if (leftf
== rightf
) {
783 if (left
->objectAddress() != right
->objectAddress()) {
784 return left
->objectAddress() < right
->objectAddress();
786 // for atoms in the same file with the same address, zero sized
787 // atoms must sort before nonzero sized atoms
788 if ((left
->size() == 0 && right
->size() > 0) || (left
->size() > 0 && right
->size() == 0))
789 return left
->size() < right
->size();
790 return strcmp(left
->name(), right
->name());
793 return (leftf
->ordinal() < rightf
->ordinal());
797 static void sortAtomVector(std::vector
<const Atom
*> &atoms
) {
798 std::sort(atoms
.begin(), atoms
.end(), AtomSorter());
801 template <typename A
>
802 void OptimizeCategories
<A
>::doit(const Options
& opts
, ld::Internal
& state
)
804 // first find all categories referenced by __objc_nlcatlist section
805 std::set
<const ld::Atom
*> nlcatListAtoms
;
806 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
807 ld::Internal::FinalSection
* sect
= *sit
;
808 if ( (strcmp(sect
->sectionName(), "__objc_nlcatlist") == 0) && (strcmp(sect
->segmentName(), "__DATA") == 0) ) {
809 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
810 const ld::Atom
* categoryListElementAtom
= *ait
;
811 for (unsigned int offset
=0; offset
< categoryListElementAtom
->size(); offset
+= sizeof(pint_t
)) {
812 const ld::Atom
* categoryAtom
= ObjCData
<A
>::getPointerInContent(state
, categoryListElementAtom
, offset
);
813 //fprintf(stderr, "offset=%d, cat=%p %s\n", offset, categoryAtom, categoryAtom->name());
814 assert(categoryAtom
!= NULL
);
815 nlcatListAtoms
.insert(categoryAtom
);
821 // build map of all classes in this image that have categories on them
822 typedef std::map
<const ld::Atom
*, std::vector
<const ld::Atom
*>*> CatMap
;
823 CatMap classToCategories
;
824 std::vector
<const ld::Atom
*> classOrder
;
825 std::set
<const ld::Atom
*> deadAtoms
;
826 ld::Internal::FinalSection
* methodListSection
= NULL
;
827 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
828 ld::Internal::FinalSection
* sect
= *sit
;
829 if ( sect
->type() == ld::Section::typeObjC2CategoryList
) {
830 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
831 const ld::Atom
* categoryListElementAtom
= *ait
;
833 const ld::Atom
* categoryAtom
= ObjCData
<A
>::getPointerInContent(state
, categoryListElementAtom
, 0, &hasAddend
);
834 if ( hasAddend
|| (categoryAtom
->symbolTableInclusion() == ld::Atom::symbolTableNotIn
)) {
835 //<rdar://problem/8309530> gcc-4.0 uses 'L' labels on categories which disables this optimization
836 //warning("__objc_catlist element does not point to start of category");
839 assert(categoryAtom
!= NULL
);
840 assert(categoryAtom
->size() >= Category
<A
>::size());
841 // ignore categories also in __objc_nlcatlist
842 if ( nlcatListAtoms
.count(categoryAtom
) != 0 )
844 const ld::Atom
* categoryOnClassAtom
= Category
<A
>::getClass(state
, categoryAtom
, hasAddend
);
845 assert(categoryOnClassAtom
!= NULL
);
846 // only look at classes defined in this image
847 if ( categoryOnClassAtom
->definition() != ld::Atom::definitionProxy
) {
848 // <rdar://problem/16107696> for now, back off optimization on new style classes
849 if ( hasAddend
!= 0 )
851 // <rdar://problem/17249777> don't apply categories to swift classes
852 if ( categoryOnClassAtom
->hasFixupsOfKind(ld::Fixup::kindNoneGroupSubordinate
) )
855 CatMap::iterator pos
= classToCategories
.find(categoryOnClassAtom
);
856 if ( pos
== classToCategories
.end() ) {
857 classToCategories
[categoryOnClassAtom
] = new std::vector
<const ld::Atom
*>();
858 classOrder
.push_back(categoryOnClassAtom
);
860 classToCategories
[categoryOnClassAtom
]->push_back(categoryAtom
);
861 // mark category atom and catlist atom as dead
862 deadAtoms
.insert(categoryAtom
);
863 deadAtoms
.insert(categoryListElementAtom
);
867 // record method list section
868 if ( (strcmp(sect
->sectionName(), "__objc_const") == 0) && (strcmp(sect
->segmentName(), "__DATA") == 0) )
869 methodListSection
= sect
;
872 // if found some categories
873 if ( classToCategories
.size() != 0 ) {
874 assert(methodListSection
!= NULL
);
875 sortAtomVector(classOrder
);
876 // alter each class definition to have new method list which includes all category methods
877 for (std::vector
<const ld::Atom
*>::iterator it
= classOrder
.begin(); it
!= classOrder
.end(); it
++) {
878 const ld::Atom
* classAtom
= *it
;
879 const std::vector
<const ld::Atom
*>* categories
= classToCategories
[classAtom
];
880 assert(categories
->size() != 0);
881 // if any category adds instance methods, generate new merged method list, and replace
882 if ( OptimizeCategories
<A
>::hasInstanceMethods(state
, categories
) ) {
883 const ld::Atom
* baseInstanceMethodListAtom
= Class
<A
>::getInstanceMethodList(state
, classAtom
);
884 const ld::Atom
* newInstanceMethodListAtom
= new MethodListAtom
<A
>(state
, baseInstanceMethodListAtom
, false, categories
, deadAtoms
);
885 const ld::Atom
* newClassRO
= Class
<A
>::setInstanceMethodList(state
, classAtom
, newInstanceMethodListAtom
, deadAtoms
);
886 // add new method list to final sections
887 methodListSection
->atoms
.push_back(newInstanceMethodListAtom
);
888 if ( newClassRO
!= NULL
) {
889 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
890 methodListSection
->atoms
.push_back(newClassRO
);
893 // if any category adds class methods, generate new merged method list, and replace
894 if ( OptimizeCategories
<A
>::hasClassMethods(state
, categories
) ) {
895 const ld::Atom
* baseClassMethodListAtom
= Class
<A
>::getClassMethodList(state
, classAtom
);
896 const ld::Atom
* newClassMethodListAtom
= new MethodListAtom
<A
>(state
, baseClassMethodListAtom
, true, categories
, deadAtoms
);
897 const ld::Atom
* newClassRO
= Class
<A
>::setClassMethodList(state
, classAtom
, newClassMethodListAtom
, deadAtoms
);
898 // add new method list to final sections
899 methodListSection
->atoms
.push_back(newClassMethodListAtom
);
900 if ( newClassRO
!= NULL
) {
901 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
902 methodListSection
->atoms
.push_back(newClassRO
);
905 // if any category adds protocols, generate new merged protocol list, and replace
906 if ( OptimizeCategories
<A
>::hasProtocols(state
, categories
) ) {
907 const ld::Atom
* baseProtocolListAtom
= Class
<A
>::getInstanceProtocolList(state
, classAtom
);
908 const ld::Atom
* newProtocolListAtom
= new ProtocolListAtom
<A
>(state
, baseProtocolListAtom
, categories
, deadAtoms
);
909 const ld::Atom
* newClassRO
= Class
<A
>::setInstanceProtocolList(state
, classAtom
, newProtocolListAtom
, deadAtoms
);
910 const ld::Atom
* newMetaClassRO
= Class
<A
>::setClassProtocolList(state
, classAtom
, newProtocolListAtom
, deadAtoms
);
911 // add new protocol list to final sections
912 methodListSection
->atoms
.push_back(newProtocolListAtom
);
913 if ( newClassRO
!= NULL
) {
914 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
915 methodListSection
->atoms
.push_back(newClassRO
);
917 if ( newMetaClassRO
!= NULL
) {
918 assert(strcmp(newMetaClassRO
->section().sectionName(), "__objc_const") == 0);
919 methodListSection
->atoms
.push_back(newMetaClassRO
);
922 // if any category adds properties, generate new merged property list, and replace
923 if ( OptimizeCategories
<A
>::hasProperties(state
, categories
) ) {
924 const ld::Atom
* basePropertyListAtom
= Class
<A
>::getInstancePropertyList(state
, classAtom
);
925 const ld::Atom
* newPropertyListAtom
= new PropertyListAtom
<A
>(state
, basePropertyListAtom
, categories
, deadAtoms
);
926 const ld::Atom
* newClassRO
= Class
<A
>::setInstancePropertyList(state
, classAtom
, newPropertyListAtom
, deadAtoms
);
927 // add new property list to final sections
928 methodListSection
->atoms
.push_back(newPropertyListAtom
);
929 if ( newClassRO
!= NULL
) {
930 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
931 methodListSection
->atoms
.push_back(newClassRO
);
938 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
939 ld::Internal::FinalSection
* sect
= *sit
;
940 sect
->atoms
.erase(std::remove_if(sect
->atoms
.begin(), sect
->atoms
.end(), OptimizedAway(deadAtoms
)), sect
->atoms
.end());
946 template <typename A
>
947 MethodListAtom
<A
>::MethodListAtom(ld::Internal
& state
, const ld::Atom
* baseMethodList
, bool meta
,
948 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
949 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
950 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
951 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _methodCount(0)
953 unsigned int fixupCount
= 0;
954 std::set
<const ld::Atom
*> baseMethodListMethodNameAtoms
;
955 // if base class has method list, then associate new method list with file defining class
956 if ( baseMethodList
!= NULL
) {
957 _file
= baseMethodList
->file();
958 // calculate total size of merge method lists
959 _methodCount
= MethodList
<A
>::count(state
, baseMethodList
);
960 deadAtoms
.insert(baseMethodList
);
961 fixupCount
= baseMethodList
->fixupsEnd() - baseMethodList
->fixupsBegin();
962 for (ld::Fixup::iterator fit
=baseMethodList
->fixupsBegin(); fit
!= baseMethodList
->fixupsEnd(); ++fit
) {
963 if ( (fit
->offsetInAtom
- 8) % (3*sizeof(pint_t
)) == 0 ) {
964 assert(fit
->binding
== ld::Fixup::bindingsIndirectlyBound
&& "malformed method list");
965 const ld::Atom
* target
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
966 assert(target
->contentType() == ld::Atom::typeCString
&& "malformed method list");
967 baseMethodListMethodNameAtoms
.insert(target
);
971 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
972 const ld::Atom
* categoryMethodListAtom
;
974 categoryMethodListAtom
= Category
<A
>::getClassMethods(state
, *ait
);
976 categoryMethodListAtom
= Category
<A
>::getInstanceMethods(state
, *ait
);
977 if ( categoryMethodListAtom
!= NULL
) {
978 _methodCount
+= MethodList
<A
>::count(state
, categoryMethodListAtom
);
979 fixupCount
+= (categoryMethodListAtom
->fixupsEnd() - categoryMethodListAtom
->fixupsBegin());
980 deadAtoms
.insert(categoryMethodListAtom
);
981 // if base class did not have method list, associate new method list with file the defined category
983 _file
= categoryMethodListAtom
->file();
986 //if ( baseMethodList != NULL )
987 // fprintf(stderr, "total merged method count=%u for baseMethodList=%s\n", _methodCount, baseMethodList->name());
989 // fprintf(stderr, "total merged method count=%u\n", _methodCount);
990 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
992 // copy fixups and adjust offsets (in reverse order to simulator objc runtime)
993 _fixups
.reserve(fixupCount
);
995 std::set
<const ld::Atom
*> categoryMethodNameAtoms
;
996 for (std::vector
<const ld::Atom
*>::const_reverse_iterator rit
=categories
->rbegin(); rit
!= categories
->rend(); ++rit
) {
997 const ld::Atom
* categoryMethodListAtom
;
999 categoryMethodListAtom
= Category
<A
>::getClassMethods(state
, *rit
);
1001 categoryMethodListAtom
= Category
<A
>::getInstanceMethods(state
, *rit
);
1002 if ( categoryMethodListAtom
!= NULL
) {
1003 for (ld::Fixup::iterator fit
=categoryMethodListAtom
->fixupsBegin(); fit
!= categoryMethodListAtom
->fixupsEnd(); ++fit
) {
1004 ld::Fixup fixup
= *fit
;
1005 fixup
.offsetInAtom
+= slide
;
1006 _fixups
.push_back(fixup
);
1007 if ( (fixup
.offsetInAtom
- 8) % (3*sizeof(pint_t
)) == 0 ) {
1008 // <rdar://problem/8642343> warning when a method is overridden in a category in the same link unit
1009 assert(fixup
.binding
== ld::Fixup::bindingsIndirectlyBound
&& "malformed category method list");
1010 const ld::Atom
* target
= state
.indirectBindingTable
[fixup
.u
.bindingIndex
];
1011 assert(target
->contentType() == ld::Atom::typeCString
&& "malformed method list");
1012 // this objc pass happens after cstrings are coalesced, so we can just compare the atom addres instead of its content
1013 if ( baseMethodListMethodNameAtoms
.count(target
) != 0 ) {
1014 warning("%s method '%s' in category from %s overrides method from class in %s",
1015 (meta
? "meta" : "instance"), target
->rawContentPointer(),
1016 categoryMethodListAtom
->file()->path(), baseMethodList
->file()->path() );
1018 if ( categoryMethodNameAtoms
.count(target
) != 0 ) {
1019 warning("%s method '%s' in category from %s conflicts with same method from another category",
1020 (meta
? "meta" : "instance"), target
->rawContentPointer(),
1021 categoryMethodListAtom
->file()->path());
1023 categoryMethodNameAtoms
.insert(target
);
1026 slide
+= 3*sizeof(pint_t
) * MethodList
<A
>::count(state
, categoryMethodListAtom
);
1029 // add method list from base class last
1030 if ( baseMethodList
!= NULL
) {
1031 for (ld::Fixup::iterator fit
=baseMethodList
->fixupsBegin(); fit
!= baseMethodList
->fixupsEnd(); ++fit
) {
1032 ld::Fixup fixup
= *fit
;
1033 fixup
.offsetInAtom
+= slide
;
1034 _fixups
.push_back(fixup
);
1040 template <typename A
>
1041 ProtocolListAtom
<A
>::ProtocolListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
1042 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
1043 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
1044 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
1045 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _protocolCount(0)
1047 unsigned int fixupCount
= 0;
1048 if ( baseProtocolList
!= NULL
) {
1049 // if base class has protocol list, then associate new protocol list with file defining class
1050 _file
= baseProtocolList
->file();
1051 // calculate total size of merged protocol list
1052 _protocolCount
= ProtocolList
<A
>::count(state
, baseProtocolList
);
1053 deadAtoms
.insert(baseProtocolList
);
1054 fixupCount
= baseProtocolList
->fixupsEnd() - baseProtocolList
->fixupsBegin();
1056 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
1057 const ld::Atom
* categoryProtocolListAtom
= Category
<A
>::getProtocols(state
, *ait
);
1058 if ( categoryProtocolListAtom
!= NULL
) {
1059 _protocolCount
+= ProtocolList
<A
>::count(state
, categoryProtocolListAtom
);
1060 fixupCount
+= (categoryProtocolListAtom
->fixupsEnd() - categoryProtocolListAtom
->fixupsBegin());
1061 deadAtoms
.insert(categoryProtocolListAtom
);
1062 // if base class did not have protocol list, associate new protocol list with file the defined category
1063 if ( _file
== NULL
)
1064 _file
= categoryProtocolListAtom
->file();
1067 //fprintf(stderr, "total merged protocol count=%u\n", _protocolCount);
1068 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
1070 // copy fixups and adjust offsets
1071 _fixups
.reserve(fixupCount
);
1073 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
1074 const ld::Atom
* categoryProtocolListAtom
= Category
<A
>::getProtocols(state
, *it
);
1075 if ( categoryProtocolListAtom
!= NULL
) {
1076 for (ld::Fixup::iterator fit
=categoryProtocolListAtom
->fixupsBegin(); fit
!= categoryProtocolListAtom
->fixupsEnd(); ++fit
) {
1077 ld::Fixup fixup
= *fit
;
1078 fixup
.offsetInAtom
+= slide
;
1079 _fixups
.push_back(fixup
);
1080 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
1081 // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
1083 slide
+= sizeof(pint_t
) * ProtocolList
<A
>::count(state
, categoryProtocolListAtom
);
1086 // add method list from base class last
1087 if ( baseProtocolList
!= NULL
) {
1088 for (ld::Fixup::iterator fit
=baseProtocolList
->fixupsBegin(); fit
!= baseProtocolList
->fixupsEnd(); ++fit
) {
1089 ld::Fixup fixup
= *fit
;
1090 fixup
.offsetInAtom
+= slide
;
1091 _fixups
.push_back(fixup
);
1097 template <typename A
>
1098 PropertyListAtom
<A
>::PropertyListAtom(ld::Internal
& state
, const ld::Atom
* basePropertyList
,
1099 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
1100 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
1101 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
1102 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _propertyCount(0)
1104 unsigned int fixupCount
= 0;
1105 if ( basePropertyList
!= NULL
) {
1106 // if base class has property list, then associate new property list with file defining class
1107 _file
= basePropertyList
->file();
1108 // calculate total size of merged property list
1109 _propertyCount
= PropertyList
<A
>::count(state
, basePropertyList
);
1110 deadAtoms
.insert(basePropertyList
);
1111 fixupCount
= basePropertyList
->fixupsEnd() - basePropertyList
->fixupsBegin();
1113 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
1114 const ld::Atom
* categoryPropertyListAtom
= Category
<A
>::getProperties(state
, *ait
);
1115 if ( categoryPropertyListAtom
!= NULL
) {
1116 _propertyCount
+= PropertyList
<A
>::count(state
, categoryPropertyListAtom
);
1117 fixupCount
+= (categoryPropertyListAtom
->fixupsEnd() - categoryPropertyListAtom
->fixupsBegin());
1118 deadAtoms
.insert(categoryPropertyListAtom
);
1119 // if base class did not have property list, associate new property list with file the defined category
1120 if ( _file
== NULL
)
1121 _file
= categoryPropertyListAtom
->file();
1124 //fprintf(stderr, "total merged property count=%u\n", _propertyCount);
1125 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
1127 // copy fixups and adjust offsets
1128 _fixups
.reserve(fixupCount
);
1130 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
1131 const ld::Atom
* categoryPropertyListAtom
= Category
<A
>::getProperties(state
, *it
);
1132 if ( categoryPropertyListAtom
!= NULL
) {
1133 for (ld::Fixup::iterator fit
=categoryPropertyListAtom
->fixupsBegin(); fit
!= categoryPropertyListAtom
->fixupsEnd(); ++fit
) {
1134 ld::Fixup fixup
= *fit
;
1135 fixup
.offsetInAtom
+= slide
;
1136 _fixups
.push_back(fixup
);
1137 //fprintf(stderr, "offset=0x%08X, binding=%d\n", fixup.offsetInAtom, fixup.binding);
1138 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
1139 // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
1140 //else if ( fixup.binding == ld::Fixup::bindingsIndirectlyBound )
1141 // fprintf(stderr, "offset=0x%08X, indirect index=%u, name=%s\n", fixup.offsetInAtom, fixup.u.bindingIndex,
1142 // (char*)(state.indirectBindingTable[fixup.u.bindingIndex]->rawContentPointer()));
1144 slide
+= 2*sizeof(pint_t
) * PropertyList
<A
>::count(state
, categoryPropertyListAtom
);
1147 // add method list from base class last
1148 if ( basePropertyList
!= NULL
) {
1149 for (ld::Fixup::iterator fit
=basePropertyList
->fixupsBegin(); fit
!= basePropertyList
->fixupsEnd(); ++fit
) {
1150 ld::Fixup fixup
= *fit
;
1151 fixup
.offsetInAtom
+= slide
;
1152 _fixups
.push_back(fixup
);
1160 void doPass(const Options
& opts
, ld::Internal
& state
)
1162 // only make image info section if objc was used
1163 if ( state
.objcObjectConstraint
!= ld::File::objcConstraintNone
) {
1165 // verify dylibs are GC compatible with object files
1166 if ( state
.objcObjectConstraint
!= state
.objcDylibConstraint
) {
1167 if ( (state
.objcDylibConstraint
== ld::File::objcConstraintRetainRelease
)
1168 && (state
.objcObjectConstraint
== ld::File::objcConstraintGC
) ) {
1169 throw "Linked dylibs built for retain/release but object files built for GC-only";
1171 else if ( (state
.objcDylibConstraint
== ld::File::objcConstraintGC
)
1172 && (state
.objcObjectConstraint
== ld::File::objcConstraintRetainRelease
) ) {
1173 throw "Linked dylibs built for GC-only but object files built for retain/release";
1177 const bool compaction
= opts
.objcGcCompaction();
1179 // add image info atom
1180 switch ( opts
.architecture() ) {
1181 #if SUPPORT_ARCH_x86_64
1182 case CPU_TYPE_X86_64
:
1183 state
.addAtom(*new ObjCImageInfoAtom
<x86_64
>(state
.objcObjectConstraint
, compaction
,
1184 true, state
.swiftVersion
));
1187 #if SUPPORT_ARCH_i386
1189 state
.addAtom(*new ObjCImageInfoAtom
<x86
>(state
.objcObjectConstraint
, compaction
,
1190 opts
.objCABIVersion2POverride() ? true : false, state
.swiftVersion
));
1193 #if SUPPORT_ARCH_arm_any
1195 state
.addAtom(*new ObjCImageInfoAtom
<arm
>(state
.objcObjectConstraint
, compaction
,
1196 true, state
.swiftVersion
));
1199 #if SUPPORT_ARCH_arm64
1200 case CPU_TYPE_ARM64
:
1201 state
.addAtom(*new ObjCImageInfoAtom
<arm64
>(state
.objcObjectConstraint
, compaction
,
1202 true, state
.swiftVersion
));
1206 assert(0 && "unknown objc arch");
1210 if ( opts
.objcCategoryMerging() ) {
1211 // optimize classes defined in this linkage unit by merging in categories also in this linkage unit
1212 switch ( opts
.architecture() ) {
1213 #if SUPPORT_ARCH_x86_64
1214 case CPU_TYPE_X86_64
:
1215 OptimizeCategories
<x86_64
>::doit(opts
, state
);
1218 #if SUPPORT_ARCH_i386
1220 if ( opts
.objCABIVersion2POverride() )
1221 OptimizeCategories
<x86
>::doit(opts
, state
);
1224 #if SUPPORT_ARCH_arm_any
1226 OptimizeCategories
<arm
>::doit(opts
, state
);
1229 #if SUPPORT_ARCH_arm64
1230 case CPU_TYPE_ARM64
:
1231 // disabled until tested
1235 assert(0 && "unknown objc arch");
1242 } // namespace passes