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
);
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
,
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 _content
.version
= 0;
121 A::P::E::set32(_content
.flags
, value
);
127 // This class is for a new Atom which is an ObjC method list created by merging method lists from categories
129 template <typename A
>
130 class MethodListAtom
: public ld::Atom
{
132 MethodListAtom(ld::Internal
& state
, const ld::Atom
* baseMethodList
, bool meta
,
133 const std::vector
<const ld::Atom
*>* categories
,
134 std::set
<const ld::Atom
*>& deadAtoms
);
136 virtual const ld::File
* file() const { return _file
; }
137 virtual const char* name() const { return "objc merged method list"; }
138 virtual uint64_t size() const { return _methodCount
*3*sizeof(pint_t
) + 8; }
139 virtual uint64_t objectAddress() const { return 0; }
140 virtual void setScope(Scope
) { }
141 virtual void copyRawContent(uint8_t buffer
[]) const {
142 bzero(buffer
, size());
143 A::P::E::set32(*((uint32_t*)(&buffer
[0])), 3*sizeof(pint_t
)); // entry size
144 A::P::E::set32(*((uint32_t*)(&buffer
[4])), _methodCount
);
146 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
147 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
150 typedef typename
A::P::uint_t pint_t
;
152 const ld::File
* _file
;
153 unsigned int _methodCount
;
154 std::vector
<ld::Fixup
> _fixups
;
156 static ld::Section _s_section
;
159 template <typename A
>
160 ld::Section MethodListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
164 // This class is for a new Atom which is an ObjC protocol list created by merging protocol lists from categories
166 template <typename A
>
167 class ProtocolListAtom
: public ld::Atom
{
169 ProtocolListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
170 const std::vector
<const ld::Atom
*>* categories
,
171 std::set
<const ld::Atom
*>& deadAtoms
);
173 virtual const ld::File
* file() const { return _file
; }
174 virtual const char* name() const { return "objc merged protocol list"; }
175 virtual uint64_t size() const { return (_protocolCount
+1)*sizeof(pint_t
); }
176 virtual uint64_t objectAddress() const { return 0; }
177 virtual void setScope(Scope
) { }
178 virtual void copyRawContent(uint8_t buffer
[]) const {
179 bzero(buffer
, size());
180 A::P::setP(*((pint_t
*)(buffer
)), _protocolCount
);
182 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
183 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
186 typedef typename
A::P::uint_t pint_t
;
188 const ld::File
* _file
;
189 unsigned int _protocolCount
;
190 std::vector
<ld::Fixup
> _fixups
;
192 static ld::Section _s_section
;
195 template <typename A
>
196 ld::Section ProtocolListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
201 // This class is for a new Atom which is an ObjC property list created by merging property lists from categories
203 template <typename A
>
204 class PropertyListAtom
: public ld::Atom
{
206 PropertyListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
207 const std::vector
<const ld::Atom
*>* categories
,
208 std::set
<const ld::Atom
*>& deadAtoms
);
210 virtual const ld::File
* file() const { return _file
; }
211 virtual const char* name() const { return "objc merged property list"; }
212 virtual uint64_t size() const { return _propertyCount
*2*sizeof(pint_t
) + 8; }
213 virtual uint64_t objectAddress() const { return 0; }
214 virtual void setScope(Scope
) { }
215 virtual void copyRawContent(uint8_t buffer
[]) const {
216 bzero(buffer
, size());
217 A::P::E::set32(((uint32_t*)(buffer
))[0], 2*sizeof(pint_t
)); // sizeof(objc_property)
218 A::P::E::set32(((uint32_t*)(buffer
))[1], _propertyCount
);
220 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
221 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
224 typedef typename
A::P::uint_t pint_t
;
226 const ld::File
* _file
;
227 unsigned int _propertyCount
;
228 std::vector
<ld::Fixup
> _fixups
;
230 static ld::Section _s_section
;
233 template <typename A
>
234 ld::Section PropertyListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
241 // This class is used to create an Atom that replaces an atom from a .o file that holds a class_ro_t.
242 // It is needed because there is no way to add Fixups to an existing atom.
244 template <typename A
>
245 class ClassROOverlayAtom
: public ld::Atom
{
247 ClassROOverlayAtom(const ld::Atom
* classROAtom
);
249 // overrides of ld::Atom
250 virtual const ld::File
* file() const { return _atom
->file(); }
251 virtual const char* name() const { return _atom
->name(); }
252 virtual uint64_t size() const { return _atom
->size(); }
253 virtual uint64_t objectAddress() const { return _atom
->objectAddress(); }
254 virtual void copyRawContent(uint8_t buffer
[]) const
255 { _atom
->copyRawContent(buffer
); }
256 virtual const uint8_t* rawContentPointer() const
257 { return _atom
->rawContentPointer(); }
258 virtual unsigned long contentHash(const class ld::IndirectBindingTable
& ibt
) const
259 { return _atom
->contentHash(ibt
); }
260 virtual bool canCoalesceWith(const ld::Atom
& rhs
, const class ld::IndirectBindingTable
& ibt
) const
261 { return _atom
->canCoalesceWith(rhs
,ibt
); }
263 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
264 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
266 void addProtocolListFixup();
267 void addPropertyListFixup();
268 void addMethodListFixup();
271 typedef typename
A::P::uint_t pint_t
;
273 const ld::Atom
* _atom
;
274 std::vector
<ld::Fixup
> _fixups
;
277 template <typename A
>
278 ClassROOverlayAtom
<A
>::ClassROOverlayAtom(const ld::Atom
* classROAtom
)
279 : ld::Atom(classROAtom
->section(), ld::Atom::definitionRegular
, ld::Atom::combineNever
,
280 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
281 classROAtom
->symbolTableInclusion(), false, false, false, classROAtom
->alignment()),
284 // ensure all attributes are same as original
285 this->setAttributesFromAtom(*classROAtom
);
287 // copy fixups from orginal atom
288 for (ld::Fixup::iterator fit
=classROAtom
->fixupsBegin(); fit
!= classROAtom
->fixupsEnd(); ++fit
) {
289 ld::Fixup fixup
= *fit
;
290 _fixups
.push_back(fixup
);
296 // Base class for reading and updating existing ObjC atoms from .o files
298 template <typename A
>
301 static const ld::Atom
* getPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
, unsigned int offset
, bool* hasAddend
=NULL
);
302 static void setPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
,
303 unsigned int offset
, const ld::Atom
* newAtom
);
304 typedef typename
A::P::uint_t pint_t
;
307 template <typename A
>
308 const ld::Atom
* ObjCData
<A
>::getPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
, unsigned int offset
, bool* hasAddend
)
310 const ld::Atom
* target
= NULL
;
311 if ( hasAddend
!= NULL
)
313 for (ld::Fixup::iterator fit
=contentAtom
->fixupsBegin(); fit
!= contentAtom
->fixupsEnd(); ++fit
) {
314 if ( fit
->offsetInAtom
== offset
) {
315 switch ( fit
->binding
) {
316 case ld::Fixup::bindingsIndirectlyBound
:
317 target
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
319 case ld::Fixup::bindingDirectlyBound
:
320 target
= fit
->u
.target
;
322 case ld::Fixup::bindingNone
:
323 if ( fit
->kind
== ld::Fixup::kindAddAddend
) {
324 if ( hasAddend
!= NULL
)
336 template <typename A
>
337 void ObjCData
<A
>::setPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
,
338 unsigned int offset
, const ld::Atom
* newAtom
)
340 for (ld::Fixup::iterator fit
=contentAtom
->fixupsBegin(); fit
!= contentAtom
->fixupsEnd(); ++fit
) {
341 if ( fit
->offsetInAtom
== offset
) {
342 switch ( fit
->binding
) {
343 case ld::Fixup::bindingsIndirectlyBound
:
344 state
.indirectBindingTable
[fit
->u
.bindingIndex
] = newAtom
;
346 case ld::Fixup::bindingDirectlyBound
:
347 fit
->u
.target
= newAtom
;
354 assert(0 && "could not update method list");
360 // Helper class for reading and updating existing ObjC category atoms from .o files
362 template <typename A
>
363 class Category
: public ObjCData
<A
> {
365 static const ld::Atom
* getClass(ld::Internal
& state
, const ld::Atom
* contentAtom
);
366 static const ld::Atom
* getInstanceMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
);
367 static const ld::Atom
* getClassMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
);
368 static const ld::Atom
* getProtocols(ld::Internal
& state
, const ld::Atom
* contentAtom
);
369 static const ld::Atom
* getProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
);
370 static uint32_t size() { return 6*sizeof(pint_t
); }
372 typedef typename
A::P::uint_t pint_t
;
376 template <typename A
>
377 const ld::Atom
* Category
<A
>::getClass(ld::Internal
& state
, const ld::Atom
* contentAtom
)
379 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, sizeof(pint_t
)); // category_t.cls
382 template <typename A
>
383 const ld::Atom
* Category
<A
>::getInstanceMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
)
385 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 2*sizeof(pint_t
)); // category_t.instanceMethods
388 template <typename A
>
389 const ld::Atom
* Category
<A
>::getClassMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
)
391 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 3*sizeof(pint_t
)); // category_t.classMethods
394 template <typename A
>
395 const ld::Atom
* Category
<A
>::getProtocols(ld::Internal
& state
, const ld::Atom
* contentAtom
)
397 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 4*sizeof(pint_t
)); // category_t.protocols
400 template <typename A
>
401 const ld::Atom
* Category
<A
>::getProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
)
403 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 5*sizeof(pint_t
)); // category_t.instanceProperties
407 template <typename A
>
408 class MethodList
: public ObjCData
<A
> {
410 static uint32_t count(ld::Internal
& state
, const ld::Atom
* methodListAtom
) {
411 const uint32_t* methodListData
= (uint32_t*)(methodListAtom
->rawContentPointer());
412 return A::P::E::get32(methodListData
[1]); // method_list_t.count
416 template <typename A
>
417 class ProtocolList
: public ObjCData
<A
> {
419 static uint32_t count(ld::Internal
& state
, const ld::Atom
* protocolListAtom
) {
420 pint_t
* protocolListData
= (pint_t
*)(protocolListAtom
->rawContentPointer());
421 return A::P::getP(*protocolListData
); // protocol_list_t.count
424 typedef typename
A::P::uint_t pint_t
;
427 template <typename A
>
428 class PropertyList
: public ObjCData
<A
> {
430 static uint32_t count(ld::Internal
& state
, const ld::Atom
* protocolListAtom
) {
431 uint32_t* protocolListData
= (uint32_t*)(protocolListAtom
->rawContentPointer());
432 return A::P::E::get32(protocolListData
[1]); // property_list_t.count
435 typedef typename
A::P::uint_t pint_t
;
441 // Helper class for reading and updating existing ObjC class atoms from .o files
443 template <typename A
>
444 class Class
: public ObjCData
<A
> {
446 static const ld::Atom
* getInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
);
447 static const ld::Atom
* getInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
);
448 static const ld::Atom
* getInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
);
449 static const ld::Atom
* getClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
);
450 static const ld::Atom
* setInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
451 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
452 static const ld::Atom
* setInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
453 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
454 static const ld::Atom
* setInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,
455 const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
456 static const ld::Atom
* setClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
457 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
458 static const ld::Atom
* setClassProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
459 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
460 static uint32_t size() { return 5*sizeof(pint_t
); }
461 static unsigned int class_ro_header_size();
463 typedef typename
A::P::uint_t pint_t
;
464 static const ld::Atom
* getROData(ld::Internal
& state
, const ld::Atom
* classAtom
);
467 template <> unsigned int Class
<x86_64
>::class_ro_header_size() { return 16; }
468 template <> unsigned int Class
<arm
>::class_ro_header_size() { return 12;}
469 template <> unsigned int Class
<x86
>::class_ro_header_size() { return 12; }
472 template <typename A
>
473 const ld::Atom
* Class
<A
>::getROData(ld::Internal
& state
, const ld::Atom
* classAtom
)
475 return ObjCData
<A
>::getPointerInContent(state
, classAtom
, 4*sizeof(pint_t
)); // class_t.data
479 template <typename A
>
480 const ld::Atom
* Class
<A
>::getInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
)
482 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
483 assert(classROAtom
!= NULL
);
484 return ObjCData
<A
>::getPointerInContent(state
, classROAtom
, class_ro_header_size() + 2*sizeof(pint_t
)); // class_ro_t.baseMethods
487 template <typename A
>
488 const ld::Atom
* Class
<A
>::getInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
)
490 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
491 assert(classROAtom
!= NULL
);
492 return ObjCData
<A
>::getPointerInContent(state
, classROAtom
, class_ro_header_size() + 3*sizeof(pint_t
)); // class_ro_t.baseProtocols
495 template <typename A
>
496 const ld::Atom
* Class
<A
>::getInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
)
498 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
499 assert(classROAtom
!= NULL
);
500 return ObjCData
<A
>::getPointerInContent(state
, classROAtom
, class_ro_header_size() + 6*sizeof(pint_t
)); // class_ro_t.baseProperties
503 template <typename A
>
504 const ld::Atom
* Class
<A
>::getClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
)
506 const ld::Atom
* metaClassAtom
= ObjCData
<A
>::getPointerInContent(state
, classAtom
, 0); // class_t.isa
507 assert(metaClassAtom
!= NULL
);
508 return Class
<A
>::getInstanceMethodList(state
, metaClassAtom
);
511 template <typename A
>
512 const ld::Atom
* Class
<A
>::setInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
513 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
515 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
516 assert(classROAtom
!= NULL
);
517 // if the base class does not already have a method list, we need to create an overlay
518 if ( getInstanceMethodList(state
, classAtom
) == NULL
) {
519 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(classROAtom
);
520 //fprintf(stderr, "replace class RO atom %p with %p for method list in class atom %s\n", classROAtom, overlay, classAtom->name());
521 overlay
->addMethodListFixup();
522 ObjCData
<A
>::setPointerInContent(state
, classAtom
, 4*sizeof(pint_t
), overlay
); // class_t.data
523 deadAtoms
.insert(classROAtom
);
524 ObjCData
<A
>::setPointerInContent(state
, overlay
, class_ro_header_size() + 2*sizeof(pint_t
), methodListAtom
); // class_ro_t.baseMethods
527 ObjCData
<A
>::setPointerInContent(state
, classROAtom
, class_ro_header_size() + 2*sizeof(pint_t
), methodListAtom
); // class_ro_t.baseMethods
528 return NULL
; // means classRO atom was not replaced
531 template <typename A
>
532 const ld::Atom
* Class
<A
>::setInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
533 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
535 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
536 assert(classROAtom
!= NULL
);
537 // if the base class does not already have a protocol list, we need to create an overlay
538 if ( getInstanceProtocolList(state
, classAtom
) == NULL
) {
539 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(classROAtom
);
540 //fprintf(stderr, "replace class RO atom %p with %p for protocol list in class atom %s\n", classROAtom, overlay, classAtom->name());
541 overlay
->addProtocolListFixup();
542 ObjCData
<A
>::setPointerInContent(state
, classAtom
, 4*sizeof(pint_t
), overlay
); // class_t.data
543 deadAtoms
.insert(classROAtom
);
544 ObjCData
<A
>::setPointerInContent(state
, overlay
, class_ro_header_size() + 3*sizeof(pint_t
), protocolListAtom
); // class_ro_t.baseProtocols
547 //fprintf(stderr, "set class RO atom %p protocol list in class atom %s\n", classROAtom, classAtom->name());
548 ObjCData
<A
>::setPointerInContent(state
, classROAtom
, class_ro_header_size() + 3*sizeof(pint_t
), protocolListAtom
); // class_ro_t.baseProtocols
549 return NULL
; // means classRO atom was not replaced
552 template <typename A
>
553 const ld::Atom
* Class
<A
>::setClassProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
554 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
556 // meta class also points to same protocol list as class
557 const ld::Atom
* metaClassAtom
= ObjCData
<A
>::getPointerInContent(state
, classAtom
, 0); // class_t.isa
558 //fprintf(stderr, "setClassProtocolList(), classAtom=%p %s, metaClass=%p %s\n", classAtom, classAtom->name(), metaClassAtom, metaClassAtom->name());
559 assert(metaClassAtom
!= NULL
);
560 return setInstanceProtocolList(state
, metaClassAtom
, protocolListAtom
, deadAtoms
);
565 template <typename A
>
566 const ld::Atom
* Class
<A
>::setInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,
567 const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
569 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
570 assert(classROAtom
!= NULL
);
571 // if the base class does not already have a property list, we need to create an overlay
572 if ( getInstancePropertyList(state
, classAtom
) == NULL
) {
573 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(classROAtom
);
574 //fprintf(stderr, "replace class RO atom %p with %p for property list in class atom %s\n", classROAtom, overlay, classAtom->name());
575 overlay
->addPropertyListFixup();
576 ObjCData
<A
>::setPointerInContent(state
, classAtom
, 4*sizeof(pint_t
), overlay
); // class_t.data
577 deadAtoms
.insert(classROAtom
);
578 ObjCData
<A
>::setPointerInContent(state
, overlay
, class_ro_header_size() + 6*sizeof(pint_t
), propertyListAtom
); // class_ro_t.baseProperties
581 ObjCData
<A
>::setPointerInContent(state
, classROAtom
, class_ro_header_size() + 6*sizeof(pint_t
), propertyListAtom
); // class_ro_t.baseProperties
582 return NULL
; // means classRO atom was not replaced
585 template <typename A
>
586 const ld::Atom
* Class
<A
>::setClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
587 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
589 // class methods is just instance methods of metaClass
590 const ld::Atom
* metaClassAtom
= ObjCData
<A
>::getPointerInContent(state
, classAtom
, 0); // class_t.isa
591 assert(metaClassAtom
!= NULL
);
592 return setInstanceMethodList(state
, metaClassAtom
, methodListAtom
, deadAtoms
);
598 void ClassROOverlayAtom
<x86_64
>::addMethodListFixup()
600 const ld::Atom
* targetAtom
= this; // temporary
601 uint32_t offset
= Class
<x86_64
>::class_ro_header_size() + 2*8; // class_ro_t.baseMethods
602 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian64
, targetAtom
));
606 void ClassROOverlayAtom
<arm
>::addMethodListFixup()
608 const ld::Atom
* targetAtom
= this; // temporary
609 uint32_t offset
= Class
<arm
>::class_ro_header_size() + 2*4; // class_ro_t.baseMethods
610 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
614 void ClassROOverlayAtom
<x86
>::addMethodListFixup()
616 const ld::Atom
* targetAtom
= this; // temporary
617 uint32_t offset
= Class
<x86
>::class_ro_header_size() + 2*4; // class_ro_t.baseMethods
618 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
624 void ClassROOverlayAtom
<x86_64
>::addProtocolListFixup()
626 const ld::Atom
* targetAtom
= this; // temporary
627 uint32_t offset
= Class
<x86_64
>::class_ro_header_size() + 3*8; // class_ro_t.baseProtocols
628 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian64
, targetAtom
));
632 void ClassROOverlayAtom
<arm
>::addProtocolListFixup()
634 const ld::Atom
* targetAtom
= this; // temporary
635 uint32_t offset
= Class
<arm
>::class_ro_header_size() + 3*4; // class_ro_t.baseProtocols
636 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
640 void ClassROOverlayAtom
<x86
>::addProtocolListFixup()
642 const ld::Atom
* targetAtom
= this; // temporary
643 uint32_t offset
= Class
<x86
>::class_ro_header_size() + 3*4; // class_ro_t.baseProtocols
644 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
649 void ClassROOverlayAtom
<x86_64
>::addPropertyListFixup()
651 const ld::Atom
* targetAtom
= this; // temporary
652 uint32_t offset
= Class
<x86_64
>::class_ro_header_size() + 6*8; // class_ro_t.baseProperties
653 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian64
, targetAtom
));
657 void ClassROOverlayAtom
<arm
>::addPropertyListFixup()
659 const ld::Atom
* targetAtom
= this; // temporary
660 uint32_t offset
= Class
<arm
>::class_ro_header_size() + 6*4; // class_ro_t.baseProperties
661 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
665 void ClassROOverlayAtom
<x86
>::addPropertyListFixup()
667 const ld::Atom
* targetAtom
= this; // temporary
668 uint32_t offset
= Class
<x86
>::class_ro_header_size() + 6*4; // class_ro_t.baseProperties
669 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
676 // Encapsulates merging of ObjC categories
678 template <typename A
>
679 class OptimizeCategories
{
681 static void doit(const Options
& opts
, ld::Internal
& state
);
682 static bool hasInstanceMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
683 static bool hasClassMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
684 static bool hasProtocols(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
685 static bool hasProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
688 static unsigned int class_ro_baseMethods_offset();
690 typedef typename
A::P::uint_t pint_t
;
695 template <typename A
>
696 bool OptimizeCategories
<A
>::hasInstanceMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
698 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
699 const ld::Atom
* categoryAtom
= *it
;
700 const ld::Atom
* methodList
= Category
<A
>::getInstanceMethods(state
, categoryAtom
);
701 if ( methodList
!= NULL
) {
702 if ( MethodList
<A
>::count(state
, methodList
) > 0 )
710 template <typename A
>
711 bool OptimizeCategories
<A
>::hasClassMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
713 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
714 const ld::Atom
* categoryAtom
= *it
;
715 const ld::Atom
* methodList
= Category
<A
>::getClassMethods(state
, categoryAtom
);
716 if ( methodList
!= NULL
) {
717 if ( MethodList
<A
>::count(state
, methodList
) > 0 )
724 template <typename A
>
725 bool OptimizeCategories
<A
>::hasProtocols(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
727 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
728 const ld::Atom
* categoryAtom
= *it
;
729 const ld::Atom
* protocolListAtom
= Category
<A
>::getProtocols(state
, categoryAtom
);
730 if ( protocolListAtom
!= NULL
) {
731 if ( ProtocolList
<A
>::count(state
, protocolListAtom
) > 0 ) {
740 template <typename A
>
741 bool OptimizeCategories
<A
>::hasProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
743 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
744 const ld::Atom
* categoryAtom
= *it
;
745 const ld::Atom
* propertyListAtom
= Category
<A
>::getProperties(state
, categoryAtom
);
746 if ( propertyListAtom
!= NULL
) {
747 if ( PropertyList
<A
>::count(state
, propertyListAtom
) > 0 )
757 // Helper for std::remove_if
759 class OptimizedAway
{
761 OptimizedAway(const std::set
<const ld::Atom
*>& oa
) : _dead(oa
) {}
762 bool operator()(const ld::Atom
* atom
) const {
763 return ( _dead
.count(atom
) != 0 );
766 const std::set
<const ld::Atom
*>& _dead
;
771 bool operator()(const Atom
* left
, const Atom
* right
)
773 // sort by file ordinal, then object address, then zero size, then symbol name
774 // only file based atoms are supported (file() != NULL)
775 if (left
==right
) return false;
776 const File
*leftf
= left
->file();
777 const File
*rightf
= right
->file();
779 if (leftf
== rightf
) {
780 if (left
->objectAddress() != right
->objectAddress()) {
781 return left
->objectAddress() < right
->objectAddress();
783 // for atoms in the same file with the same address, zero sized
784 // atoms must sort before nonzero sized atoms
785 if ((left
->size() == 0 && right
->size() > 0) || (left
->size() > 0 && right
->size() == 0))
786 return left
->size() < right
->size();
787 return strcmp(left
->name(), right
->name());
790 return (leftf
->ordinal() < rightf
->ordinal());
794 static void sortAtomVector(std::vector
<const Atom
*> &atoms
) {
795 std::sort(atoms
.begin(), atoms
.end(), AtomSorter());
798 template <typename A
>
799 void OptimizeCategories
<A
>::doit(const Options
& opts
, ld::Internal
& state
)
801 // first find all categories referenced by __objc_nlcatlist section
802 std::set
<const ld::Atom
*> nlcatListAtoms
;
803 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
804 ld::Internal::FinalSection
* sect
= *sit
;
805 if ( (strcmp(sect
->sectionName(), "__objc_nlcatlist") == 0) && (strcmp(sect
->segmentName(), "__DATA") == 0) ) {
806 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
807 const ld::Atom
* categoryListElementAtom
= *ait
;
808 for (unsigned int offset
=0; offset
< categoryListElementAtom
->size(); offset
+= sizeof(pint_t
)) {
809 const ld::Atom
* categoryAtom
= ObjCData
<A
>::getPointerInContent(state
, categoryListElementAtom
, offset
);
810 //fprintf(stderr, "offset=%d, cat=%p %s\n", offset, categoryAtom, categoryAtom->name());
811 assert(categoryAtom
!= NULL
);
812 nlcatListAtoms
.insert(categoryAtom
);
818 // build map of all classes in this image that have categories on them
819 typedef std::map
<const ld::Atom
*, std::vector
<const ld::Atom
*>*> CatMap
;
820 CatMap classToCategories
;
821 std::vector
<const ld::Atom
*> classOrder
;
822 std::set
<const ld::Atom
*> deadAtoms
;
823 ld::Internal::FinalSection
* methodListSection
= NULL
;
824 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
825 ld::Internal::FinalSection
* sect
= *sit
;
826 if ( sect
->type() == ld::Section::typeObjC2CategoryList
) {
827 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
828 const ld::Atom
* categoryListElementAtom
= *ait
;
830 const ld::Atom
* categoryAtom
= ObjCData
<A
>::getPointerInContent(state
, categoryListElementAtom
, 0, &hasAddend
);
831 if ( hasAddend
|| (categoryAtom
->symbolTableInclusion() == ld::Atom::symbolTableNotIn
)) {
832 //<rdar://problem/8309530> gcc-4.0 uses 'L' labels on categories which disables this optimization
833 //warning("__objc_catlist element does not point to start of category");
836 assert(categoryAtom
!= NULL
);
837 assert(categoryAtom
->size() >= Category
<A
>::size());
838 // ignore categories also in __objc_nlcatlist
839 if ( nlcatListAtoms
.count(categoryAtom
) != 0 )
841 const ld::Atom
* categoryOnClassAtom
= Category
<A
>::getClass(state
, categoryAtom
);
842 assert(categoryOnClassAtom
!= NULL
);
843 if ( categoryOnClassAtom
->definition() != ld::Atom::definitionProxy
) {
844 // only look at classes defined in this image
845 CatMap::iterator pos
= classToCategories
.find(categoryOnClassAtom
);
846 if ( pos
== classToCategories
.end() ) {
847 classToCategories
[categoryOnClassAtom
] = new std::vector
<const ld::Atom
*>();
848 classOrder
.push_back(categoryOnClassAtom
);
850 classToCategories
[categoryOnClassAtom
]->push_back(categoryAtom
);
851 // mark category atom and catlist atom as dead
852 deadAtoms
.insert(categoryAtom
);
853 deadAtoms
.insert(categoryListElementAtom
);
857 // record method list section
858 if ( (strcmp(sect
->sectionName(), "__objc_const") == 0) && (strcmp(sect
->segmentName(), "__DATA") == 0) )
859 methodListSection
= sect
;
862 // if found some categories
863 if ( classToCategories
.size() != 0 ) {
864 assert(methodListSection
!= NULL
);
865 sortAtomVector(classOrder
);
866 // alter each class definition to have new method list which includes all category methods
867 for (std::vector
<const ld::Atom
*>::iterator it
= classOrder
.begin(); it
!= classOrder
.end(); it
++) {
868 const ld::Atom
* classAtom
= *it
;
869 const std::vector
<const ld::Atom
*>* categories
= classToCategories
[classAtom
];
870 assert(categories
->size() != 0);
871 // if any category adds instance methods, generate new merged method list, and replace
872 if ( OptimizeCategories
<A
>::hasInstanceMethods(state
, categories
) ) {
873 const ld::Atom
* baseInstanceMethodListAtom
= Class
<A
>::getInstanceMethodList(state
, classAtom
);
874 const ld::Atom
* newInstanceMethodListAtom
= new MethodListAtom
<A
>(state
, baseInstanceMethodListAtom
, false, categories
, deadAtoms
);
875 const ld::Atom
* newClassRO
= Class
<A
>::setInstanceMethodList(state
, classAtom
, newInstanceMethodListAtom
, deadAtoms
);
876 // add new method list to final sections
877 methodListSection
->atoms
.push_back(newInstanceMethodListAtom
);
878 if ( newClassRO
!= NULL
) {
879 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
880 methodListSection
->atoms
.push_back(newClassRO
);
883 // if any category adds class methods, generate new merged method list, and replace
884 if ( OptimizeCategories
<A
>::hasClassMethods(state
, categories
) ) {
885 const ld::Atom
* baseClassMethodListAtom
= Class
<A
>::getClassMethodList(state
, classAtom
);
886 const ld::Atom
* newClassMethodListAtom
= new MethodListAtom
<A
>(state
, baseClassMethodListAtom
, true, categories
, deadAtoms
);
887 const ld::Atom
* newClassRO
= Class
<A
>::setClassMethodList(state
, classAtom
, newClassMethodListAtom
, deadAtoms
);
888 // add new method list to final sections
889 methodListSection
->atoms
.push_back(newClassMethodListAtom
);
890 if ( newClassRO
!= NULL
) {
891 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
892 methodListSection
->atoms
.push_back(newClassRO
);
895 // if any category adds protocols, generate new merged protocol list, and replace
896 if ( OptimizeCategories
<A
>::hasProtocols(state
, categories
) ) {
897 const ld::Atom
* baseProtocolListAtom
= Class
<A
>::getInstanceProtocolList(state
, classAtom
);
898 const ld::Atom
* newProtocolListAtom
= new ProtocolListAtom
<A
>(state
, baseProtocolListAtom
, categories
, deadAtoms
);
899 const ld::Atom
* newClassRO
= Class
<A
>::setInstanceProtocolList(state
, classAtom
, newProtocolListAtom
, deadAtoms
);
900 const ld::Atom
* newMetaClassRO
= Class
<A
>::setClassProtocolList(state
, classAtom
, newProtocolListAtom
, deadAtoms
);
901 // add new protocol list to final sections
902 methodListSection
->atoms
.push_back(newProtocolListAtom
);
903 if ( newClassRO
!= NULL
) {
904 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
905 methodListSection
->atoms
.push_back(newClassRO
);
907 if ( newMetaClassRO
!= NULL
) {
908 assert(strcmp(newMetaClassRO
->section().sectionName(), "__objc_const") == 0);
909 methodListSection
->atoms
.push_back(newMetaClassRO
);
912 // if any category adds properties, generate new merged property list, and replace
913 if ( OptimizeCategories
<A
>::hasProperties(state
, categories
) ) {
914 const ld::Atom
* basePropertyListAtom
= Class
<A
>::getInstancePropertyList(state
, classAtom
);
915 const ld::Atom
* newPropertyListAtom
= new PropertyListAtom
<A
>(state
, basePropertyListAtom
, categories
, deadAtoms
);
916 const ld::Atom
* newClassRO
= Class
<A
>::setInstancePropertyList(state
, classAtom
, newPropertyListAtom
, deadAtoms
);
917 // add new property list to final sections
918 methodListSection
->atoms
.push_back(newPropertyListAtom
);
919 if ( newClassRO
!= NULL
) {
920 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
921 methodListSection
->atoms
.push_back(newClassRO
);
928 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
929 ld::Internal::FinalSection
* sect
= *sit
;
930 sect
->atoms
.erase(std::remove_if(sect
->atoms
.begin(), sect
->atoms
.end(), OptimizedAway(deadAtoms
)), sect
->atoms
.end());
936 template <typename A
>
937 MethodListAtom
<A
>::MethodListAtom(ld::Internal
& state
, const ld::Atom
* baseMethodList
, bool meta
,
938 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
939 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
940 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
941 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _methodCount(0)
943 unsigned int fixupCount
= 0;
944 std::set
<const ld::Atom
*> baseMethodListMethodNameAtoms
;
945 // if base class has method list, then associate new method list with file defining class
946 if ( baseMethodList
!= NULL
) {
947 _file
= baseMethodList
->file();
948 // calculate total size of merge method lists
949 _methodCount
= MethodList
<A
>::count(state
, baseMethodList
);
950 deadAtoms
.insert(baseMethodList
);
951 fixupCount
= baseMethodList
->fixupsEnd() - baseMethodList
->fixupsBegin();
952 for (ld::Fixup::iterator fit
=baseMethodList
->fixupsBegin(); fit
!= baseMethodList
->fixupsEnd(); ++fit
) {
953 if ( (fit
->offsetInAtom
- 8) % (3*sizeof(pint_t
)) == 0 ) {
954 assert(fit
->binding
== ld::Fixup::bindingsIndirectlyBound
&& "malformed method list");
955 const ld::Atom
* target
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
956 assert(target
->contentType() == ld::Atom::typeCString
&& "malformed method list");
957 baseMethodListMethodNameAtoms
.insert(target
);
961 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
962 const ld::Atom
* categoryMethodListAtom
;
964 categoryMethodListAtom
= Category
<A
>::getClassMethods(state
, *ait
);
966 categoryMethodListAtom
= Category
<A
>::getInstanceMethods(state
, *ait
);
967 if ( categoryMethodListAtom
!= NULL
) {
968 _methodCount
+= MethodList
<A
>::count(state
, categoryMethodListAtom
);
969 fixupCount
+= (categoryMethodListAtom
->fixupsEnd() - categoryMethodListAtom
->fixupsBegin());
970 deadAtoms
.insert(categoryMethodListAtom
);
971 // if base class did not have method list, associate new method list with file the defined category
973 _file
= categoryMethodListAtom
->file();
976 //if ( baseMethodList != NULL )
977 // fprintf(stderr, "total merged method count=%u for baseMethodList=%s\n", _methodCount, baseMethodList->name());
979 // fprintf(stderr, "total merged method count=%u\n", _methodCount);
980 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
982 // copy fixups and adjust offsets (in reverse order to simulator objc runtime)
983 _fixups
.reserve(fixupCount
);
985 std::set
<const ld::Atom
*> categoryMethodNameAtoms
;
986 for (std::vector
<const ld::Atom
*>::const_reverse_iterator rit
=categories
->rbegin(); rit
!= categories
->rend(); ++rit
) {
987 const ld::Atom
* categoryMethodListAtom
;
989 categoryMethodListAtom
= Category
<A
>::getClassMethods(state
, *rit
);
991 categoryMethodListAtom
= Category
<A
>::getInstanceMethods(state
, *rit
);
992 if ( categoryMethodListAtom
!= NULL
) {
993 for (ld::Fixup::iterator fit
=categoryMethodListAtom
->fixupsBegin(); fit
!= categoryMethodListAtom
->fixupsEnd(); ++fit
) {
994 ld::Fixup fixup
= *fit
;
995 fixup
.offsetInAtom
+= slide
;
996 _fixups
.push_back(fixup
);
997 if ( (fixup
.offsetInAtom
- 8) % (3*sizeof(pint_t
)) == 0 ) {
998 // <rdar://problem/8642343> warning when a method is overridden in a category in the same link unit
999 assert(fixup
.binding
== ld::Fixup::bindingsIndirectlyBound
&& "malformed category method list");
1000 const ld::Atom
* target
= state
.indirectBindingTable
[fixup
.u
.bindingIndex
];
1001 assert(target
->contentType() == ld::Atom::typeCString
&& "malformed method list");
1002 // this objc pass happens after cstrings are coalesced, so we can just compare the atom addres instead of its content
1003 if ( baseMethodListMethodNameAtoms
.count(target
) != 0 ) {
1004 warning("%s method '%s' in category from %s overrides method from class in %s",
1005 (meta
? "meta" : "instance"), target
->rawContentPointer(),
1006 categoryMethodListAtom
->file()->path(), baseMethodList
->file()->path() );
1008 if ( categoryMethodNameAtoms
.count(target
) != 0 ) {
1009 warning("%s method '%s' in category from %s conflicts with same method from another category",
1010 (meta
? "meta" : "instance"), target
->rawContentPointer(),
1011 categoryMethodListAtom
->file()->path());
1013 categoryMethodNameAtoms
.insert(target
);
1016 slide
+= 3*sizeof(pint_t
) * MethodList
<A
>::count(state
, categoryMethodListAtom
);
1019 // add method list from base class last
1020 if ( baseMethodList
!= NULL
) {
1021 for (ld::Fixup::iterator fit
=baseMethodList
->fixupsBegin(); fit
!= baseMethodList
->fixupsEnd(); ++fit
) {
1022 ld::Fixup fixup
= *fit
;
1023 fixup
.offsetInAtom
+= slide
;
1024 _fixups
.push_back(fixup
);
1030 template <typename A
>
1031 ProtocolListAtom
<A
>::ProtocolListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
1032 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
1033 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
1034 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
1035 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _protocolCount(0)
1037 unsigned int fixupCount
= 0;
1038 if ( baseProtocolList
!= NULL
) {
1039 // if base class has protocol list, then associate new protocol list with file defining class
1040 _file
= baseProtocolList
->file();
1041 // calculate total size of merged protocol list
1042 _protocolCount
= ProtocolList
<A
>::count(state
, baseProtocolList
);
1043 deadAtoms
.insert(baseProtocolList
);
1044 fixupCount
= baseProtocolList
->fixupsEnd() - baseProtocolList
->fixupsBegin();
1046 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
1047 const ld::Atom
* categoryProtocolListAtom
= Category
<A
>::getProtocols(state
, *ait
);
1048 if ( categoryProtocolListAtom
!= NULL
) {
1049 _protocolCount
+= ProtocolList
<A
>::count(state
, categoryProtocolListAtom
);
1050 fixupCount
+= (categoryProtocolListAtom
->fixupsEnd() - categoryProtocolListAtom
->fixupsBegin());
1051 deadAtoms
.insert(categoryProtocolListAtom
);
1052 // if base class did not have protocol list, associate new protocol list with file the defined category
1053 if ( _file
== NULL
)
1054 _file
= categoryProtocolListAtom
->file();
1057 //fprintf(stderr, "total merged protocol count=%u\n", _protocolCount);
1058 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
1060 // copy fixups and adjust offsets
1061 _fixups
.reserve(fixupCount
);
1063 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
1064 const ld::Atom
* categoryProtocolListAtom
= Category
<A
>::getProtocols(state
, *it
);
1065 if ( categoryProtocolListAtom
!= NULL
) {
1066 for (ld::Fixup::iterator fit
=categoryProtocolListAtom
->fixupsBegin(); fit
!= categoryProtocolListAtom
->fixupsEnd(); ++fit
) {
1067 ld::Fixup fixup
= *fit
;
1068 fixup
.offsetInAtom
+= slide
;
1069 _fixups
.push_back(fixup
);
1070 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
1071 // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
1073 slide
+= sizeof(pint_t
) * ProtocolList
<A
>::count(state
, categoryProtocolListAtom
);
1076 // add method list from base class last
1077 if ( baseProtocolList
!= NULL
) {
1078 for (ld::Fixup::iterator fit
=baseProtocolList
->fixupsBegin(); fit
!= baseProtocolList
->fixupsEnd(); ++fit
) {
1079 ld::Fixup fixup
= *fit
;
1080 fixup
.offsetInAtom
+= slide
;
1081 _fixups
.push_back(fixup
);
1087 template <typename A
>
1088 PropertyListAtom
<A
>::PropertyListAtom(ld::Internal
& state
, const ld::Atom
* basePropertyList
,
1089 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
1090 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
1091 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
1092 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _propertyCount(0)
1094 unsigned int fixupCount
= 0;
1095 if ( basePropertyList
!= NULL
) {
1096 // if base class has property list, then associate new property list with file defining class
1097 _file
= basePropertyList
->file();
1098 // calculate total size of merged property list
1099 _propertyCount
= PropertyList
<A
>::count(state
, basePropertyList
);
1100 deadAtoms
.insert(basePropertyList
);
1101 fixupCount
= basePropertyList
->fixupsEnd() - basePropertyList
->fixupsBegin();
1103 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
1104 const ld::Atom
* categoryPropertyListAtom
= Category
<A
>::getProperties(state
, *ait
);
1105 if ( categoryPropertyListAtom
!= NULL
) {
1106 _propertyCount
+= PropertyList
<A
>::count(state
, categoryPropertyListAtom
);
1107 fixupCount
+= (categoryPropertyListAtom
->fixupsEnd() - categoryPropertyListAtom
->fixupsBegin());
1108 deadAtoms
.insert(categoryPropertyListAtom
);
1109 // if base class did not have property list, associate new property list with file the defined category
1110 if ( _file
== NULL
)
1111 _file
= categoryPropertyListAtom
->file();
1114 //fprintf(stderr, "total merged property count=%u\n", _propertyCount);
1115 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
1117 // copy fixups and adjust offsets
1118 _fixups
.reserve(fixupCount
);
1120 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
1121 const ld::Atom
* categoryPropertyListAtom
= Category
<A
>::getProperties(state
, *it
);
1122 if ( categoryPropertyListAtom
!= NULL
) {
1123 for (ld::Fixup::iterator fit
=categoryPropertyListAtom
->fixupsBegin(); fit
!= categoryPropertyListAtom
->fixupsEnd(); ++fit
) {
1124 ld::Fixup fixup
= *fit
;
1125 fixup
.offsetInAtom
+= slide
;
1126 _fixups
.push_back(fixup
);
1127 //fprintf(stderr, "offset=0x%08X, binding=%d\n", fixup.offsetInAtom, fixup.binding);
1128 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
1129 // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
1130 //else if ( fixup.binding == ld::Fixup::bindingsIndirectlyBound )
1131 // fprintf(stderr, "offset=0x%08X, indirect index=%u, name=%s\n", fixup.offsetInAtom, fixup.u.bindingIndex,
1132 // (char*)(state.indirectBindingTable[fixup.u.bindingIndex]->rawContentPointer()));
1134 slide
+= 2*sizeof(pint_t
) * PropertyList
<A
>::count(state
, categoryPropertyListAtom
);
1137 // add method list from base class last
1138 if ( basePropertyList
!= NULL
) {
1139 for (ld::Fixup::iterator fit
=basePropertyList
->fixupsBegin(); fit
!= basePropertyList
->fixupsEnd(); ++fit
) {
1140 ld::Fixup fixup
= *fit
;
1141 fixup
.offsetInAtom
+= slide
;
1142 _fixups
.push_back(fixup
);
1150 void doPass(const Options
& opts
, ld::Internal
& state
)
1152 // only make image info section if objc was used
1153 if ( state
.objcObjectConstraint
!= ld::File::objcConstraintNone
) {
1155 // verify dylibs are GC compatible with object files
1156 if ( state
.objcObjectConstraint
!= state
.objcDylibConstraint
) {
1157 if ( (state
.objcDylibConstraint
== ld::File::objcConstraintRetainRelease
)
1158 && (state
.objcObjectConstraint
== ld::File::objcConstraintGC
) ) {
1159 throw "Linked dylibs built for retain/release but object files built for GC-only";
1161 else if ( (state
.objcDylibConstraint
== ld::File::objcConstraintGC
)
1162 && (state
.objcObjectConstraint
== ld::File::objcConstraintRetainRelease
) ) {
1163 throw "Linked dylibs built for GC-only but object files built for retain/release";
1167 const bool compaction
= opts
.objcGcCompaction();
1169 // add image info atom
1170 switch ( opts
.architecture() ) {
1171 #if SUPPORT_ARCH_x86_64
1172 case CPU_TYPE_X86_64
:
1173 state
.addAtom(*new ObjCImageInfoAtom
<x86_64
>(state
.objcObjectConstraint
, compaction
,
1177 #if SUPPORT_ARCH_i386
1179 state
.addAtom(*new ObjCImageInfoAtom
<x86
>(state
.objcObjectConstraint
, compaction
,
1180 opts
.objCABIVersion2POverride() ? true : false));
1183 #if SUPPORT_ARCH_arm_any
1185 state
.addAtom(*new ObjCImageInfoAtom
<arm
>(state
.objcObjectConstraint
, compaction
,
1189 #if SUPPORT_ARCH_arm64
1190 case CPU_TYPE_ARM64
:
1191 state
.addAtom(*new ObjCImageInfoAtom
<arm64
>(state
.objcObjectConstraint
, compaction
,
1196 assert(0 && "unknown objc arch");
1200 if ( opts
.objcCategoryMerging() ) {
1201 // optimize classes defined in this linkage unit by merging in categories also in this linkage unit
1202 switch ( opts
.architecture() ) {
1203 #if SUPPORT_ARCH_x86_64
1204 case CPU_TYPE_X86_64
:
1205 OptimizeCategories
<x86_64
>::doit(opts
, state
);
1208 #if SUPPORT_ARCH_i386
1210 if ( opts
.objCABIVersion2POverride() )
1211 OptimizeCategories
<x86
>::doit(opts
, state
);
1214 #if SUPPORT_ARCH_arm_any
1216 OptimizeCategories
<arm
>::doit(opts
, state
);
1219 #if SUPPORT_ARCH_arm64
1220 case CPU_TYPE_ARM64
:
1221 // disabled until tested
1225 assert(0 && "unknown objc arch");
1232 } // namespace passes