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_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 std::set
<const ld::Atom
*> baseMethodListMethodNameAtoms
;
922 // if base class has method list, then associate new method list with file defining class
923 if ( baseMethodList
!= NULL
) {
924 _file
= baseMethodList
->file();
925 // calculate total size of merge method lists
926 _methodCount
= MethodList
<A
>::count(state
, baseMethodList
);
927 deadAtoms
.insert(baseMethodList
);
928 fixupCount
= baseMethodList
->fixupsEnd() - baseMethodList
->fixupsBegin();
929 for (ld::Fixup::iterator fit
=baseMethodList
->fixupsBegin(); fit
!= baseMethodList
->fixupsEnd(); ++fit
) {
930 if ( (fit
->offsetInAtom
- 8) % (3*sizeof(pint_t
)) == 0 ) {
931 assert(fit
->binding
== ld::Fixup::bindingsIndirectlyBound
&& "malformed method list");
932 const ld::Atom
* target
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
933 assert(target
->contentType() == ld::Atom::typeCString
&& "malformed method list");
934 baseMethodListMethodNameAtoms
.insert(target
);
938 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
939 const ld::Atom
* categoryMethodListAtom
;
941 categoryMethodListAtom
= Category
<A
>::getClassMethods(state
, *ait
);
943 categoryMethodListAtom
= Category
<A
>::getInstanceMethods(state
, *ait
);
944 if ( categoryMethodListAtom
!= NULL
) {
945 _methodCount
+= MethodList
<A
>::count(state
, categoryMethodListAtom
);
946 fixupCount
+= (categoryMethodListAtom
->fixupsEnd() - categoryMethodListAtom
->fixupsBegin());
947 deadAtoms
.insert(categoryMethodListAtom
);
948 // if base class did not have method list, associate new method list with file the defined category
950 _file
= categoryMethodListAtom
->file();
953 //if ( baseMethodList != NULL )
954 // fprintf(stderr, "total merged method count=%u for baseMethodList=%s\n", _methodCount, baseMethodList->name());
956 // fprintf(stderr, "total merged method count=%u\n", _methodCount);
957 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
959 // copy fixups and adjust offsets (in reverse order to simulator objc runtime)
960 _fixups
.reserve(fixupCount
);
962 std::set
<const ld::Atom
*> categoryMethodNameAtoms
;
963 for (std::vector
<const ld::Atom
*>::const_reverse_iterator rit
=categories
->rbegin(); rit
!= categories
->rend(); ++rit
) {
964 const ld::Atom
* categoryMethodListAtom
;
966 categoryMethodListAtom
= Category
<A
>::getClassMethods(state
, *rit
);
968 categoryMethodListAtom
= Category
<A
>::getInstanceMethods(state
, *rit
);
969 if ( categoryMethodListAtom
!= NULL
) {
970 for (ld::Fixup::iterator fit
=categoryMethodListAtom
->fixupsBegin(); fit
!= categoryMethodListAtom
->fixupsEnd(); ++fit
) {
971 ld::Fixup fixup
= *fit
;
972 fixup
.offsetInAtom
+= slide
;
973 _fixups
.push_back(fixup
);
974 if ( (fixup
.offsetInAtom
- 8) % (3*sizeof(pint_t
)) == 0 ) {
975 // <rdar://problem/8642343> warning when a method is overridden in a category in the same link unit
976 assert(fixup
.binding
== ld::Fixup::bindingsIndirectlyBound
&& "malformed category method list");
977 const ld::Atom
* target
= state
.indirectBindingTable
[fixup
.u
.bindingIndex
];
978 assert(target
->contentType() == ld::Atom::typeCString
&& "malformed method list");
979 // this objc pass happens after cstrings are coalesced, so we can just compare the atom addres instead of its content
980 if ( baseMethodListMethodNameAtoms
.count(target
) != 0 ) {
981 warning("%s method '%s' in category from %s overrides method from class in %s",
982 (meta
? "meta" : "instance"), target
->rawContentPointer(),
983 categoryMethodListAtom
->file()->path(), baseMethodList
->file()->path() );
985 if ( categoryMethodNameAtoms
.count(target
) != 0 ) {
986 warning("%s method '%s' in category from %s conflicts with same method from another category",
987 (meta
? "meta" : "instance"), target
->rawContentPointer(),
988 categoryMethodListAtom
->file()->path());
990 categoryMethodNameAtoms
.insert(target
);
993 slide
+= 3*sizeof(pint_t
) * MethodList
<A
>::count(state
, categoryMethodListAtom
);
996 // add method list from base class last
997 if ( baseMethodList
!= NULL
) {
998 for (ld::Fixup::iterator fit
=baseMethodList
->fixupsBegin(); fit
!= baseMethodList
->fixupsEnd(); ++fit
) {
999 ld::Fixup fixup
= *fit
;
1000 fixup
.offsetInAtom
+= slide
;
1001 _fixups
.push_back(fixup
);
1007 template <typename A
>
1008 ProtocolListAtom
<A
>::ProtocolListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
1009 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
1010 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
1011 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
1012 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _protocolCount(0)
1014 unsigned int fixupCount
= 0;
1015 if ( baseProtocolList
!= NULL
) {
1016 // if base class has protocol list, then associate new protocol list with file defining class
1017 _file
= baseProtocolList
->file();
1018 // calculate total size of merged protocol list
1019 _protocolCount
= ProtocolList
<A
>::count(state
, baseProtocolList
);
1020 deadAtoms
.insert(baseProtocolList
);
1021 fixupCount
= baseProtocolList
->fixupsEnd() - baseProtocolList
->fixupsBegin();
1023 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
1024 const ld::Atom
* categoryProtocolListAtom
= Category
<A
>::getProtocols(state
, *ait
);
1025 if ( categoryProtocolListAtom
!= NULL
) {
1026 _protocolCount
+= ProtocolList
<A
>::count(state
, categoryProtocolListAtom
);
1027 fixupCount
+= (categoryProtocolListAtom
->fixupsEnd() - categoryProtocolListAtom
->fixupsBegin());
1028 deadAtoms
.insert(categoryProtocolListAtom
);
1029 // if base class did not have protocol list, associate new protocol list with file the defined category
1030 if ( _file
== NULL
)
1031 _file
= categoryProtocolListAtom
->file();
1034 //fprintf(stderr, "total merged protocol count=%u\n", _protocolCount);
1035 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
1037 // copy fixups and adjust offsets
1038 _fixups
.reserve(fixupCount
);
1040 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
1041 const ld::Atom
* categoryProtocolListAtom
= Category
<A
>::getProtocols(state
, *it
);
1042 if ( categoryProtocolListAtom
!= NULL
) {
1043 for (ld::Fixup::iterator fit
=categoryProtocolListAtom
->fixupsBegin(); fit
!= categoryProtocolListAtom
->fixupsEnd(); ++fit
) {
1044 ld::Fixup fixup
= *fit
;
1045 fixup
.offsetInAtom
+= slide
;
1046 _fixups
.push_back(fixup
);
1047 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
1048 // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
1050 slide
+= sizeof(pint_t
) * ProtocolList
<A
>::count(state
, categoryProtocolListAtom
);
1053 // add method list from base class last
1054 if ( baseProtocolList
!= NULL
) {
1055 for (ld::Fixup::iterator fit
=baseProtocolList
->fixupsBegin(); fit
!= baseProtocolList
->fixupsEnd(); ++fit
) {
1056 ld::Fixup fixup
= *fit
;
1057 fixup
.offsetInAtom
+= slide
;
1058 _fixups
.push_back(fixup
);
1064 template <typename A
>
1065 PropertyListAtom
<A
>::PropertyListAtom(ld::Internal
& state
, const ld::Atom
* basePropertyList
,
1066 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
1067 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
1068 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
1069 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _propertyCount(0)
1071 unsigned int fixupCount
= 0;
1072 if ( basePropertyList
!= NULL
) {
1073 // if base class has property list, then associate new property list with file defining class
1074 _file
= basePropertyList
->file();
1075 // calculate total size of merged property list
1076 _propertyCount
= PropertyList
<A
>::count(state
, basePropertyList
);
1077 deadAtoms
.insert(basePropertyList
);
1078 fixupCount
= basePropertyList
->fixupsEnd() - basePropertyList
->fixupsBegin();
1080 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
1081 const ld::Atom
* categoryPropertyListAtom
= Category
<A
>::getProperties(state
, *ait
);
1082 if ( categoryPropertyListAtom
!= NULL
) {
1083 _propertyCount
+= PropertyList
<A
>::count(state
, categoryPropertyListAtom
);
1084 fixupCount
+= (categoryPropertyListAtom
->fixupsEnd() - categoryPropertyListAtom
->fixupsBegin());
1085 deadAtoms
.insert(categoryPropertyListAtom
);
1086 // if base class did not have property list, associate new property list with file the defined category
1087 if ( _file
== NULL
)
1088 _file
= categoryPropertyListAtom
->file();
1091 //fprintf(stderr, "total merged property count=%u\n", _propertyCount);
1092 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
1094 // copy fixups and adjust offsets
1095 _fixups
.reserve(fixupCount
);
1097 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
1098 const ld::Atom
* categoryPropertyListAtom
= Category
<A
>::getProperties(state
, *it
);
1099 if ( categoryPropertyListAtom
!= NULL
) {
1100 for (ld::Fixup::iterator fit
=categoryPropertyListAtom
->fixupsBegin(); fit
!= categoryPropertyListAtom
->fixupsEnd(); ++fit
) {
1101 ld::Fixup fixup
= *fit
;
1102 fixup
.offsetInAtom
+= slide
;
1103 _fixups
.push_back(fixup
);
1104 //fprintf(stderr, "offset=0x%08X, binding=%d\n", fixup.offsetInAtom, fixup.binding);
1105 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
1106 // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
1107 //else if ( fixup.binding == ld::Fixup::bindingsIndirectlyBound )
1108 // fprintf(stderr, "offset=0x%08X, indirect index=%u, name=%s\n", fixup.offsetInAtom, fixup.u.bindingIndex,
1109 // (char*)(state.indirectBindingTable[fixup.u.bindingIndex]->rawContentPointer()));
1111 slide
+= 2*sizeof(pint_t
) * PropertyList
<A
>::count(state
, categoryPropertyListAtom
);
1114 // add method list from base class last
1115 if ( basePropertyList
!= NULL
) {
1116 for (ld::Fixup::iterator fit
=basePropertyList
->fixupsBegin(); fit
!= basePropertyList
->fixupsEnd(); ++fit
) {
1117 ld::Fixup fixup
= *fit
;
1118 fixup
.offsetInAtom
+= slide
;
1119 _fixups
.push_back(fixup
);
1127 void doPass(const Options
& opts
, ld::Internal
& state
)
1129 // only make image info section if objc was used
1130 if ( state
.objcObjectConstraint
!= ld::File::objcConstraintNone
) {
1132 // verify dylibs are GC compatible with object files
1133 if ( state
.objcObjectConstraint
!= state
.objcDylibConstraint
) {
1134 if ( (state
.objcDylibConstraint
== ld::File::objcConstraintRetainRelease
)
1135 && (state
.objcObjectConstraint
== ld::File::objcConstraintGC
) ) {
1136 throw "Linked dylibs built for retain/release but object files built for GC-only";
1138 else if ( (state
.objcDylibConstraint
== ld::File::objcConstraintGC
)
1139 && (state
.objcObjectConstraint
== ld::File::objcConstraintRetainRelease
) ) {
1140 throw "Linked dylibs built for GC-only but object files built for retain/release";
1144 const bool compaction
= opts
.objcGcCompaction();
1146 // add image info atom
1147 switch ( opts
.architecture() ) {
1148 case CPU_TYPE_X86_64
:
1149 state
.addAtom(*new ObjCImageInfoAtom
<x86_64
>(state
.objcObjectConstraint
, compaction
,
1150 state
.hasObjcReplacementClasses
, true));
1153 state
.addAtom(*new ObjCImageInfoAtom
<x86
>(state
.objcObjectConstraint
, compaction
,
1154 state
.hasObjcReplacementClasses
, opts
.objCABIVersion2POverride() ? true : false));
1157 state
.addAtom(*new ObjCImageInfoAtom
<arm
>(state
.objcObjectConstraint
, compaction
,
1158 state
.hasObjcReplacementClasses
, true));
1161 assert(0 && "unknown objc arch");
1165 if ( opts
.objcCategoryMerging() ) {
1166 // optimize classes defined in this linkage unit by merging in categories also in this linkage unit
1167 switch ( opts
.architecture() ) {
1168 case CPU_TYPE_X86_64
:
1169 OptimizeCategories
<x86_64
>::doit(opts
, state
);
1172 // disable optimization until fully tested
1173 //if ( opts.objCABIVersion2POverride() )
1174 // OptimizeCategories<x86>::doit(opts, state);
1177 // disable optimization until fully tested
1178 //OptimizeCategories<arm>::doit(opts, state);
1181 assert(0 && "unknown objc arch");
1188 } // namespace passes