1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2010 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_IS_REPLACEMENT (1<<0)
54 #define OBJC_IMAGE_SUPPORTS_GC (1<<1)
55 #define OBJC_IMAGE_REQUIRES_GC (1<<2)
56 #define OBJC_IMAGE_OPTIMIZED_BY_DYLD (1<<3)
57 #define OBJC_IMAGE_SUPPORTS_COMPACTION (1<<4)
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 objcReplacementClasses
, bool abi2
);
70 virtual const ld::File
* file() const { return NULL
; }
71 virtual bool translationUnitSource(const char** dir
, const char**) const
73 virtual const char* name() const { return "objc image info"; }
74 virtual uint64_t size() const { return sizeof(objc_image_info
); }
75 virtual uint64_t objectAddress() const { return 0; }
76 virtual void setScope(Scope
) { }
77 virtual void copyRawContent(uint8_t buffer
[]) const {
78 memcpy(buffer
, &_content
, sizeof(objc_image_info
));
82 objc_image_info _content
;
84 static ld::Section _s_sectionABI1
;
85 static ld::Section _s_sectionABI2
;
88 template <typename A
> ld::Section ObjCImageInfoAtom
<A
>::_s_sectionABI1("__OBJC", "__image_info", ld::Section::typeUnclassified
);
89 template <typename A
> ld::Section ObjCImageInfoAtom
<A
>::_s_sectionABI2("__DATA", "__objc_imageinfo", ld::Section::typeUnclassified
);
93 ObjCImageInfoAtom
<A
>::ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint
, bool compaction
,
94 bool objcReplacementClasses
, bool abi2
)
95 : ld::Atom(abi2
? _s_sectionABI2
: _s_sectionABI1
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
96 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
97 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(2))
101 if ( objcReplacementClasses
)
102 value
= OBJC_IMAGE_IS_REPLACEMENT
;
103 switch ( objcConstraint
) {
104 case ld::File::objcConstraintNone
:
105 case ld::File::objcConstraintRetainRelease
:
107 warning("ignoring -objc_gc_compaction because code not compiled for ObjC garbage collection");
109 case ld::File::objcConstraintRetainReleaseOrGC
:
110 value
|= OBJC_IMAGE_SUPPORTS_GC
;
112 value
|= OBJC_IMAGE_SUPPORTS_COMPACTION
;
114 case ld::File::objcConstraintGC
:
115 value
|= OBJC_IMAGE_SUPPORTS_GC
| OBJC_IMAGE_REQUIRES_GC
;
117 value
|= OBJC_IMAGE_SUPPORTS_COMPACTION
;
121 _content
.version
= 0;
122 A::P::E::set32(_content
.flags
, value
);
128 // This class is for a new Atom which is an ObjC method list created by merging method lists from categories
130 template <typename A
>
131 class MethodListAtom
: public ld::Atom
{
133 MethodListAtom(ld::Internal
& state
, const ld::Atom
* baseMethodList
, bool meta
,
134 const std::vector
<const ld::Atom
*>* categories
,
135 std::set
<const ld::Atom
*>& deadAtoms
);
137 virtual const ld::File
* file() const { return _file
; }
138 virtual bool translationUnitSource(const char** dir
, const char**) const
140 virtual const char* name() const { return "objc merged method list"; }
141 virtual uint64_t size() const { return _methodCount
*3*sizeof(pint_t
) + 8; }
142 virtual uint64_t objectAddress() const { return 0; }
143 virtual void setScope(Scope
) { }
144 virtual void copyRawContent(uint8_t buffer
[]) const {
145 bzero(buffer
, size());
146 A::P::E::set32(*((uint32_t*)(&buffer
[0])), 24);
147 A::P::E::set32(*((uint32_t*)(&buffer
[4])), _methodCount
);
149 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
150 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
153 typedef typename
A::P::uint_t pint_t
;
155 const ld::File
* _file
;
156 unsigned int _methodCount
;
157 std::vector
<ld::Fixup
> _fixups
;
159 static ld::Section _s_section
;
162 template <typename A
>
163 ld::Section MethodListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
167 // This class is for a new Atom which is an ObjC protocol list created by merging protocol lists from categories
169 template <typename A
>
170 class ProtocolListAtom
: public ld::Atom
{
172 ProtocolListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
173 const std::vector
<const ld::Atom
*>* categories
,
174 std::set
<const ld::Atom
*>& deadAtoms
);
176 virtual const ld::File
* file() const { return _file
; }
177 virtual bool translationUnitSource(const char** dir
, const char**) const
179 virtual const char* name() const { return "objc merged protocol list"; }
180 virtual uint64_t size() const { return (_protocolCount
+1)*sizeof(pint_t
); }
181 virtual uint64_t objectAddress() const { return 0; }
182 virtual void setScope(Scope
) { }
183 virtual void copyRawContent(uint8_t buffer
[]) const {
184 bzero(buffer
, size());
185 A::P::setP(*((pint_t
*)(buffer
)), _protocolCount
);
187 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
188 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
191 typedef typename
A::P::uint_t pint_t
;
193 const ld::File
* _file
;
194 unsigned int _protocolCount
;
195 std::vector
<ld::Fixup
> _fixups
;
197 static ld::Section _s_section
;
200 template <typename A
>
201 ld::Section ProtocolListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
206 // This class is for a new Atom which is an ObjC property list created by merging property lists from categories
208 template <typename A
>
209 class PropertyListAtom
: public ld::Atom
{
211 PropertyListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
212 const std::vector
<const ld::Atom
*>* categories
,
213 std::set
<const ld::Atom
*>& deadAtoms
);
215 virtual const ld::File
* file() const { return _file
; }
216 virtual bool translationUnitSource(const char** dir
, const char**) const
218 virtual const char* name() const { return "objc merged property list"; }
219 virtual uint64_t size() const { return _propertyCount
*2*sizeof(pint_t
) + 8; }
220 virtual uint64_t objectAddress() const { return 0; }
221 virtual void setScope(Scope
) { }
222 virtual void copyRawContent(uint8_t buffer
[]) const {
223 bzero(buffer
, size());
224 A::P::E::set32(((uint32_t*)(buffer
))[0], 2*sizeof(pint_t
)); // sizeof(objc_property)
225 A::P::E::set32(((uint32_t*)(buffer
))[1], _propertyCount
);
227 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
228 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
231 typedef typename
A::P::uint_t pint_t
;
233 const ld::File
* _file
;
234 unsigned int _propertyCount
;
235 std::vector
<ld::Fixup
> _fixups
;
237 static ld::Section _s_section
;
240 template <typename A
>
241 ld::Section PropertyListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
248 // This class is used to create an Atom that replaces an atom from a .o file that holds a class_ro_t.
249 // It is needed because there is no way to add Fixups to an existing atom.
251 template <typename A
>
252 class ClassROOverlayAtom
: public ld::Atom
{
254 ClassROOverlayAtom(const ld::Atom
* classROAtom
);
256 // overrides of ld::Atom
257 virtual const ld::File
* file() const { return _atom
->file(); }
258 virtual bool translationUnitSource(const char** dir
, const char** nm
) const
259 { return _atom
->translationUnitSource(dir
, nm
); }
260 virtual const char* name() const { return _atom
->name(); }
261 virtual uint64_t size() const { return _atom
->size(); }
262 virtual uint64_t objectAddress() const { return _atom
->objectAddress(); }
263 virtual void copyRawContent(uint8_t buffer
[]) const
264 { _atom
->copyRawContent(buffer
); }
265 virtual const uint8_t* rawContentPointer() const
266 { return _atom
->rawContentPointer(); }
267 virtual unsigned long contentHash(const class ld::IndirectBindingTable
& ibt
) const
268 { return _atom
->contentHash(ibt
); }
269 virtual bool canCoalesceWith(const ld::Atom
& rhs
, const class ld::IndirectBindingTable
& ibt
) const
270 { return _atom
->canCoalesceWith(rhs
,ibt
); }
272 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
273 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
275 void addProtocolListFixup();
276 void addPropertyListFixup();
277 void addMethodListFixup();
280 typedef typename
A::P::uint_t pint_t
;
282 const ld::Atom
* _atom
;
283 std::vector
<ld::Fixup
> _fixups
;
286 template <typename A
>
287 ClassROOverlayAtom
<A
>::ClassROOverlayAtom(const ld::Atom
* classROAtom
)
288 : ld::Atom(classROAtom
->section(), ld::Atom::definitionRegular
, ld::Atom::combineNever
,
289 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
290 classROAtom
->symbolTableInclusion(), false, false, false, classROAtom
->alignment()),
293 // ensure all attributes are same as original
294 this->setAttributesFromAtom(*classROAtom
);
296 // copy fixups from orginal atom
297 for (ld::Fixup::iterator fit
=classROAtom
->fixupsBegin(); fit
!= classROAtom
->fixupsEnd(); ++fit
) {
298 ld::Fixup fixup
= *fit
;
299 _fixups
.push_back(fixup
);
305 // Base class for reading and updating existing ObjC atoms from .o files
307 template <typename A
>
310 static const ld::Atom
* getPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
, unsigned int offset
, bool* hasAddend
=NULL
);
311 static void setPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
,
312 unsigned int offset
, const ld::Atom
* newAtom
);
313 typedef typename
A::P::uint_t pint_t
;
316 template <typename A
>
317 const ld::Atom
* ObjCData
<A
>::getPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
, unsigned int offset
, bool* hasAddend
)
319 const ld::Atom
* target
= NULL
;
320 if ( hasAddend
!= NULL
)
322 for (ld::Fixup::iterator fit
=contentAtom
->fixupsBegin(); fit
!= contentAtom
->fixupsEnd(); ++fit
) {
323 if ( fit
->offsetInAtom
== offset
) {
324 switch ( fit
->binding
) {
325 case ld::Fixup::bindingsIndirectlyBound
:
326 target
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
328 case ld::Fixup::bindingDirectlyBound
:
329 target
= fit
->u
.target
;
331 case ld::Fixup::bindingNone
:
332 if ( fit
->kind
== ld::Fixup::kindAddAddend
) {
333 if ( hasAddend
!= NULL
)
345 template <typename A
>
346 void ObjCData
<A
>::setPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
,
347 unsigned int offset
, const ld::Atom
* newAtom
)
349 for (ld::Fixup::iterator fit
=contentAtom
->fixupsBegin(); fit
!= contentAtom
->fixupsEnd(); ++fit
) {
350 if ( fit
->offsetInAtom
== offset
) {
351 switch ( fit
->binding
) {
352 case ld::Fixup::bindingsIndirectlyBound
:
353 state
.indirectBindingTable
[fit
->u
.bindingIndex
] = newAtom
;
355 case ld::Fixup::bindingDirectlyBound
:
356 fit
->u
.target
= newAtom
;
363 assert(0 && "could not update method list");
369 // Helper class for reading and updating existing ObjC category atoms from .o files
371 template <typename A
>
372 class Category
: public ObjCData
<A
> {
374 static const ld::Atom
* getClass(ld::Internal
& state
, const ld::Atom
* contentAtom
);
375 static const ld::Atom
* getInstanceMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
);
376 static const ld::Atom
* getClassMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
);
377 static const ld::Atom
* getProtocols(ld::Internal
& state
, const ld::Atom
* contentAtom
);
378 static const ld::Atom
* getProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
);
379 static uint32_t size() { return 6*sizeof(pint_t
); }
381 typedef typename
A::P::uint_t pint_t
;
385 template <typename A
>
386 const ld::Atom
* Category
<A
>::getClass(ld::Internal
& state
, const ld::Atom
* contentAtom
)
388 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, sizeof(pint_t
)); // category_t.cls
391 template <typename A
>
392 const ld::Atom
* Category
<A
>::getInstanceMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
)
394 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 2*sizeof(pint_t
)); // category_t.instanceMethods
397 template <typename A
>
398 const ld::Atom
* Category
<A
>::getClassMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
)
400 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 3*sizeof(pint_t
)); // category_t.classMethods
403 template <typename A
>
404 const ld::Atom
* Category
<A
>::getProtocols(ld::Internal
& state
, const ld::Atom
* contentAtom
)
406 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 4*sizeof(pint_t
)); // category_t.protocols
409 template <typename A
>
410 const ld::Atom
* Category
<A
>::getProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
)
412 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 5*sizeof(pint_t
)); // category_t.instanceProperties
416 template <typename A
>
417 class MethodList
: public ObjCData
<A
> {
419 static uint32_t count(ld::Internal
& state
, const ld::Atom
* methodListAtom
) {
420 const uint32_t* methodListData
= (uint32_t*)(methodListAtom
->rawContentPointer());
421 return A::P::E::get32(methodListData
[1]); // method_list_t.count
425 template <typename A
>
426 class ProtocolList
: public ObjCData
<A
> {
428 static uint32_t count(ld::Internal
& state
, const ld::Atom
* protocolListAtom
) {
429 pint_t
* protocolListData
= (pint_t
*)(protocolListAtom
->rawContentPointer());
430 return A::P::getP(*protocolListData
); // protocol_list_t.count
433 typedef typename
A::P::uint_t pint_t
;
436 template <typename A
>
437 class PropertyList
: public ObjCData
<A
> {
439 static uint32_t count(ld::Internal
& state
, const ld::Atom
* protocolListAtom
) {
440 uint32_t* protocolListData
= (uint32_t*)(protocolListAtom
->rawContentPointer());
441 return A::P::E::get32(protocolListData
[1]); // property_list_t.count
444 typedef typename
A::P::uint_t pint_t
;
450 // Helper class for reading and updating existing ObjC class atoms from .o files
452 template <typename A
>
453 class Class
: public ObjCData
<A
> {
455 static const ld::Atom
* getInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
);
456 static const ld::Atom
* getInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
);
457 static const ld::Atom
* getInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
);
458 static const ld::Atom
* getClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
);
459 static const ld::Atom
* setInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
460 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
461 static const ld::Atom
* setInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
462 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
463 static const ld::Atom
* setInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,
464 const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
465 static const ld::Atom
* setClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
466 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
467 static const ld::Atom
* setClassProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
468 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
469 static uint32_t size() { return 5*sizeof(pint_t
); }
470 static unsigned int class_ro_header_size();
472 typedef typename
A::P::uint_t pint_t
;
473 static const ld::Atom
* getROData(ld::Internal
& state
, const ld::Atom
* classAtom
);
476 template <> unsigned int Class
<x86_64
>::class_ro_header_size() { return 16; }
477 template <> unsigned int Class
<arm
>::class_ro_header_size() { return 12;}
478 template <> unsigned int Class
<x86
>::class_ro_header_size() { return 12; }
481 template <typename A
>
482 const ld::Atom
* Class
<A
>::getROData(ld::Internal
& state
, const ld::Atom
* classAtom
)
484 return ObjCData
<A
>::getPointerInContent(state
, classAtom
, 4*sizeof(pint_t
)); // class_t.data
488 template <typename A
>
489 const ld::Atom
* Class
<A
>::getInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
)
491 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
492 assert(classROAtom
!= NULL
);
493 return ObjCData
<A
>::getPointerInContent(state
, classROAtom
, class_ro_header_size() + 2*sizeof(pint_t
)); // class_ro_t.baseMethods
496 template <typename A
>
497 const ld::Atom
* Class
<A
>::getInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
)
499 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
500 assert(classROAtom
!= NULL
);
501 return ObjCData
<A
>::getPointerInContent(state
, classROAtom
, class_ro_header_size() + 3*sizeof(pint_t
)); // class_ro_t.baseProtocols
504 template <typename A
>
505 const ld::Atom
* Class
<A
>::getInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
)
507 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
508 assert(classROAtom
!= NULL
);
509 return ObjCData
<A
>::getPointerInContent(state
, classROAtom
, class_ro_header_size() + 6*sizeof(pint_t
)); // class_ro_t.baseProperties
512 template <typename A
>
513 const ld::Atom
* Class
<A
>::getClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
)
515 const ld::Atom
* metaClassAtom
= ObjCData
<A
>::getPointerInContent(state
, classAtom
, 0); // class_t.isa
516 assert(metaClassAtom
!= NULL
);
517 return Class
<A
>::getInstanceMethodList(state
, metaClassAtom
);
520 template <typename A
>
521 const ld::Atom
* Class
<A
>::setInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
522 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
524 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
525 assert(classROAtom
!= NULL
);
526 // if the base class does not already have a method list, we need to create an overlay
527 if ( getInstanceMethodList(state
, classAtom
) == NULL
) {
528 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(classROAtom
);
529 //fprintf(stderr, "replace class RO atom %p with %p for method list in class atom %s\n", classROAtom, overlay, classAtom->name());
530 overlay
->addMethodListFixup();
531 ObjCData
<A
>::setPointerInContent(state
, classAtom
, 4*sizeof(pint_t
), overlay
); // class_t.data
532 deadAtoms
.insert(classROAtom
);
533 ObjCData
<A
>::setPointerInContent(state
, overlay
, class_ro_header_size() + 2*sizeof(pint_t
), methodListAtom
); // class_ro_t.baseMethods
536 ObjCData
<A
>::setPointerInContent(state
, classROAtom
, class_ro_header_size() + 2*sizeof(pint_t
), methodListAtom
); // class_ro_t.baseMethods
537 return NULL
; // means classRO atom was not replaced
540 template <typename A
>
541 const ld::Atom
* Class
<A
>::setInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
542 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
544 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
545 assert(classROAtom
!= NULL
);
546 // if the base class does not already have a protocol list, we need to create an overlay
547 if ( getInstanceProtocolList(state
, classAtom
) == NULL
) {
548 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(classROAtom
);
549 //fprintf(stderr, "replace class RO atom %p with %p for protocol list in class atom %s\n", classROAtom, overlay, classAtom->name());
550 overlay
->addProtocolListFixup();
551 ObjCData
<A
>::setPointerInContent(state
, classAtom
, 4*sizeof(pint_t
), overlay
); // class_t.data
552 deadAtoms
.insert(classROAtom
);
553 ObjCData
<A
>::setPointerInContent(state
, overlay
, class_ro_header_size() + 3*sizeof(pint_t
), protocolListAtom
); // class_ro_t.baseProtocols
556 //fprintf(stderr, "set class RO atom %p protocol list in class atom %s\n", classROAtom, classAtom->name());
557 ObjCData
<A
>::setPointerInContent(state
, classROAtom
, class_ro_header_size() + 3*sizeof(pint_t
), protocolListAtom
); // class_ro_t.baseProtocols
558 return NULL
; // means classRO atom was not replaced
561 template <typename A
>
562 const ld::Atom
* Class
<A
>::setClassProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
563 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
565 // meta class also points to same protocol list as class
566 const ld::Atom
* metaClassAtom
= ObjCData
<A
>::getPointerInContent(state
, classAtom
, 0); // class_t.isa
567 //fprintf(stderr, "setClassProtocolList(), classAtom=%p %s, metaClass=%p %s\n", classAtom, classAtom->name(), metaClassAtom, metaClassAtom->name());
568 assert(metaClassAtom
!= NULL
);
569 return setInstanceProtocolList(state
, metaClassAtom
, protocolListAtom
, deadAtoms
);
574 template <typename A
>
575 const ld::Atom
* Class
<A
>::setInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,
576 const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
578 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
579 assert(classROAtom
!= NULL
);
580 // if the base class does not already have a property list, we need to create an overlay
581 if ( getInstancePropertyList(state
, classAtom
) == NULL
) {
582 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(classROAtom
);
583 //fprintf(stderr, "replace class RO atom %p with %p for property list in class atom %s\n", classROAtom, overlay, classAtom->name());
584 overlay
->addPropertyListFixup();
585 ObjCData
<A
>::setPointerInContent(state
, classAtom
, 4*sizeof(pint_t
), overlay
); // class_t.data
586 deadAtoms
.insert(classROAtom
);
587 ObjCData
<A
>::setPointerInContent(state
, overlay
, class_ro_header_size() + 6*sizeof(pint_t
), propertyListAtom
); // class_ro_t.baseProperties
590 ObjCData
<A
>::setPointerInContent(state
, classROAtom
, class_ro_header_size() + 6*sizeof(pint_t
), propertyListAtom
); // class_ro_t.baseProperties
591 return NULL
; // means classRO atom was not replaced
594 template <typename A
>
595 const ld::Atom
* Class
<A
>::setClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
596 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
598 // class methods is just instance methods of metaClass
599 const ld::Atom
* metaClassAtom
= ObjCData
<A
>::getPointerInContent(state
, classAtom
, 0); // class_t.isa
600 assert(metaClassAtom
!= NULL
);
601 return setInstanceMethodList(state
, metaClassAtom
, methodListAtom
, deadAtoms
);
607 void ClassROOverlayAtom
<x86_64
>::addMethodListFixup()
609 const ld::Atom
* targetAtom
= this; // temporary
610 uint32_t offset
= Class
<x86_64
>::class_ro_header_size() + 2*8; // class_ro_t.baseMethods
611 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian64
, targetAtom
));
615 void ClassROOverlayAtom
<arm
>::addMethodListFixup()
617 const ld::Atom
* targetAtom
= this; // temporary
618 uint32_t offset
= Class
<arm
>::class_ro_header_size() + 2*4; // class_ro_t.baseMethods
619 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
623 void ClassROOverlayAtom
<x86
>::addMethodListFixup()
625 const ld::Atom
* targetAtom
= this; // temporary
626 uint32_t offset
= Class
<x86
>::class_ro_header_size() + 2*4; // class_ro_t.baseMethods
627 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
633 void ClassROOverlayAtom
<x86_64
>::addProtocolListFixup()
635 const ld::Atom
* targetAtom
= this; // temporary
636 uint32_t offset
= Class
<x86_64
>::class_ro_header_size() + 3*8; // class_ro_t.baseProtocols
637 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian64
, targetAtom
));
641 void ClassROOverlayAtom
<arm
>::addProtocolListFixup()
643 const ld::Atom
* targetAtom
= this; // temporary
644 uint32_t offset
= Class
<arm
>::class_ro_header_size() + 3*4; // class_ro_t.baseProtocols
645 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
649 void ClassROOverlayAtom
<x86
>::addProtocolListFixup()
651 const ld::Atom
* targetAtom
= this; // temporary
652 uint32_t offset
= Class
<x86
>::class_ro_header_size() + 3*4; // class_ro_t.baseProtocols
653 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
658 void ClassROOverlayAtom
<x86_64
>::addPropertyListFixup()
660 const ld::Atom
* targetAtom
= this; // temporary
661 uint32_t offset
= Class
<x86_64
>::class_ro_header_size() + 6*8; // class_ro_t.baseProperties
662 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian64
, targetAtom
));
666 void ClassROOverlayAtom
<arm
>::addPropertyListFixup()
668 const ld::Atom
* targetAtom
= this; // temporary
669 uint32_t offset
= Class
<arm
>::class_ro_header_size() + 6*4; // class_ro_t.baseProperties
670 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
674 void ClassROOverlayAtom
<x86
>::addPropertyListFixup()
676 const ld::Atom
* targetAtom
= this; // temporary
677 uint32_t offset
= Class
<x86
>::class_ro_header_size() + 6*4; // class_ro_t.baseProperties
678 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
685 // Encapsulates merging of ObjC categories
687 template <typename A
>
688 class OptimizeCategories
{
690 static void doit(const Options
& opts
, ld::Internal
& state
);
691 static bool hasInstanceMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
692 static bool hasClassMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
693 static bool hasProtocols(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
694 static bool hasProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
697 static unsigned int class_ro_baseMethods_offset();
699 typedef typename
A::P::uint_t pint_t
;
704 template <typename A
>
705 bool OptimizeCategories
<A
>::hasInstanceMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
707 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
708 const ld::Atom
* categoryAtom
= *it
;
709 const ld::Atom
* methodList
= Category
<A
>::getInstanceMethods(state
, categoryAtom
);
710 if ( methodList
!= NULL
) {
711 if ( MethodList
<A
>::count(state
, methodList
) > 0 )
719 template <typename A
>
720 bool OptimizeCategories
<A
>::hasClassMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
722 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
723 const ld::Atom
* categoryAtom
= *it
;
724 const ld::Atom
* methodList
= Category
<A
>::getClassMethods(state
, categoryAtom
);
725 if ( methodList
!= NULL
) {
726 if ( MethodList
<A
>::count(state
, methodList
) > 0 )
733 template <typename A
>
734 bool OptimizeCategories
<A
>::hasProtocols(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
736 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
737 const ld::Atom
* categoryAtom
= *it
;
738 const ld::Atom
* protocolListAtom
= Category
<A
>::getProtocols(state
, categoryAtom
);
739 if ( protocolListAtom
!= NULL
) {
740 if ( ProtocolList
<A
>::count(state
, protocolListAtom
) > 0 ) {
749 template <typename A
>
750 bool OptimizeCategories
<A
>::hasProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
752 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
753 const ld::Atom
* categoryAtom
= *it
;
754 const ld::Atom
* propertyListAtom
= Category
<A
>::getProperties(state
, categoryAtom
);
755 if ( propertyListAtom
!= NULL
) {
756 if ( PropertyList
<A
>::count(state
, propertyListAtom
) > 0 )
766 // Helper for std::remove_if
768 class OptimizedAway
{
770 OptimizedAway(const std::set
<const ld::Atom
*>& oa
) : _dead(oa
) {}
771 bool operator()(const ld::Atom
* atom
) const {
772 return ( _dead
.count(atom
) != 0 );
775 const std::set
<const ld::Atom
*>& _dead
;
778 template <typename A
>
779 void OptimizeCategories
<A
>::doit(const Options
& opts
, ld::Internal
& state
)
781 // first find all categories referenced by __objc_nlcatlist section
782 std::set
<const ld::Atom
*> nlcatListAtoms
;
783 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
784 ld::Internal::FinalSection
* sect
= *sit
;
785 if ( (strcmp(sect
->sectionName(), "__objc_nlcatlist") == 0) && (strcmp(sect
->segmentName(), "__DATA") == 0) ) {
786 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
787 const ld::Atom
* categoryListElementAtom
= *ait
;
788 for (unsigned int offset
=0; offset
< categoryListElementAtom
->size(); offset
+= sizeof(pint_t
)) {
789 const ld::Atom
* categoryAtom
= ObjCData
<A
>::getPointerInContent(state
, categoryListElementAtom
, offset
);
790 //fprintf(stderr, "offset=%d, cat=%p %s\n", offset, categoryAtom, categoryAtom->name());
791 assert(categoryAtom
!= NULL
);
792 nlcatListAtoms
.insert(categoryAtom
);
798 // build map of all classes in this image that have categories on them
799 typedef std::map
<const ld::Atom
*, std::vector
<const ld::Atom
*>*> CatMap
;
800 CatMap classToCategories
;
801 std::set
<const ld::Atom
*> deadAtoms
;
802 ld::Internal::FinalSection
* methodListSection
= NULL
;
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 ( sect
->type() == ld::Section::typeObjC2CategoryList
) {
806 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
807 const ld::Atom
* categoryListElementAtom
= *ait
;
809 const ld::Atom
* categoryAtom
= ObjCData
<A
>::getPointerInContent(state
, categoryListElementAtom
, 0, &hasAddend
);
810 if ( hasAddend
|| (categoryAtom
->symbolTableInclusion() == ld::Atom::symbolTableNotIn
)) {
811 //<rdar://problem/8309530> gcc-4.0 uses 'L' labels on categories which disables this optimization
812 //warning("__objc_catlist element does not point to start of category");
815 assert(categoryAtom
!= NULL
);
816 assert(categoryAtom
->size() == Category
<A
>::size());
817 // ignore categories also in __objc_nlcatlist
818 if ( nlcatListAtoms
.count(categoryAtom
) != 0 )
820 const ld::Atom
* categoryOnClassAtom
= Category
<A
>::getClass(state
, categoryAtom
);
821 assert(categoryOnClassAtom
!= NULL
);
822 if ( categoryOnClassAtom
->definition() != ld::Atom::definitionProxy
) {
823 // only look at classes defined in this image
824 CatMap::iterator pos
= classToCategories
.find(categoryOnClassAtom
);
825 if ( pos
== classToCategories
.end() ) {
826 classToCategories
[categoryOnClassAtom
] = new std::vector
<const ld::Atom
*>();
828 classToCategories
[categoryOnClassAtom
]->push_back(categoryAtom
);
829 // mark category atom and catlist atom as dead
830 deadAtoms
.insert(categoryAtom
);
831 deadAtoms
.insert(categoryListElementAtom
);
835 // record method list section
836 if ( (strcmp(sect
->sectionName(), "__objc_const") == 0) && (strcmp(sect
->segmentName(), "__DATA") == 0) )
837 methodListSection
= sect
;
840 // if found some categories
841 if ( classToCategories
.size() != 0 ) {
842 assert(methodListSection
!= NULL
);
843 // alter each class definition to have new method list which includes all category methods
844 for (CatMap::iterator it
=classToCategories
.begin(); it
!= classToCategories
.end(); ++it
) {
845 const ld::Atom
* classAtom
= it
->first
;
846 const std::vector
<const ld::Atom
*>* categories
= it
->second
;
847 assert(categories
->size() != 0);
848 // if any category adds instance methods, generate new merged method list, and replace
849 if ( OptimizeCategories
<A
>::hasInstanceMethods(state
, categories
) ) {
850 const ld::Atom
* baseInstanceMethodListAtom
= Class
<A
>::getInstanceMethodList(state
, classAtom
);
851 const ld::Atom
* newInstanceMethodListAtom
= new MethodListAtom
<A
>(state
, baseInstanceMethodListAtom
, false, categories
, deadAtoms
);
852 const ld::Atom
* newClassRO
= Class
<A
>::setInstanceMethodList(state
, classAtom
, newInstanceMethodListAtom
, deadAtoms
);
853 // add new method list to final sections
854 methodListSection
->atoms
.push_back(newInstanceMethodListAtom
);
855 if ( newClassRO
!= NULL
) {
856 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
857 methodListSection
->atoms
.push_back(newClassRO
);
860 // if any category adds class methods, generate new merged method list, and replace
861 if ( OptimizeCategories
<A
>::hasClassMethods(state
, categories
) ) {
862 const ld::Atom
* baseClassMethodListAtom
= Class
<A
>::getClassMethodList(state
, classAtom
);
863 const ld::Atom
* newClassMethodListAtom
= new MethodListAtom
<A
>(state
, baseClassMethodListAtom
, true, categories
, deadAtoms
);
864 const ld::Atom
* newClassRO
= Class
<A
>::setClassMethodList(state
, classAtom
, newClassMethodListAtom
, deadAtoms
);
865 // add new method list to final sections
866 methodListSection
->atoms
.push_back(newClassMethodListAtom
);
867 if ( newClassRO
!= NULL
) {
868 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
869 methodListSection
->atoms
.push_back(newClassRO
);
872 // if any category adds protocols, generate new merged protocol list, and replace
873 if ( OptimizeCategories
<A
>::hasProtocols(state
, categories
) ) {
874 const ld::Atom
* baseProtocolListAtom
= Class
<A
>::getInstanceProtocolList(state
, classAtom
);
875 const ld::Atom
* newProtocolListAtom
= new ProtocolListAtom
<A
>(state
, baseProtocolListAtom
, categories
, deadAtoms
);
876 const ld::Atom
* newClassRO
= Class
<A
>::setInstanceProtocolList(state
, classAtom
, newProtocolListAtom
, deadAtoms
);
877 const ld::Atom
* newMetaClassRO
= Class
<A
>::setClassProtocolList(state
, classAtom
, newProtocolListAtom
, deadAtoms
);
878 // add new protocol list to final sections
879 methodListSection
->atoms
.push_back(newProtocolListAtom
);
880 if ( newClassRO
!= NULL
) {
881 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
882 methodListSection
->atoms
.push_back(newClassRO
);
884 if ( newMetaClassRO
!= NULL
) {
885 assert(strcmp(newMetaClassRO
->section().sectionName(), "__objc_const") == 0);
886 methodListSection
->atoms
.push_back(newMetaClassRO
);
889 // if any category adds properties, generate new merged property list, and replace
890 if ( OptimizeCategories
<A
>::hasProperties(state
, categories
) ) {
891 const ld::Atom
* basePropertyListAtom
= Class
<A
>::getInstancePropertyList(state
, classAtom
);
892 const ld::Atom
* newPropertyListAtom
= new PropertyListAtom
<A
>(state
, basePropertyListAtom
, categories
, deadAtoms
);
893 const ld::Atom
* newClassRO
= Class
<A
>::setInstancePropertyList(state
, classAtom
, newPropertyListAtom
, deadAtoms
);
894 // add new property list to final sections
895 methodListSection
->atoms
.push_back(newPropertyListAtom
);
896 if ( newClassRO
!= NULL
) {
897 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
898 methodListSection
->atoms
.push_back(newClassRO
);
905 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
906 ld::Internal::FinalSection
* sect
= *sit
;
907 sect
->atoms
.erase(std::remove_if(sect
->atoms
.begin(), sect
->atoms
.end(), OptimizedAway(deadAtoms
)), sect
->atoms
.end());
913 template <typename A
>
914 MethodListAtom
<A
>::MethodListAtom(ld::Internal
& state
, const ld::Atom
* baseMethodList
, bool meta
,
915 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
916 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
917 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
918 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _methodCount(0)
920 unsigned int fixupCount
= 0;
921 // if base class has method list, then associate new method list with file defining class
922 if ( baseMethodList
!= NULL
) {
923 _file
= baseMethodList
->file();
924 // calculate total size of merge method lists
925 _methodCount
= MethodList
<A
>::count(state
, baseMethodList
);
926 deadAtoms
.insert(baseMethodList
);
927 fixupCount
= baseMethodList
->fixupsEnd() - baseMethodList
->fixupsBegin();
929 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
930 const ld::Atom
* categoryMethodListAtom
;
932 categoryMethodListAtom
= Category
<A
>::getClassMethods(state
, *ait
);
934 categoryMethodListAtom
= Category
<A
>::getInstanceMethods(state
, *ait
);
935 if ( categoryMethodListAtom
!= NULL
) {
936 _methodCount
+= MethodList
<A
>::count(state
, categoryMethodListAtom
);
937 fixupCount
+= (categoryMethodListAtom
->fixupsEnd() - categoryMethodListAtom
->fixupsBegin());
938 deadAtoms
.insert(categoryMethodListAtom
);
939 // if base class did not have method list, associate new method list with file the defined category
941 _file
= categoryMethodListAtom
->file();
944 //if ( baseMethodList != NULL )
945 // fprintf(stderr, "total merged method count=%u for baseMethodList=%s\n", _methodCount, baseMethodList->name());
947 // fprintf(stderr, "total merged method count=%u\n", _methodCount);
948 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
950 // copy fixups and adjust offsets (in reverse order to simulator objc runtime)
951 _fixups
.reserve(fixupCount
);
953 for (std::vector
<const ld::Atom
*>::const_reverse_iterator rit
=categories
->rbegin(); rit
!= categories
->rend(); ++rit
) {
954 const ld::Atom
* categoryMethodListAtom
;
956 categoryMethodListAtom
= Category
<A
>::getClassMethods(state
, *rit
);
958 categoryMethodListAtom
= Category
<A
>::getInstanceMethods(state
, *rit
);
959 if ( categoryMethodListAtom
!= NULL
) {
960 for (ld::Fixup::iterator fit
=categoryMethodListAtom
->fixupsBegin(); fit
!= categoryMethodListAtom
->fixupsEnd(); ++fit
) {
961 ld::Fixup fixup
= *fit
;
962 fixup
.offsetInAtom
+= slide
;
963 _fixups
.push_back(fixup
);
964 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
965 // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
967 slide
+= 3*sizeof(pint_t
) * MethodList
<A
>::count(state
, categoryMethodListAtom
);
970 // add method list from base class last
971 if ( baseMethodList
!= NULL
) {
972 for (ld::Fixup::iterator fit
=baseMethodList
->fixupsBegin(); fit
!= baseMethodList
->fixupsEnd(); ++fit
) {
973 ld::Fixup fixup
= *fit
;
974 fixup
.offsetInAtom
+= slide
;
975 _fixups
.push_back(fixup
);
981 template <typename A
>
982 ProtocolListAtom
<A
>::ProtocolListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
983 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
984 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
985 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
986 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _protocolCount(0)
988 unsigned int fixupCount
= 0;
989 if ( baseProtocolList
!= NULL
) {
990 // if base class has protocol list, then associate new protocol list with file defining class
991 _file
= baseProtocolList
->file();
992 // calculate total size of merged protocol list
993 _protocolCount
= ProtocolList
<A
>::count(state
, baseProtocolList
);
994 deadAtoms
.insert(baseProtocolList
);
995 fixupCount
= baseProtocolList
->fixupsEnd() - baseProtocolList
->fixupsBegin();
997 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
998 const ld::Atom
* categoryProtocolListAtom
= Category
<A
>::getProtocols(state
, *ait
);
999 if ( categoryProtocolListAtom
!= NULL
) {
1000 _protocolCount
+= ProtocolList
<A
>::count(state
, categoryProtocolListAtom
);
1001 fixupCount
+= (categoryProtocolListAtom
->fixupsEnd() - categoryProtocolListAtom
->fixupsBegin());
1002 deadAtoms
.insert(categoryProtocolListAtom
);
1003 // if base class did not have protocol list, associate new protocol list with file the defined category
1004 if ( _file
== NULL
)
1005 _file
= categoryProtocolListAtom
->file();
1008 //fprintf(stderr, "total merged protocol count=%u\n", _protocolCount);
1009 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
1011 // copy fixups and adjust offsets
1012 _fixups
.reserve(fixupCount
);
1014 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
1015 const ld::Atom
* categoryProtocolListAtom
= Category
<A
>::getProtocols(state
, *it
);
1016 if ( categoryProtocolListAtom
!= NULL
) {
1017 for (ld::Fixup::iterator fit
=categoryProtocolListAtom
->fixupsBegin(); fit
!= categoryProtocolListAtom
->fixupsEnd(); ++fit
) {
1018 ld::Fixup fixup
= *fit
;
1019 fixup
.offsetInAtom
+= slide
;
1020 _fixups
.push_back(fixup
);
1021 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
1022 // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
1024 slide
+= sizeof(pint_t
) * ProtocolList
<A
>::count(state
, categoryProtocolListAtom
);
1027 // add method list from base class last
1028 if ( baseProtocolList
!= NULL
) {
1029 for (ld::Fixup::iterator fit
=baseProtocolList
->fixupsBegin(); fit
!= baseProtocolList
->fixupsEnd(); ++fit
) {
1030 ld::Fixup fixup
= *fit
;
1031 fixup
.offsetInAtom
+= slide
;
1032 _fixups
.push_back(fixup
);
1038 template <typename A
>
1039 PropertyListAtom
<A
>::PropertyListAtom(ld::Internal
& state
, const ld::Atom
* basePropertyList
,
1040 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
1041 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
1042 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
1043 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _propertyCount(0)
1045 unsigned int fixupCount
= 0;
1046 if ( basePropertyList
!= NULL
) {
1047 // if base class has property list, then associate new property list with file defining class
1048 _file
= basePropertyList
->file();
1049 // calculate total size of merged property list
1050 _propertyCount
= PropertyList
<A
>::count(state
, basePropertyList
);
1051 deadAtoms
.insert(basePropertyList
);
1052 fixupCount
= basePropertyList
->fixupsEnd() - basePropertyList
->fixupsBegin();
1054 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
1055 const ld::Atom
* categoryPropertyListAtom
= Category
<A
>::getProperties(state
, *ait
);
1056 if ( categoryPropertyListAtom
!= NULL
) {
1057 _propertyCount
+= PropertyList
<A
>::count(state
, categoryPropertyListAtom
);
1058 fixupCount
+= (categoryPropertyListAtom
->fixupsEnd() - categoryPropertyListAtom
->fixupsBegin());
1059 deadAtoms
.insert(categoryPropertyListAtom
);
1060 // if base class did not have property list, associate new property list with file the defined category
1061 if ( _file
== NULL
)
1062 _file
= categoryPropertyListAtom
->file();
1065 //fprintf(stderr, "total merged property count=%u\n", _propertyCount);
1066 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
1068 // copy fixups and adjust offsets
1069 _fixups
.reserve(fixupCount
);
1071 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
1072 const ld::Atom
* categoryPropertyListAtom
= Category
<A
>::getProperties(state
, *it
);
1073 if ( categoryPropertyListAtom
!= NULL
) {
1074 for (ld::Fixup::iterator fit
=categoryPropertyListAtom
->fixupsBegin(); fit
!= categoryPropertyListAtom
->fixupsEnd(); ++fit
) {
1075 ld::Fixup fixup
= *fit
;
1076 fixup
.offsetInAtom
+= slide
;
1077 _fixups
.push_back(fixup
);
1078 //fprintf(stderr, "offset=0x%08X, binding=%d\n", fixup.offsetInAtom, fixup.binding);
1079 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
1080 // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
1081 //else if ( fixup.binding == ld::Fixup::bindingsIndirectlyBound )
1082 // fprintf(stderr, "offset=0x%08X, indirect index=%u, name=%s\n", fixup.offsetInAtom, fixup.u.bindingIndex,
1083 // (char*)(state.indirectBindingTable[fixup.u.bindingIndex]->rawContentPointer()));
1085 slide
+= 2*sizeof(pint_t
) * PropertyList
<A
>::count(state
, categoryPropertyListAtom
);
1088 // add method list from base class last
1089 if ( basePropertyList
!= NULL
) {
1090 for (ld::Fixup::iterator fit
=basePropertyList
->fixupsBegin(); fit
!= basePropertyList
->fixupsEnd(); ++fit
) {
1091 ld::Fixup fixup
= *fit
;
1092 fixup
.offsetInAtom
+= slide
;
1093 _fixups
.push_back(fixup
);
1101 void doPass(const Options
& opts
, ld::Internal
& state
)
1103 // only make image info section if objc was used
1104 if ( state
.objcObjectConstraint
!= ld::File::objcConstraintNone
) {
1106 // verify dylibs are GC compatible with object files
1107 if ( state
.objcObjectConstraint
!= state
.objcDylibConstraint
) {
1108 if ( (state
.objcDylibConstraint
== ld::File::objcConstraintRetainRelease
)
1109 && (state
.objcObjectConstraint
== ld::File::objcConstraintGC
) ) {
1110 throw "Linked dylibs built for retain/release but object files built for GC-only";
1112 else if ( (state
.objcDylibConstraint
== ld::File::objcConstraintGC
)
1113 && (state
.objcObjectConstraint
== ld::File::objcConstraintRetainRelease
) ) {
1114 throw "Linked dylibs built for GC-only but object files built for retain/release";
1118 const bool compaction
= opts
.objcGcCompaction();
1120 // add image info atom
1121 switch ( opts
.architecture() ) {
1122 case CPU_TYPE_X86_64
:
1123 state
.addAtom(*new ObjCImageInfoAtom
<x86_64
>(state
.objcObjectConstraint
, compaction
,
1124 state
.hasObjcReplacementClasses
, true));
1127 state
.addAtom(*new ObjCImageInfoAtom
<x86
>(state
.objcObjectConstraint
, compaction
,
1128 state
.hasObjcReplacementClasses
, opts
.objCABIVersion2POverride() ? true : false));
1130 case CPU_TYPE_POWERPC
:
1131 state
.addAtom(*new ObjCImageInfoAtom
<ppc
>(state
.objcObjectConstraint
, compaction
,
1132 state
.hasObjcReplacementClasses
, false));
1135 state
.addAtom(*new ObjCImageInfoAtom
<arm
>(state
.objcObjectConstraint
, compaction
,
1136 state
.hasObjcReplacementClasses
, true));
1138 case CPU_TYPE_POWERPC64
:
1139 state
.addAtom(*new ObjCImageInfoAtom
<ppc64
>(state
.objcObjectConstraint
, compaction
,
1140 state
.hasObjcReplacementClasses
, true));
1143 assert(0 && "unknown objc arch");
1147 if ( opts
.objcCategoryMerging() ) {
1148 // optimize classes defined in this linkage unit by merging in categories also in this linkage unit
1149 switch ( opts
.architecture() ) {
1150 case CPU_TYPE_X86_64
:
1151 OptimizeCategories
<x86_64
>::doit(opts
, state
);
1154 // disable optimization until fully tested
1155 //if ( opts.objCABIVersion2POverride() )
1156 // OptimizeCategories<x86>::doit(opts, state);
1159 // disable optimization until fully tested
1160 //OptimizeCategories<arm>::doit(opts, state);
1162 case CPU_TYPE_POWERPC64
:
1163 case CPU_TYPE_POWERPC
:
1166 assert(0 && "unknown objc arch");
1173 } // namespace passes