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)
61 // This class is the 8 byte section containing ObjC flags
64 class ObjCImageInfoAtom
: public ld::Atom
{
66 ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint
,
67 bool compaction
, bool abi2
);
69 virtual const ld::File
* file() const { return NULL
; }
70 virtual const char* name() const { return "objc image info"; }
71 virtual uint64_t size() const { return sizeof(objc_image_info
); }
72 virtual uint64_t objectAddress() const { return 0; }
73 virtual void setScope(Scope
) { }
74 virtual void copyRawContent(uint8_t buffer
[]) const {
75 memcpy(buffer
, &_content
, sizeof(objc_image_info
));
79 objc_image_info _content
;
81 static ld::Section _s_sectionABI1
;
82 static ld::Section _s_sectionABI2
;
85 template <typename A
> ld::Section ObjCImageInfoAtom
<A
>::_s_sectionABI1("__OBJC", "__image_info", ld::Section::typeUnclassified
);
86 template <typename A
> ld::Section ObjCImageInfoAtom
<A
>::_s_sectionABI2("__DATA", "__objc_imageinfo", ld::Section::typeUnclassified
);
90 ObjCImageInfoAtom
<A
>::ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint
, bool compaction
,
92 : ld::Atom(abi2
? _s_sectionABI2
: _s_sectionABI1
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
93 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
94 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(2))
98 switch ( objcConstraint
) {
99 case ld::File::objcConstraintNone
:
100 case ld::File::objcConstraintRetainRelease
:
102 warning("ignoring -objc_gc_compaction because code not compiled for ObjC garbage collection");
104 case ld::File::objcConstraintRetainReleaseOrGC
:
105 value
|= OBJC_IMAGE_SUPPORTS_GC
;
107 value
|= OBJC_IMAGE_SUPPORTS_COMPACTION
;
109 case ld::File::objcConstraintGC
:
110 value
|= OBJC_IMAGE_SUPPORTS_GC
| OBJC_IMAGE_REQUIRES_GC
;
112 value
|= OBJC_IMAGE_SUPPORTS_COMPACTION
;
116 _content
.version
= 0;
117 A::P::E::set32(_content
.flags
, value
);
123 // This class is for a new Atom which is an ObjC method list created by merging method lists from categories
125 template <typename A
>
126 class MethodListAtom
: public ld::Atom
{
128 MethodListAtom(ld::Internal
& state
, const ld::Atom
* baseMethodList
, bool meta
,
129 const std::vector
<const ld::Atom
*>* categories
,
130 std::set
<const ld::Atom
*>& deadAtoms
);
132 virtual const ld::File
* file() const { return _file
; }
133 virtual const char* name() const { return "objc merged method list"; }
134 virtual uint64_t size() const { return _methodCount
*3*sizeof(pint_t
) + 8; }
135 virtual uint64_t objectAddress() const { return 0; }
136 virtual void setScope(Scope
) { }
137 virtual void copyRawContent(uint8_t buffer
[]) const {
138 bzero(buffer
, size());
139 A::P::E::set32(*((uint32_t*)(&buffer
[0])), 3*sizeof(pint_t
)); // entry size
140 A::P::E::set32(*((uint32_t*)(&buffer
[4])), _methodCount
);
142 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
143 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
146 typedef typename
A::P::uint_t pint_t
;
148 const ld::File
* _file
;
149 unsigned int _methodCount
;
150 std::vector
<ld::Fixup
> _fixups
;
152 static ld::Section _s_section
;
155 template <typename A
>
156 ld::Section MethodListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
160 // This class is for a new Atom which is an ObjC protocol list created by merging protocol lists from categories
162 template <typename A
>
163 class ProtocolListAtom
: public ld::Atom
{
165 ProtocolListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
166 const std::vector
<const ld::Atom
*>* categories
,
167 std::set
<const ld::Atom
*>& deadAtoms
);
169 virtual const ld::File
* file() const { return _file
; }
170 virtual const char* name() const { return "objc merged protocol list"; }
171 virtual uint64_t size() const { return (_protocolCount
+1)*sizeof(pint_t
); }
172 virtual uint64_t objectAddress() const { return 0; }
173 virtual void setScope(Scope
) { }
174 virtual void copyRawContent(uint8_t buffer
[]) const {
175 bzero(buffer
, size());
176 A::P::setP(*((pint_t
*)(buffer
)), _protocolCount
);
178 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
179 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
182 typedef typename
A::P::uint_t pint_t
;
184 const ld::File
* _file
;
185 unsigned int _protocolCount
;
186 std::vector
<ld::Fixup
> _fixups
;
188 static ld::Section _s_section
;
191 template <typename A
>
192 ld::Section ProtocolListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
197 // This class is for a new Atom which is an ObjC property list created by merging property lists from categories
199 template <typename A
>
200 class PropertyListAtom
: public ld::Atom
{
202 PropertyListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
203 const std::vector
<const ld::Atom
*>* categories
,
204 std::set
<const ld::Atom
*>& deadAtoms
);
206 virtual const ld::File
* file() const { return _file
; }
207 virtual const char* name() const { return "objc merged property list"; }
208 virtual uint64_t size() const { return _propertyCount
*2*sizeof(pint_t
) + 8; }
209 virtual uint64_t objectAddress() const { return 0; }
210 virtual void setScope(Scope
) { }
211 virtual void copyRawContent(uint8_t buffer
[]) const {
212 bzero(buffer
, size());
213 A::P::E::set32(((uint32_t*)(buffer
))[0], 2*sizeof(pint_t
)); // sizeof(objc_property)
214 A::P::E::set32(((uint32_t*)(buffer
))[1], _propertyCount
);
216 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
217 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
220 typedef typename
A::P::uint_t pint_t
;
222 const ld::File
* _file
;
223 unsigned int _propertyCount
;
224 std::vector
<ld::Fixup
> _fixups
;
226 static ld::Section _s_section
;
229 template <typename A
>
230 ld::Section PropertyListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
237 // This class is used to create an Atom that replaces an atom from a .o file that holds a class_ro_t.
238 // It is needed because there is no way to add Fixups to an existing atom.
240 template <typename A
>
241 class ClassROOverlayAtom
: public ld::Atom
{
243 ClassROOverlayAtom(const ld::Atom
* classROAtom
);
245 // overrides of ld::Atom
246 virtual const ld::File
* file() const { return _atom
->file(); }
247 virtual const char* name() const { return _atom
->name(); }
248 virtual uint64_t size() const { return _atom
->size(); }
249 virtual uint64_t objectAddress() const { return _atom
->objectAddress(); }
250 virtual void copyRawContent(uint8_t buffer
[]) const
251 { _atom
->copyRawContent(buffer
); }
252 virtual const uint8_t* rawContentPointer() const
253 { return _atom
->rawContentPointer(); }
254 virtual unsigned long contentHash(const class ld::IndirectBindingTable
& ibt
) const
255 { return _atom
->contentHash(ibt
); }
256 virtual bool canCoalesceWith(const ld::Atom
& rhs
, const class ld::IndirectBindingTable
& ibt
) const
257 { return _atom
->canCoalesceWith(rhs
,ibt
); }
259 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
260 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
262 void addProtocolListFixup();
263 void addPropertyListFixup();
264 void addMethodListFixup();
267 typedef typename
A::P::uint_t pint_t
;
269 const ld::Atom
* _atom
;
270 std::vector
<ld::Fixup
> _fixups
;
273 template <typename A
>
274 ClassROOverlayAtom
<A
>::ClassROOverlayAtom(const ld::Atom
* classROAtom
)
275 : ld::Atom(classROAtom
->section(), ld::Atom::definitionRegular
, ld::Atom::combineNever
,
276 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
277 classROAtom
->symbolTableInclusion(), false, false, false, classROAtom
->alignment()),
280 // ensure all attributes are same as original
281 this->setAttributesFromAtom(*classROAtom
);
283 // copy fixups from orginal atom
284 for (ld::Fixup::iterator fit
=classROAtom
->fixupsBegin(); fit
!= classROAtom
->fixupsEnd(); ++fit
) {
285 ld::Fixup fixup
= *fit
;
286 _fixups
.push_back(fixup
);
292 // Base class for reading and updating existing ObjC atoms from .o files
294 template <typename A
>
297 static const ld::Atom
* getPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
, unsigned int offset
, bool* hasAddend
=NULL
);
298 static void setPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
,
299 unsigned int offset
, const ld::Atom
* newAtom
);
300 typedef typename
A::P::uint_t pint_t
;
303 template <typename A
>
304 const ld::Atom
* ObjCData
<A
>::getPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
, unsigned int offset
, bool* hasAddend
)
306 const ld::Atom
* target
= NULL
;
307 if ( hasAddend
!= NULL
)
309 for (ld::Fixup::iterator fit
=contentAtom
->fixupsBegin(); fit
!= contentAtom
->fixupsEnd(); ++fit
) {
310 if ( fit
->offsetInAtom
== offset
) {
311 switch ( fit
->binding
) {
312 case ld::Fixup::bindingsIndirectlyBound
:
313 target
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
315 case ld::Fixup::bindingDirectlyBound
:
316 target
= fit
->u
.target
;
318 case ld::Fixup::bindingNone
:
319 if ( fit
->kind
== ld::Fixup::kindAddAddend
) {
320 if ( hasAddend
!= NULL
)
332 template <typename A
>
333 void ObjCData
<A
>::setPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
,
334 unsigned int offset
, const ld::Atom
* newAtom
)
336 for (ld::Fixup::iterator fit
=contentAtom
->fixupsBegin(); fit
!= contentAtom
->fixupsEnd(); ++fit
) {
337 if ( fit
->offsetInAtom
== offset
) {
338 switch ( fit
->binding
) {
339 case ld::Fixup::bindingsIndirectlyBound
:
340 state
.indirectBindingTable
[fit
->u
.bindingIndex
] = newAtom
;
342 case ld::Fixup::bindingDirectlyBound
:
343 fit
->u
.target
= newAtom
;
350 assert(0 && "could not update method list");
356 // Helper class for reading and updating existing ObjC category atoms from .o files
358 template <typename A
>
359 class Category
: public ObjCData
<A
> {
361 static const ld::Atom
* getClass(ld::Internal
& state
, const ld::Atom
* contentAtom
);
362 static const ld::Atom
* getInstanceMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
);
363 static const ld::Atom
* getClassMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
);
364 static const ld::Atom
* getProtocols(ld::Internal
& state
, const ld::Atom
* contentAtom
);
365 static const ld::Atom
* getProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
);
366 static uint32_t size() { return 6*sizeof(pint_t
); }
368 typedef typename
A::P::uint_t pint_t
;
372 template <typename A
>
373 const ld::Atom
* Category
<A
>::getClass(ld::Internal
& state
, const ld::Atom
* contentAtom
)
375 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, sizeof(pint_t
)); // category_t.cls
378 template <typename A
>
379 const ld::Atom
* Category
<A
>::getInstanceMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
)
381 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 2*sizeof(pint_t
)); // category_t.instanceMethods
384 template <typename A
>
385 const ld::Atom
* Category
<A
>::getClassMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
)
387 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 3*sizeof(pint_t
)); // category_t.classMethods
390 template <typename A
>
391 const ld::Atom
* Category
<A
>::getProtocols(ld::Internal
& state
, const ld::Atom
* contentAtom
)
393 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 4*sizeof(pint_t
)); // category_t.protocols
396 template <typename A
>
397 const ld::Atom
* Category
<A
>::getProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
)
399 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 5*sizeof(pint_t
)); // category_t.instanceProperties
403 template <typename A
>
404 class MethodList
: public ObjCData
<A
> {
406 static uint32_t count(ld::Internal
& state
, const ld::Atom
* methodListAtom
) {
407 const uint32_t* methodListData
= (uint32_t*)(methodListAtom
->rawContentPointer());
408 return A::P::E::get32(methodListData
[1]); // method_list_t.count
412 template <typename A
>
413 class ProtocolList
: public ObjCData
<A
> {
415 static uint32_t count(ld::Internal
& state
, const ld::Atom
* protocolListAtom
) {
416 pint_t
* protocolListData
= (pint_t
*)(protocolListAtom
->rawContentPointer());
417 return A::P::getP(*protocolListData
); // protocol_list_t.count
420 typedef typename
A::P::uint_t pint_t
;
423 template <typename A
>
424 class PropertyList
: public ObjCData
<A
> {
426 static uint32_t count(ld::Internal
& state
, const ld::Atom
* protocolListAtom
) {
427 uint32_t* protocolListData
= (uint32_t*)(protocolListAtom
->rawContentPointer());
428 return A::P::E::get32(protocolListData
[1]); // property_list_t.count
431 typedef typename
A::P::uint_t pint_t
;
437 // Helper class for reading and updating existing ObjC class atoms from .o files
439 template <typename A
>
440 class Class
: public ObjCData
<A
> {
442 static const ld::Atom
* getInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
);
443 static const ld::Atom
* getInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
);
444 static const ld::Atom
* getInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
);
445 static const ld::Atom
* getClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
);
446 static const ld::Atom
* setInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
447 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
448 static const ld::Atom
* setInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
449 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
450 static const ld::Atom
* setInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,
451 const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
452 static const ld::Atom
* setClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
453 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
454 static const ld::Atom
* setClassProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
455 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
456 static uint32_t size() { return 5*sizeof(pint_t
); }
457 static unsigned int class_ro_header_size();
459 typedef typename
A::P::uint_t pint_t
;
460 static const ld::Atom
* getROData(ld::Internal
& state
, const ld::Atom
* classAtom
);
463 template <> unsigned int Class
<x86_64
>::class_ro_header_size() { return 16; }
464 template <> unsigned int Class
<arm
>::class_ro_header_size() { return 12;}
465 template <> unsigned int Class
<x86
>::class_ro_header_size() { return 12; }
468 template <typename A
>
469 const ld::Atom
* Class
<A
>::getROData(ld::Internal
& state
, const ld::Atom
* classAtom
)
471 return ObjCData
<A
>::getPointerInContent(state
, classAtom
, 4*sizeof(pint_t
)); // class_t.data
475 template <typename A
>
476 const ld::Atom
* Class
<A
>::getInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
)
478 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
479 assert(classROAtom
!= NULL
);
480 return ObjCData
<A
>::getPointerInContent(state
, classROAtom
, class_ro_header_size() + 2*sizeof(pint_t
)); // class_ro_t.baseMethods
483 template <typename A
>
484 const ld::Atom
* Class
<A
>::getInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
)
486 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
487 assert(classROAtom
!= NULL
);
488 return ObjCData
<A
>::getPointerInContent(state
, classROAtom
, class_ro_header_size() + 3*sizeof(pint_t
)); // class_ro_t.baseProtocols
491 template <typename A
>
492 const ld::Atom
* Class
<A
>::getInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
)
494 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
495 assert(classROAtom
!= NULL
);
496 return ObjCData
<A
>::getPointerInContent(state
, classROAtom
, class_ro_header_size() + 6*sizeof(pint_t
)); // class_ro_t.baseProperties
499 template <typename A
>
500 const ld::Atom
* Class
<A
>::getClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
)
502 const ld::Atom
* metaClassAtom
= ObjCData
<A
>::getPointerInContent(state
, classAtom
, 0); // class_t.isa
503 assert(metaClassAtom
!= NULL
);
504 return Class
<A
>::getInstanceMethodList(state
, metaClassAtom
);
507 template <typename A
>
508 const ld::Atom
* Class
<A
>::setInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
509 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
511 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
512 assert(classROAtom
!= NULL
);
513 // if the base class does not already have a method list, we need to create an overlay
514 if ( getInstanceMethodList(state
, classAtom
) == NULL
) {
515 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(classROAtom
);
516 //fprintf(stderr, "replace class RO atom %p with %p for method list in class atom %s\n", classROAtom, overlay, classAtom->name());
517 overlay
->addMethodListFixup();
518 ObjCData
<A
>::setPointerInContent(state
, classAtom
, 4*sizeof(pint_t
), overlay
); // class_t.data
519 deadAtoms
.insert(classROAtom
);
520 ObjCData
<A
>::setPointerInContent(state
, overlay
, class_ro_header_size() + 2*sizeof(pint_t
), methodListAtom
); // class_ro_t.baseMethods
523 ObjCData
<A
>::setPointerInContent(state
, classROAtom
, class_ro_header_size() + 2*sizeof(pint_t
), methodListAtom
); // class_ro_t.baseMethods
524 return NULL
; // means classRO atom was not replaced
527 template <typename A
>
528 const ld::Atom
* Class
<A
>::setInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
529 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
531 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
532 assert(classROAtom
!= NULL
);
533 // if the base class does not already have a protocol list, we need to create an overlay
534 if ( getInstanceProtocolList(state
, classAtom
) == NULL
) {
535 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(classROAtom
);
536 //fprintf(stderr, "replace class RO atom %p with %p for protocol list in class atom %s\n", classROAtom, overlay, classAtom->name());
537 overlay
->addProtocolListFixup();
538 ObjCData
<A
>::setPointerInContent(state
, classAtom
, 4*sizeof(pint_t
), overlay
); // class_t.data
539 deadAtoms
.insert(classROAtom
);
540 ObjCData
<A
>::setPointerInContent(state
, overlay
, class_ro_header_size() + 3*sizeof(pint_t
), protocolListAtom
); // class_ro_t.baseProtocols
543 //fprintf(stderr, "set class RO atom %p protocol list in class atom %s\n", classROAtom, classAtom->name());
544 ObjCData
<A
>::setPointerInContent(state
, classROAtom
, class_ro_header_size() + 3*sizeof(pint_t
), protocolListAtom
); // class_ro_t.baseProtocols
545 return NULL
; // means classRO atom was not replaced
548 template <typename A
>
549 const ld::Atom
* Class
<A
>::setClassProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
550 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
552 // meta class also points to same protocol list as class
553 const ld::Atom
* metaClassAtom
= ObjCData
<A
>::getPointerInContent(state
, classAtom
, 0); // class_t.isa
554 //fprintf(stderr, "setClassProtocolList(), classAtom=%p %s, metaClass=%p %s\n", classAtom, classAtom->name(), metaClassAtom, metaClassAtom->name());
555 assert(metaClassAtom
!= NULL
);
556 return setInstanceProtocolList(state
, metaClassAtom
, protocolListAtom
, deadAtoms
);
561 template <typename A
>
562 const ld::Atom
* Class
<A
>::setInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,
563 const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
565 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
566 assert(classROAtom
!= NULL
);
567 // if the base class does not already have a property list, we need to create an overlay
568 if ( getInstancePropertyList(state
, classAtom
) == NULL
) {
569 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(classROAtom
);
570 //fprintf(stderr, "replace class RO atom %p with %p for property list in class atom %s\n", classROAtom, overlay, classAtom->name());
571 overlay
->addPropertyListFixup();
572 ObjCData
<A
>::setPointerInContent(state
, classAtom
, 4*sizeof(pint_t
), overlay
); // class_t.data
573 deadAtoms
.insert(classROAtom
);
574 ObjCData
<A
>::setPointerInContent(state
, overlay
, class_ro_header_size() + 6*sizeof(pint_t
), propertyListAtom
); // class_ro_t.baseProperties
577 ObjCData
<A
>::setPointerInContent(state
, classROAtom
, class_ro_header_size() + 6*sizeof(pint_t
), propertyListAtom
); // class_ro_t.baseProperties
578 return NULL
; // means classRO atom was not replaced
581 template <typename A
>
582 const ld::Atom
* Class
<A
>::setClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
583 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
585 // class methods is just instance methods of metaClass
586 const ld::Atom
* metaClassAtom
= ObjCData
<A
>::getPointerInContent(state
, classAtom
, 0); // class_t.isa
587 assert(metaClassAtom
!= NULL
);
588 return setInstanceMethodList(state
, metaClassAtom
, methodListAtom
, deadAtoms
);
594 void ClassROOverlayAtom
<x86_64
>::addMethodListFixup()
596 const ld::Atom
* targetAtom
= this; // temporary
597 uint32_t offset
= Class
<x86_64
>::class_ro_header_size() + 2*8; // class_ro_t.baseMethods
598 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian64
, targetAtom
));
602 void ClassROOverlayAtom
<arm
>::addMethodListFixup()
604 const ld::Atom
* targetAtom
= this; // temporary
605 uint32_t offset
= Class
<arm
>::class_ro_header_size() + 2*4; // class_ro_t.baseMethods
606 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
610 void ClassROOverlayAtom
<x86
>::addMethodListFixup()
612 const ld::Atom
* targetAtom
= this; // temporary
613 uint32_t offset
= Class
<x86
>::class_ro_header_size() + 2*4; // class_ro_t.baseMethods
614 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
620 void ClassROOverlayAtom
<x86_64
>::addProtocolListFixup()
622 const ld::Atom
* targetAtom
= this; // temporary
623 uint32_t offset
= Class
<x86_64
>::class_ro_header_size() + 3*8; // class_ro_t.baseProtocols
624 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian64
, targetAtom
));
628 void ClassROOverlayAtom
<arm
>::addProtocolListFixup()
630 const ld::Atom
* targetAtom
= this; // temporary
631 uint32_t offset
= Class
<arm
>::class_ro_header_size() + 3*4; // class_ro_t.baseProtocols
632 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
636 void ClassROOverlayAtom
<x86
>::addProtocolListFixup()
638 const ld::Atom
* targetAtom
= this; // temporary
639 uint32_t offset
= Class
<x86
>::class_ro_header_size() + 3*4; // class_ro_t.baseProtocols
640 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
645 void ClassROOverlayAtom
<x86_64
>::addPropertyListFixup()
647 const ld::Atom
* targetAtom
= this; // temporary
648 uint32_t offset
= Class
<x86_64
>::class_ro_header_size() + 6*8; // class_ro_t.baseProperties
649 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian64
, targetAtom
));
653 void ClassROOverlayAtom
<arm
>::addPropertyListFixup()
655 const ld::Atom
* targetAtom
= this; // temporary
656 uint32_t offset
= Class
<arm
>::class_ro_header_size() + 6*4; // class_ro_t.baseProperties
657 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
661 void ClassROOverlayAtom
<x86
>::addPropertyListFixup()
663 const ld::Atom
* targetAtom
= this; // temporary
664 uint32_t offset
= Class
<x86
>::class_ro_header_size() + 6*4; // class_ro_t.baseProperties
665 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
672 // Encapsulates merging of ObjC categories
674 template <typename A
>
675 class OptimizeCategories
{
677 static void doit(const Options
& opts
, ld::Internal
& state
);
678 static bool hasInstanceMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
679 static bool hasClassMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
680 static bool hasProtocols(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
681 static bool hasProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
684 static unsigned int class_ro_baseMethods_offset();
686 typedef typename
A::P::uint_t pint_t
;
691 template <typename A
>
692 bool OptimizeCategories
<A
>::hasInstanceMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
694 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
695 const ld::Atom
* categoryAtom
= *it
;
696 const ld::Atom
* methodList
= Category
<A
>::getInstanceMethods(state
, categoryAtom
);
697 if ( methodList
!= NULL
) {
698 if ( MethodList
<A
>::count(state
, methodList
) > 0 )
706 template <typename A
>
707 bool OptimizeCategories
<A
>::hasClassMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
709 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
710 const ld::Atom
* categoryAtom
= *it
;
711 const ld::Atom
* methodList
= Category
<A
>::getClassMethods(state
, categoryAtom
);
712 if ( methodList
!= NULL
) {
713 if ( MethodList
<A
>::count(state
, methodList
) > 0 )
720 template <typename A
>
721 bool OptimizeCategories
<A
>::hasProtocols(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
723 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
724 const ld::Atom
* categoryAtom
= *it
;
725 const ld::Atom
* protocolListAtom
= Category
<A
>::getProtocols(state
, categoryAtom
);
726 if ( protocolListAtom
!= NULL
) {
727 if ( ProtocolList
<A
>::count(state
, protocolListAtom
) > 0 ) {
736 template <typename A
>
737 bool OptimizeCategories
<A
>::hasProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
739 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
740 const ld::Atom
* categoryAtom
= *it
;
741 const ld::Atom
* propertyListAtom
= Category
<A
>::getProperties(state
, categoryAtom
);
742 if ( propertyListAtom
!= NULL
) {
743 if ( PropertyList
<A
>::count(state
, propertyListAtom
) > 0 )
753 // Helper for std::remove_if
755 class OptimizedAway
{
757 OptimizedAway(const std::set
<const ld::Atom
*>& oa
) : _dead(oa
) {}
758 bool operator()(const ld::Atom
* atom
) const {
759 return ( _dead
.count(atom
) != 0 );
762 const std::set
<const ld::Atom
*>& _dead
;
767 bool operator()(const Atom
* left
, const Atom
* right
)
769 // sort by file ordinal, then object address, then zero size, then symbol name
770 // only file based atoms are supported (file() != NULL)
771 if (left
==right
) return false;
772 const File
*leftf
= left
->file();
773 const File
*rightf
= right
->file();
775 if (leftf
== rightf
) {
776 if (left
->objectAddress() != right
->objectAddress()) {
777 return left
->objectAddress() < right
->objectAddress();
779 // for atoms in the same file with the same address, zero sized
780 // atoms must sort before nonzero sized atoms
781 if ((left
->size() == 0 && right
->size() > 0) || (left
->size() > 0 && right
->size() == 0))
782 return left
->size() < right
->size();
783 return strcmp(left
->name(), right
->name());
786 return (leftf
->ordinal() < rightf
->ordinal());
790 static void sortAtomVector(std::vector
<const Atom
*> &atoms
) {
791 std::sort(atoms
.begin(), atoms
.end(), AtomSorter());
794 template <typename A
>
795 void OptimizeCategories
<A
>::doit(const Options
& opts
, ld::Internal
& state
)
797 // first find all categories referenced by __objc_nlcatlist section
798 std::set
<const ld::Atom
*> nlcatListAtoms
;
799 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
800 ld::Internal::FinalSection
* sect
= *sit
;
801 if ( (strcmp(sect
->sectionName(), "__objc_nlcatlist") == 0) && (strcmp(sect
->segmentName(), "__DATA") == 0) ) {
802 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
803 const ld::Atom
* categoryListElementAtom
= *ait
;
804 for (unsigned int offset
=0; offset
< categoryListElementAtom
->size(); offset
+= sizeof(pint_t
)) {
805 const ld::Atom
* categoryAtom
= ObjCData
<A
>::getPointerInContent(state
, categoryListElementAtom
, offset
);
806 //fprintf(stderr, "offset=%d, cat=%p %s\n", offset, categoryAtom, categoryAtom->name());
807 assert(categoryAtom
!= NULL
);
808 nlcatListAtoms
.insert(categoryAtom
);
814 // build map of all classes in this image that have categories on them
815 typedef std::map
<const ld::Atom
*, std::vector
<const ld::Atom
*>*> CatMap
;
816 CatMap classToCategories
;
817 std::vector
<const ld::Atom
*> classOrder
;
818 std::set
<const ld::Atom
*> deadAtoms
;
819 ld::Internal::FinalSection
* methodListSection
= NULL
;
820 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
821 ld::Internal::FinalSection
* sect
= *sit
;
822 if ( sect
->type() == ld::Section::typeObjC2CategoryList
) {
823 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
824 const ld::Atom
* categoryListElementAtom
= *ait
;
826 const ld::Atom
* categoryAtom
= ObjCData
<A
>::getPointerInContent(state
, categoryListElementAtom
, 0, &hasAddend
);
827 if ( hasAddend
|| (categoryAtom
->symbolTableInclusion() == ld::Atom::symbolTableNotIn
)) {
828 //<rdar://problem/8309530> gcc-4.0 uses 'L' labels on categories which disables this optimization
829 //warning("__objc_catlist element does not point to start of category");
832 assert(categoryAtom
!= NULL
);
833 assert(categoryAtom
->size() >= Category
<A
>::size());
834 // ignore categories also in __objc_nlcatlist
835 if ( nlcatListAtoms
.count(categoryAtom
) != 0 )
837 const ld::Atom
* categoryOnClassAtom
= Category
<A
>::getClass(state
, categoryAtom
);
838 assert(categoryOnClassAtom
!= NULL
);
839 if ( categoryOnClassAtom
->definition() != ld::Atom::definitionProxy
) {
840 // only look at classes defined in this image
841 CatMap::iterator pos
= classToCategories
.find(categoryOnClassAtom
);
842 if ( pos
== classToCategories
.end() ) {
843 classToCategories
[categoryOnClassAtom
] = new std::vector
<const ld::Atom
*>();
844 classOrder
.push_back(categoryOnClassAtom
);
846 classToCategories
[categoryOnClassAtom
]->push_back(categoryAtom
);
847 // mark category atom and catlist atom as dead
848 deadAtoms
.insert(categoryAtom
);
849 deadAtoms
.insert(categoryListElementAtom
);
853 // record method list section
854 if ( (strcmp(sect
->sectionName(), "__objc_const") == 0) && (strcmp(sect
->segmentName(), "__DATA") == 0) )
855 methodListSection
= sect
;
858 // if found some categories
859 if ( classToCategories
.size() != 0 ) {
860 assert(methodListSection
!= NULL
);
861 sortAtomVector(classOrder
);
862 // alter each class definition to have new method list which includes all category methods
863 for (std::vector
<const ld::Atom
*>::iterator it
= classOrder
.begin(); it
!= classOrder
.end(); it
++) {
864 const ld::Atom
* classAtom
= *it
;
865 const std::vector
<const ld::Atom
*>* categories
= classToCategories
[classAtom
];
866 assert(categories
->size() != 0);
867 // if any category adds instance methods, generate new merged method list, and replace
868 if ( OptimizeCategories
<A
>::hasInstanceMethods(state
, categories
) ) {
869 const ld::Atom
* baseInstanceMethodListAtom
= Class
<A
>::getInstanceMethodList(state
, classAtom
);
870 const ld::Atom
* newInstanceMethodListAtom
= new MethodListAtom
<A
>(state
, baseInstanceMethodListAtom
, false, categories
, deadAtoms
);
871 const ld::Atom
* newClassRO
= Class
<A
>::setInstanceMethodList(state
, classAtom
, newInstanceMethodListAtom
, deadAtoms
);
872 // add new method list to final sections
873 methodListSection
->atoms
.push_back(newInstanceMethodListAtom
);
874 if ( newClassRO
!= NULL
) {
875 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
876 methodListSection
->atoms
.push_back(newClassRO
);
879 // if any category adds class methods, generate new merged method list, and replace
880 if ( OptimizeCategories
<A
>::hasClassMethods(state
, categories
) ) {
881 const ld::Atom
* baseClassMethodListAtom
= Class
<A
>::getClassMethodList(state
, classAtom
);
882 const ld::Atom
* newClassMethodListAtom
= new MethodListAtom
<A
>(state
, baseClassMethodListAtom
, true, categories
, deadAtoms
);
883 const ld::Atom
* newClassRO
= Class
<A
>::setClassMethodList(state
, classAtom
, newClassMethodListAtom
, deadAtoms
);
884 // add new method list to final sections
885 methodListSection
->atoms
.push_back(newClassMethodListAtom
);
886 if ( newClassRO
!= NULL
) {
887 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
888 methodListSection
->atoms
.push_back(newClassRO
);
891 // if any category adds protocols, generate new merged protocol list, and replace
892 if ( OptimizeCategories
<A
>::hasProtocols(state
, categories
) ) {
893 const ld::Atom
* baseProtocolListAtom
= Class
<A
>::getInstanceProtocolList(state
, classAtom
);
894 const ld::Atom
* newProtocolListAtom
= new ProtocolListAtom
<A
>(state
, baseProtocolListAtom
, categories
, deadAtoms
);
895 const ld::Atom
* newClassRO
= Class
<A
>::setInstanceProtocolList(state
, classAtom
, newProtocolListAtom
, deadAtoms
);
896 const ld::Atom
* newMetaClassRO
= Class
<A
>::setClassProtocolList(state
, classAtom
, newProtocolListAtom
, deadAtoms
);
897 // add new protocol list to final sections
898 methodListSection
->atoms
.push_back(newProtocolListAtom
);
899 if ( newClassRO
!= NULL
) {
900 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
901 methodListSection
->atoms
.push_back(newClassRO
);
903 if ( newMetaClassRO
!= NULL
) {
904 assert(strcmp(newMetaClassRO
->section().sectionName(), "__objc_const") == 0);
905 methodListSection
->atoms
.push_back(newMetaClassRO
);
908 // if any category adds properties, generate new merged property list, and replace
909 if ( OptimizeCategories
<A
>::hasProperties(state
, categories
) ) {
910 const ld::Atom
* basePropertyListAtom
= Class
<A
>::getInstancePropertyList(state
, classAtom
);
911 const ld::Atom
* newPropertyListAtom
= new PropertyListAtom
<A
>(state
, basePropertyListAtom
, categories
, deadAtoms
);
912 const ld::Atom
* newClassRO
= Class
<A
>::setInstancePropertyList(state
, classAtom
, newPropertyListAtom
, deadAtoms
);
913 // add new property list to final sections
914 methodListSection
->atoms
.push_back(newPropertyListAtom
);
915 if ( newClassRO
!= NULL
) {
916 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
917 methodListSection
->atoms
.push_back(newClassRO
);
924 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
925 ld::Internal::FinalSection
* sect
= *sit
;
926 sect
->atoms
.erase(std::remove_if(sect
->atoms
.begin(), sect
->atoms
.end(), OptimizedAway(deadAtoms
)), sect
->atoms
.end());
932 template <typename A
>
933 MethodListAtom
<A
>::MethodListAtom(ld::Internal
& state
, const ld::Atom
* baseMethodList
, bool meta
,
934 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
935 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
936 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
937 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _methodCount(0)
939 unsigned int fixupCount
= 0;
940 std::set
<const ld::Atom
*> baseMethodListMethodNameAtoms
;
941 // if base class has method list, then associate new method list with file defining class
942 if ( baseMethodList
!= NULL
) {
943 _file
= baseMethodList
->file();
944 // calculate total size of merge method lists
945 _methodCount
= MethodList
<A
>::count(state
, baseMethodList
);
946 deadAtoms
.insert(baseMethodList
);
947 fixupCount
= baseMethodList
->fixupsEnd() - baseMethodList
->fixupsBegin();
948 for (ld::Fixup::iterator fit
=baseMethodList
->fixupsBegin(); fit
!= baseMethodList
->fixupsEnd(); ++fit
) {
949 if ( (fit
->offsetInAtom
- 8) % (3*sizeof(pint_t
)) == 0 ) {
950 assert(fit
->binding
== ld::Fixup::bindingsIndirectlyBound
&& "malformed method list");
951 const ld::Atom
* target
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
952 assert(target
->contentType() == ld::Atom::typeCString
&& "malformed method list");
953 baseMethodListMethodNameAtoms
.insert(target
);
957 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
958 const ld::Atom
* categoryMethodListAtom
;
960 categoryMethodListAtom
= Category
<A
>::getClassMethods(state
, *ait
);
962 categoryMethodListAtom
= Category
<A
>::getInstanceMethods(state
, *ait
);
963 if ( categoryMethodListAtom
!= NULL
) {
964 _methodCount
+= MethodList
<A
>::count(state
, categoryMethodListAtom
);
965 fixupCount
+= (categoryMethodListAtom
->fixupsEnd() - categoryMethodListAtom
->fixupsBegin());
966 deadAtoms
.insert(categoryMethodListAtom
);
967 // if base class did not have method list, associate new method list with file the defined category
969 _file
= categoryMethodListAtom
->file();
972 //if ( baseMethodList != NULL )
973 // fprintf(stderr, "total merged method count=%u for baseMethodList=%s\n", _methodCount, baseMethodList->name());
975 // fprintf(stderr, "total merged method count=%u\n", _methodCount);
976 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
978 // copy fixups and adjust offsets (in reverse order to simulator objc runtime)
979 _fixups
.reserve(fixupCount
);
981 std::set
<const ld::Atom
*> categoryMethodNameAtoms
;
982 for (std::vector
<const ld::Atom
*>::const_reverse_iterator rit
=categories
->rbegin(); rit
!= categories
->rend(); ++rit
) {
983 const ld::Atom
* categoryMethodListAtom
;
985 categoryMethodListAtom
= Category
<A
>::getClassMethods(state
, *rit
);
987 categoryMethodListAtom
= Category
<A
>::getInstanceMethods(state
, *rit
);
988 if ( categoryMethodListAtom
!= NULL
) {
989 for (ld::Fixup::iterator fit
=categoryMethodListAtom
->fixupsBegin(); fit
!= categoryMethodListAtom
->fixupsEnd(); ++fit
) {
990 ld::Fixup fixup
= *fit
;
991 fixup
.offsetInAtom
+= slide
;
992 _fixups
.push_back(fixup
);
993 if ( (fixup
.offsetInAtom
- 8) % (3*sizeof(pint_t
)) == 0 ) {
994 // <rdar://problem/8642343> warning when a method is overridden in a category in the same link unit
995 assert(fixup
.binding
== ld::Fixup::bindingsIndirectlyBound
&& "malformed category method list");
996 const ld::Atom
* target
= state
.indirectBindingTable
[fixup
.u
.bindingIndex
];
997 assert(target
->contentType() == ld::Atom::typeCString
&& "malformed method list");
998 // this objc pass happens after cstrings are coalesced, so we can just compare the atom addres instead of its content
999 if ( baseMethodListMethodNameAtoms
.count(target
) != 0 ) {
1000 warning("%s method '%s' in category from %s overrides method from class in %s",
1001 (meta
? "meta" : "instance"), target
->rawContentPointer(),
1002 categoryMethodListAtom
->file()->path(), baseMethodList
->file()->path() );
1004 if ( categoryMethodNameAtoms
.count(target
) != 0 ) {
1005 warning("%s method '%s' in category from %s conflicts with same method from another category",
1006 (meta
? "meta" : "instance"), target
->rawContentPointer(),
1007 categoryMethodListAtom
->file()->path());
1009 categoryMethodNameAtoms
.insert(target
);
1012 slide
+= 3*sizeof(pint_t
) * MethodList
<A
>::count(state
, categoryMethodListAtom
);
1015 // add method list from base class last
1016 if ( baseMethodList
!= NULL
) {
1017 for (ld::Fixup::iterator fit
=baseMethodList
->fixupsBegin(); fit
!= baseMethodList
->fixupsEnd(); ++fit
) {
1018 ld::Fixup fixup
= *fit
;
1019 fixup
.offsetInAtom
+= slide
;
1020 _fixups
.push_back(fixup
);
1026 template <typename A
>
1027 ProtocolListAtom
<A
>::ProtocolListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
1028 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
1029 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
1030 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
1031 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _protocolCount(0)
1033 unsigned int fixupCount
= 0;
1034 if ( baseProtocolList
!= NULL
) {
1035 // if base class has protocol list, then associate new protocol list with file defining class
1036 _file
= baseProtocolList
->file();
1037 // calculate total size of merged protocol list
1038 _protocolCount
= ProtocolList
<A
>::count(state
, baseProtocolList
);
1039 deadAtoms
.insert(baseProtocolList
);
1040 fixupCount
= baseProtocolList
->fixupsEnd() - baseProtocolList
->fixupsBegin();
1042 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
1043 const ld::Atom
* categoryProtocolListAtom
= Category
<A
>::getProtocols(state
, *ait
);
1044 if ( categoryProtocolListAtom
!= NULL
) {
1045 _protocolCount
+= ProtocolList
<A
>::count(state
, categoryProtocolListAtom
);
1046 fixupCount
+= (categoryProtocolListAtom
->fixupsEnd() - categoryProtocolListAtom
->fixupsBegin());
1047 deadAtoms
.insert(categoryProtocolListAtom
);
1048 // if base class did not have protocol list, associate new protocol list with file the defined category
1049 if ( _file
== NULL
)
1050 _file
= categoryProtocolListAtom
->file();
1053 //fprintf(stderr, "total merged protocol count=%u\n", _protocolCount);
1054 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
1056 // copy fixups and adjust offsets
1057 _fixups
.reserve(fixupCount
);
1059 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
1060 const ld::Atom
* categoryProtocolListAtom
= Category
<A
>::getProtocols(state
, *it
);
1061 if ( categoryProtocolListAtom
!= NULL
) {
1062 for (ld::Fixup::iterator fit
=categoryProtocolListAtom
->fixupsBegin(); fit
!= categoryProtocolListAtom
->fixupsEnd(); ++fit
) {
1063 ld::Fixup fixup
= *fit
;
1064 fixup
.offsetInAtom
+= slide
;
1065 _fixups
.push_back(fixup
);
1066 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
1067 // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
1069 slide
+= sizeof(pint_t
) * ProtocolList
<A
>::count(state
, categoryProtocolListAtom
);
1072 // add method list from base class last
1073 if ( baseProtocolList
!= NULL
) {
1074 for (ld::Fixup::iterator fit
=baseProtocolList
->fixupsBegin(); fit
!= baseProtocolList
->fixupsEnd(); ++fit
) {
1075 ld::Fixup fixup
= *fit
;
1076 fixup
.offsetInAtom
+= slide
;
1077 _fixups
.push_back(fixup
);
1083 template <typename A
>
1084 PropertyListAtom
<A
>::PropertyListAtom(ld::Internal
& state
, const ld::Atom
* basePropertyList
,
1085 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
1086 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
1087 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
1088 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _propertyCount(0)
1090 unsigned int fixupCount
= 0;
1091 if ( basePropertyList
!= NULL
) {
1092 // if base class has property list, then associate new property list with file defining class
1093 _file
= basePropertyList
->file();
1094 // calculate total size of merged property list
1095 _propertyCount
= PropertyList
<A
>::count(state
, basePropertyList
);
1096 deadAtoms
.insert(basePropertyList
);
1097 fixupCount
= basePropertyList
->fixupsEnd() - basePropertyList
->fixupsBegin();
1099 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
1100 const ld::Atom
* categoryPropertyListAtom
= Category
<A
>::getProperties(state
, *ait
);
1101 if ( categoryPropertyListAtom
!= NULL
) {
1102 _propertyCount
+= PropertyList
<A
>::count(state
, categoryPropertyListAtom
);
1103 fixupCount
+= (categoryPropertyListAtom
->fixupsEnd() - categoryPropertyListAtom
->fixupsBegin());
1104 deadAtoms
.insert(categoryPropertyListAtom
);
1105 // if base class did not have property list, associate new property list with file the defined category
1106 if ( _file
== NULL
)
1107 _file
= categoryPropertyListAtom
->file();
1110 //fprintf(stderr, "total merged property count=%u\n", _propertyCount);
1111 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
1113 // copy fixups and adjust offsets
1114 _fixups
.reserve(fixupCount
);
1116 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
1117 const ld::Atom
* categoryPropertyListAtom
= Category
<A
>::getProperties(state
, *it
);
1118 if ( categoryPropertyListAtom
!= NULL
) {
1119 for (ld::Fixup::iterator fit
=categoryPropertyListAtom
->fixupsBegin(); fit
!= categoryPropertyListAtom
->fixupsEnd(); ++fit
) {
1120 ld::Fixup fixup
= *fit
;
1121 fixup
.offsetInAtom
+= slide
;
1122 _fixups
.push_back(fixup
);
1123 //fprintf(stderr, "offset=0x%08X, binding=%d\n", fixup.offsetInAtom, fixup.binding);
1124 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
1125 // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
1126 //else if ( fixup.binding == ld::Fixup::bindingsIndirectlyBound )
1127 // fprintf(stderr, "offset=0x%08X, indirect index=%u, name=%s\n", fixup.offsetInAtom, fixup.u.bindingIndex,
1128 // (char*)(state.indirectBindingTable[fixup.u.bindingIndex]->rawContentPointer()));
1130 slide
+= 2*sizeof(pint_t
) * PropertyList
<A
>::count(state
, categoryPropertyListAtom
);
1133 // add method list from base class last
1134 if ( basePropertyList
!= NULL
) {
1135 for (ld::Fixup::iterator fit
=basePropertyList
->fixupsBegin(); fit
!= basePropertyList
->fixupsEnd(); ++fit
) {
1136 ld::Fixup fixup
= *fit
;
1137 fixup
.offsetInAtom
+= slide
;
1138 _fixups
.push_back(fixup
);
1146 void doPass(const Options
& opts
, ld::Internal
& state
)
1148 // only make image info section if objc was used
1149 if ( state
.objcObjectConstraint
!= ld::File::objcConstraintNone
) {
1151 // verify dylibs are GC compatible with object files
1152 if ( state
.objcObjectConstraint
!= state
.objcDylibConstraint
) {
1153 if ( (state
.objcDylibConstraint
== ld::File::objcConstraintRetainRelease
)
1154 && (state
.objcObjectConstraint
== ld::File::objcConstraintGC
) ) {
1155 throw "Linked dylibs built for retain/release but object files built for GC-only";
1157 else if ( (state
.objcDylibConstraint
== ld::File::objcConstraintGC
)
1158 && (state
.objcObjectConstraint
== ld::File::objcConstraintRetainRelease
) ) {
1159 throw "Linked dylibs built for GC-only but object files built for retain/release";
1163 const bool compaction
= opts
.objcGcCompaction();
1165 // add image info atom
1166 switch ( opts
.architecture() ) {
1167 #if SUPPORT_ARCH_x86_64
1168 case CPU_TYPE_X86_64
:
1169 state
.addAtom(*new ObjCImageInfoAtom
<x86_64
>(state
.objcObjectConstraint
, compaction
,
1173 #if SUPPORT_ARCH_i386
1175 state
.addAtom(*new ObjCImageInfoAtom
<x86
>(state
.objcObjectConstraint
, compaction
,
1176 opts
.objCABIVersion2POverride() ? true : false));
1180 state
.addAtom(*new ObjCImageInfoAtom
<arm
>(state
.objcObjectConstraint
, compaction
,
1184 assert(0 && "unknown objc arch");
1188 if ( opts
.objcCategoryMerging() ) {
1189 // optimize classes defined in this linkage unit by merging in categories also in this linkage unit
1190 switch ( opts
.architecture() ) {
1191 #if SUPPORT_ARCH_x86_64
1192 case CPU_TYPE_X86_64
:
1193 OptimizeCategories
<x86_64
>::doit(opts
, state
);
1196 #if SUPPORT_ARCH_i386
1198 // disable optimization until fully tested
1199 if ( opts
.objCABIVersion2POverride() )
1200 OptimizeCategories
<x86
>::doit(opts
, state
);
1203 #if SUPPORT_ARCH_arm_any
1205 // disable optimization until fully tested
1206 OptimizeCategories
<arm
>::doit(opts
, state
);
1210 assert(0 && "unknown objc arch");
1217 } // namespace passes