1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2010-2011 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
30 #include <mach/machine.h>
36 #include "Architectures.hpp"
37 #include "MachOFileAbstraction.hpp"
48 struct objc_image_info
{
49 uint32_t version
; // initially 0
53 #define OBJC_IMAGE_SUPPORTS_GC (1<<1)
54 #define OBJC_IMAGE_REQUIRES_GC (1<<2)
55 #define OBJC_IMAGE_OPTIMIZED_BY_DYLD (1<<3)
56 #define OBJC_IMAGE_SUPPORTS_COMPACTION (1<<4)
61 // This class is the 8 byte section containing ObjC flags
64 class ObjCImageInfoAtom
: public ld::Atom
{
66 ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint
,
67 bool compaction
, bool abi2
);
69 virtual const ld::File
* file() const { return NULL
; }
70 virtual bool translationUnitSource(const char** dir
, const char**) const
72 virtual const char* name() const { return "objc image info"; }
73 virtual uint64_t size() const { return sizeof(objc_image_info
); }
74 virtual uint64_t objectAddress() const { return 0; }
75 virtual void setScope(Scope
) { }
76 virtual void copyRawContent(uint8_t buffer
[]) const {
77 memcpy(buffer
, &_content
, sizeof(objc_image_info
));
81 objc_image_info _content
;
83 static ld::Section _s_sectionABI1
;
84 static ld::Section _s_sectionABI2
;
87 template <typename A
> ld::Section ObjCImageInfoAtom
<A
>::_s_sectionABI1("__OBJC", "__image_info", ld::Section::typeUnclassified
);
88 template <typename A
> ld::Section ObjCImageInfoAtom
<A
>::_s_sectionABI2("__DATA", "__objc_imageinfo", ld::Section::typeUnclassified
);
92 ObjCImageInfoAtom
<A
>::ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint
, bool compaction
,
94 : ld::Atom(abi2
? _s_sectionABI2
: _s_sectionABI1
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
95 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
96 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(2))
100 switch ( objcConstraint
) {
101 case ld::File::objcConstraintNone
:
102 case ld::File::objcConstraintRetainRelease
:
104 warning("ignoring -objc_gc_compaction because code not compiled for ObjC garbage collection");
106 case ld::File::objcConstraintRetainReleaseOrGC
:
107 value
|= OBJC_IMAGE_SUPPORTS_GC
;
109 value
|= OBJC_IMAGE_SUPPORTS_COMPACTION
;
111 case ld::File::objcConstraintGC
:
112 value
|= OBJC_IMAGE_SUPPORTS_GC
| OBJC_IMAGE_REQUIRES_GC
;
114 value
|= OBJC_IMAGE_SUPPORTS_COMPACTION
;
118 _content
.version
= 0;
119 A::P::E::set32(_content
.flags
, value
);
125 // This class is for a new Atom which is an ObjC method list created by merging method lists from categories
127 template <typename A
>
128 class MethodListAtom
: public ld::Atom
{
130 MethodListAtom(ld::Internal
& state
, const ld::Atom
* baseMethodList
, bool meta
,
131 const std::vector
<const ld::Atom
*>* categories
,
132 std::set
<const ld::Atom
*>& deadAtoms
);
134 virtual const ld::File
* file() const { return _file
; }
135 virtual bool translationUnitSource(const char** dir
, const char**) const
137 virtual const char* name() const { return "objc merged method list"; }
138 virtual uint64_t size() const { return _methodCount
*3*sizeof(pint_t
) + 8; }
139 virtual uint64_t objectAddress() const { return 0; }
140 virtual void setScope(Scope
) { }
141 virtual void copyRawContent(uint8_t buffer
[]) const {
142 bzero(buffer
, size());
143 A::P::E::set32(*((uint32_t*)(&buffer
[0])), 3*sizeof(pint_t
)); // entry size
144 A::P::E::set32(*((uint32_t*)(&buffer
[4])), _methodCount
);
146 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
147 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
150 typedef typename
A::P::uint_t pint_t
;
152 const ld::File
* _file
;
153 unsigned int _methodCount
;
154 std::vector
<ld::Fixup
> _fixups
;
156 static ld::Section _s_section
;
159 template <typename A
>
160 ld::Section MethodListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
164 // This class is for a new Atom which is an ObjC protocol list created by merging protocol lists from categories
166 template <typename A
>
167 class ProtocolListAtom
: public ld::Atom
{
169 ProtocolListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
170 const std::vector
<const ld::Atom
*>* categories
,
171 std::set
<const ld::Atom
*>& deadAtoms
);
173 virtual const ld::File
* file() const { return _file
; }
174 virtual bool translationUnitSource(const char** dir
, const char**) const
176 virtual const char* name() const { return "objc merged protocol list"; }
177 virtual uint64_t size() const { return (_protocolCount
+1)*sizeof(pint_t
); }
178 virtual uint64_t objectAddress() const { return 0; }
179 virtual void setScope(Scope
) { }
180 virtual void copyRawContent(uint8_t buffer
[]) const {
181 bzero(buffer
, size());
182 A::P::setP(*((pint_t
*)(buffer
)), _protocolCount
);
184 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
185 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
188 typedef typename
A::P::uint_t pint_t
;
190 const ld::File
* _file
;
191 unsigned int _protocolCount
;
192 std::vector
<ld::Fixup
> _fixups
;
194 static ld::Section _s_section
;
197 template <typename A
>
198 ld::Section ProtocolListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
203 // This class is for a new Atom which is an ObjC property list created by merging property lists from categories
205 template <typename A
>
206 class PropertyListAtom
: public ld::Atom
{
208 PropertyListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
209 const std::vector
<const ld::Atom
*>* categories
,
210 std::set
<const ld::Atom
*>& deadAtoms
);
212 virtual const ld::File
* file() const { return _file
; }
213 virtual bool translationUnitSource(const char** dir
, const char**) const
215 virtual const char* name() const { return "objc merged property list"; }
216 virtual uint64_t size() const { return _propertyCount
*2*sizeof(pint_t
) + 8; }
217 virtual uint64_t objectAddress() const { return 0; }
218 virtual void setScope(Scope
) { }
219 virtual void copyRawContent(uint8_t buffer
[]) const {
220 bzero(buffer
, size());
221 A::P::E::set32(((uint32_t*)(buffer
))[0], 2*sizeof(pint_t
)); // sizeof(objc_property)
222 A::P::E::set32(((uint32_t*)(buffer
))[1], _propertyCount
);
224 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
225 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
228 typedef typename
A::P::uint_t pint_t
;
230 const ld::File
* _file
;
231 unsigned int _propertyCount
;
232 std::vector
<ld::Fixup
> _fixups
;
234 static ld::Section _s_section
;
237 template <typename A
>
238 ld::Section PropertyListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
245 // This class is used to create an Atom that replaces an atom from a .o file that holds a class_ro_t.
246 // It is needed because there is no way to add Fixups to an existing atom.
248 template <typename A
>
249 class ClassROOverlayAtom
: public ld::Atom
{
251 ClassROOverlayAtom(const ld::Atom
* classROAtom
);
253 // overrides of ld::Atom
254 virtual const ld::File
* file() const { return _atom
->file(); }
255 virtual bool translationUnitSource(const char** dir
, const char** nm
) const
256 { return _atom
->translationUnitSource(dir
, nm
); }
257 virtual const char* name() const { return _atom
->name(); }
258 virtual uint64_t size() const { return _atom
->size(); }
259 virtual uint64_t objectAddress() const { return _atom
->objectAddress(); }
260 virtual void copyRawContent(uint8_t buffer
[]) const
261 { _atom
->copyRawContent(buffer
); }
262 virtual const uint8_t* rawContentPointer() const
263 { return _atom
->rawContentPointer(); }
264 virtual unsigned long contentHash(const class ld::IndirectBindingTable
& ibt
) const
265 { return _atom
->contentHash(ibt
); }
266 virtual bool canCoalesceWith(const ld::Atom
& rhs
, const class ld::IndirectBindingTable
& ibt
) const
267 { return _atom
->canCoalesceWith(rhs
,ibt
); }
269 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
270 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
272 void addProtocolListFixup();
273 void addPropertyListFixup();
274 void addMethodListFixup();
277 typedef typename
A::P::uint_t pint_t
;
279 const ld::Atom
* _atom
;
280 std::vector
<ld::Fixup
> _fixups
;
283 template <typename A
>
284 ClassROOverlayAtom
<A
>::ClassROOverlayAtom(const ld::Atom
* classROAtom
)
285 : ld::Atom(classROAtom
->section(), ld::Atom::definitionRegular
, ld::Atom::combineNever
,
286 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
287 classROAtom
->symbolTableInclusion(), false, false, false, classROAtom
->alignment()),
290 // ensure all attributes are same as original
291 this->setAttributesFromAtom(*classROAtom
);
293 // copy fixups from orginal atom
294 for (ld::Fixup::iterator fit
=classROAtom
->fixupsBegin(); fit
!= classROAtom
->fixupsEnd(); ++fit
) {
295 ld::Fixup fixup
= *fit
;
296 _fixups
.push_back(fixup
);
302 // Base class for reading and updating existing ObjC atoms from .o files
304 template <typename A
>
307 static const ld::Atom
* getPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
, unsigned int offset
, bool* hasAddend
=NULL
);
308 static void setPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
,
309 unsigned int offset
, const ld::Atom
* newAtom
);
310 typedef typename
A::P::uint_t pint_t
;
313 template <typename A
>
314 const ld::Atom
* ObjCData
<A
>::getPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
, unsigned int offset
, bool* hasAddend
)
316 const ld::Atom
* target
= NULL
;
317 if ( hasAddend
!= NULL
)
319 for (ld::Fixup::iterator fit
=contentAtom
->fixupsBegin(); fit
!= contentAtom
->fixupsEnd(); ++fit
) {
320 if ( fit
->offsetInAtom
== offset
) {
321 switch ( fit
->binding
) {
322 case ld::Fixup::bindingsIndirectlyBound
:
323 target
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
325 case ld::Fixup::bindingDirectlyBound
:
326 target
= fit
->u
.target
;
328 case ld::Fixup::bindingNone
:
329 if ( fit
->kind
== ld::Fixup::kindAddAddend
) {
330 if ( hasAddend
!= NULL
)
342 template <typename A
>
343 void ObjCData
<A
>::setPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
,
344 unsigned int offset
, const ld::Atom
* newAtom
)
346 for (ld::Fixup::iterator fit
=contentAtom
->fixupsBegin(); fit
!= contentAtom
->fixupsEnd(); ++fit
) {
347 if ( fit
->offsetInAtom
== offset
) {
348 switch ( fit
->binding
) {
349 case ld::Fixup::bindingsIndirectlyBound
:
350 state
.indirectBindingTable
[fit
->u
.bindingIndex
] = newAtom
;
352 case ld::Fixup::bindingDirectlyBound
:
353 fit
->u
.target
= newAtom
;
360 assert(0 && "could not update method list");
366 // Helper class for reading and updating existing ObjC category atoms from .o files
368 template <typename A
>
369 class Category
: public ObjCData
<A
> {
371 static const ld::Atom
* getClass(ld::Internal
& state
, const ld::Atom
* contentAtom
);
372 static const ld::Atom
* getInstanceMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
);
373 static const ld::Atom
* getClassMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
);
374 static const ld::Atom
* getProtocols(ld::Internal
& state
, const ld::Atom
* contentAtom
);
375 static const ld::Atom
* getProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
);
376 static uint32_t size() { return 6*sizeof(pint_t
); }
378 typedef typename
A::P::uint_t pint_t
;
382 template <typename A
>
383 const ld::Atom
* Category
<A
>::getClass(ld::Internal
& state
, const ld::Atom
* contentAtom
)
385 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, sizeof(pint_t
)); // category_t.cls
388 template <typename A
>
389 const ld::Atom
* Category
<A
>::getInstanceMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
)
391 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 2*sizeof(pint_t
)); // category_t.instanceMethods
394 template <typename A
>
395 const ld::Atom
* Category
<A
>::getClassMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
)
397 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 3*sizeof(pint_t
)); // category_t.classMethods
400 template <typename A
>
401 const ld::Atom
* Category
<A
>::getProtocols(ld::Internal
& state
, const ld::Atom
* contentAtom
)
403 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 4*sizeof(pint_t
)); // category_t.protocols
406 template <typename A
>
407 const ld::Atom
* Category
<A
>::getProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
)
409 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 5*sizeof(pint_t
)); // category_t.instanceProperties
413 template <typename A
>
414 class MethodList
: public ObjCData
<A
> {
416 static uint32_t count(ld::Internal
& state
, const ld::Atom
* methodListAtom
) {
417 const uint32_t* methodListData
= (uint32_t*)(methodListAtom
->rawContentPointer());
418 return A::P::E::get32(methodListData
[1]); // method_list_t.count
422 template <typename A
>
423 class ProtocolList
: public ObjCData
<A
> {
425 static uint32_t count(ld::Internal
& state
, const ld::Atom
* protocolListAtom
) {
426 pint_t
* protocolListData
= (pint_t
*)(protocolListAtom
->rawContentPointer());
427 return A::P::getP(*protocolListData
); // protocol_list_t.count
430 typedef typename
A::P::uint_t pint_t
;
433 template <typename A
>
434 class PropertyList
: public ObjCData
<A
> {
436 static uint32_t count(ld::Internal
& state
, const ld::Atom
* protocolListAtom
) {
437 uint32_t* protocolListData
= (uint32_t*)(protocolListAtom
->rawContentPointer());
438 return A::P::E::get32(protocolListData
[1]); // property_list_t.count
441 typedef typename
A::P::uint_t pint_t
;
447 // Helper class for reading and updating existing ObjC class atoms from .o files
449 template <typename A
>
450 class Class
: public ObjCData
<A
> {
452 static const ld::Atom
* getInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
);
453 static const ld::Atom
* getInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
);
454 static const ld::Atom
* getInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
);
455 static const ld::Atom
* getClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
);
456 static const ld::Atom
* setInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
457 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
458 static const ld::Atom
* setInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
459 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
460 static const ld::Atom
* setInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,
461 const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
462 static const ld::Atom
* setClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
463 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
464 static const ld::Atom
* setClassProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
465 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
466 static uint32_t size() { return 5*sizeof(pint_t
); }
467 static unsigned int class_ro_header_size();
469 typedef typename
A::P::uint_t pint_t
;
470 static const ld::Atom
* getROData(ld::Internal
& state
, const ld::Atom
* classAtom
);
473 template <> unsigned int Class
<x86_64
>::class_ro_header_size() { return 16; }
474 template <> unsigned int Class
<arm
>::class_ro_header_size() { return 12;}
475 template <> unsigned int Class
<x86
>::class_ro_header_size() { return 12; }
478 template <typename A
>
479 const ld::Atom
* Class
<A
>::getROData(ld::Internal
& state
, const ld::Atom
* classAtom
)
481 return ObjCData
<A
>::getPointerInContent(state
, classAtom
, 4*sizeof(pint_t
)); // class_t.data
485 template <typename A
>
486 const ld::Atom
* Class
<A
>::getInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
)
488 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
489 assert(classROAtom
!= NULL
);
490 return ObjCData
<A
>::getPointerInContent(state
, classROAtom
, class_ro_header_size() + 2*sizeof(pint_t
)); // class_ro_t.baseMethods
493 template <typename A
>
494 const ld::Atom
* Class
<A
>::getInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
)
496 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
497 assert(classROAtom
!= NULL
);
498 return ObjCData
<A
>::getPointerInContent(state
, classROAtom
, class_ro_header_size() + 3*sizeof(pint_t
)); // class_ro_t.baseProtocols
501 template <typename A
>
502 const ld::Atom
* Class
<A
>::getInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
)
504 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
505 assert(classROAtom
!= NULL
);
506 return ObjCData
<A
>::getPointerInContent(state
, classROAtom
, class_ro_header_size() + 6*sizeof(pint_t
)); // class_ro_t.baseProperties
509 template <typename A
>
510 const ld::Atom
* Class
<A
>::getClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
)
512 const ld::Atom
* metaClassAtom
= ObjCData
<A
>::getPointerInContent(state
, classAtom
, 0); // class_t.isa
513 assert(metaClassAtom
!= NULL
);
514 return Class
<A
>::getInstanceMethodList(state
, metaClassAtom
);
517 template <typename A
>
518 const ld::Atom
* Class
<A
>::setInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
519 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
521 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
522 assert(classROAtom
!= NULL
);
523 // if the base class does not already have a method list, we need to create an overlay
524 if ( getInstanceMethodList(state
, classAtom
) == NULL
) {
525 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(classROAtom
);
526 //fprintf(stderr, "replace class RO atom %p with %p for method list in class atom %s\n", classROAtom, overlay, classAtom->name());
527 overlay
->addMethodListFixup();
528 ObjCData
<A
>::setPointerInContent(state
, classAtom
, 4*sizeof(pint_t
), overlay
); // class_t.data
529 deadAtoms
.insert(classROAtom
);
530 ObjCData
<A
>::setPointerInContent(state
, overlay
, class_ro_header_size() + 2*sizeof(pint_t
), methodListAtom
); // class_ro_t.baseMethods
533 ObjCData
<A
>::setPointerInContent(state
, classROAtom
, class_ro_header_size() + 2*sizeof(pint_t
), methodListAtom
); // class_ro_t.baseMethods
534 return NULL
; // means classRO atom was not replaced
537 template <typename A
>
538 const ld::Atom
* Class
<A
>::setInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
539 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
541 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
542 assert(classROAtom
!= NULL
);
543 // if the base class does not already have a protocol list, we need to create an overlay
544 if ( getInstanceProtocolList(state
, classAtom
) == NULL
) {
545 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(classROAtom
);
546 //fprintf(stderr, "replace class RO atom %p with %p for protocol list in class atom %s\n", classROAtom, overlay, classAtom->name());
547 overlay
->addProtocolListFixup();
548 ObjCData
<A
>::setPointerInContent(state
, classAtom
, 4*sizeof(pint_t
), overlay
); // class_t.data
549 deadAtoms
.insert(classROAtom
);
550 ObjCData
<A
>::setPointerInContent(state
, overlay
, class_ro_header_size() + 3*sizeof(pint_t
), protocolListAtom
); // class_ro_t.baseProtocols
553 //fprintf(stderr, "set class RO atom %p protocol list in class atom %s\n", classROAtom, classAtom->name());
554 ObjCData
<A
>::setPointerInContent(state
, classROAtom
, class_ro_header_size() + 3*sizeof(pint_t
), protocolListAtom
); // class_ro_t.baseProtocols
555 return NULL
; // means classRO atom was not replaced
558 template <typename A
>
559 const ld::Atom
* Class
<A
>::setClassProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
560 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
562 // meta class also points to same protocol list as class
563 const ld::Atom
* metaClassAtom
= ObjCData
<A
>::getPointerInContent(state
, classAtom
, 0); // class_t.isa
564 //fprintf(stderr, "setClassProtocolList(), classAtom=%p %s, metaClass=%p %s\n", classAtom, classAtom->name(), metaClassAtom, metaClassAtom->name());
565 assert(metaClassAtom
!= NULL
);
566 return setInstanceProtocolList(state
, metaClassAtom
, protocolListAtom
, deadAtoms
);
571 template <typename A
>
572 const ld::Atom
* Class
<A
>::setInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,
573 const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
575 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
576 assert(classROAtom
!= NULL
);
577 // if the base class does not already have a property list, we need to create an overlay
578 if ( getInstancePropertyList(state
, classAtom
) == NULL
) {
579 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(classROAtom
);
580 //fprintf(stderr, "replace class RO atom %p with %p for property list in class atom %s\n", classROAtom, overlay, classAtom->name());
581 overlay
->addPropertyListFixup();
582 ObjCData
<A
>::setPointerInContent(state
, classAtom
, 4*sizeof(pint_t
), overlay
); // class_t.data
583 deadAtoms
.insert(classROAtom
);
584 ObjCData
<A
>::setPointerInContent(state
, overlay
, class_ro_header_size() + 6*sizeof(pint_t
), propertyListAtom
); // class_ro_t.baseProperties
587 ObjCData
<A
>::setPointerInContent(state
, classROAtom
, class_ro_header_size() + 6*sizeof(pint_t
), propertyListAtom
); // class_ro_t.baseProperties
588 return NULL
; // means classRO atom was not replaced
591 template <typename A
>
592 const ld::Atom
* Class
<A
>::setClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
593 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
595 // class methods is just instance methods of metaClass
596 const ld::Atom
* metaClassAtom
= ObjCData
<A
>::getPointerInContent(state
, classAtom
, 0); // class_t.isa
597 assert(metaClassAtom
!= NULL
);
598 return setInstanceMethodList(state
, metaClassAtom
, methodListAtom
, deadAtoms
);
604 void ClassROOverlayAtom
<x86_64
>::addMethodListFixup()
606 const ld::Atom
* targetAtom
= this; // temporary
607 uint32_t offset
= Class
<x86_64
>::class_ro_header_size() + 2*8; // class_ro_t.baseMethods
608 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian64
, targetAtom
));
612 void ClassROOverlayAtom
<arm
>::addMethodListFixup()
614 const ld::Atom
* targetAtom
= this; // temporary
615 uint32_t offset
= Class
<arm
>::class_ro_header_size() + 2*4; // class_ro_t.baseMethods
616 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
620 void ClassROOverlayAtom
<x86
>::addMethodListFixup()
622 const ld::Atom
* targetAtom
= this; // temporary
623 uint32_t offset
= Class
<x86
>::class_ro_header_size() + 2*4; // class_ro_t.baseMethods
624 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
630 void ClassROOverlayAtom
<x86_64
>::addProtocolListFixup()
632 const ld::Atom
* targetAtom
= this; // temporary
633 uint32_t offset
= Class
<x86_64
>::class_ro_header_size() + 3*8; // class_ro_t.baseProtocols
634 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian64
, targetAtom
));
638 void ClassROOverlayAtom
<arm
>::addProtocolListFixup()
640 const ld::Atom
* targetAtom
= this; // temporary
641 uint32_t offset
= Class
<arm
>::class_ro_header_size() + 3*4; // class_ro_t.baseProtocols
642 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
646 void ClassROOverlayAtom
<x86
>::addProtocolListFixup()
648 const ld::Atom
* targetAtom
= this; // temporary
649 uint32_t offset
= Class
<x86
>::class_ro_header_size() + 3*4; // class_ro_t.baseProtocols
650 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
655 void ClassROOverlayAtom
<x86_64
>::addPropertyListFixup()
657 const ld::Atom
* targetAtom
= this; // temporary
658 uint32_t offset
= Class
<x86_64
>::class_ro_header_size() + 6*8; // class_ro_t.baseProperties
659 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian64
, targetAtom
));
663 void ClassROOverlayAtom
<arm
>::addPropertyListFixup()
665 const ld::Atom
* targetAtom
= this; // temporary
666 uint32_t offset
= Class
<arm
>::class_ro_header_size() + 6*4; // class_ro_t.baseProperties
667 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
671 void ClassROOverlayAtom
<x86
>::addPropertyListFixup()
673 const ld::Atom
* targetAtom
= this; // temporary
674 uint32_t offset
= Class
<x86
>::class_ro_header_size() + 6*4; // class_ro_t.baseProperties
675 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
682 // Encapsulates merging of ObjC categories
684 template <typename A
>
685 class OptimizeCategories
{
687 static void doit(const Options
& opts
, ld::Internal
& state
);
688 static bool hasInstanceMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
689 static bool hasClassMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
690 static bool hasProtocols(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
691 static bool hasProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
694 static unsigned int class_ro_baseMethods_offset();
696 typedef typename
A::P::uint_t pint_t
;
701 template <typename A
>
702 bool OptimizeCategories
<A
>::hasInstanceMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
704 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
705 const ld::Atom
* categoryAtom
= *it
;
706 const ld::Atom
* methodList
= Category
<A
>::getInstanceMethods(state
, categoryAtom
);
707 if ( methodList
!= NULL
) {
708 if ( MethodList
<A
>::count(state
, methodList
) > 0 )
716 template <typename A
>
717 bool OptimizeCategories
<A
>::hasClassMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
719 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
720 const ld::Atom
* categoryAtom
= *it
;
721 const ld::Atom
* methodList
= Category
<A
>::getClassMethods(state
, categoryAtom
);
722 if ( methodList
!= NULL
) {
723 if ( MethodList
<A
>::count(state
, methodList
) > 0 )
730 template <typename A
>
731 bool OptimizeCategories
<A
>::hasProtocols(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
733 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
734 const ld::Atom
* categoryAtom
= *it
;
735 const ld::Atom
* protocolListAtom
= Category
<A
>::getProtocols(state
, categoryAtom
);
736 if ( protocolListAtom
!= NULL
) {
737 if ( ProtocolList
<A
>::count(state
, protocolListAtom
) > 0 ) {
746 template <typename A
>
747 bool OptimizeCategories
<A
>::hasProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
749 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
750 const ld::Atom
* categoryAtom
= *it
;
751 const ld::Atom
* propertyListAtom
= Category
<A
>::getProperties(state
, categoryAtom
);
752 if ( propertyListAtom
!= NULL
) {
753 if ( PropertyList
<A
>::count(state
, propertyListAtom
) > 0 )
763 // Helper for std::remove_if
765 class OptimizedAway
{
767 OptimizedAway(const std::set
<const ld::Atom
*>& oa
) : _dead(oa
) {}
768 bool operator()(const ld::Atom
* atom
) const {
769 return ( _dead
.count(atom
) != 0 );
772 const std::set
<const ld::Atom
*>& _dead
;
777 bool operator()(const Atom
* left
, const Atom
* right
)
779 // sort by file ordinal, then object address, then zero size, then symbol name
780 // only file based atoms are supported (file() != NULL)
781 if (left
==right
) return false;
782 const File
*leftf
= left
->file();
783 const File
*rightf
= right
->file();
785 if (leftf
== rightf
) {
786 if (left
->objectAddress() != right
->objectAddress()) {
787 return left
->objectAddress() < right
->objectAddress();
789 // for atoms in the same file with the same address, zero sized
790 // atoms must sort before nonzero sized atoms
791 if ((left
->size() == 0 && right
->size() > 0) || (left
->size() > 0 && right
->size() == 0))
792 return left
->size() < right
->size();
793 return strcmp(left
->name(), right
->name());
796 return (leftf
->ordinal() < rightf
->ordinal());
800 static void sortAtomVector(std::vector
<const Atom
*> &atoms
) {
801 std::sort(atoms
.begin(), atoms
.end(), AtomSorter());
804 template <typename A
>
805 void OptimizeCategories
<A
>::doit(const Options
& opts
, ld::Internal
& state
)
807 // first find all categories referenced by __objc_nlcatlist section
808 std::set
<const ld::Atom
*> nlcatListAtoms
;
809 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
810 ld::Internal::FinalSection
* sect
= *sit
;
811 if ( (strcmp(sect
->sectionName(), "__objc_nlcatlist") == 0) && (strcmp(sect
->segmentName(), "__DATA") == 0) ) {
812 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
813 const ld::Atom
* categoryListElementAtom
= *ait
;
814 for (unsigned int offset
=0; offset
< categoryListElementAtom
->size(); offset
+= sizeof(pint_t
)) {
815 const ld::Atom
* categoryAtom
= ObjCData
<A
>::getPointerInContent(state
, categoryListElementAtom
, offset
);
816 //fprintf(stderr, "offset=%d, cat=%p %s\n", offset, categoryAtom, categoryAtom->name());
817 assert(categoryAtom
!= NULL
);
818 nlcatListAtoms
.insert(categoryAtom
);
824 // build map of all classes in this image that have categories on them
825 typedef std::map
<const ld::Atom
*, std::vector
<const ld::Atom
*>*> CatMap
;
826 CatMap classToCategories
;
827 std::vector
<const ld::Atom
*> classOrder
;
828 std::set
<const ld::Atom
*> deadAtoms
;
829 ld::Internal::FinalSection
* methodListSection
= NULL
;
830 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
831 ld::Internal::FinalSection
* sect
= *sit
;
832 if ( sect
->type() == ld::Section::typeObjC2CategoryList
) {
833 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
834 const ld::Atom
* categoryListElementAtom
= *ait
;
836 const ld::Atom
* categoryAtom
= ObjCData
<A
>::getPointerInContent(state
, categoryListElementAtom
, 0, &hasAddend
);
837 if ( hasAddend
|| (categoryAtom
->symbolTableInclusion() == ld::Atom::symbolTableNotIn
)) {
838 //<rdar://problem/8309530> gcc-4.0 uses 'L' labels on categories which disables this optimization
839 //warning("__objc_catlist element does not point to start of category");
842 assert(categoryAtom
!= NULL
);
843 assert(categoryAtom
->size() >= Category
<A
>::size());
844 // ignore categories also in __objc_nlcatlist
845 if ( nlcatListAtoms
.count(categoryAtom
) != 0 )
847 const ld::Atom
* categoryOnClassAtom
= Category
<A
>::getClass(state
, categoryAtom
);
848 assert(categoryOnClassAtom
!= NULL
);
849 if ( categoryOnClassAtom
->definition() != ld::Atom::definitionProxy
) {
850 // only look at classes defined in this image
851 CatMap::iterator pos
= classToCategories
.find(categoryOnClassAtom
);
852 if ( pos
== classToCategories
.end() ) {
853 classToCategories
[categoryOnClassAtom
] = new std::vector
<const ld::Atom
*>();
854 classOrder
.push_back(categoryOnClassAtom
);
856 classToCategories
[categoryOnClassAtom
]->push_back(categoryAtom
);
857 // mark category atom and catlist atom as dead
858 deadAtoms
.insert(categoryAtom
);
859 deadAtoms
.insert(categoryListElementAtom
);
863 // record method list section
864 if ( (strcmp(sect
->sectionName(), "__objc_const") == 0) && (strcmp(sect
->segmentName(), "__DATA") == 0) )
865 methodListSection
= sect
;
868 // if found some categories
869 if ( classToCategories
.size() != 0 ) {
870 assert(methodListSection
!= NULL
);
871 sortAtomVector(classOrder
);
872 // alter each class definition to have new method list which includes all category methods
873 for (std::vector
<const ld::Atom
*>::iterator it
= classOrder
.begin(); it
!= classOrder
.end(); it
++) {
874 const ld::Atom
* classAtom
= *it
;
875 const std::vector
<const ld::Atom
*>* categories
= classToCategories
[classAtom
];
876 assert(categories
->size() != 0);
877 // if any category adds instance methods, generate new merged method list, and replace
878 if ( OptimizeCategories
<A
>::hasInstanceMethods(state
, categories
) ) {
879 const ld::Atom
* baseInstanceMethodListAtom
= Class
<A
>::getInstanceMethodList(state
, classAtom
);
880 const ld::Atom
* newInstanceMethodListAtom
= new MethodListAtom
<A
>(state
, baseInstanceMethodListAtom
, false, categories
, deadAtoms
);
881 const ld::Atom
* newClassRO
= Class
<A
>::setInstanceMethodList(state
, classAtom
, newInstanceMethodListAtom
, deadAtoms
);
882 // add new method list to final sections
883 methodListSection
->atoms
.push_back(newInstanceMethodListAtom
);
884 if ( newClassRO
!= NULL
) {
885 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
886 methodListSection
->atoms
.push_back(newClassRO
);
889 // if any category adds class methods, generate new merged method list, and replace
890 if ( OptimizeCategories
<A
>::hasClassMethods(state
, categories
) ) {
891 const ld::Atom
* baseClassMethodListAtom
= Class
<A
>::getClassMethodList(state
, classAtom
);
892 const ld::Atom
* newClassMethodListAtom
= new MethodListAtom
<A
>(state
, baseClassMethodListAtom
, true, categories
, deadAtoms
);
893 const ld::Atom
* newClassRO
= Class
<A
>::setClassMethodList(state
, classAtom
, newClassMethodListAtom
, deadAtoms
);
894 // add new method list to final sections
895 methodListSection
->atoms
.push_back(newClassMethodListAtom
);
896 if ( newClassRO
!= NULL
) {
897 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
898 methodListSection
->atoms
.push_back(newClassRO
);
901 // if any category adds protocols, generate new merged protocol list, and replace
902 if ( OptimizeCategories
<A
>::hasProtocols(state
, categories
) ) {
903 const ld::Atom
* baseProtocolListAtom
= Class
<A
>::getInstanceProtocolList(state
, classAtom
);
904 const ld::Atom
* newProtocolListAtom
= new ProtocolListAtom
<A
>(state
, baseProtocolListAtom
, categories
, deadAtoms
);
905 const ld::Atom
* newClassRO
= Class
<A
>::setInstanceProtocolList(state
, classAtom
, newProtocolListAtom
, deadAtoms
);
906 const ld::Atom
* newMetaClassRO
= Class
<A
>::setClassProtocolList(state
, classAtom
, newProtocolListAtom
, deadAtoms
);
907 // add new protocol list to final sections
908 methodListSection
->atoms
.push_back(newProtocolListAtom
);
909 if ( newClassRO
!= NULL
) {
910 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
911 methodListSection
->atoms
.push_back(newClassRO
);
913 if ( newMetaClassRO
!= NULL
) {
914 assert(strcmp(newMetaClassRO
->section().sectionName(), "__objc_const") == 0);
915 methodListSection
->atoms
.push_back(newMetaClassRO
);
918 // if any category adds properties, generate new merged property list, and replace
919 if ( OptimizeCategories
<A
>::hasProperties(state
, categories
) ) {
920 const ld::Atom
* basePropertyListAtom
= Class
<A
>::getInstancePropertyList(state
, classAtom
);
921 const ld::Atom
* newPropertyListAtom
= new PropertyListAtom
<A
>(state
, basePropertyListAtom
, categories
, deadAtoms
);
922 const ld::Atom
* newClassRO
= Class
<A
>::setInstancePropertyList(state
, classAtom
, newPropertyListAtom
, deadAtoms
);
923 // add new property list to final sections
924 methodListSection
->atoms
.push_back(newPropertyListAtom
);
925 if ( newClassRO
!= NULL
) {
926 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
927 methodListSection
->atoms
.push_back(newClassRO
);
934 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
935 ld::Internal::FinalSection
* sect
= *sit
;
936 sect
->atoms
.erase(std::remove_if(sect
->atoms
.begin(), sect
->atoms
.end(), OptimizedAway(deadAtoms
)), sect
->atoms
.end());
942 template <typename A
>
943 MethodListAtom
<A
>::MethodListAtom(ld::Internal
& state
, const ld::Atom
* baseMethodList
, bool meta
,
944 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
945 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
946 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
947 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _methodCount(0)
949 unsigned int fixupCount
= 0;
950 std::set
<const ld::Atom
*> baseMethodListMethodNameAtoms
;
951 // if base class has method list, then associate new method list with file defining class
952 if ( baseMethodList
!= NULL
) {
953 _file
= baseMethodList
->file();
954 // calculate total size of merge method lists
955 _methodCount
= MethodList
<A
>::count(state
, baseMethodList
);
956 deadAtoms
.insert(baseMethodList
);
957 fixupCount
= baseMethodList
->fixupsEnd() - baseMethodList
->fixupsBegin();
958 for (ld::Fixup::iterator fit
=baseMethodList
->fixupsBegin(); fit
!= baseMethodList
->fixupsEnd(); ++fit
) {
959 if ( (fit
->offsetInAtom
- 8) % (3*sizeof(pint_t
)) == 0 ) {
960 assert(fit
->binding
== ld::Fixup::bindingsIndirectlyBound
&& "malformed method list");
961 const ld::Atom
* target
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
962 assert(target
->contentType() == ld::Atom::typeCString
&& "malformed method list");
963 baseMethodListMethodNameAtoms
.insert(target
);
967 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
968 const ld::Atom
* categoryMethodListAtom
;
970 categoryMethodListAtom
= Category
<A
>::getClassMethods(state
, *ait
);
972 categoryMethodListAtom
= Category
<A
>::getInstanceMethods(state
, *ait
);
973 if ( categoryMethodListAtom
!= NULL
) {
974 _methodCount
+= MethodList
<A
>::count(state
, categoryMethodListAtom
);
975 fixupCount
+= (categoryMethodListAtom
->fixupsEnd() - categoryMethodListAtom
->fixupsBegin());
976 deadAtoms
.insert(categoryMethodListAtom
);
977 // if base class did not have method list, associate new method list with file the defined category
979 _file
= categoryMethodListAtom
->file();
982 //if ( baseMethodList != NULL )
983 // fprintf(stderr, "total merged method count=%u for baseMethodList=%s\n", _methodCount, baseMethodList->name());
985 // fprintf(stderr, "total merged method count=%u\n", _methodCount);
986 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
988 // copy fixups and adjust offsets (in reverse order to simulator objc runtime)
989 _fixups
.reserve(fixupCount
);
991 std::set
<const ld::Atom
*> categoryMethodNameAtoms
;
992 for (std::vector
<const ld::Atom
*>::const_reverse_iterator rit
=categories
->rbegin(); rit
!= categories
->rend(); ++rit
) {
993 const ld::Atom
* categoryMethodListAtom
;
995 categoryMethodListAtom
= Category
<A
>::getClassMethods(state
, *rit
);
997 categoryMethodListAtom
= Category
<A
>::getInstanceMethods(state
, *rit
);
998 if ( categoryMethodListAtom
!= NULL
) {
999 for (ld::Fixup::iterator fit
=categoryMethodListAtom
->fixupsBegin(); fit
!= categoryMethodListAtom
->fixupsEnd(); ++fit
) {
1000 ld::Fixup fixup
= *fit
;
1001 fixup
.offsetInAtom
+= slide
;
1002 _fixups
.push_back(fixup
);
1003 if ( (fixup
.offsetInAtom
- 8) % (3*sizeof(pint_t
)) == 0 ) {
1004 // <rdar://problem/8642343> warning when a method is overridden in a category in the same link unit
1005 assert(fixup
.binding
== ld::Fixup::bindingsIndirectlyBound
&& "malformed category method list");
1006 const ld::Atom
* target
= state
.indirectBindingTable
[fixup
.u
.bindingIndex
];
1007 assert(target
->contentType() == ld::Atom::typeCString
&& "malformed method list");
1008 // this objc pass happens after cstrings are coalesced, so we can just compare the atom addres instead of its content
1009 if ( baseMethodListMethodNameAtoms
.count(target
) != 0 ) {
1010 warning("%s method '%s' in category from %s overrides method from class in %s",
1011 (meta
? "meta" : "instance"), target
->rawContentPointer(),
1012 categoryMethodListAtom
->file()->path(), baseMethodList
->file()->path() );
1014 if ( categoryMethodNameAtoms
.count(target
) != 0 ) {
1015 warning("%s method '%s' in category from %s conflicts with same method from another category",
1016 (meta
? "meta" : "instance"), target
->rawContentPointer(),
1017 categoryMethodListAtom
->file()->path());
1019 categoryMethodNameAtoms
.insert(target
);
1022 slide
+= 3*sizeof(pint_t
) * MethodList
<A
>::count(state
, categoryMethodListAtom
);
1025 // add method list from base class last
1026 if ( baseMethodList
!= NULL
) {
1027 for (ld::Fixup::iterator fit
=baseMethodList
->fixupsBegin(); fit
!= baseMethodList
->fixupsEnd(); ++fit
) {
1028 ld::Fixup fixup
= *fit
;
1029 fixup
.offsetInAtom
+= slide
;
1030 _fixups
.push_back(fixup
);
1036 template <typename A
>
1037 ProtocolListAtom
<A
>::ProtocolListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
1038 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
1039 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
1040 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
1041 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _protocolCount(0)
1043 unsigned int fixupCount
= 0;
1044 if ( baseProtocolList
!= NULL
) {
1045 // if base class has protocol list, then associate new protocol list with file defining class
1046 _file
= baseProtocolList
->file();
1047 // calculate total size of merged protocol list
1048 _protocolCount
= ProtocolList
<A
>::count(state
, baseProtocolList
);
1049 deadAtoms
.insert(baseProtocolList
);
1050 fixupCount
= baseProtocolList
->fixupsEnd() - baseProtocolList
->fixupsBegin();
1052 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
1053 const ld::Atom
* categoryProtocolListAtom
= Category
<A
>::getProtocols(state
, *ait
);
1054 if ( categoryProtocolListAtom
!= NULL
) {
1055 _protocolCount
+= ProtocolList
<A
>::count(state
, categoryProtocolListAtom
);
1056 fixupCount
+= (categoryProtocolListAtom
->fixupsEnd() - categoryProtocolListAtom
->fixupsBegin());
1057 deadAtoms
.insert(categoryProtocolListAtom
);
1058 // if base class did not have protocol list, associate new protocol list with file the defined category
1059 if ( _file
== NULL
)
1060 _file
= categoryProtocolListAtom
->file();
1063 //fprintf(stderr, "total merged protocol count=%u\n", _protocolCount);
1064 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
1066 // copy fixups and adjust offsets
1067 _fixups
.reserve(fixupCount
);
1069 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
1070 const ld::Atom
* categoryProtocolListAtom
= Category
<A
>::getProtocols(state
, *it
);
1071 if ( categoryProtocolListAtom
!= NULL
) {
1072 for (ld::Fixup::iterator fit
=categoryProtocolListAtom
->fixupsBegin(); fit
!= categoryProtocolListAtom
->fixupsEnd(); ++fit
) {
1073 ld::Fixup fixup
= *fit
;
1074 fixup
.offsetInAtom
+= slide
;
1075 _fixups
.push_back(fixup
);
1076 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
1077 // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
1079 slide
+= sizeof(pint_t
) * ProtocolList
<A
>::count(state
, categoryProtocolListAtom
);
1082 // add method list from base class last
1083 if ( baseProtocolList
!= NULL
) {
1084 for (ld::Fixup::iterator fit
=baseProtocolList
->fixupsBegin(); fit
!= baseProtocolList
->fixupsEnd(); ++fit
) {
1085 ld::Fixup fixup
= *fit
;
1086 fixup
.offsetInAtom
+= slide
;
1087 _fixups
.push_back(fixup
);
1093 template <typename A
>
1094 PropertyListAtom
<A
>::PropertyListAtom(ld::Internal
& state
, const ld::Atom
* basePropertyList
,
1095 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
1096 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
1097 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
1098 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _propertyCount(0)
1100 unsigned int fixupCount
= 0;
1101 if ( basePropertyList
!= NULL
) {
1102 // if base class has property list, then associate new property list with file defining class
1103 _file
= basePropertyList
->file();
1104 // calculate total size of merged property list
1105 _propertyCount
= PropertyList
<A
>::count(state
, basePropertyList
);
1106 deadAtoms
.insert(basePropertyList
);
1107 fixupCount
= basePropertyList
->fixupsEnd() - basePropertyList
->fixupsBegin();
1109 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
1110 const ld::Atom
* categoryPropertyListAtom
= Category
<A
>::getProperties(state
, *ait
);
1111 if ( categoryPropertyListAtom
!= NULL
) {
1112 _propertyCount
+= PropertyList
<A
>::count(state
, categoryPropertyListAtom
);
1113 fixupCount
+= (categoryPropertyListAtom
->fixupsEnd() - categoryPropertyListAtom
->fixupsBegin());
1114 deadAtoms
.insert(categoryPropertyListAtom
);
1115 // if base class did not have property list, associate new property list with file the defined category
1116 if ( _file
== NULL
)
1117 _file
= categoryPropertyListAtom
->file();
1120 //fprintf(stderr, "total merged property count=%u\n", _propertyCount);
1121 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
1123 // copy fixups and adjust offsets
1124 _fixups
.reserve(fixupCount
);
1126 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
1127 const ld::Atom
* categoryPropertyListAtom
= Category
<A
>::getProperties(state
, *it
);
1128 if ( categoryPropertyListAtom
!= NULL
) {
1129 for (ld::Fixup::iterator fit
=categoryPropertyListAtom
->fixupsBegin(); fit
!= categoryPropertyListAtom
->fixupsEnd(); ++fit
) {
1130 ld::Fixup fixup
= *fit
;
1131 fixup
.offsetInAtom
+= slide
;
1132 _fixups
.push_back(fixup
);
1133 //fprintf(stderr, "offset=0x%08X, binding=%d\n", fixup.offsetInAtom, fixup.binding);
1134 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
1135 // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
1136 //else if ( fixup.binding == ld::Fixup::bindingsIndirectlyBound )
1137 // fprintf(stderr, "offset=0x%08X, indirect index=%u, name=%s\n", fixup.offsetInAtom, fixup.u.bindingIndex,
1138 // (char*)(state.indirectBindingTable[fixup.u.bindingIndex]->rawContentPointer()));
1140 slide
+= 2*sizeof(pint_t
) * PropertyList
<A
>::count(state
, categoryPropertyListAtom
);
1143 // add method list from base class last
1144 if ( basePropertyList
!= NULL
) {
1145 for (ld::Fixup::iterator fit
=basePropertyList
->fixupsBegin(); fit
!= basePropertyList
->fixupsEnd(); ++fit
) {
1146 ld::Fixup fixup
= *fit
;
1147 fixup
.offsetInAtom
+= slide
;
1148 _fixups
.push_back(fixup
);
1156 void doPass(const Options
& opts
, ld::Internal
& state
)
1158 // only make image info section if objc was used
1159 if ( state
.objcObjectConstraint
!= ld::File::objcConstraintNone
) {
1161 // verify dylibs are GC compatible with object files
1162 if ( state
.objcObjectConstraint
!= state
.objcDylibConstraint
) {
1163 if ( (state
.objcDylibConstraint
== ld::File::objcConstraintRetainRelease
)
1164 && (state
.objcObjectConstraint
== ld::File::objcConstraintGC
) ) {
1165 throw "Linked dylibs built for retain/release but object files built for GC-only";
1167 else if ( (state
.objcDylibConstraint
== ld::File::objcConstraintGC
)
1168 && (state
.objcObjectConstraint
== ld::File::objcConstraintRetainRelease
) ) {
1169 throw "Linked dylibs built for GC-only but object files built for retain/release";
1173 const bool compaction
= opts
.objcGcCompaction();
1175 // add image info atom
1176 switch ( opts
.architecture() ) {
1177 #if SUPPORT_ARCH_x86_64
1178 case CPU_TYPE_X86_64
:
1179 state
.addAtom(*new ObjCImageInfoAtom
<x86_64
>(state
.objcObjectConstraint
, compaction
,
1183 #if SUPPORT_ARCH_i386
1185 state
.addAtom(*new ObjCImageInfoAtom
<x86
>(state
.objcObjectConstraint
, compaction
,
1186 opts
.objCABIVersion2POverride() ? true : false));
1190 state
.addAtom(*new ObjCImageInfoAtom
<arm
>(state
.objcObjectConstraint
, compaction
,
1194 assert(0 && "unknown objc arch");
1198 if ( opts
.objcCategoryMerging() ) {
1199 // optimize classes defined in this linkage unit by merging in categories also in this linkage unit
1200 switch ( opts
.architecture() ) {
1201 #if SUPPORT_ARCH_x86_64
1202 case CPU_TYPE_X86_64
:
1203 OptimizeCategories
<x86_64
>::doit(opts
, state
);
1206 #if SUPPORT_ARCH_i386
1208 // disable optimization until fully tested
1209 if ( opts
.objCABIVersion2POverride() )
1210 OptimizeCategories
<x86
>::doit(opts
, state
);
1213 #if SUPPORT_ARCH_arm_any
1215 // disable optimization until fully tested
1216 OptimizeCategories
<arm
>::doit(opts
, state
);
1220 assert(0 && "unknown objc arch");
1227 } // namespace passes