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