1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2010-2011 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
30 #include <mach/machine.h>
36 #include "Architectures.hpp"
37 #include "MachOFileAbstraction.hpp"
48 struct objc_image_info
{
49 uint32_t version
; // initially 0
53 #define OBJC_IMAGE_SUPPORTS_GC (1<<1)
54 #define OBJC_IMAGE_REQUIRES_GC (1<<2)
55 #define OBJC_IMAGE_OPTIMIZED_BY_DYLD (1<<3)
56 #define OBJC_IMAGE_SUPPORTS_COMPACTION (1<<4)
57 #define OBJC_IMAGE_IS_SIMULATED (1<<5)
62 // This class is the 8 byte section containing ObjC flags
65 class ObjCImageInfoAtom
: public ld::Atom
{
67 ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint
,
68 bool compaction
, bool abi2
, uint8_t swiftVersion
);
70 virtual const ld::File
* file() const { return NULL
; }
71 virtual const char* name() const { return "objc image info"; }
72 virtual uint64_t size() const { return sizeof(objc_image_info
); }
73 virtual uint64_t objectAddress() const { return 0; }
74 virtual void setScope(Scope
) { }
75 virtual void copyRawContent(uint8_t buffer
[]) const {
76 memcpy(buffer
, &_content
, sizeof(objc_image_info
));
80 objc_image_info _content
;
82 static ld::Section _s_sectionABI1
;
83 static ld::Section _s_sectionABI2
;
86 template <typename A
> ld::Section ObjCImageInfoAtom
<A
>::_s_sectionABI1("__OBJC", "__image_info", ld::Section::typeUnclassified
);
87 template <typename A
> ld::Section ObjCImageInfoAtom
<A
>::_s_sectionABI2("__DATA", "__objc_imageinfo", ld::Section::typeUnclassified
);
91 ObjCImageInfoAtom
<A
>::ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint
, bool compaction
,
92 bool abi2
, uint8_t swiftVersion
)
93 : ld::Atom(abi2
? _s_sectionABI2
: _s_sectionABI1
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
94 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
95 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(2))
99 switch ( objcConstraint
) {
100 case ld::File::objcConstraintNone
:
101 case ld::File::objcConstraintRetainRelease
:
103 warning("ignoring -objc_gc_compaction because code not compiled for ObjC garbage collection");
105 case ld::File::objcConstraintRetainReleaseOrGC
:
106 value
|= OBJC_IMAGE_SUPPORTS_GC
;
108 value
|= OBJC_IMAGE_SUPPORTS_COMPACTION
;
110 case ld::File::objcConstraintGC
:
111 value
|= OBJC_IMAGE_SUPPORTS_GC
| OBJC_IMAGE_REQUIRES_GC
;
113 value
|= OBJC_IMAGE_SUPPORTS_COMPACTION
;
115 case ld::File::objcConstraintRetainReleaseForSimulator
:
116 value
|= OBJC_IMAGE_IS_SIMULATED
;
120 // provide swift language version in final binary for runtime to inspect
121 value
|= (swiftVersion
<< 8);
123 _content
.version
= 0;
124 A::P::E::set32(_content
.flags
, value
);
130 // This class is for a new Atom which is an ObjC method list created by merging method lists from categories
132 template <typename A
>
133 class MethodListAtom
: public ld::Atom
{
135 MethodListAtom(ld::Internal
& state
, const ld::Atom
* baseMethodList
, bool meta
,
136 const std::vector
<const ld::Atom
*>* categories
,
137 std::set
<const ld::Atom
*>& deadAtoms
);
139 virtual const ld::File
* file() const { return _file
; }
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])), 3*sizeof(pint_t
)); // entry size
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 const char* name() const { return "objc merged protocol list"; }
178 virtual uint64_t size() const { return (_protocolCount
+1)*sizeof(pint_t
); }
179 virtual uint64_t objectAddress() const { return 0; }
180 virtual void setScope(Scope
) { }
181 virtual void copyRawContent(uint8_t buffer
[]) const {
182 bzero(buffer
, size());
183 A::P::setP(*((pint_t
*)(buffer
)), _protocolCount
);
185 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
186 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
189 typedef typename
A::P::uint_t pint_t
;
191 const ld::File
* _file
;
192 unsigned int _protocolCount
;
193 std::vector
<ld::Fixup
> _fixups
;
195 static ld::Section _s_section
;
198 template <typename A
>
199 ld::Section ProtocolListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
204 // This class is for a new Atom which is an ObjC property list created by merging property lists from categories
206 template <typename A
>
207 class PropertyListAtom
: public ld::Atom
{
209 PropertyListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
210 const std::vector
<const ld::Atom
*>* categories
,
211 std::set
<const ld::Atom
*>& deadAtoms
);
213 virtual const ld::File
* file() const { return _file
; }
214 virtual const char* name() const { return "objc merged property list"; }
215 virtual uint64_t size() const { return _propertyCount
*2*sizeof(pint_t
) + 8; }
216 virtual uint64_t objectAddress() const { return 0; }
217 virtual void setScope(Scope
) { }
218 virtual void copyRawContent(uint8_t buffer
[]) const {
219 bzero(buffer
, size());
220 A::P::E::set32(((uint32_t*)(buffer
))[0], 2*sizeof(pint_t
)); // sizeof(objc_property)
221 A::P::E::set32(((uint32_t*)(buffer
))[1], _propertyCount
);
223 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
224 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
227 typedef typename
A::P::uint_t pint_t
;
229 const ld::File
* _file
;
230 unsigned int _propertyCount
;
231 std::vector
<ld::Fixup
> _fixups
;
233 static ld::Section _s_section
;
236 template <typename A
>
237 ld::Section PropertyListAtom
<A
>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified
);
244 // This class is used to create an Atom that replaces an atom from a .o file that holds a class_ro_t.
245 // It is needed because there is no way to add Fixups to an existing atom.
247 template <typename A
>
248 class ClassROOverlayAtom
: public ld::Atom
{
250 ClassROOverlayAtom(const ld::Atom
* classROAtom
);
252 // overrides of ld::Atom
253 virtual const ld::File
* file() const { return _atom
->file(); }
254 virtual const char* name() const { return _atom
->name(); }
255 virtual uint64_t size() const { return _atom
->size(); }
256 virtual uint64_t objectAddress() const { return _atom
->objectAddress(); }
257 virtual void copyRawContent(uint8_t buffer
[]) const
258 { _atom
->copyRawContent(buffer
); }
259 virtual const uint8_t* rawContentPointer() const
260 { return _atom
->rawContentPointer(); }
261 virtual unsigned long contentHash(const class ld::IndirectBindingTable
& ibt
) const
262 { return _atom
->contentHash(ibt
); }
263 virtual bool canCoalesceWith(const ld::Atom
& rhs
, const class ld::IndirectBindingTable
& ibt
) const
264 { return _atom
->canCoalesceWith(rhs
,ibt
); }
266 virtual ld::Fixup::iterator
fixupsBegin() const { return (ld::Fixup
*)&_fixups
[0]; }
267 virtual ld::Fixup::iterator
fixupsEnd() const { return (ld::Fixup
*)&_fixups
[_fixups
.size()]; }
269 void addProtocolListFixup();
270 void addPropertyListFixup();
271 void addMethodListFixup();
274 typedef typename
A::P::uint_t pint_t
;
276 const ld::Atom
* _atom
;
277 std::vector
<ld::Fixup
> _fixups
;
280 template <typename A
>
281 ClassROOverlayAtom
<A
>::ClassROOverlayAtom(const ld::Atom
* classROAtom
)
282 : ld::Atom(classROAtom
->section(), ld::Atom::definitionRegular
, ld::Atom::combineNever
,
283 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
284 classROAtom
->symbolTableInclusion(), false, false, false, classROAtom
->alignment()),
287 // ensure all attributes are same as original
288 this->setAttributesFromAtom(*classROAtom
);
290 // copy fixups from orginal atom
291 for (ld::Fixup::iterator fit
=classROAtom
->fixupsBegin(); fit
!= classROAtom
->fixupsEnd(); ++fit
) {
292 ld::Fixup fixup
= *fit
;
293 _fixups
.push_back(fixup
);
299 // Base class for reading and updating existing ObjC atoms from .o files
301 template <typename A
>
304 static const ld::Atom
* getPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
, unsigned int offset
, bool* hasAddend
=NULL
);
305 static void setPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
,
306 unsigned int offset
, const ld::Atom
* newAtom
);
307 typedef typename
A::P::uint_t pint_t
;
310 template <typename A
>
311 const ld::Atom
* ObjCData
<A
>::getPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
, unsigned int offset
, bool* hasAddend
)
313 const ld::Atom
* target
= NULL
;
314 if ( hasAddend
!= NULL
)
316 for (ld::Fixup::iterator fit
=contentAtom
->fixupsBegin(); fit
!= contentAtom
->fixupsEnd(); ++fit
) {
317 if ( fit
->offsetInAtom
== offset
) {
318 switch ( fit
->binding
) {
319 case ld::Fixup::bindingsIndirectlyBound
:
320 target
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
322 case ld::Fixup::bindingDirectlyBound
:
323 target
= fit
->u
.target
;
325 case ld::Fixup::bindingNone
:
326 if ( fit
->kind
== ld::Fixup::kindAddAddend
) {
327 if ( hasAddend
!= NULL
)
339 template <typename A
>
340 void ObjCData
<A
>::setPointerInContent(ld::Internal
& state
, const ld::Atom
* contentAtom
,
341 unsigned int offset
, const ld::Atom
* newAtom
)
343 for (ld::Fixup::iterator fit
=contentAtom
->fixupsBegin(); fit
!= contentAtom
->fixupsEnd(); ++fit
) {
344 if ( fit
->offsetInAtom
== offset
) {
345 switch ( fit
->binding
) {
346 case ld::Fixup::bindingsIndirectlyBound
:
347 state
.indirectBindingTable
[fit
->u
.bindingIndex
] = newAtom
;
349 case ld::Fixup::bindingDirectlyBound
:
350 fit
->u
.target
= newAtom
;
357 assert(0 && "could not update method list");
363 // Helper class for reading and updating existing ObjC category atoms from .o files
365 template <typename A
>
366 class Category
: public ObjCData
<A
> {
368 static const ld::Atom
* getClass(ld::Internal
& state
, const ld::Atom
* contentAtom
, bool& hasAddend
);
369 static const ld::Atom
* getInstanceMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
);
370 static const ld::Atom
* getClassMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
);
371 static const ld::Atom
* getProtocols(ld::Internal
& state
, const ld::Atom
* contentAtom
);
372 static const ld::Atom
* getProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
);
373 static uint32_t size() { return 6*sizeof(pint_t
); }
375 typedef typename
A::P::uint_t pint_t
;
379 template <typename A
>
380 const ld::Atom
* Category
<A
>::getClass(ld::Internal
& state
, const ld::Atom
* contentAtom
, bool& hasAddend
)
382 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, sizeof(pint_t
), &hasAddend
); // category_t.cls
385 template <typename A
>
386 const ld::Atom
* Category
<A
>::getInstanceMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
)
388 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 2*sizeof(pint_t
)); // category_t.instanceMethods
391 template <typename A
>
392 const ld::Atom
* Category
<A
>::getClassMethods(ld::Internal
& state
, const ld::Atom
* contentAtom
)
394 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 3*sizeof(pint_t
)); // category_t.classMethods
397 template <typename A
>
398 const ld::Atom
* Category
<A
>::getProtocols(ld::Internal
& state
, const ld::Atom
* contentAtom
)
400 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 4*sizeof(pint_t
)); // category_t.protocols
403 template <typename A
>
404 const ld::Atom
* Category
<A
>::getProperties(ld::Internal
& state
, const ld::Atom
* contentAtom
)
406 return ObjCData
<A
>::getPointerInContent(state
, contentAtom
, 5*sizeof(pint_t
)); // category_t.instanceProperties
410 template <typename A
>
411 class MethodList
: public ObjCData
<A
> {
413 static uint32_t count(ld::Internal
& state
, const ld::Atom
* methodListAtom
) {
414 const uint32_t* methodListData
= (uint32_t*)(methodListAtom
->rawContentPointer());
415 return A::P::E::get32(methodListData
[1]); // method_list_t.count
419 template <typename A
>
420 class ProtocolList
: public ObjCData
<A
> {
422 static uint32_t count(ld::Internal
& state
, const ld::Atom
* protocolListAtom
) {
423 pint_t
* protocolListData
= (pint_t
*)(protocolListAtom
->rawContentPointer());
424 return A::P::getP(*protocolListData
); // protocol_list_t.count
427 typedef typename
A::P::uint_t pint_t
;
430 template <typename A
>
431 class PropertyList
: public ObjCData
<A
> {
433 static uint32_t count(ld::Internal
& state
, const ld::Atom
* protocolListAtom
) {
434 uint32_t* protocolListData
= (uint32_t*)(protocolListAtom
->rawContentPointer());
435 return A::P::E::get32(protocolListData
[1]); // property_list_t.count
438 typedef typename
A::P::uint_t pint_t
;
444 // Helper class for reading and updating existing ObjC class atoms from .o files
446 template <typename A
>
447 class Class
: public ObjCData
<A
> {
449 static const ld::Atom
* getInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
);
450 static const ld::Atom
* getInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
);
451 static const ld::Atom
* getInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
);
452 static const ld::Atom
* getClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
);
453 static const ld::Atom
* setInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
454 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
455 static const ld::Atom
* setInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
456 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
457 static const ld::Atom
* setInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,
458 const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
459 static const ld::Atom
* setClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
460 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
461 static const ld::Atom
* setClassProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
462 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
);
463 static uint32_t size() { return 5*sizeof(pint_t
); }
464 static unsigned int class_ro_header_size();
466 typedef typename
A::P::uint_t pint_t
;
467 static const ld::Atom
* getROData(ld::Internal
& state
, const ld::Atom
* classAtom
);
470 template <> unsigned int Class
<x86_64
>::class_ro_header_size() { return 16; }
471 template <> unsigned int Class
<arm
>::class_ro_header_size() { return 12;}
472 template <> unsigned int Class
<x86
>::class_ro_header_size() { return 12; }
475 template <typename A
>
476 const ld::Atom
* Class
<A
>::getROData(ld::Internal
& state
, const ld::Atom
* classAtom
)
478 return ObjCData
<A
>::getPointerInContent(state
, classAtom
, 4*sizeof(pint_t
)); // class_t.data
482 template <typename A
>
483 const ld::Atom
* Class
<A
>::getInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
)
485 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
486 assert(classROAtom
!= NULL
);
487 return ObjCData
<A
>::getPointerInContent(state
, classROAtom
, class_ro_header_size() + 2*sizeof(pint_t
)); // class_ro_t.baseMethods
490 template <typename A
>
491 const ld::Atom
* Class
<A
>::getInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
)
493 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
494 assert(classROAtom
!= NULL
);
495 return ObjCData
<A
>::getPointerInContent(state
, classROAtom
, class_ro_header_size() + 3*sizeof(pint_t
)); // class_ro_t.baseProtocols
498 template <typename A
>
499 const ld::Atom
* Class
<A
>::getInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
)
501 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
502 assert(classROAtom
!= NULL
);
503 return ObjCData
<A
>::getPointerInContent(state
, classROAtom
, class_ro_header_size() + 6*sizeof(pint_t
)); // class_ro_t.baseProperties
506 template <typename A
>
507 const ld::Atom
* Class
<A
>::getClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
)
509 const ld::Atom
* metaClassAtom
= ObjCData
<A
>::getPointerInContent(state
, classAtom
, 0); // class_t.isa
510 assert(metaClassAtom
!= NULL
);
511 return Class
<A
>::getInstanceMethodList(state
, metaClassAtom
);
514 template <typename A
>
515 const ld::Atom
* Class
<A
>::setInstanceMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
516 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
518 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
519 assert(classROAtom
!= NULL
);
520 // if the base class does not already have a method list, we need to create an overlay
521 if ( getInstanceMethodList(state
, classAtom
) == NULL
) {
522 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(classROAtom
);
523 //fprintf(stderr, "replace class RO atom %p with %p for method list in class atom %s\n", classROAtom, overlay, classAtom->name());
524 overlay
->addMethodListFixup();
525 ObjCData
<A
>::setPointerInContent(state
, classAtom
, 4*sizeof(pint_t
), overlay
); // class_t.data
526 deadAtoms
.insert(classROAtom
);
527 ObjCData
<A
>::setPointerInContent(state
, overlay
, class_ro_header_size() + 2*sizeof(pint_t
), methodListAtom
); // class_ro_t.baseMethods
530 ObjCData
<A
>::setPointerInContent(state
, classROAtom
, class_ro_header_size() + 2*sizeof(pint_t
), methodListAtom
); // class_ro_t.baseMethods
531 return NULL
; // means classRO atom was not replaced
534 template <typename A
>
535 const ld::Atom
* Class
<A
>::setInstanceProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
536 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
538 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
539 assert(classROAtom
!= NULL
);
540 // if the base class does not already have a protocol list, we need to create an overlay
541 if ( getInstanceProtocolList(state
, classAtom
) == NULL
) {
542 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(classROAtom
);
543 //fprintf(stderr, "replace class RO atom %p with %p for protocol list in class atom %s\n", classROAtom, overlay, classAtom->name());
544 overlay
->addProtocolListFixup();
545 ObjCData
<A
>::setPointerInContent(state
, classAtom
, 4*sizeof(pint_t
), overlay
); // class_t.data
546 deadAtoms
.insert(classROAtom
);
547 ObjCData
<A
>::setPointerInContent(state
, overlay
, class_ro_header_size() + 3*sizeof(pint_t
), protocolListAtom
); // class_ro_t.baseProtocols
550 //fprintf(stderr, "set class RO atom %p protocol list in class atom %s\n", classROAtom, classAtom->name());
551 ObjCData
<A
>::setPointerInContent(state
, classROAtom
, class_ro_header_size() + 3*sizeof(pint_t
), protocolListAtom
); // class_ro_t.baseProtocols
552 return NULL
; // means classRO atom was not replaced
555 template <typename A
>
556 const ld::Atom
* Class
<A
>::setClassProtocolList(ld::Internal
& state
, const ld::Atom
* classAtom
,
557 const ld::Atom
* protocolListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
559 // meta class also points to same protocol list as class
560 const ld::Atom
* metaClassAtom
= ObjCData
<A
>::getPointerInContent(state
, classAtom
, 0); // class_t.isa
561 //fprintf(stderr, "setClassProtocolList(), classAtom=%p %s, metaClass=%p %s\n", classAtom, classAtom->name(), metaClassAtom, metaClassAtom->name());
562 assert(metaClassAtom
!= NULL
);
563 return setInstanceProtocolList(state
, metaClassAtom
, protocolListAtom
, deadAtoms
);
568 template <typename A
>
569 const ld::Atom
* Class
<A
>::setInstancePropertyList(ld::Internal
& state
, const ld::Atom
* classAtom
,
570 const ld::Atom
* propertyListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
572 const ld::Atom
* classROAtom
= getROData(state
, classAtom
); // class_t.data
573 assert(classROAtom
!= NULL
);
574 // if the base class does not already have a property list, we need to create an overlay
575 if ( getInstancePropertyList(state
, classAtom
) == NULL
) {
576 ClassROOverlayAtom
<A
>* overlay
= new ClassROOverlayAtom
<A
>(classROAtom
);
577 //fprintf(stderr, "replace class RO atom %p with %p for property list in class atom %s\n", classROAtom, overlay, classAtom->name());
578 overlay
->addPropertyListFixup();
579 ObjCData
<A
>::setPointerInContent(state
, classAtom
, 4*sizeof(pint_t
), overlay
); // class_t.data
580 deadAtoms
.insert(classROAtom
);
581 ObjCData
<A
>::setPointerInContent(state
, overlay
, class_ro_header_size() + 6*sizeof(pint_t
), propertyListAtom
); // class_ro_t.baseProperties
584 ObjCData
<A
>::setPointerInContent(state
, classROAtom
, class_ro_header_size() + 6*sizeof(pint_t
), propertyListAtom
); // class_ro_t.baseProperties
585 return NULL
; // means classRO atom was not replaced
588 template <typename A
>
589 const ld::Atom
* Class
<A
>::setClassMethodList(ld::Internal
& state
, const ld::Atom
* classAtom
,
590 const ld::Atom
* methodListAtom
, std::set
<const ld::Atom
*>& deadAtoms
)
592 // class methods is just instance methods of metaClass
593 const ld::Atom
* metaClassAtom
= ObjCData
<A
>::getPointerInContent(state
, classAtom
, 0); // class_t.isa
594 assert(metaClassAtom
!= NULL
);
595 return setInstanceMethodList(state
, metaClassAtom
, methodListAtom
, deadAtoms
);
601 void ClassROOverlayAtom
<x86_64
>::addMethodListFixup()
603 const ld::Atom
* targetAtom
= this; // temporary
604 uint32_t offset
= Class
<x86_64
>::class_ro_header_size() + 2*8; // class_ro_t.baseMethods
605 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian64
, targetAtom
));
609 void ClassROOverlayAtom
<arm
>::addMethodListFixup()
611 const ld::Atom
* targetAtom
= this; // temporary
612 uint32_t offset
= Class
<arm
>::class_ro_header_size() + 2*4; // class_ro_t.baseMethods
613 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
617 void ClassROOverlayAtom
<x86
>::addMethodListFixup()
619 const ld::Atom
* targetAtom
= this; // temporary
620 uint32_t offset
= Class
<x86
>::class_ro_header_size() + 2*4; // class_ro_t.baseMethods
621 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
627 void ClassROOverlayAtom
<x86_64
>::addProtocolListFixup()
629 const ld::Atom
* targetAtom
= this; // temporary
630 uint32_t offset
= Class
<x86_64
>::class_ro_header_size() + 3*8; // class_ro_t.baseProtocols
631 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian64
, targetAtom
));
635 void ClassROOverlayAtom
<arm
>::addProtocolListFixup()
637 const ld::Atom
* targetAtom
= this; // temporary
638 uint32_t offset
= Class
<arm
>::class_ro_header_size() + 3*4; // class_ro_t.baseProtocols
639 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
643 void ClassROOverlayAtom
<x86
>::addProtocolListFixup()
645 const ld::Atom
* targetAtom
= this; // temporary
646 uint32_t offset
= Class
<x86
>::class_ro_header_size() + 3*4; // class_ro_t.baseProtocols
647 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
652 void ClassROOverlayAtom
<x86_64
>::addPropertyListFixup()
654 const ld::Atom
* targetAtom
= this; // temporary
655 uint32_t offset
= Class
<x86_64
>::class_ro_header_size() + 6*8; // class_ro_t.baseProperties
656 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian64
, targetAtom
));
660 void ClassROOverlayAtom
<arm
>::addPropertyListFixup()
662 const ld::Atom
* targetAtom
= this; // temporary
663 uint32_t offset
= Class
<arm
>::class_ro_header_size() + 6*4; // class_ro_t.baseProperties
664 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
668 void ClassROOverlayAtom
<x86
>::addPropertyListFixup()
670 const ld::Atom
* targetAtom
= this; // temporary
671 uint32_t offset
= Class
<x86
>::class_ro_header_size() + 6*4; // class_ro_t.baseProperties
672 _fixups
.push_back(ld::Fixup(offset
, ld::Fixup::k1of1
, ld::Fixup::kindStoreTargetAddressLittleEndian32
, targetAtom
));
679 // Encapsulates merging of ObjC categories
681 template <typename A
>
682 class OptimizeCategories
{
684 static void doit(const Options
& opts
, ld::Internal
& state
);
685 static bool hasInstanceMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
686 static bool hasClassMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
687 static bool hasProtocols(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
688 static bool hasProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
);
691 static unsigned int class_ro_baseMethods_offset();
693 typedef typename
A::P::uint_t pint_t
;
698 template <typename A
>
699 bool OptimizeCategories
<A
>::hasInstanceMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
701 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
702 const ld::Atom
* categoryAtom
= *it
;
703 const ld::Atom
* methodList
= Category
<A
>::getInstanceMethods(state
, categoryAtom
);
704 if ( methodList
!= NULL
) {
705 if ( MethodList
<A
>::count(state
, methodList
) > 0 )
713 template <typename A
>
714 bool OptimizeCategories
<A
>::hasClassMethods(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
716 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
717 const ld::Atom
* categoryAtom
= *it
;
718 const ld::Atom
* methodList
= Category
<A
>::getClassMethods(state
, categoryAtom
);
719 if ( methodList
!= NULL
) {
720 if ( MethodList
<A
>::count(state
, methodList
) > 0 )
727 template <typename A
>
728 bool OptimizeCategories
<A
>::hasProtocols(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
730 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
731 const ld::Atom
* categoryAtom
= *it
;
732 const ld::Atom
* protocolListAtom
= Category
<A
>::getProtocols(state
, categoryAtom
);
733 if ( protocolListAtom
!= NULL
) {
734 if ( ProtocolList
<A
>::count(state
, protocolListAtom
) > 0 ) {
743 template <typename A
>
744 bool OptimizeCategories
<A
>::hasProperties(ld::Internal
& state
, const std::vector
<const ld::Atom
*>* categories
)
746 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
747 const ld::Atom
* categoryAtom
= *it
;
748 const ld::Atom
* propertyListAtom
= Category
<A
>::getProperties(state
, categoryAtom
);
749 if ( propertyListAtom
!= NULL
) {
750 if ( PropertyList
<A
>::count(state
, propertyListAtom
) > 0 )
758 static const ld::Atom
* fixClassAliases(const ld::Atom
* classAtom
)
760 if ( (classAtom
->size() != 0) || (classAtom
->definition() == ld::Atom::definitionProxy
) )
763 for (ld::Fixup::iterator fit
=classAtom
->fixupsBegin(); fit
!= classAtom
->fixupsEnd(); ++fit
) {
764 if ( fit
->kind
== ld::Fixup::kindNoneFollowOn
) {
765 assert(fit
->offsetInAtom
== 0);
766 assert(fit
->binding
== ld::Fixup::bindingDirectlyBound
);
767 return fit
->u
.target
;
775 // Helper for std::remove_if
777 class OptimizedAway
{
779 OptimizedAway(const std::set
<const ld::Atom
*>& oa
) : _dead(oa
) {}
780 bool operator()(const ld::Atom
* atom
) const {
781 return ( _dead
.count(atom
) != 0 );
784 const std::set
<const ld::Atom
*>& _dead
;
789 bool operator()(const Atom
* left
, const Atom
* right
)
791 // sort by file ordinal, then object address, then zero size, then symbol name
792 // only file based atoms are supported (file() != NULL)
793 if (left
==right
) return false;
794 const File
*leftf
= left
->file();
795 const File
*rightf
= right
->file();
797 if (leftf
== rightf
) {
798 if (left
->objectAddress() != right
->objectAddress()) {
799 return left
->objectAddress() < right
->objectAddress();
801 // for atoms in the same file with the same address, zero sized
802 // atoms must sort before nonzero sized atoms
803 if ((left
->size() == 0 && right
->size() > 0) || (left
->size() > 0 && right
->size() == 0))
804 return left
->size() < right
->size();
805 return strcmp(left
->name(), right
->name());
808 return (leftf
->ordinal() < rightf
->ordinal());
812 static void sortAtomVector(std::vector
<const Atom
*> &atoms
) {
813 std::sort(atoms
.begin(), atoms
.end(), AtomSorter());
816 template <typename A
>
817 void OptimizeCategories
<A
>::doit(const Options
& opts
, ld::Internal
& state
)
819 // first find all categories referenced by __objc_nlcatlist section
820 std::set
<const ld::Atom
*> nlcatListAtoms
;
821 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
822 ld::Internal::FinalSection
* sect
= *sit
;
823 if ( (strcmp(sect
->sectionName(), "__objc_nlcatlist") == 0) && (strncmp(sect
->segmentName(), "__DATA", 6) == 0) ) {
824 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
825 const ld::Atom
* categoryListElementAtom
= *ait
;
826 for (unsigned int offset
=0; offset
< categoryListElementAtom
->size(); offset
+= sizeof(pint_t
)) {
827 const ld::Atom
* categoryAtom
= ObjCData
<A
>::getPointerInContent(state
, categoryListElementAtom
, offset
);
828 //fprintf(stderr, "offset=%d, cat=%p %s\n", offset, categoryAtom, categoryAtom->name());
829 assert(categoryAtom
!= NULL
);
830 nlcatListAtoms
.insert(categoryAtom
);
836 // build map of all classes in this image that have categories on them
837 typedef std::map
<const ld::Atom
*, std::vector
<const ld::Atom
*>*> CatMap
;
838 CatMap classToCategories
;
839 std::vector
<const ld::Atom
*> classOrder
;
840 std::set
<const ld::Atom
*> deadAtoms
;
841 ld::Internal::FinalSection
* methodListSection
= NULL
;
842 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
843 ld::Internal::FinalSection
* sect
= *sit
;
844 if ( sect
->type() == ld::Section::typeObjC2CategoryList
) {
845 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
846 const ld::Atom
* categoryListElementAtom
= *ait
;
848 const ld::Atom
* categoryAtom
= ObjCData
<A
>::getPointerInContent(state
, categoryListElementAtom
, 0, &hasAddend
);
849 if ( hasAddend
|| (categoryAtom
->symbolTableInclusion() == ld::Atom::symbolTableNotIn
)) {
850 //<rdar://problem/8309530> gcc-4.0 uses 'L' labels on categories which disables this optimization
851 //warning("__objc_catlist element does not point to start of category");
854 assert(categoryAtom
!= NULL
);
855 assert(categoryAtom
->size() >= Category
<A
>::size());
856 // ignore categories also in __objc_nlcatlist
857 if ( nlcatListAtoms
.count(categoryAtom
) != 0 )
859 const ld::Atom
* categoryOnClassAtom
= fixClassAliases(Category
<A
>::getClass(state
, categoryAtom
, hasAddend
));
860 assert(categoryOnClassAtom
!= NULL
);
861 // only look at classes defined in this image
862 if ( categoryOnClassAtom
->definition() != ld::Atom::definitionProxy
) {
863 // <rdar://problem/16107696> for now, back off optimization on new style classes
864 if ( hasAddend
!= 0 )
866 // <rdar://problem/17249777> don't apply categories to swift classes
867 if ( categoryOnClassAtom
->hasFixupsOfKind(ld::Fixup::kindNoneGroupSubordinate
) )
870 CatMap::iterator pos
= classToCategories
.find(categoryOnClassAtom
);
871 if ( pos
== classToCategories
.end() ) {
872 classToCategories
[categoryOnClassAtom
] = new std::vector
<const ld::Atom
*>();
873 classOrder
.push_back(categoryOnClassAtom
);
875 classToCategories
[categoryOnClassAtom
]->push_back(categoryAtom
);
876 // mark category atom and catlist atom as dead
877 deadAtoms
.insert(categoryAtom
);
878 deadAtoms
.insert(categoryListElementAtom
);
882 // record method list section
883 if ( (strcmp(sect
->sectionName(), "__objc_const") == 0) && (strncmp(sect
->segmentName(), "__DATA", 6) == 0) )
884 methodListSection
= sect
;
887 // if found some categories
888 if ( classToCategories
.size() != 0 ) {
889 assert(methodListSection
!= NULL
);
890 sortAtomVector(classOrder
);
891 // alter each class definition to have new method list which includes all category methods
892 for (std::vector
<const ld::Atom
*>::iterator it
= classOrder
.begin(); it
!= classOrder
.end(); it
++) {
893 const ld::Atom
* classAtom
= *it
;
894 const std::vector
<const ld::Atom
*>* categories
= classToCategories
[classAtom
];
895 assert(categories
->size() != 0);
896 // if any category adds instance methods, generate new merged method list, and replace
897 if ( OptimizeCategories
<A
>::hasInstanceMethods(state
, categories
) ) {
898 const ld::Atom
* baseInstanceMethodListAtom
= Class
<A
>::getInstanceMethodList(state
, classAtom
);
899 const ld::Atom
* newInstanceMethodListAtom
= new MethodListAtom
<A
>(state
, baseInstanceMethodListAtom
, false, categories
, deadAtoms
);
900 const ld::Atom
* newClassRO
= Class
<A
>::setInstanceMethodList(state
, classAtom
, newInstanceMethodListAtom
, deadAtoms
);
901 // add new method list to final sections
902 methodListSection
->atoms
.push_back(newInstanceMethodListAtom
);
903 state
.atomToSection
[newInstanceMethodListAtom
] = methodListSection
;
904 if ( newClassRO
!= NULL
) {
905 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
906 methodListSection
->atoms
.push_back(newClassRO
);
907 state
.atomToSection
[newClassRO
] = methodListSection
;
910 // if any category adds class methods, generate new merged method list, and replace
911 if ( OptimizeCategories
<A
>::hasClassMethods(state
, categories
) ) {
912 const ld::Atom
* baseClassMethodListAtom
= Class
<A
>::getClassMethodList(state
, classAtom
);
913 const ld::Atom
* newClassMethodListAtom
= new MethodListAtom
<A
>(state
, baseClassMethodListAtom
, true, categories
, deadAtoms
);
914 const ld::Atom
* newClassRO
= Class
<A
>::setClassMethodList(state
, classAtom
, newClassMethodListAtom
, deadAtoms
);
915 // add new method list to final sections
916 methodListSection
->atoms
.push_back(newClassMethodListAtom
);
917 state
.atomToSection
[newClassMethodListAtom
] = methodListSection
;
918 if ( newClassRO
!= NULL
) {
919 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
920 methodListSection
->atoms
.push_back(newClassRO
);
921 state
.atomToSection
[newClassRO
] = methodListSection
;
924 // if any category adds protocols, generate new merged protocol list, and replace
925 if ( OptimizeCategories
<A
>::hasProtocols(state
, categories
) ) {
926 const ld::Atom
* baseProtocolListAtom
= Class
<A
>::getInstanceProtocolList(state
, classAtom
);
927 const ld::Atom
* newProtocolListAtom
= new ProtocolListAtom
<A
>(state
, baseProtocolListAtom
, categories
, deadAtoms
);
928 const ld::Atom
* newClassRO
= Class
<A
>::setInstanceProtocolList(state
, classAtom
, newProtocolListAtom
, deadAtoms
);
929 const ld::Atom
* newMetaClassRO
= Class
<A
>::setClassProtocolList(state
, classAtom
, newProtocolListAtom
, deadAtoms
);
930 // add new protocol list to final sections
931 methodListSection
->atoms
.push_back(newProtocolListAtom
);
932 state
.atomToSection
[newProtocolListAtom
] = methodListSection
;
933 if ( newClassRO
!= NULL
) {
934 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
935 methodListSection
->atoms
.push_back(newClassRO
);
936 state
.atomToSection
[newClassRO
] = methodListSection
;
938 if ( newMetaClassRO
!= NULL
) {
939 assert(strcmp(newMetaClassRO
->section().sectionName(), "__objc_const") == 0);
940 methodListSection
->atoms
.push_back(newMetaClassRO
);
941 state
.atomToSection
[newMetaClassRO
] = methodListSection
;
944 // if any category adds properties, generate new merged property list, and replace
945 if ( OptimizeCategories
<A
>::hasProperties(state
, categories
) ) {
946 const ld::Atom
* basePropertyListAtom
= Class
<A
>::getInstancePropertyList(state
, classAtom
);
947 const ld::Atom
* newPropertyListAtom
= new PropertyListAtom
<A
>(state
, basePropertyListAtom
, categories
, deadAtoms
);
948 const ld::Atom
* newClassRO
= Class
<A
>::setInstancePropertyList(state
, classAtom
, newPropertyListAtom
, deadAtoms
);
949 // add new property list to final sections
950 methodListSection
->atoms
.push_back(newPropertyListAtom
);
951 state
.atomToSection
[newPropertyListAtom
] = methodListSection
;
952 if ( newClassRO
!= NULL
) {
953 assert(strcmp(newClassRO
->section().sectionName(), "__objc_const") == 0);
954 methodListSection
->atoms
.push_back(newClassRO
);
955 state
.atomToSection
[newClassRO
] = methodListSection
;
962 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=state
.sections
.begin(); sit
!= state
.sections
.end(); ++sit
) {
963 ld::Internal::FinalSection
* sect
= *sit
;
964 sect
->atoms
.erase(std::remove_if(sect
->atoms
.begin(), sect
->atoms
.end(), OptimizedAway(deadAtoms
)), sect
->atoms
.end());
970 template <typename A
>
971 MethodListAtom
<A
>::MethodListAtom(ld::Internal
& state
, const ld::Atom
* baseMethodList
, bool meta
,
972 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
973 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
974 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
975 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _methodCount(0)
977 unsigned int fixupCount
= 0;
978 std::set
<const ld::Atom
*> baseMethodListMethodNameAtoms
;
979 // if base class has method list, then associate new method list with file defining class
980 if ( baseMethodList
!= NULL
) {
981 _file
= baseMethodList
->file();
982 // calculate total size of merge method lists
983 _methodCount
= MethodList
<A
>::count(state
, baseMethodList
);
984 deadAtoms
.insert(baseMethodList
);
985 fixupCount
= baseMethodList
->fixupsEnd() - baseMethodList
->fixupsBegin();
986 for (ld::Fixup::iterator fit
=baseMethodList
->fixupsBegin(); fit
!= baseMethodList
->fixupsEnd(); ++fit
) {
987 if ( (fit
->offsetInAtom
- 8) % (3*sizeof(pint_t
)) == 0 ) {
988 assert(fit
->binding
== ld::Fixup::bindingsIndirectlyBound
&& "malformed method list");
989 const ld::Atom
* target
= state
.indirectBindingTable
[fit
->u
.bindingIndex
];
990 assert(target
->contentType() == ld::Atom::typeCString
&& "malformed method list");
991 baseMethodListMethodNameAtoms
.insert(target
);
995 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
996 const ld::Atom
* categoryMethodListAtom
;
998 categoryMethodListAtom
= Category
<A
>::getClassMethods(state
, *ait
);
1000 categoryMethodListAtom
= Category
<A
>::getInstanceMethods(state
, *ait
);
1001 if ( categoryMethodListAtom
!= NULL
) {
1002 _methodCount
+= MethodList
<A
>::count(state
, categoryMethodListAtom
);
1003 fixupCount
+= (categoryMethodListAtom
->fixupsEnd() - categoryMethodListAtom
->fixupsBegin());
1004 deadAtoms
.insert(categoryMethodListAtom
);
1005 // if base class did not have method list, associate new method list with file the defined category
1006 if ( _file
== NULL
)
1007 _file
= categoryMethodListAtom
->file();
1010 //if ( baseMethodList != NULL )
1011 // fprintf(stderr, "total merged method count=%u for baseMethodList=%s\n", _methodCount, baseMethodList->name());
1013 // fprintf(stderr, "total merged method count=%u\n", _methodCount);
1014 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
1016 // copy fixups and adjust offsets (in reverse order to simulator objc runtime)
1017 _fixups
.reserve(fixupCount
);
1019 std::set
<const ld::Atom
*> categoryMethodNameAtoms
;
1020 for (std::vector
<const ld::Atom
*>::const_reverse_iterator rit
=categories
->rbegin(); rit
!= categories
->rend(); ++rit
) {
1021 const ld::Atom
* categoryMethodListAtom
;
1023 categoryMethodListAtom
= Category
<A
>::getClassMethods(state
, *rit
);
1025 categoryMethodListAtom
= Category
<A
>::getInstanceMethods(state
, *rit
);
1026 if ( categoryMethodListAtom
!= NULL
) {
1027 for (ld::Fixup::iterator fit
=categoryMethodListAtom
->fixupsBegin(); fit
!= categoryMethodListAtom
->fixupsEnd(); ++fit
) {
1028 ld::Fixup fixup
= *fit
;
1029 fixup
.offsetInAtom
+= slide
;
1030 _fixups
.push_back(fixup
);
1031 if ( (fixup
.offsetInAtom
- 8) % (3*sizeof(pint_t
)) == 0 ) {
1032 // <rdar://problem/8642343> warning when a method is overridden in a category in the same link unit
1033 assert(fixup
.binding
== ld::Fixup::bindingsIndirectlyBound
&& "malformed category method list");
1034 const ld::Atom
* target
= state
.indirectBindingTable
[fixup
.u
.bindingIndex
];
1035 assert(target
->contentType() == ld::Atom::typeCString
&& "malformed method list");
1036 // this objc pass happens after cstrings are coalesced, so we can just compare the atom addres instead of its content
1037 if ( baseMethodListMethodNameAtoms
.count(target
) != 0 ) {
1038 warning("%s method '%s' in category from %s overrides method from class in %s",
1039 (meta
? "meta" : "instance"), target
->rawContentPointer(),
1040 categoryMethodListAtom
->file()->path(), baseMethodList
->file()->path() );
1042 if ( categoryMethodNameAtoms
.count(target
) != 0 ) {
1043 warning("%s method '%s' in category from %s conflicts with same method from another category",
1044 (meta
? "meta" : "instance"), target
->rawContentPointer(),
1045 categoryMethodListAtom
->file()->path());
1047 categoryMethodNameAtoms
.insert(target
);
1050 slide
+= 3*sizeof(pint_t
) * MethodList
<A
>::count(state
, categoryMethodListAtom
);
1053 // add method list from base class last
1054 if ( baseMethodList
!= NULL
) {
1055 for (ld::Fixup::iterator fit
=baseMethodList
->fixupsBegin(); fit
!= baseMethodList
->fixupsEnd(); ++fit
) {
1056 ld::Fixup fixup
= *fit
;
1057 fixup
.offsetInAtom
+= slide
;
1058 _fixups
.push_back(fixup
);
1064 template <typename A
>
1065 ProtocolListAtom
<A
>::ProtocolListAtom(ld::Internal
& state
, const ld::Atom
* baseProtocolList
,
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
), _protocolCount(0)
1071 unsigned int fixupCount
= 0;
1072 if ( baseProtocolList
!= NULL
) {
1073 // if base class has protocol list, then associate new protocol list with file defining class
1074 _file
= baseProtocolList
->file();
1075 // calculate total size of merged protocol list
1076 _protocolCount
= ProtocolList
<A
>::count(state
, baseProtocolList
);
1077 deadAtoms
.insert(baseProtocolList
);
1078 fixupCount
= baseProtocolList
->fixupsEnd() - baseProtocolList
->fixupsBegin();
1080 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
1081 const ld::Atom
* categoryProtocolListAtom
= Category
<A
>::getProtocols(state
, *ait
);
1082 if ( categoryProtocolListAtom
!= NULL
) {
1083 _protocolCount
+= ProtocolList
<A
>::count(state
, categoryProtocolListAtom
);
1084 fixupCount
+= (categoryProtocolListAtom
->fixupsEnd() - categoryProtocolListAtom
->fixupsBegin());
1085 deadAtoms
.insert(categoryProtocolListAtom
);
1086 // if base class did not have protocol list, associate new protocol list with file the defined category
1087 if ( _file
== NULL
)
1088 _file
= categoryProtocolListAtom
->file();
1091 //fprintf(stderr, "total merged protocol count=%u\n", _protocolCount);
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
* categoryProtocolListAtom
= Category
<A
>::getProtocols(state
, *it
);
1099 if ( categoryProtocolListAtom
!= NULL
) {
1100 for (ld::Fixup::iterator fit
=categoryProtocolListAtom
->fixupsBegin(); fit
!= categoryProtocolListAtom
->fixupsEnd(); ++fit
) {
1101 ld::Fixup fixup
= *fit
;
1102 fixup
.offsetInAtom
+= slide
;
1103 _fixups
.push_back(fixup
);
1104 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
1105 // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
1107 slide
+= sizeof(pint_t
) * ProtocolList
<A
>::count(state
, categoryProtocolListAtom
);
1110 // add method list from base class last
1111 if ( baseProtocolList
!= NULL
) {
1112 for (ld::Fixup::iterator fit
=baseProtocolList
->fixupsBegin(); fit
!= baseProtocolList
->fixupsEnd(); ++fit
) {
1113 ld::Fixup fixup
= *fit
;
1114 fixup
.offsetInAtom
+= slide
;
1115 _fixups
.push_back(fixup
);
1121 template <typename A
>
1122 PropertyListAtom
<A
>::PropertyListAtom(ld::Internal
& state
, const ld::Atom
* basePropertyList
,
1123 const std::vector
<const ld::Atom
*>* categories
, std::set
<const ld::Atom
*>& deadAtoms
)
1124 : ld::Atom(_s_section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
1125 ld::Atom::scopeLinkageUnit
, ld::Atom::typeUnclassified
,
1126 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(3)), _file(NULL
), _propertyCount(0)
1128 unsigned int fixupCount
= 0;
1129 if ( basePropertyList
!= NULL
) {
1130 // if base class has property list, then associate new property list with file defining class
1131 _file
= basePropertyList
->file();
1132 // calculate total size of merged property list
1133 _propertyCount
= PropertyList
<A
>::count(state
, basePropertyList
);
1134 deadAtoms
.insert(basePropertyList
);
1135 fixupCount
= basePropertyList
->fixupsEnd() - basePropertyList
->fixupsBegin();
1137 for (std::vector
<const ld::Atom
*>::const_iterator ait
=categories
->begin(); ait
!= categories
->end(); ++ait
) {
1138 const ld::Atom
* categoryPropertyListAtom
= Category
<A
>::getProperties(state
, *ait
);
1139 if ( categoryPropertyListAtom
!= NULL
) {
1140 _propertyCount
+= PropertyList
<A
>::count(state
, categoryPropertyListAtom
);
1141 fixupCount
+= (categoryPropertyListAtom
->fixupsEnd() - categoryPropertyListAtom
->fixupsBegin());
1142 deadAtoms
.insert(categoryPropertyListAtom
);
1143 // if base class did not have property list, associate new property list with file the defined category
1144 if ( _file
== NULL
)
1145 _file
= categoryPropertyListAtom
->file();
1148 //fprintf(stderr, "total merged property count=%u\n", _propertyCount);
1149 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
1151 // copy fixups and adjust offsets
1152 _fixups
.reserve(fixupCount
);
1154 for (std::vector
<const ld::Atom
*>::const_iterator it
=categories
->begin(); it
!= categories
->end(); ++it
) {
1155 const ld::Atom
* categoryPropertyListAtom
= Category
<A
>::getProperties(state
, *it
);
1156 if ( categoryPropertyListAtom
!= NULL
) {
1157 for (ld::Fixup::iterator fit
=categoryPropertyListAtom
->fixupsBegin(); fit
!= categoryPropertyListAtom
->fixupsEnd(); ++fit
) {
1158 ld::Fixup fixup
= *fit
;
1159 fixup
.offsetInAtom
+= slide
;
1160 _fixups
.push_back(fixup
);
1161 //fprintf(stderr, "offset=0x%08X, binding=%d\n", fixup.offsetInAtom, fixup.binding);
1162 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
1163 // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
1164 //else if ( fixup.binding == ld::Fixup::bindingsIndirectlyBound )
1165 // fprintf(stderr, "offset=0x%08X, indirect index=%u, name=%s\n", fixup.offsetInAtom, fixup.u.bindingIndex,
1166 // (char*)(state.indirectBindingTable[fixup.u.bindingIndex]->rawContentPointer()));
1168 slide
+= 2*sizeof(pint_t
) * PropertyList
<A
>::count(state
, categoryPropertyListAtom
);
1171 // add method list from base class last
1172 if ( basePropertyList
!= NULL
) {
1173 for (ld::Fixup::iterator fit
=basePropertyList
->fixupsBegin(); fit
!= basePropertyList
->fixupsEnd(); ++fit
) {
1174 ld::Fixup fixup
= *fit
;
1175 fixup
.offsetInAtom
+= slide
;
1176 _fixups
.push_back(fixup
);
1184 void doPass(const Options
& opts
, ld::Internal
& state
)
1186 // only make image info section if objc was used
1187 if ( state
.objcObjectConstraint
!= ld::File::objcConstraintNone
) {
1189 // verify dylibs are GC compatible with object files
1190 if ( state
.objcObjectConstraint
!= state
.objcDylibConstraint
) {
1191 if ( (state
.objcDylibConstraint
== ld::File::objcConstraintRetainRelease
)
1192 && (state
.objcObjectConstraint
== ld::File::objcConstraintGC
) ) {
1193 throw "Linked dylibs built for retain/release but object files built for GC-only";
1195 else if ( (state
.objcDylibConstraint
== ld::File::objcConstraintGC
)
1196 && (state
.objcObjectConstraint
== ld::File::objcConstraintRetainRelease
) ) {
1197 throw "Linked dylibs built for GC-only but object files built for retain/release";
1201 const bool compaction
= opts
.objcGcCompaction();
1203 // add image info atom
1204 switch ( opts
.architecture() ) {
1205 #if SUPPORT_ARCH_x86_64
1206 case CPU_TYPE_X86_64
:
1207 state
.addAtom(*new ObjCImageInfoAtom
<x86_64
>(state
.objcObjectConstraint
, compaction
,
1208 true, state
.swiftVersion
));
1211 #if SUPPORT_ARCH_i386
1213 state
.addAtom(*new ObjCImageInfoAtom
<x86
>(state
.objcObjectConstraint
, compaction
,
1214 opts
.objCABIVersion2POverride() ? true : false, state
.swiftVersion
));
1217 #if SUPPORT_ARCH_arm_any
1219 state
.addAtom(*new ObjCImageInfoAtom
<arm
>(state
.objcObjectConstraint
, compaction
,
1220 true, state
.swiftVersion
));
1223 #if SUPPORT_ARCH_arm64
1224 case CPU_TYPE_ARM64
:
1225 state
.addAtom(*new ObjCImageInfoAtom
<arm64
>(state
.objcObjectConstraint
, compaction
,
1226 true, state
.swiftVersion
));
1230 assert(0 && "unknown objc arch");
1234 if ( opts
.objcCategoryMerging() ) {
1235 // optimize classes defined in this linkage unit by merging in categories also in this linkage unit
1236 switch ( opts
.architecture() ) {
1237 #if SUPPORT_ARCH_x86_64
1238 case CPU_TYPE_X86_64
:
1239 OptimizeCategories
<x86_64
>::doit(opts
, state
);
1242 #if SUPPORT_ARCH_i386
1244 if ( opts
.objCABIVersion2POverride() )
1245 OptimizeCategories
<x86
>::doit(opts
, state
);
1248 #if SUPPORT_ARCH_arm_any
1250 OptimizeCategories
<arm
>::doit(opts
, state
);
1253 #if SUPPORT_ARCH_arm64
1254 case CPU_TYPE_ARM64
:
1255 // disabled until tested
1259 assert(0 && "unknown objc arch");
1266 } // namespace passes