]> git.saurik.com Git - apple/ld64.git/blob - src/ld/passes/objc.cpp
ld64-236.3.tar.gz
[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_SUPPORTS_GC (1<<1)
54 #define OBJC_IMAGE_REQUIRES_GC (1<<2)
55 #define OBJC_IMAGE_OPTIMIZED_BY_DYLD (1<<3)
56 #define OBJC_IMAGE_SUPPORTS_COMPACTION (1<<4)
57 #define OBJC_IMAGE_IS_SIMULATED (1<<5)
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 abi2);
69
70 virtual const ld::File* file() const { return NULL; }
71 virtual const char* name() const { return "objc image info"; }
72 virtual uint64_t size() const { return sizeof(objc_image_info); }
73 virtual uint64_t objectAddress() const { return 0; }
74 virtual void setScope(Scope) { }
75 virtual void copyRawContent(uint8_t buffer[]) const {
76 memcpy(buffer, &_content, sizeof(objc_image_info));
77 }
78
79 private:
80 objc_image_info _content;
81
82 static ld::Section _s_sectionABI1;
83 static ld::Section _s_sectionABI2;
84 };
85
86 template <typename A> ld::Section ObjCImageInfoAtom<A>::_s_sectionABI1("__OBJC", "__image_info", ld::Section::typeUnclassified);
87 template <typename A> ld::Section ObjCImageInfoAtom<A>::_s_sectionABI2("__DATA", "__objc_imageinfo", ld::Section::typeUnclassified);
88
89
90 template <typename A>
91 ObjCImageInfoAtom<A>::ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint, bool compaction,
92 bool abi2)
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;
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;
115 case ld::File::objcConstraintRetainReleaseForSimulator:
116 value |= OBJC_IMAGE_IS_SIMULATED;
117 break;
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 //
129 template <typename A>
130 class MethodListAtom : public ld::Atom {
131 public:
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; }
137 virtual const char* name() const { return "objc merged method list"; }
138 virtual uint64_t size() const { return _methodCount*3*sizeof(pint_t) + 8; }
139 virtual uint64_t objectAddress() const { return 0; }
140 virtual void setScope(Scope) { }
141 virtual void copyRawContent(uint8_t buffer[]) const {
142 bzero(buffer, size());
143 A::P::E::set32(*((uint32_t*)(&buffer[0])), 3*sizeof(pint_t)); // entry size
144 A::P::E::set32(*((uint32_t*)(&buffer[4])), _methodCount);
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
149 private:
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
159 template <typename A>
160 ld::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 //
166 template <typename A>
167 class ProtocolListAtom : public ld::Atom {
168 public:
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; }
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
185 private:
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
195 template <typename A>
196 ld::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 //
203 template <typename A>
204 class PropertyListAtom : public ld::Atom {
205 public:
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; }
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
223 private:
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
233 template <typename A>
234 ld::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 //
244 template <typename A>
245 class ClassROOverlayAtom : public ld::Atom {
246 public:
247 ClassROOverlayAtom(const ld::Atom* classROAtom);
248
249 // overrides of ld::Atom
250 virtual const ld::File* file() const { return _atom->file(); }
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
270 private:
271 typedef typename A::P::uint_t pint_t;
272
273 const ld::Atom* _atom;
274 std::vector<ld::Fixup> _fixups;
275 };
276
277 template <typename A>
278 ClassROOverlayAtom<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 //
298 template <typename A>
299 class ObjCData {
300 public:
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
307 template <typename A>
308 const 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
336 template <typename A>
337 void 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 //
362 template <typename A>
363 class Category : public ObjCData<A> {
364 public:
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); }
371 private:
372 typedef typename A::P::uint_t pint_t;
373 };
374
375
376 template <typename A>
377 const 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
382 template <typename A>
383 const 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
388 template <typename A>
389 const 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
394 template <typename A>
395 const 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
400 template <typename A>
401 const 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
407 template <typename A>
408 class MethodList : public ObjCData<A> {
409 public:
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
416 template <typename A>
417 class ProtocolList : public ObjCData<A> {
418 public:
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 }
423 private:
424 typedef typename A::P::uint_t pint_t;
425 };
426
427 template <typename A>
428 class PropertyList : public ObjCData<A> {
429 public:
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 }
434 private:
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 //
443 template <typename A>
444 class Class : public ObjCData<A> {
445 public:
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();
462 private:
463 typedef typename A::P::uint_t pint_t;
464 static const ld::Atom* getROData(ld::Internal& state, const ld::Atom* classAtom);
465 };
466
467 template <> unsigned int Class<x86_64>::class_ro_header_size() { return 16; }
468 template <> unsigned int Class<arm>::class_ro_header_size() { return 12;}
469 template <> unsigned int Class<x86>::class_ro_header_size() { return 12; }
470
471
472 template <typename A>
473 const 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
479 template <typename A>
480 const 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
487 template <typename A>
488 const 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
495 template <typename A>
496 const 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
503 template <typename A>
504 const 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
511 template <typename A>
512 const 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
531 template <typename A>
532 const 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
552 template <typename A>
553 const 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
565 template <typename A>
566 const 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
585 template <typename A>
586 const 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
597 template <>
598 void 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
605 template <>
606 void 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
613 template <>
614 void 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
623 template <>
624 void 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
631 template <>
632 void 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
639 template <>
640 void 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
648 template <>
649 void 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
656 template <>
657 void 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
664 template <>
665 void 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 //
678 template <typename A>
679 class OptimizeCategories {
680 public:
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();
689 private:
690 typedef typename A::P::uint_t pint_t;
691
692 };
693
694
695 template <typename A>
696 bool 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
710 template <typename A>
711 bool 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
724 template <typename A>
725 bool 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
740 template <typename A>
741 bool 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 //
759 class OptimizedAway {
760 public:
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 }
765 private:
766 const std::set<const ld::Atom*>& _dead;
767 };
768
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
798 template <typename A>
799 void 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;
821 std::vector<const ld::Atom*> classOrder;
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);
837 assert(categoryAtom->size() >= Category<A>::size());
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*>();
848 classOrder.push_back(categoryOnClassAtom);
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);
865 sortAtomVector(classOrder);
866 // alter each class definition to have new method list which includes all category methods
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];
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
936 template <typename A>
937 MethodListAtom<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;
944 std::set<const ld::Atom*> baseMethodListMethodNameAtoms;
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();
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 }
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;
985 std::set<const ld::Atom*> categoryMethodNameAtoms;
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);
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 }
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
1030 template <typename A>
1031 ProtocolListAtom<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
1087 template <typename A>
1088 PropertyListAtom<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
1150 void 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() ) {
1171 #if SUPPORT_ARCH_x86_64
1172 case CPU_TYPE_X86_64:
1173 state.addAtom(*new ObjCImageInfoAtom<x86_64>(state.objcObjectConstraint, compaction,
1174 true));
1175 break;
1176 #endif
1177 #if SUPPORT_ARCH_i386
1178 case CPU_TYPE_I386:
1179 state.addAtom(*new ObjCImageInfoAtom<x86>(state.objcObjectConstraint, compaction,
1180 opts.objCABIVersion2POverride() ? true : false));
1181 break;
1182 #endif
1183 #if SUPPORT_ARCH_arm_any
1184 case CPU_TYPE_ARM:
1185 state.addAtom(*new ObjCImageInfoAtom<arm>(state.objcObjectConstraint, compaction,
1186 true));
1187 break;
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
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() ) {
1203 #if SUPPORT_ARCH_x86_64
1204 case CPU_TYPE_X86_64:
1205 OptimizeCategories<x86_64>::doit(opts, state);
1206 break;
1207 #endif
1208 #if SUPPORT_ARCH_i386
1209 case CPU_TYPE_I386:
1210 if ( opts.objCABIVersion2POverride() )
1211 OptimizeCategories<x86>::doit(opts, state);
1212 break;
1213 #endif
1214 #if SUPPORT_ARCH_arm_any
1215 case CPU_TYPE_ARM:
1216 OptimizeCategories<arm>::doit(opts, state);
1217 break;
1218 #endif
1219 #if SUPPORT_ARCH_arm64
1220 case CPU_TYPE_ARM64:
1221 // disabled until tested
1222 break;
1223 #endif
1224 default:
1225 assert(0 && "unknown objc arch");
1226 }
1227 }
1228 }
1229
1230
1231 } // namespace objc
1232 } // namespace passes
1233 } // namespace ld