]> git.saurik.com Git - apple/ld64.git/blame - src/ld/passes/objc.cpp
ld64-224.1.tar.gz
[apple/ld64.git] / src / ld / passes / objc.cpp
CommitLineData
a645023d
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
afe874b1 3 * Copyright (c) 2010-2011 Apple Inc. All rights reserved.
a645023d
A
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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
12 * file.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25
26#include <stdint.h>
27#include <math.h>
28#include <unistd.h>
29#include <dlfcn.h>
30#include <mach/machine.h>
31
32#include <vector>
33#include <map>
34#include <set>
35
36#include "Architectures.hpp"
37#include "MachOFileAbstraction.hpp"
38
39#include "ld.hpp"
40#include "objc.h"
41
42namespace ld {
43namespace passes {
44namespace objc {
45
46
47
48struct objc_image_info {
49 uint32_t version; // initially 0
50 uint32_t flags;
51};
52
a645023d
A
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)
f80fe69f 57#define OBJC_IMAGE_IS_SIMULATED (1<<5)
a645023d
A
58
59
60
61//
62// This class is the 8 byte section containing ObjC flags
63//
64template <typename A>
65class ObjCImageInfoAtom : public ld::Atom {
66public:
67 ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint,
ebf6f434 68 bool compaction, bool abi2);
a645023d
A
69
70 virtual const ld::File* file() const { return NULL; }
a645023d
A
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));
77 }
78
79private:
80 objc_image_info _content;
81
82 static ld::Section _s_sectionABI1;
83 static ld::Section _s_sectionABI2;
84};
85
86template <typename A> ld::Section ObjCImageInfoAtom<A>::_s_sectionABI1("__OBJC", "__image_info", ld::Section::typeUnclassified);
87template <typename A> ld::Section ObjCImageInfoAtom<A>::_s_sectionABI2("__DATA", "__objc_imageinfo", ld::Section::typeUnclassified);
88
89
90template <typename A>
91ObjCImageInfoAtom<A>::ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint, bool compaction,
ebf6f434 92 bool abi2)
a645023d
A
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))
96{
97
98 uint32_t value = 0;
a645023d
A
99 switch ( objcConstraint ) {
100 case ld::File::objcConstraintNone:
101 case ld::File::objcConstraintRetainRelease:
102 if ( compaction )
103 warning("ignoring -objc_gc_compaction because code not compiled for ObjC garbage collection");
104 break;
105 case ld::File::objcConstraintRetainReleaseOrGC:
106 value |= OBJC_IMAGE_SUPPORTS_GC;
107 if ( compaction )
108 value |= OBJC_IMAGE_SUPPORTS_COMPACTION;
109 break;
110 case ld::File::objcConstraintGC:
111 value |= OBJC_IMAGE_SUPPORTS_GC | OBJC_IMAGE_REQUIRES_GC;
112 if ( compaction )
113 value |= OBJC_IMAGE_SUPPORTS_COMPACTION;
114 break;
f80fe69f
A
115 case ld::File::objcConstraintRetainReleaseForSimulator:
116 value |= OBJC_IMAGE_IS_SIMULATED;
117 break;
a645023d
A
118 }
119
120 _content.version = 0;
121 A::P::E::set32(_content.flags, value);
122}
123
124
125
126//
127// This class is for a new Atom which is an ObjC method list created by merging method lists from categories
128//
129template <typename A>
130class MethodListAtom : public ld::Atom {
131public:
132 MethodListAtom(ld::Internal& state, const ld::Atom* baseMethodList, bool meta,
133 const std::vector<const ld::Atom*>* categories,
134 std::set<const ld::Atom*>& deadAtoms);
135
136 virtual const ld::File* file() const { return _file; }
a645023d
A
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());
ebf6f434 143 A::P::E::set32(*((uint32_t*)(&buffer[0])), 3*sizeof(pint_t)); // entry size
a645023d
A
144 A::P::E::set32(*((uint32_t*)(&buffer[4])), _methodCount);
145 }
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()]; }
148
149private:
150 typedef typename A::P::uint_t pint_t;
151
152 const ld::File* _file;
153 unsigned int _methodCount;
154 std::vector<ld::Fixup> _fixups;
155
156 static ld::Section _s_section;
157};
158
159template <typename A>
160ld::Section MethodListAtom<A>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified);
161
162
163//
164// This class is for a new Atom which is an ObjC protocol list created by merging protocol lists from categories
165//
166template <typename A>
167class ProtocolListAtom : public ld::Atom {
168public:
169 ProtocolListAtom(ld::Internal& state, const ld::Atom* baseProtocolList,
170 const std::vector<const ld::Atom*>* categories,
171 std::set<const ld::Atom*>& deadAtoms);
172
173 virtual const ld::File* file() const { return _file; }
a645023d
A
174 virtual const char* name() const { return "objc merged protocol list"; }
175 virtual uint64_t size() const { return (_protocolCount+1)*sizeof(pint_t); }
176 virtual uint64_t objectAddress() const { return 0; }
177 virtual void setScope(Scope) { }
178 virtual void copyRawContent(uint8_t buffer[]) const {
179 bzero(buffer, size());
180 A::P::setP(*((pint_t*)(buffer)), _protocolCount);
181 }
182 virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixups[0]; }
183 virtual ld::Fixup::iterator fixupsEnd() const { return (ld::Fixup*)&_fixups[_fixups.size()]; }
184
185private:
186 typedef typename A::P::uint_t pint_t;
187
188 const ld::File* _file;
189 unsigned int _protocolCount;
190 std::vector<ld::Fixup> _fixups;
191
192 static ld::Section _s_section;
193};
194
195template <typename A>
196ld::Section ProtocolListAtom<A>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified);
197
198
199
200//
201// This class is for a new Atom which is an ObjC property list created by merging property lists from categories
202//
203template <typename A>
204class PropertyListAtom : public ld::Atom {
205public:
206 PropertyListAtom(ld::Internal& state, const ld::Atom* baseProtocolList,
207 const std::vector<const ld::Atom*>* categories,
208 std::set<const ld::Atom*>& deadAtoms);
209
210 virtual const ld::File* file() const { return _file; }
a645023d
A
211 virtual const char* name() const { return "objc merged property list"; }
212 virtual uint64_t size() const { return _propertyCount*2*sizeof(pint_t) + 8; }
213 virtual uint64_t objectAddress() const { return 0; }
214 virtual void setScope(Scope) { }
215 virtual void copyRawContent(uint8_t buffer[]) const {
216 bzero(buffer, size());
217 A::P::E::set32(((uint32_t*)(buffer))[0], 2*sizeof(pint_t)); // sizeof(objc_property)
218 A::P::E::set32(((uint32_t*)(buffer))[1], _propertyCount);
219 }
220 virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixups[0]; }
221 virtual ld::Fixup::iterator fixupsEnd() const { return (ld::Fixup*)&_fixups[_fixups.size()]; }
222
223private:
224 typedef typename A::P::uint_t pint_t;
225
226 const ld::File* _file;
227 unsigned int _propertyCount;
228 std::vector<ld::Fixup> _fixups;
229
230 static ld::Section _s_section;
231};
232
233template <typename A>
234ld::Section PropertyListAtom<A>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified);
235
236
237
238
239
240//
241// This class is used to create an Atom that replaces an atom from a .o file that holds a class_ro_t.
242// It is needed because there is no way to add Fixups to an existing atom.
243//
244template <typename A>
245class ClassROOverlayAtom : public ld::Atom {
246public:
247 ClassROOverlayAtom(const ld::Atom* classROAtom);
248
249 // overrides of ld::Atom
250 virtual const ld::File* file() const { return _atom->file(); }
a645023d
A
251 virtual const char* name() const { return _atom->name(); }
252 virtual uint64_t size() const { return _atom->size(); }
253 virtual uint64_t objectAddress() const { return _atom->objectAddress(); }
254 virtual void copyRawContent(uint8_t buffer[]) const
255 { _atom->copyRawContent(buffer); }
256 virtual const uint8_t* rawContentPointer() const
257 { return _atom->rawContentPointer(); }
258 virtual unsigned long contentHash(const class ld::IndirectBindingTable& ibt) const
259 { return _atom->contentHash(ibt); }
260 virtual bool canCoalesceWith(const ld::Atom& rhs, const class ld::IndirectBindingTable& ibt) const
261 { return _atom->canCoalesceWith(rhs,ibt); }
262
263 virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixups[0]; }
264 virtual ld::Fixup::iterator fixupsEnd() const { return (ld::Fixup*)&_fixups[_fixups.size()]; }
265
266 void addProtocolListFixup();
267 void addPropertyListFixup();
268 void addMethodListFixup();
269
270private:
271 typedef typename A::P::uint_t pint_t;
272
273 const ld::Atom* _atom;
274 std::vector<ld::Fixup> _fixups;
275};
276
277template <typename A>
278ClassROOverlayAtom<A>::ClassROOverlayAtom(const ld::Atom* classROAtom)
279 : ld::Atom(classROAtom->section(), ld::Atom::definitionRegular, ld::Atom::combineNever,
280 ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
281 classROAtom->symbolTableInclusion(), false, false, false, classROAtom->alignment()),
282 _atom(classROAtom)
283{
284 // ensure all attributes are same as original
285 this->setAttributesFromAtom(*classROAtom);
286
287 // copy fixups from orginal atom
288 for (ld::Fixup::iterator fit=classROAtom->fixupsBegin(); fit != classROAtom->fixupsEnd(); ++fit) {
289 ld::Fixup fixup = *fit;
290 _fixups.push_back(fixup);
291 }
292}
293
294
295//
296// Base class for reading and updating existing ObjC atoms from .o files
297//
298template <typename A>
299class ObjCData {
300public:
301 static const ld::Atom* getPointerInContent(ld::Internal& state, const ld::Atom* contentAtom, unsigned int offset, bool* hasAddend=NULL);
302 static void setPointerInContent(ld::Internal& state, const ld::Atom* contentAtom,
303 unsigned int offset, const ld::Atom* newAtom);
304 typedef typename A::P::uint_t pint_t;
305};
306
307template <typename A>
308const ld::Atom* ObjCData<A>::getPointerInContent(ld::Internal& state, const ld::Atom* contentAtom, unsigned int offset, bool* hasAddend)
309{
310 const ld::Atom* target = NULL;
311 if ( hasAddend != NULL )
312 *hasAddend = false;
313 for (ld::Fixup::iterator fit=contentAtom->fixupsBegin(); fit != contentAtom->fixupsEnd(); ++fit) {
314 if ( fit->offsetInAtom == offset ) {
315 switch ( fit->binding ) {
316 case ld::Fixup::bindingsIndirectlyBound:
317 target = state.indirectBindingTable[fit->u.bindingIndex];
318 break;
319 case ld::Fixup::bindingDirectlyBound:
320 target = fit->u.target;
321 break;
322 case ld::Fixup::bindingNone:
323 if ( fit->kind == ld::Fixup::kindAddAddend ) {
324 if ( hasAddend != NULL )
325 *hasAddend = true;
326 }
327 break;
328 default:
329 break;
330 }
331 }
332 }
333 return target;
334}
335
336template <typename A>
337void ObjCData<A>::setPointerInContent(ld::Internal& state, const ld::Atom* contentAtom,
338 unsigned int offset, const ld::Atom* newAtom)
339{
340 for (ld::Fixup::iterator fit=contentAtom->fixupsBegin(); fit != contentAtom->fixupsEnd(); ++fit) {
341 if ( fit->offsetInAtom == offset ) {
342 switch ( fit->binding ) {
343 case ld::Fixup::bindingsIndirectlyBound:
344 state.indirectBindingTable[fit->u.bindingIndex] = newAtom;
345 return;
346 case ld::Fixup::bindingDirectlyBound:
347 fit->u.target = newAtom;
348 return;
349 default:
350 break;
351 }
352 }
353 }
354 assert(0 && "could not update method list");
355}
356
357
358
359//
360// Helper class for reading and updating existing ObjC category atoms from .o files
361//
362template <typename A>
363class Category : public ObjCData<A> {
364public:
365 static const ld::Atom* getClass(ld::Internal& state, const ld::Atom* contentAtom);
366 static const ld::Atom* getInstanceMethods(ld::Internal& state, const ld::Atom* contentAtom);
367 static const ld::Atom* getClassMethods(ld::Internal& state, const ld::Atom* contentAtom);
368 static const ld::Atom* getProtocols(ld::Internal& state, const ld::Atom* contentAtom);
369 static const ld::Atom* getProperties(ld::Internal& state, const ld::Atom* contentAtom);
370 static uint32_t size() { return 6*sizeof(pint_t); }
371private:
372 typedef typename A::P::uint_t pint_t;
373};
374
375
376template <typename A>
377const ld::Atom* Category<A>::getClass(ld::Internal& state, const ld::Atom* contentAtom)
378{
379 return ObjCData<A>::getPointerInContent(state, contentAtom, sizeof(pint_t)); // category_t.cls
380}
381
382template <typename A>
383const ld::Atom* Category<A>::getInstanceMethods(ld::Internal& state, const ld::Atom* contentAtom)
384{
385 return ObjCData<A>::getPointerInContent(state, contentAtom, 2*sizeof(pint_t)); // category_t.instanceMethods
386}
387
388template <typename A>
389const ld::Atom* Category<A>::getClassMethods(ld::Internal& state, const ld::Atom* contentAtom)
390{
391 return ObjCData<A>::getPointerInContent(state, contentAtom, 3*sizeof(pint_t)); // category_t.classMethods
392}
393
394template <typename A>
395const ld::Atom* Category<A>::getProtocols(ld::Internal& state, const ld::Atom* contentAtom)
396{
397 return ObjCData<A>::getPointerInContent(state, contentAtom, 4*sizeof(pint_t)); // category_t.protocols
398}
399
400template <typename A>
401const ld::Atom* Category<A>::getProperties(ld::Internal& state, const ld::Atom* contentAtom)
402{
403 return ObjCData<A>::getPointerInContent(state, contentAtom, 5*sizeof(pint_t)); // category_t.instanceProperties
404}
405
406
407template <typename A>
408class MethodList : public ObjCData<A> {
409public:
410 static uint32_t count(ld::Internal& state, const ld::Atom* methodListAtom) {
411 const uint32_t* methodListData = (uint32_t*)(methodListAtom->rawContentPointer());
412 return A::P::E::get32(methodListData[1]); // method_list_t.count
413 }
414};
415
416template <typename A>
417class ProtocolList : public ObjCData<A> {
418public:
419 static uint32_t count(ld::Internal& state, const ld::Atom* protocolListAtom) {
420 pint_t* protocolListData = (pint_t*)(protocolListAtom->rawContentPointer());
421 return A::P::getP(*protocolListData); // protocol_list_t.count
422 }
423private:
424 typedef typename A::P::uint_t pint_t;
425};
426
427template <typename A>
428class PropertyList : public ObjCData<A> {
429public:
430 static uint32_t count(ld::Internal& state, const ld::Atom* protocolListAtom) {
431 uint32_t* protocolListData = (uint32_t*)(protocolListAtom->rawContentPointer());
432 return A::P::E::get32(protocolListData[1]); // property_list_t.count
433 }
434private:
435 typedef typename A::P::uint_t pint_t;
436};
437
438
439
440//
441// Helper class for reading and updating existing ObjC class atoms from .o files
442//
443template <typename A>
444class Class : public ObjCData<A> {
445public:
446 static const ld::Atom* getInstanceMethodList(ld::Internal& state, const ld::Atom* classAtom);
447 static const ld::Atom* getInstanceProtocolList(ld::Internal& state, const ld::Atom* classAtom);
448 static const ld::Atom* getInstancePropertyList(ld::Internal& state, const ld::Atom* classAtom);
449 static const ld::Atom* getClassMethodList(ld::Internal& state, const ld::Atom* classAtom);
450 static const ld::Atom* setInstanceMethodList(ld::Internal& state, const ld::Atom* classAtom,
451 const ld::Atom* methodListAtom, std::set<const ld::Atom*>& deadAtoms);
452 static const ld::Atom* setInstanceProtocolList(ld::Internal& state, const ld::Atom* classAtom,
453 const ld::Atom* protocolListAtom, std::set<const ld::Atom*>& deadAtoms);
454 static const ld::Atom* setInstancePropertyList(ld::Internal& state, const ld::Atom* classAtom,
455 const ld::Atom* propertyListAtom, std::set<const ld::Atom*>& deadAtoms);
456 static const ld::Atom* setClassMethodList(ld::Internal& state, const ld::Atom* classAtom,
457 const ld::Atom* methodListAtom, std::set<const ld::Atom*>& deadAtoms);
458 static const ld::Atom* setClassProtocolList(ld::Internal& state, const ld::Atom* classAtom,
459 const ld::Atom* protocolListAtom, std::set<const ld::Atom*>& deadAtoms);
460 static uint32_t size() { return 5*sizeof(pint_t); }
461 static unsigned int class_ro_header_size();
462private:
463 typedef typename A::P::uint_t pint_t;
464 static const ld::Atom* getROData(ld::Internal& state, const ld::Atom* classAtom);
465};
466
467template <> unsigned int Class<x86_64>::class_ro_header_size() { return 16; }
468template <> unsigned int Class<arm>::class_ro_header_size() { return 12;}
469template <> unsigned int Class<x86>::class_ro_header_size() { return 12; }
470
471
472template <typename A>
473const ld::Atom* Class<A>::getROData(ld::Internal& state, const ld::Atom* classAtom)
474{
475 return ObjCData<A>::getPointerInContent(state, classAtom, 4*sizeof(pint_t)); // class_t.data
476
477}
478
479template <typename A>
480const ld::Atom* Class<A>::getInstanceMethodList(ld::Internal& state, const ld::Atom* classAtom)
481{
482 const ld::Atom* classROAtom = getROData(state, classAtom); // class_t.data
483 assert(classROAtom != NULL);
484 return ObjCData<A>::getPointerInContent(state, classROAtom, class_ro_header_size() + 2*sizeof(pint_t)); // class_ro_t.baseMethods
485}
486
487template <typename A>
488const ld::Atom* Class<A>::getInstanceProtocolList(ld::Internal& state, const ld::Atom* classAtom)
489{
490 const ld::Atom* classROAtom = getROData(state, classAtom); // class_t.data
491 assert(classROAtom != NULL);
492 return ObjCData<A>::getPointerInContent(state, classROAtom, class_ro_header_size() + 3*sizeof(pint_t)); // class_ro_t.baseProtocols
493}
494
495template <typename A>
496const ld::Atom* Class<A>::getInstancePropertyList(ld::Internal& state, const ld::Atom* classAtom)
497{
498 const ld::Atom* classROAtom = getROData(state, classAtom); // class_t.data
499 assert(classROAtom != NULL);
500 return ObjCData<A>::getPointerInContent(state, classROAtom, class_ro_header_size() + 6*sizeof(pint_t)); // class_ro_t.baseProperties
501}
502
503template <typename A>
504const ld::Atom* Class<A>::getClassMethodList(ld::Internal& state, const ld::Atom* classAtom)
505{
506 const ld::Atom* metaClassAtom = ObjCData<A>::getPointerInContent(state, classAtom, 0); // class_t.isa
507 assert(metaClassAtom != NULL);
508 return Class<A>::getInstanceMethodList(state, metaClassAtom);
509}
510
511template <typename A>
512const ld::Atom* Class<A>::setInstanceMethodList(ld::Internal& state, const ld::Atom* classAtom,
513 const ld::Atom* methodListAtom, std::set<const ld::Atom*>& deadAtoms)
514{
515 const ld::Atom* classROAtom = getROData(state, classAtom); // class_t.data
516 assert(classROAtom != NULL);
517 // if the base class does not already have a method list, we need to create an overlay
518 if ( getInstanceMethodList(state, classAtom) == NULL ) {
519 ClassROOverlayAtom<A>* overlay = new ClassROOverlayAtom<A>(classROAtom);
520 //fprintf(stderr, "replace class RO atom %p with %p for method list in class atom %s\n", classROAtom, overlay, classAtom->name());
521 overlay->addMethodListFixup();
522 ObjCData<A>::setPointerInContent(state, classAtom, 4*sizeof(pint_t), overlay); // class_t.data
523 deadAtoms.insert(classROAtom);
524 ObjCData<A>::setPointerInContent(state, overlay, class_ro_header_size() + 2*sizeof(pint_t), methodListAtom); // class_ro_t.baseMethods
525 return overlay;
526 }
527 ObjCData<A>::setPointerInContent(state, classROAtom, class_ro_header_size() + 2*sizeof(pint_t), methodListAtom); // class_ro_t.baseMethods
528 return NULL; // means classRO atom was not replaced
529}
530
531template <typename A>
532const ld::Atom* Class<A>::setInstanceProtocolList(ld::Internal& state, const ld::Atom* classAtom,
533 const ld::Atom* protocolListAtom, std::set<const ld::Atom*>& deadAtoms)
534{
535 const ld::Atom* classROAtom = getROData(state, classAtom); // class_t.data
536 assert(classROAtom != NULL);
537 // if the base class does not already have a protocol list, we need to create an overlay
538 if ( getInstanceProtocolList(state, classAtom) == NULL ) {
539 ClassROOverlayAtom<A>* overlay = new ClassROOverlayAtom<A>(classROAtom);
540 //fprintf(stderr, "replace class RO atom %p with %p for protocol list in class atom %s\n", classROAtom, overlay, classAtom->name());
541 overlay->addProtocolListFixup();
542 ObjCData<A>::setPointerInContent(state, classAtom, 4*sizeof(pint_t), overlay); // class_t.data
543 deadAtoms.insert(classROAtom);
544 ObjCData<A>::setPointerInContent(state, overlay, class_ro_header_size() + 3*sizeof(pint_t), protocolListAtom); // class_ro_t.baseProtocols
545 return overlay;
546 }
547 //fprintf(stderr, "set class RO atom %p protocol list in class atom %s\n", classROAtom, classAtom->name());
548 ObjCData<A>::setPointerInContent(state, classROAtom, class_ro_header_size() + 3*sizeof(pint_t), protocolListAtom); // class_ro_t.baseProtocols
549 return NULL; // means classRO atom was not replaced
550}
551
552template <typename A>
553const ld::Atom* Class<A>::setClassProtocolList(ld::Internal& state, const ld::Atom* classAtom,
554 const ld::Atom* protocolListAtom, std::set<const ld::Atom*>& deadAtoms)
555{
556 // meta class also points to same protocol list as class
557 const ld::Atom* metaClassAtom = ObjCData<A>::getPointerInContent(state, classAtom, 0); // class_t.isa
558 //fprintf(stderr, "setClassProtocolList(), classAtom=%p %s, metaClass=%p %s\n", classAtom, classAtom->name(), metaClassAtom, metaClassAtom->name());
559 assert(metaClassAtom != NULL);
560 return setInstanceProtocolList(state, metaClassAtom, protocolListAtom, deadAtoms);
561}
562
563
564
565template <typename A>
566const ld::Atom* Class<A>::setInstancePropertyList(ld::Internal& state, const ld::Atom* classAtom,
567 const ld::Atom* propertyListAtom, std::set<const ld::Atom*>& deadAtoms)
568{
569 const ld::Atom* classROAtom = getROData(state, classAtom); // class_t.data
570 assert(classROAtom != NULL);
571 // if the base class does not already have a property list, we need to create an overlay
572 if ( getInstancePropertyList(state, classAtom) == NULL ) {
573 ClassROOverlayAtom<A>* overlay = new ClassROOverlayAtom<A>(classROAtom);
574 //fprintf(stderr, "replace class RO atom %p with %p for property list in class atom %s\n", classROAtom, overlay, classAtom->name());
575 overlay->addPropertyListFixup();
576 ObjCData<A>::setPointerInContent(state, classAtom, 4*sizeof(pint_t), overlay); // class_t.data
577 deadAtoms.insert(classROAtom);
578 ObjCData<A>::setPointerInContent(state, overlay, class_ro_header_size() + 6*sizeof(pint_t), propertyListAtom); // class_ro_t.baseProperties
579 return overlay;
580 }
581 ObjCData<A>::setPointerInContent(state, classROAtom, class_ro_header_size() + 6*sizeof(pint_t), propertyListAtom); // class_ro_t.baseProperties
582 return NULL; // means classRO atom was not replaced
583}
584
585template <typename A>
586const ld::Atom* Class<A>::setClassMethodList(ld::Internal& state, const ld::Atom* classAtom,
587 const ld::Atom* methodListAtom, std::set<const ld::Atom*>& deadAtoms)
588{
589 // class methods is just instance methods of metaClass
590 const ld::Atom* metaClassAtom = ObjCData<A>::getPointerInContent(state, classAtom, 0); // class_t.isa
591 assert(metaClassAtom != NULL);
592 return setInstanceMethodList(state, metaClassAtom, methodListAtom, deadAtoms);
593}
594
595
596
597template <>
598void ClassROOverlayAtom<x86_64>::addMethodListFixup()
599{
600 const ld::Atom* targetAtom = this; // temporary
601 uint32_t offset = Class<x86_64>::class_ro_header_size() + 2*8; // class_ro_t.baseMethods
602 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, targetAtom));
603}
604
605template <>
606void ClassROOverlayAtom<arm>::addMethodListFixup()
607{
608 const ld::Atom* targetAtom = this; // temporary
609 uint32_t offset = Class<arm>::class_ro_header_size() + 2*4; // class_ro_t.baseMethods
610 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, targetAtom));
611}
612
613template <>
614void ClassROOverlayAtom<x86>::addMethodListFixup()
615{
616 const ld::Atom* targetAtom = this; // temporary
617 uint32_t offset = Class<x86>::class_ro_header_size() + 2*4; // class_ro_t.baseMethods
618 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, targetAtom));
619}
620
621
622
623template <>
624void ClassROOverlayAtom<x86_64>::addProtocolListFixup()
625{
626 const ld::Atom* targetAtom = this; // temporary
627 uint32_t offset = Class<x86_64>::class_ro_header_size() + 3*8; // class_ro_t.baseProtocols
628 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, targetAtom));
629}
630
631template <>
632void ClassROOverlayAtom<arm>::addProtocolListFixup()
633{
634 const ld::Atom* targetAtom = this; // temporary
635 uint32_t offset = Class<arm>::class_ro_header_size() + 3*4; // class_ro_t.baseProtocols
636 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, targetAtom));
637}
638
639template <>
640void ClassROOverlayAtom<x86>::addProtocolListFixup()
641{
642 const ld::Atom* targetAtom = this; // temporary
643 uint32_t offset = Class<x86>::class_ro_header_size() + 3*4; // class_ro_t.baseProtocols
644 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, targetAtom));
645}
646
647
648template <>
649void ClassROOverlayAtom<x86_64>::addPropertyListFixup()
650{
651 const ld::Atom* targetAtom = this; // temporary
652 uint32_t offset = Class<x86_64>::class_ro_header_size() + 6*8; // class_ro_t.baseProperties
653 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, targetAtom));
654}
655
656template <>
657void ClassROOverlayAtom<arm>::addPropertyListFixup()
658{
659 const ld::Atom* targetAtom = this; // temporary
660 uint32_t offset = Class<arm>::class_ro_header_size() + 6*4; // class_ro_t.baseProperties
661 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, targetAtom));
662}
663
664template <>
665void ClassROOverlayAtom<x86>::addPropertyListFixup()
666{
667 const ld::Atom* targetAtom = this; // temporary
668 uint32_t offset = Class<x86>::class_ro_header_size() + 6*4; // class_ro_t.baseProperties
669 _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, targetAtom));
670}
671
672
673
674
675//
676// Encapsulates merging of ObjC categories
677//
678template <typename A>
679class OptimizeCategories {
680public:
681 static void doit(const Options& opts, ld::Internal& state);
682 static bool hasInstanceMethods(ld::Internal& state, const std::vector<const ld::Atom*>* categories);
683 static bool hasClassMethods(ld::Internal& state, const std::vector<const ld::Atom*>* categories);
684 static bool hasProtocols(ld::Internal& state, const std::vector<const ld::Atom*>* categories);
685 static bool hasProperties(ld::Internal& state, const std::vector<const ld::Atom*>* categories);
686
687
688 static unsigned int class_ro_baseMethods_offset();
689private:
690 typedef typename A::P::uint_t pint_t;
691
692};
693
694
695template <typename A>
696bool OptimizeCategories<A>::hasInstanceMethods(ld::Internal& state, const std::vector<const ld::Atom*>* categories)
697{
698 for (std::vector<const ld::Atom*>::const_iterator it=categories->begin(); it != categories->end(); ++it) {
699 const ld::Atom* categoryAtom = *it;
700 const ld::Atom* methodList = Category<A>::getInstanceMethods(state, categoryAtom);
701 if ( methodList != NULL ) {
702 if ( MethodList<A>::count(state, methodList) > 0 )
703 return true;
704 }
705 }
706 return false;
707}
708
709
710template <typename A>
711bool OptimizeCategories<A>::hasClassMethods(ld::Internal& state, const std::vector<const ld::Atom*>* categories)
712{
713 for (std::vector<const ld::Atom*>::const_iterator it=categories->begin(); it != categories->end(); ++it) {
714 const ld::Atom* categoryAtom = *it;
715 const ld::Atom* methodList = Category<A>::getClassMethods(state, categoryAtom);
716 if ( methodList != NULL ) {
717 if ( MethodList<A>::count(state, methodList) > 0 )
718 return true;
719 }
720 }
721 return false;
722}
723
724template <typename A>
725bool OptimizeCategories<A>::hasProtocols(ld::Internal& state, const std::vector<const ld::Atom*>* categories)
726{
727 for (std::vector<const ld::Atom*>::const_iterator it=categories->begin(); it != categories->end(); ++it) {
728 const ld::Atom* categoryAtom = *it;
729 const ld::Atom* protocolListAtom = Category<A>::getProtocols(state, categoryAtom);
730 if ( protocolListAtom != NULL ) {
731 if ( ProtocolList<A>::count(state, protocolListAtom) > 0 ) {
732 return true;
733 }
734 }
735 }
736 return false;
737}
738
739
740template <typename A>
741bool OptimizeCategories<A>::hasProperties(ld::Internal& state, const std::vector<const ld::Atom*>* categories)
742{
743 for (std::vector<const ld::Atom*>::const_iterator it=categories->begin(); it != categories->end(); ++it) {
744 const ld::Atom* categoryAtom = *it;
745 const ld::Atom* propertyListAtom = Category<A>::getProperties(state, categoryAtom);
746 if ( propertyListAtom != NULL ) {
747 if ( PropertyList<A>::count(state, propertyListAtom) > 0 )
748 return true;
749 }
750 }
751 return false;
752}
753
754
755
756//
757// Helper for std::remove_if
758//
759class OptimizedAway {
760public:
761 OptimizedAway(const std::set<const ld::Atom*>& oa) : _dead(oa) {}
762 bool operator()(const ld::Atom* atom) const {
763 return ( _dead.count(atom) != 0 );
764 }
765private:
766 const std::set<const ld::Atom*>& _dead;
767};
768
ebf6f434
A
769 struct AtomSorter
770 {
771 bool operator()(const Atom* left, const Atom* right)
772 {
773 // sort by file ordinal, then object address, then zero size, then symbol name
774 // only file based atoms are supported (file() != NULL)
775 if (left==right) return false;
776 const File *leftf = left->file();
777 const File *rightf = right->file();
778
779 if (leftf == rightf) {
780 if (left->objectAddress() != right->objectAddress()) {
781 return left->objectAddress() < right->objectAddress();
782 } else {
783 // for atoms in the same file with the same address, zero sized
784 // atoms must sort before nonzero sized atoms
785 if ((left->size() == 0 && right->size() > 0) || (left->size() > 0 && right->size() == 0))
786 return left->size() < right->size();
787 return strcmp(left->name(), right->name());
788 }
789 }
790 return (leftf->ordinal() < rightf->ordinal());
791 }
792 };
793
794 static void sortAtomVector(std::vector<const Atom*> &atoms) {
795 std::sort(atoms.begin(), atoms.end(), AtomSorter());
796 }
797
a645023d
A
798template <typename A>
799void OptimizeCategories<A>::doit(const Options& opts, ld::Internal& state)
800{
801 // first find all categories referenced by __objc_nlcatlist section
802 std::set<const ld::Atom*> nlcatListAtoms;
803 for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
804 ld::Internal::FinalSection* sect = *sit;
805 if ( (strcmp(sect->sectionName(), "__objc_nlcatlist") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) ) {
806 for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
807 const ld::Atom* categoryListElementAtom = *ait;
808 for (unsigned int offset=0; offset < categoryListElementAtom->size(); offset += sizeof(pint_t)) {
809 const ld::Atom* categoryAtom = ObjCData<A>::getPointerInContent(state, categoryListElementAtom, offset);
810 //fprintf(stderr, "offset=%d, cat=%p %s\n", offset, categoryAtom, categoryAtom->name());
811 assert(categoryAtom != NULL);
812 nlcatListAtoms.insert(categoryAtom);
813 }
814 }
815 }
816 }
817
818 // build map of all classes in this image that have categories on them
819 typedef std::map<const ld::Atom*, std::vector<const ld::Atom*>*> CatMap;
820 CatMap classToCategories;
ebf6f434 821 std::vector<const ld::Atom*> classOrder;
a645023d
A
822 std::set<const ld::Atom*> deadAtoms;
823 ld::Internal::FinalSection* methodListSection = NULL;
824 for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
825 ld::Internal::FinalSection* sect = *sit;
826 if ( sect->type() == ld::Section::typeObjC2CategoryList ) {
827 for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
828 const ld::Atom* categoryListElementAtom = *ait;
829 bool hasAddend;
830 const ld::Atom* categoryAtom = ObjCData<A>::getPointerInContent(state, categoryListElementAtom, 0, &hasAddend);
831 if ( hasAddend || (categoryAtom->symbolTableInclusion() == ld::Atom::symbolTableNotIn)) {
832 //<rdar://problem/8309530> gcc-4.0 uses 'L' labels on categories which disables this optimization
833 //warning("__objc_catlist element does not point to start of category");
834 continue;
835 }
836 assert(categoryAtom != NULL);
ebf6f434 837 assert(categoryAtom->size() >= Category<A>::size());
a645023d
A
838 // ignore categories also in __objc_nlcatlist
839 if ( nlcatListAtoms.count(categoryAtom) != 0 )
840 continue;
841 const ld::Atom* categoryOnClassAtom = Category<A>::getClass(state, categoryAtom);
842 assert(categoryOnClassAtom != NULL);
843 if ( categoryOnClassAtom->definition() != ld::Atom::definitionProxy ) {
844 // only look at classes defined in this image
845 CatMap::iterator pos = classToCategories.find(categoryOnClassAtom);
846 if ( pos == classToCategories.end() ) {
847 classToCategories[categoryOnClassAtom] = new std::vector<const ld::Atom*>();
ebf6f434 848 classOrder.push_back(categoryOnClassAtom);
a645023d
A
849 }
850 classToCategories[categoryOnClassAtom]->push_back(categoryAtom);
851 // mark category atom and catlist atom as dead
852 deadAtoms.insert(categoryAtom);
853 deadAtoms.insert(categoryListElementAtom);
854 }
855 }
856 }
857 // record method list section
858 if ( (strcmp(sect->sectionName(), "__objc_const") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
859 methodListSection = sect;
860 }
861
862 // if found some categories
863 if ( classToCategories.size() != 0 ) {
864 assert(methodListSection != NULL);
ebf6f434 865 sortAtomVector(classOrder);
a645023d 866 // alter each class definition to have new method list which includes all category methods
ebf6f434
A
867 for (std::vector<const ld::Atom*>::iterator it = classOrder.begin(); it != classOrder.end(); it++) {
868 const ld::Atom* classAtom = *it;
869 const std::vector<const ld::Atom*>* categories = classToCategories[classAtom];
a645023d
A
870 assert(categories->size() != 0);
871 // if any category adds instance methods, generate new merged method list, and replace
872 if ( OptimizeCategories<A>::hasInstanceMethods(state, categories) ) {
873 const ld::Atom* baseInstanceMethodListAtom = Class<A>::getInstanceMethodList(state, classAtom);
874 const ld::Atom* newInstanceMethodListAtom = new MethodListAtom<A>(state, baseInstanceMethodListAtom, false, categories, deadAtoms);
875 const ld::Atom* newClassRO = Class<A>::setInstanceMethodList(state, classAtom, newInstanceMethodListAtom, deadAtoms);
876 // add new method list to final sections
877 methodListSection->atoms.push_back(newInstanceMethodListAtom);
878 if ( newClassRO != NULL ) {
879 assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
880 methodListSection->atoms.push_back(newClassRO);
881 }
882 }
883 // if any category adds class methods, generate new merged method list, and replace
884 if ( OptimizeCategories<A>::hasClassMethods(state, categories) ) {
885 const ld::Atom* baseClassMethodListAtom = Class<A>::getClassMethodList(state, classAtom);
886 const ld::Atom* newClassMethodListAtom = new MethodListAtom<A>(state, baseClassMethodListAtom, true, categories, deadAtoms);
887 const ld::Atom* newClassRO = Class<A>::setClassMethodList(state, classAtom, newClassMethodListAtom, deadAtoms);
888 // add new method list to final sections
889 methodListSection->atoms.push_back(newClassMethodListAtom);
890 if ( newClassRO != NULL ) {
891 assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
892 methodListSection->atoms.push_back(newClassRO);
893 }
894 }
895 // if any category adds protocols, generate new merged protocol list, and replace
896 if ( OptimizeCategories<A>::hasProtocols(state, categories) ) {
897 const ld::Atom* baseProtocolListAtom = Class<A>::getInstanceProtocolList(state, classAtom);
898 const ld::Atom* newProtocolListAtom = new ProtocolListAtom<A>(state, baseProtocolListAtom, categories, deadAtoms);
899 const ld::Atom* newClassRO = Class<A>::setInstanceProtocolList(state, classAtom, newProtocolListAtom, deadAtoms);
900 const ld::Atom* newMetaClassRO = Class<A>::setClassProtocolList(state, classAtom, newProtocolListAtom, deadAtoms);
901 // add new protocol list to final sections
902 methodListSection->atoms.push_back(newProtocolListAtom);
903 if ( newClassRO != NULL ) {
904 assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
905 methodListSection->atoms.push_back(newClassRO);
906 }
907 if ( newMetaClassRO != NULL ) {
908 assert(strcmp(newMetaClassRO->section().sectionName(), "__objc_const") == 0);
909 methodListSection->atoms.push_back(newMetaClassRO);
910 }
911 }
912 // if any category adds properties, generate new merged property list, and replace
913 if ( OptimizeCategories<A>::hasProperties(state, categories) ) {
914 const ld::Atom* basePropertyListAtom = Class<A>::getInstancePropertyList(state, classAtom);
915 const ld::Atom* newPropertyListAtom = new PropertyListAtom<A>(state, basePropertyListAtom, categories, deadAtoms);
916 const ld::Atom* newClassRO = Class<A>::setInstancePropertyList(state, classAtom, newPropertyListAtom, deadAtoms);
917 // add new property list to final sections
918 methodListSection->atoms.push_back(newPropertyListAtom);
919 if ( newClassRO != NULL ) {
920 assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
921 methodListSection->atoms.push_back(newClassRO);
922 }
923 }
924
925 }
926
927 // remove dead atoms
928 for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
929 ld::Internal::FinalSection* sect = *sit;
930 sect->atoms.erase(std::remove_if(sect->atoms.begin(), sect->atoms.end(), OptimizedAway(deadAtoms)), sect->atoms.end());
931 }
932 }
933}
934
935
936template <typename A>
937MethodListAtom<A>::MethodListAtom(ld::Internal& state, const ld::Atom* baseMethodList, bool meta,
938 const std::vector<const ld::Atom*>* categories, std::set<const ld::Atom*>& deadAtoms)
939 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
940 ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
941 symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), _file(NULL), _methodCount(0)
942{
943 unsigned int fixupCount = 0;
afe874b1 944 std::set<const ld::Atom*> baseMethodListMethodNameAtoms;
a645023d
A
945 // if base class has method list, then associate new method list with file defining class
946 if ( baseMethodList != NULL ) {
947 _file = baseMethodList->file();
948 // calculate total size of merge method lists
949 _methodCount = MethodList<A>::count(state, baseMethodList);
950 deadAtoms.insert(baseMethodList);
951 fixupCount = baseMethodList->fixupsEnd() - baseMethodList->fixupsBegin();
afe874b1
A
952 for (ld::Fixup::iterator fit=baseMethodList->fixupsBegin(); fit != baseMethodList->fixupsEnd(); ++fit) {
953 if ( (fit->offsetInAtom - 8) % (3*sizeof(pint_t)) == 0 ) {
954 assert(fit->binding == ld::Fixup::bindingsIndirectlyBound && "malformed method list");
955 const ld::Atom* target = state.indirectBindingTable[fit->u.bindingIndex];
956 assert(target->contentType() == ld::Atom::typeCString && "malformed method list");
957 baseMethodListMethodNameAtoms.insert(target);
958 }
959 }
a645023d
A
960 }
961 for (std::vector<const ld::Atom*>::const_iterator ait=categories->begin(); ait != categories->end(); ++ait) {
962 const ld::Atom* categoryMethodListAtom;
963 if ( meta )
964 categoryMethodListAtom = Category<A>::getClassMethods(state, *ait);
965 else
966 categoryMethodListAtom = Category<A>::getInstanceMethods(state, *ait);
967 if ( categoryMethodListAtom != NULL ) {
968 _methodCount += MethodList<A>::count(state, categoryMethodListAtom);
969 fixupCount += (categoryMethodListAtom->fixupsEnd() - categoryMethodListAtom->fixupsBegin());
970 deadAtoms.insert(categoryMethodListAtom);
971 // if base class did not have method list, associate new method list with file the defined category
972 if ( _file == NULL )
973 _file = categoryMethodListAtom->file();
974 }
975 }
976 //if ( baseMethodList != NULL )
977 // fprintf(stderr, "total merged method count=%u for baseMethodList=%s\n", _methodCount, baseMethodList->name());
978 //else
979 // fprintf(stderr, "total merged method count=%u\n", _methodCount);
980 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
981
982 // copy fixups and adjust offsets (in reverse order to simulator objc runtime)
983 _fixups.reserve(fixupCount);
984 uint32_t slide = 0;
afe874b1 985 std::set<const ld::Atom*> categoryMethodNameAtoms;
a645023d
A
986 for (std::vector<const ld::Atom*>::const_reverse_iterator rit=categories->rbegin(); rit != categories->rend(); ++rit) {
987 const ld::Atom* categoryMethodListAtom;
988 if ( meta )
989 categoryMethodListAtom = Category<A>::getClassMethods(state, *rit);
990 else
991 categoryMethodListAtom = Category<A>::getInstanceMethods(state, *rit);
992 if ( categoryMethodListAtom != NULL ) {
993 for (ld::Fixup::iterator fit=categoryMethodListAtom->fixupsBegin(); fit != categoryMethodListAtom->fixupsEnd(); ++fit) {
994 ld::Fixup fixup = *fit;
995 fixup.offsetInAtom += slide;
996 _fixups.push_back(fixup);
afe874b1
A
997 if ( (fixup.offsetInAtom - 8) % (3*sizeof(pint_t)) == 0 ) {
998 // <rdar://problem/8642343> warning when a method is overridden in a category in the same link unit
999 assert(fixup.binding == ld::Fixup::bindingsIndirectlyBound && "malformed category method list");
1000 const ld::Atom* target = state.indirectBindingTable[fixup.u.bindingIndex];
1001 assert(target->contentType() == ld::Atom::typeCString && "malformed method list");
1002 // this objc pass happens after cstrings are coalesced, so we can just compare the atom addres instead of its content
1003 if ( baseMethodListMethodNameAtoms.count(target) != 0 ) {
1004 warning("%s method '%s' in category from %s overrides method from class in %s",
1005 (meta ? "meta" : "instance"), target->rawContentPointer(),
1006 categoryMethodListAtom->file()->path(), baseMethodList->file()->path() );
1007 }
1008 if ( categoryMethodNameAtoms.count(target) != 0 ) {
1009 warning("%s method '%s' in category from %s conflicts with same method from another category",
1010 (meta ? "meta" : "instance"), target->rawContentPointer(),
1011 categoryMethodListAtom->file()->path());
1012 }
1013 categoryMethodNameAtoms.insert(target);
1014 }
a645023d
A
1015 }
1016 slide += 3*sizeof(pint_t) * MethodList<A>::count(state, categoryMethodListAtom);
1017 }
1018 }
1019 // add method list from base class last
1020 if ( baseMethodList != NULL ) {
1021 for (ld::Fixup::iterator fit=baseMethodList->fixupsBegin(); fit != baseMethodList->fixupsEnd(); ++fit) {
1022 ld::Fixup fixup = *fit;
1023 fixup.offsetInAtom += slide;
1024 _fixups.push_back(fixup);
1025 }
1026 }
1027}
1028
1029
1030template <typename A>
1031ProtocolListAtom<A>::ProtocolListAtom(ld::Internal& state, const ld::Atom* baseProtocolList,
1032 const std::vector<const ld::Atom*>* categories, std::set<const ld::Atom*>& deadAtoms)
1033 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
1034 ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
1035 symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), _file(NULL), _protocolCount(0)
1036{
1037 unsigned int fixupCount = 0;
1038 if ( baseProtocolList != NULL ) {
1039 // if base class has protocol list, then associate new protocol list with file defining class
1040 _file = baseProtocolList->file();
1041 // calculate total size of merged protocol list
1042 _protocolCount = ProtocolList<A>::count(state, baseProtocolList);
1043 deadAtoms.insert(baseProtocolList);
1044 fixupCount = baseProtocolList->fixupsEnd() - baseProtocolList->fixupsBegin();
1045 }
1046 for (std::vector<const ld::Atom*>::const_iterator ait=categories->begin(); ait != categories->end(); ++ait) {
1047 const ld::Atom* categoryProtocolListAtom = Category<A>::getProtocols(state, *ait);
1048 if ( categoryProtocolListAtom != NULL ) {
1049 _protocolCount += ProtocolList<A>::count(state, categoryProtocolListAtom);
1050 fixupCount += (categoryProtocolListAtom->fixupsEnd() - categoryProtocolListAtom->fixupsBegin());
1051 deadAtoms.insert(categoryProtocolListAtom);
1052 // if base class did not have protocol list, associate new protocol list with file the defined category
1053 if ( _file == NULL )
1054 _file = categoryProtocolListAtom->file();
1055 }
1056 }
1057 //fprintf(stderr, "total merged protocol count=%u\n", _protocolCount);
1058 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
1059
1060 // copy fixups and adjust offsets
1061 _fixups.reserve(fixupCount);
1062 uint32_t slide = 0;
1063 for (std::vector<const ld::Atom*>::const_iterator it=categories->begin(); it != categories->end(); ++it) {
1064 const ld::Atom* categoryProtocolListAtom = Category<A>::getProtocols(state, *it);
1065 if ( categoryProtocolListAtom != NULL ) {
1066 for (ld::Fixup::iterator fit=categoryProtocolListAtom->fixupsBegin(); fit != categoryProtocolListAtom->fixupsEnd(); ++fit) {
1067 ld::Fixup fixup = *fit;
1068 fixup.offsetInAtom += slide;
1069 _fixups.push_back(fixup);
1070 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
1071 // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
1072 }
1073 slide += sizeof(pint_t) * ProtocolList<A>::count(state, categoryProtocolListAtom);
1074 }
1075 }
1076 // add method list from base class last
1077 if ( baseProtocolList != NULL ) {
1078 for (ld::Fixup::iterator fit=baseProtocolList->fixupsBegin(); fit != baseProtocolList->fixupsEnd(); ++fit) {
1079 ld::Fixup fixup = *fit;
1080 fixup.offsetInAtom += slide;
1081 _fixups.push_back(fixup);
1082 }
1083 }
1084}
1085
1086
1087template <typename A>
1088PropertyListAtom<A>::PropertyListAtom(ld::Internal& state, const ld::Atom* basePropertyList,
1089 const std::vector<const ld::Atom*>* categories, std::set<const ld::Atom*>& deadAtoms)
1090 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
1091 ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
1092 symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), _file(NULL), _propertyCount(0)
1093{
1094 unsigned int fixupCount = 0;
1095 if ( basePropertyList != NULL ) {
1096 // if base class has property list, then associate new property list with file defining class
1097 _file = basePropertyList->file();
1098 // calculate total size of merged property list
1099 _propertyCount = PropertyList<A>::count(state, basePropertyList);
1100 deadAtoms.insert(basePropertyList);
1101 fixupCount = basePropertyList->fixupsEnd() - basePropertyList->fixupsBegin();
1102 }
1103 for (std::vector<const ld::Atom*>::const_iterator ait=categories->begin(); ait != categories->end(); ++ait) {
1104 const ld::Atom* categoryPropertyListAtom = Category<A>::getProperties(state, *ait);
1105 if ( categoryPropertyListAtom != NULL ) {
1106 _propertyCount += PropertyList<A>::count(state, categoryPropertyListAtom);
1107 fixupCount += (categoryPropertyListAtom->fixupsEnd() - categoryPropertyListAtom->fixupsBegin());
1108 deadAtoms.insert(categoryPropertyListAtom);
1109 // if base class did not have property list, associate new property list with file the defined category
1110 if ( _file == NULL )
1111 _file = categoryPropertyListAtom->file();
1112 }
1113 }
1114 //fprintf(stderr, "total merged property count=%u\n", _propertyCount);
1115 //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
1116
1117 // copy fixups and adjust offsets
1118 _fixups.reserve(fixupCount);
1119 uint32_t slide = 0;
1120 for (std::vector<const ld::Atom*>::const_iterator it=categories->begin(); it != categories->end(); ++it) {
1121 const ld::Atom* categoryPropertyListAtom = Category<A>::getProperties(state, *it);
1122 if ( categoryPropertyListAtom != NULL ) {
1123 for (ld::Fixup::iterator fit=categoryPropertyListAtom->fixupsBegin(); fit != categoryPropertyListAtom->fixupsEnd(); ++fit) {
1124 ld::Fixup fixup = *fit;
1125 fixup.offsetInAtom += slide;
1126 _fixups.push_back(fixup);
1127 //fprintf(stderr, "offset=0x%08X, binding=%d\n", fixup.offsetInAtom, fixup.binding);
1128 //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
1129 // fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
1130 //else if ( fixup.binding == ld::Fixup::bindingsIndirectlyBound )
1131 // fprintf(stderr, "offset=0x%08X, indirect index=%u, name=%s\n", fixup.offsetInAtom, fixup.u.bindingIndex,
1132 // (char*)(state.indirectBindingTable[fixup.u.bindingIndex]->rawContentPointer()));
1133 }
1134 slide += 2*sizeof(pint_t) * PropertyList<A>::count(state, categoryPropertyListAtom);
1135 }
1136 }
1137 // add method list from base class last
1138 if ( basePropertyList != NULL ) {
1139 for (ld::Fixup::iterator fit=basePropertyList->fixupsBegin(); fit != basePropertyList->fixupsEnd(); ++fit) {
1140 ld::Fixup fixup = *fit;
1141 fixup.offsetInAtom += slide;
1142 _fixups.push_back(fixup);
1143 }
1144 }
1145}
1146
1147
1148
1149
1150void doPass(const Options& opts, ld::Internal& state)
1151{
1152 // only make image info section if objc was used
1153 if ( state.objcObjectConstraint != ld::File::objcConstraintNone ) {
1154
1155 // verify dylibs are GC compatible with object files
1156 if ( state.objcObjectConstraint != state.objcDylibConstraint ) {
1157 if ( (state.objcDylibConstraint == ld::File::objcConstraintRetainRelease)
1158 && (state.objcObjectConstraint == ld::File::objcConstraintGC) ) {
1159 throw "Linked dylibs built for retain/release but object files built for GC-only";
1160 }
1161 else if ( (state.objcDylibConstraint == ld::File::objcConstraintGC)
1162 && (state.objcObjectConstraint == ld::File::objcConstraintRetainRelease) ) {
1163 throw "Linked dylibs built for GC-only but object files built for retain/release";
1164 }
1165 }
1166
1167 const bool compaction = opts.objcGcCompaction();
1168
1169 // add image info atom
1170 switch ( opts.architecture() ) {
ebf6f434 1171#if SUPPORT_ARCH_x86_64
a645023d
A
1172 case CPU_TYPE_X86_64:
1173 state.addAtom(*new ObjCImageInfoAtom<x86_64>(state.objcObjectConstraint, compaction,
ebf6f434 1174 true));
a645023d 1175 break;
ebf6f434
A
1176#endif
1177#if SUPPORT_ARCH_i386
a645023d
A
1178 case CPU_TYPE_I386:
1179 state.addAtom(*new ObjCImageInfoAtom<x86>(state.objcObjectConstraint, compaction,
ebf6f434 1180 opts.objCABIVersion2POverride() ? true : false));
a645023d 1181 break;
ebf6f434 1182#endif
f80fe69f 1183#if SUPPORT_ARCH_arm_any
a645023d
A
1184 case CPU_TYPE_ARM:
1185 state.addAtom(*new ObjCImageInfoAtom<arm>(state.objcObjectConstraint, compaction,
ebf6f434 1186 true));
a645023d 1187 break;
f80fe69f
A
1188#endif
1189#if SUPPORT_ARCH_arm64
1190 case CPU_TYPE_ARM64:
1191 state.addAtom(*new ObjCImageInfoAtom<arm64>(state.objcObjectConstraint, compaction,
1192 true));
1193 break;
1194#endif
a645023d
A
1195 default:
1196 assert(0 && "unknown objc arch");
1197 }
1198 }
1199
1200 if ( opts.objcCategoryMerging() ) {
1201 // optimize classes defined in this linkage unit by merging in categories also in this linkage unit
1202 switch ( opts.architecture() ) {
ebf6f434 1203#if SUPPORT_ARCH_x86_64
a645023d
A
1204 case CPU_TYPE_X86_64:
1205 OptimizeCategories<x86_64>::doit(opts, state);
1206 break;
ebf6f434
A
1207#endif
1208#if SUPPORT_ARCH_i386
a645023d 1209 case CPU_TYPE_I386:
ebf6f434
A
1210 if ( opts.objCABIVersion2POverride() )
1211 OptimizeCategories<x86>::doit(opts, state);
a645023d 1212 break;
ebf6f434
A
1213#endif
1214#if SUPPORT_ARCH_arm_any
a645023d 1215 case CPU_TYPE_ARM:
ebf6f434 1216 OptimizeCategories<arm>::doit(opts, state);
a645023d 1217 break;
f80fe69f
A
1218#endif
1219#if SUPPORT_ARCH_arm64
1220 case CPU_TYPE_ARM64:
1221 // disabled until tested
1222 break;
ebf6f434 1223#endif
a645023d
A
1224 default:
1225 assert(0 && "unknown objc arch");
1226 }
1227 }
1228}
1229
1230
1231} // namespace objc
1232} // namespace passes
1233} // namespace ld