]> git.saurik.com Git - apple/ld64.git/blame - src/ld/LinkEditClassic.hpp
ld64-128.2.tar.gz
[apple/ld64.git] / src / ld / LinkEditClassic.hpp
CommitLineData
a645023d
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
2 *
3 * Copyright (c) 2009-2010 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#ifndef __LINKEDIT_CLASSIC_HPP__
26#define __LINKEDIT_CLASSIC_HPP__
27
28#include <stdlib.h>
29#include <sys/types.h>
30#include <errno.h>
31#include <limits.h>
32#include <unistd.h>
33
34#include <vector>
35
36#include "Options.h"
37#include "ld.hpp"
38#include "Architectures.hpp"
39#include "MachOFileAbstraction.hpp"
40
41namespace ld {
42namespace tool {
43
44
45
46class ClassicLinkEditAtom : public ld::Atom
47{
48public:
49
50 // overrides of ld::Atom
51 virtual ld::File* file() const { return NULL; }
52 virtual bool translationUnitSource(const char** dir, const char** nm) const
53 { return false; }
54 virtual uint64_t objectAddress() const { return 0; }
55
56 virtual void encode() = 0;
57 virtual bool hasStabs(uint32_t& ssos, uint32_t& ssoe, uint32_t& sos, uint32_t& soe) { return false; }
58
59 ClassicLinkEditAtom(const Options& opts, ld::Internal& state,
60 OutputFile& writer, const ld::Section& sect,
61 unsigned int pointerSize)
62 : ld::Atom(sect, ld::Atom::definitionRegular,
63 ld::Atom::combineNever, ld::Atom::scopeTranslationUnit,
64 ld::Atom::typeUnclassified, ld::Atom::symbolTableNotIn,
65 false, false, false, ld::Atom::Alignment(log2(pointerSize))),
66 _options(opts), _state(state), _writer(writer) { }
67protected:
68 const Options& _options;
69 ld::Internal& _state;
70 OutputFile& _writer;
71};
72
73
74
75class StringPoolAtom : public ClassicLinkEditAtom
76{
77public:
78 StringPoolAtom(const Options& opts, ld::Internal& state,
79 OutputFile& writer, int pointerSize);
80
81 // overrides of ld::Atom
82 virtual const char* name() const { return "string pool"; }
83 virtual uint64_t size() const;
84 virtual void copyRawContent(uint8_t buffer[]) const;
85 // overrides of ClassicLinkEditAtom
86 virtual void encode() { }
87
88 int32_t add(const char* name);
89 int32_t addUnique(const char* name);
90 int32_t emptyString() { return 1; }
91 const char* stringForIndex(int32_t) const;
92 uint32_t currentOffset();
93
94private:
95 class CStringEquals
96 {
97 public:
98 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
99 };
100 enum { kBufferSize = 0x01000000 };
101 typedef __gnu_cxx::hash_map<const char*, int32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
102
103 const uint32_t _pointerSize;
104 std::vector<char*> _fullBuffers;
105 char* _currentBuffer;
106 uint32_t _currentBufferUsed;
107 StringToOffset _uniqueStrings;
108
109 static ld::Section _s_section;
110};
111
112ld::Section StringPoolAtom::_s_section("__LINKEDIT", "__string_pool", ld::Section::typeLinkEdit, true);
113
114
115StringPoolAtom::StringPoolAtom(const Options& opts, ld::Internal& state, OutputFile& writer, int pointerSize)
116 : ClassicLinkEditAtom(opts, state, writer, _s_section, pointerSize),
117 _pointerSize(pointerSize), _currentBuffer(NULL), _currentBufferUsed(0)
118{
119 _currentBuffer = new char[kBufferSize];
120 // burn first byte of string pool (so zero is never a valid string offset)
121 _currentBuffer[_currentBufferUsed++] = ' ';
122 // make offset 1 always point to an empty string
123 _currentBuffer[_currentBufferUsed++] = '\0';
124}
125
126uint64_t StringPoolAtom::size() const
127{
128 // pointer size align size
129 return (kBufferSize * _fullBuffers.size() + _currentBufferUsed + _pointerSize-1) & (-_pointerSize);
130}
131
132void StringPoolAtom::copyRawContent(uint8_t buffer[]) const
133{
134 uint64_t offset = 0;
135 for (unsigned int i=0; i < _fullBuffers.size(); ++i) {
136 memcpy(&buffer[offset], _fullBuffers[i], kBufferSize);
137 offset += kBufferSize;
138 }
139 memcpy(&buffer[offset], _currentBuffer, _currentBufferUsed);
140 // zero fill end to align
141 offset += _currentBufferUsed;
142 while ( (offset % _pointerSize) != 0 )
143 buffer[offset++] = 0;
144}
145
146int32_t StringPoolAtom::add(const char* str)
147{
148 int32_t offset = kBufferSize * _fullBuffers.size() + _currentBufferUsed;
149 int lenNeeded = strlcpy(&_currentBuffer[_currentBufferUsed], str, kBufferSize-_currentBufferUsed)+1;
150 if ( (_currentBufferUsed+lenNeeded) < kBufferSize ) {
151 _currentBufferUsed += lenNeeded;
152 }
153 else {
154 int copied = kBufferSize-_currentBufferUsed-1;
155 // change trailing '\0' that strlcpy added to real char
156 _currentBuffer[kBufferSize-1] = str[copied];
157 // alloc next buffer
158 _fullBuffers.push_back(_currentBuffer);
159 _currentBuffer = new char[kBufferSize];
160 _currentBufferUsed = 0;
161 // append rest of string
162 this->add(&str[copied+1]);
163 }
164 return offset;
165}
166
167uint32_t StringPoolAtom::currentOffset()
168{
169 return kBufferSize * _fullBuffers.size() + _currentBufferUsed;
170}
171
172
173int32_t StringPoolAtom::addUnique(const char* str)
174{
175 StringToOffset::iterator pos = _uniqueStrings.find(str);
176 if ( pos != _uniqueStrings.end() ) {
177 return pos->second;
178 }
179 else {
180 int32_t offset = this->add(str);
181 _uniqueStrings[str] = offset;
182 return offset;
183 }
184}
185
186
187const char* StringPoolAtom::stringForIndex(int32_t index) const
188{
189 int32_t currentBufferStartIndex = kBufferSize * _fullBuffers.size();
190 int32_t maxIndex = currentBufferStartIndex + _currentBufferUsed;
191 // check for out of bounds
192 if ( index > maxIndex )
193 return "";
194 // check for index in _currentBuffer
195 if ( index > currentBufferStartIndex )
196 return &_currentBuffer[index-currentBufferStartIndex];
197 // otherwise index is in a full buffer
198 uint32_t fullBufferIndex = index/kBufferSize;
199 return &_fullBuffers[fullBufferIndex][index-(kBufferSize*fullBufferIndex)];
200}
201
202
203
204template <typename A>
205class SymbolTableAtom : public ClassicLinkEditAtom
206{
207public:
208 SymbolTableAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
209 : ClassicLinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)),
210 _stabsStringsOffsetStart(0), _stabsStringsOffsetEnd(0),
211 _stabsIndexStart(0), _stabsIndexEnd(0) { }
212
213 // overrides of ld::Atom
214 virtual const char* name() const { return "symbol table"; }
215 virtual uint64_t size() const;
216 virtual void copyRawContent(uint8_t buffer[]) const;
217 // overrides of ClassicLinkEditAtom
218 virtual void encode();
219 virtual bool hasStabs(uint32_t& ssos, uint32_t& ssoe, uint32_t& sos, uint32_t& soe);
220
221private:
222 typedef typename A::P P;
223 typedef typename A::P::E E;
224 typedef typename A::P::uint_t pint_t;
225
226 bool addLocal(const ld::Atom* atom, StringPoolAtom* pool);
227 void addGlobal(const ld::Atom* atom, StringPoolAtom* pool);
228 void addImport(const ld::Atom* atom, StringPoolAtom* pool);
229 uint8_t classicOrdinalForProxy(const ld::Atom* atom);
230 uint32_t stringOffsetForStab(const ld::relocatable::File::Stab& stab, StringPoolAtom* pool);
231 uint64_t valueForStab(const ld::relocatable::File::Stab& stab);
232 uint8_t sectionIndexForStab(const ld::relocatable::File::Stab& stab);
233
234
235 mutable std::vector<macho_nlist<P> > _globals;
236 mutable std::vector<macho_nlist<P> > _locals;
237 mutable std::vector<macho_nlist<P> > _imports;
238
239 uint32_t _stabsStringsOffsetStart;
240 uint32_t _stabsStringsOffsetEnd;
241 uint32_t _stabsIndexStart;
242 uint32_t _stabsIndexEnd;
243
244 static ld::Section _s_section;
245};
246
247template <typename A>
248ld::Section SymbolTableAtom<A>::_s_section("__LINKEDIT", "__symbol_table", ld::Section::typeLinkEdit, true);
249
250
251
252template <typename A>
253bool SymbolTableAtom<A>::addLocal(const ld::Atom* atom, StringPoolAtom* pool)
254{
255 macho_nlist<P> entry;
256 static int s_anonNameIndex = 1;
257 assert(atom->symbolTableInclusion() != ld::Atom::symbolTableNotIn);
258
259 // set n_strx
260 const char* symbolName = atom->name();
261 char anonName[32];
262 if ( this->_options.outputKind() == Options::kObjectFile ) {
263 if ( atom->contentType() == ld::Atom::typeCString ) {
264 if ( atom->combine() == ld::Atom::combineByNameAndContent ) {
265 // don't use 'l' labels for x86_64 strings
266 // <rdar://problem/6605499> x86_64 obj-c runtime confused when static lib is stripped
267 sprintf(anonName, "LC%u", s_anonNameIndex++);
268 symbolName = anonName;
269 }
270 }
271 else if ( atom->contentType() == ld::Atom::typeCFI ) {
272 if ( _options.removeEHLabels() )
273 return false;
274 // synthesize .eh name
275 if ( strcmp(atom->name(), "CIE") == 0 )
276 symbolName = "EH_Frame1";
277 else
278 symbolName = "func.eh";
279 }
280 else if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInWithRandomAutoStripLabel ) {
281 // make auto-strip anonymous name for symbol
282 sprintf(anonName, "l%03u", s_anonNameIndex++);
283 symbolName = anonName;
284 }
285 }
286 entry.set_n_strx(pool->add(symbolName));
287
288 // set n_type
289 uint8_t type = N_SECT;
290 if ( atom->definition() == ld::Atom::definitionAbsolute ) {
291 type = N_ABS;
292 }
293 else if ( (atom->section().type() == ld::Section::typeObjC1Classes)
294 && (this->_options.outputKind() == Options::kObjectFile) ) {
295 // __OBJC __class has floating abs symbols for each class data structure
296 type = N_ABS;
297 }
298 if ( atom->scope() == ld::Atom::scopeLinkageUnit )
299 type |= N_PEXT;
300 entry.set_n_type(type);
301
302 // set n_sect (section number of implementation )
303 if ( atom->definition() == ld::Atom::definitionAbsolute )
304 entry.set_n_sect(0);
305 else
306 entry.set_n_sect(atom->machoSection());
307
308 // set n_desc
309 uint16_t desc = 0;
310 if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip )
311 desc |= REFERENCED_DYNAMICALLY;
312 if ( atom->dontDeadStrip() && (this->_options.outputKind() == Options::kObjectFile) )
313 desc |= N_NO_DEAD_STRIP;
314 if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) )
315 desc |= N_WEAK_DEF;
316 if ( atom->isThumb() )
317 desc |= N_ARM_THUMB_DEF;
318 entry.set_n_desc(desc);
319
320 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
321 if ( atom->definition() == ld::Atom::definitionAbsolute )
322 entry.set_n_value(atom->objectAddress());
323 else
324 entry.set_n_value(atom->finalAddress());
325
326 // add to array
327 _locals.push_back(entry);
328 return true;
329}
330
331
332template <typename A>
333void SymbolTableAtom<A>::addGlobal(const ld::Atom* atom, StringPoolAtom* pool)
334{
335 macho_nlist<P> entry;
336
337 // set n_strx
338 entry.set_n_strx(pool->add(atom->name()));
339
340 // set n_type
341 if ( atom->definition() == ld::Atom::definitionAbsolute ) {
342 entry.set_n_type(N_EXT | N_ABS);
343 }
344 else if ( (atom->section().type() == ld::Section::typeObjC1Classes)
345 && (this->_options.outputKind() == Options::kObjectFile) ) {
346 // __OBJC __class has floating abs symbols for each class data structure
347 entry.set_n_type(N_EXT | N_ABS);
348 }
349 else if ( (atom->definition() == ld::Atom::definitionProxy) && (atom->scope() == ld::Atom::scopeGlobal) ) {
350 entry.set_n_type(N_EXT | N_INDR);
351 }
352 else {
353 entry.set_n_type(N_EXT | N_SECT);
354 if ( (atom->scope() == ld::Atom::scopeLinkageUnit) && (this->_options.outputKind() == Options::kObjectFile) ) {
355 if ( this->_options.keepPrivateExterns() )
356 entry.set_n_type(N_EXT | N_SECT | N_PEXT);
357 }
358 else if ( (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip)
359 && (atom->section().type() == ld::Section::typeMachHeader) ) {
360 // the __mh_execute_header is historical magic and must be an absolute symbol
361 entry.set_n_type(N_EXT | N_ABS);
362 }
363 }
364
365 // set n_sect (section number of implementation)
366 if ( atom->definition() == ld::Atom::definitionAbsolute )
367 entry.set_n_sect(0);
368 else if ( (atom->definition() == ld::Atom::definitionProxy) && (atom->scope() == ld::Atom::scopeGlobal) )
369 entry.set_n_sect(0);
370 else
371 entry.set_n_sect(atom->machoSection());
372
373 // set n_desc
374 uint16_t desc = 0;
375 if ( atom->isThumb() )
376 desc |= N_ARM_THUMB_DEF;
377 if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip )
378 desc |= REFERENCED_DYNAMICALLY;
379 if ( (atom->contentType() == ld::Atom::typeResolver) && (this->_options.outputKind() == Options::kObjectFile) )
380 desc |= N_SYMBOL_RESOLVER;
381 if ( atom->dontDeadStrip() && (this->_options.outputKind() == Options::kObjectFile) )
382 desc |= N_NO_DEAD_STRIP;
383 if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) ) {
384 desc |= N_WEAK_DEF;
385 // <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
386 if ( (atom->scope() == ld::Atom::scopeGlobal) && atom->autoHide() && (this->_options.outputKind() == Options::kObjectFile) )
387 desc |= N_WEAK_REF;
388 }
389 entry.set_n_desc(desc);
390
391 // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
392 if ( atom->definition() == ld::Atom::definitionAbsolute )
393 entry.set_n_value(atom->objectAddress());
394 else if ( (atom->definition() == ld::Atom::definitionProxy) && (atom->scope() == ld::Atom::scopeGlobal) ) {
395 if ( atom->isAlias() ) {
396 // this re-export also renames
397 for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
398 if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
399 assert(fit->binding == ld::Fixup::bindingDirectlyBound);
400 entry.set_n_value(pool->add(fit->u.target->name()));
401 }
402 }
403 }
404 else
405 entry.set_n_value(entry.n_strx());
406 }
407 else
408 entry.set_n_value(atom->finalAddress());
409
410 // add to array
411 _globals.push_back(entry);
412}
413
414template <typename A>
415uint8_t SymbolTableAtom<A>::classicOrdinalForProxy(const ld::Atom* atom)
416{
417 assert(atom->definition() == ld::Atom::definitionProxy);
418 // when linking for flat-namespace ordinals are always zero
419 if ( _options.nameSpace() != Options::kTwoLevelNameSpace )
420 return 0;
421 const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(atom->file());
422 // when linking -undefined dynamic_lookup, unbound symbols use DYNAMIC_LOOKUP_ORDINAL
423 if ( dylib == NULL ) {
424 if (_options.undefinedTreatment() == Options::kUndefinedDynamicLookup )
425 return DYNAMIC_LOOKUP_ORDINAL;
426 if (_options.allowedUndefined(atom->name()) )
427 return DYNAMIC_LOOKUP_ORDINAL;
428 }
429 assert(dylib != NULL);
430 int ord = this->_writer.dylibToOrdinal(dylib);
431 if ( ord == BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE )
432 return EXECUTABLE_ORDINAL;
433 return ord;
434}
435
436
437template <typename A>
438void SymbolTableAtom<A>::addImport(const ld::Atom* atom, StringPoolAtom* pool)
439{
440 macho_nlist<P> entry;
441
442 // set n_strx
443 entry.set_n_strx(pool->add(atom->name()));
444
445 // set n_type
446 if ( this->_options.outputKind() == Options::kObjectFile ) {
447 if ( (atom->scope() == ld::Atom::scopeLinkageUnit)
448 && (atom->definition() == ld::Atom::definitionTentative) )
449 entry.set_n_type(N_UNDF | N_EXT | N_PEXT);
450 else
451 entry.set_n_type(N_UNDF | N_EXT);
452 }
453 else {
454 if ( this->_options.prebind() )
455 entry.set_n_type(N_PBUD | N_EXT);
456 else
457 entry.set_n_type(N_UNDF | N_EXT);
458 }
459
460 // set n_sect
461 entry.set_n_sect(0);
462
463 uint16_t desc = 0;
464 if ( this->_options.outputKind() != Options::kObjectFile ) {
465 uint8_t ordinal = this->classicOrdinalForProxy(atom);
466 //fprintf(stderr, "ordinal=%u from reader=%p for symbol=%s\n", ordinal, atom->getFile(), atom->getName());
467 SET_LIBRARY_ORDINAL(desc, ordinal);
468
469#if 0
470 // set n_desc ( high byte is library ordinal, low byte is reference type )
471 std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(atom);
472 if ( pos != fStubsMap.end() || ( strncmp(atom->getName(), ".objc_class_name_", 17) == 0) )
473 desc |= REFERENCE_FLAG_UNDEFINED_LAZY;
474 else
475 desc |= REFERENCE_FLAG_UNDEFINED_NON_LAZY;
476#endif
477 }
478 else if ( atom->definition() == ld::Atom::definitionTentative ) {
479 uint8_t align = atom->alignment().powerOf2;
480 // always record custom alignment of common symbols to match what compiler does
481 SET_COMM_ALIGN(desc, align);
482 }
483 if ( (this->_options.outputKind() != Options::kObjectFile)
484 && (atom->definition() == ld::Atom::definitionProxy)
485 && (atom->combine() == ld::Atom::combineByName) ) {
486 desc |= N_REF_TO_WEAK;
487 }
afe874b1
A
488 const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(atom->file());
489 if ( atom->weakImported() || ((dylib != NULL) && dylib->forcedWeakLinked()) )
a645023d
A
490 desc |= N_WEAK_REF;
491 entry.set_n_desc(desc);
492
493 // set n_value, zero for import proxy and size for tentative definition
494 if ( atom->definition() == ld::Atom::definitionTentative )
495 entry.set_n_value(atom->size());
496 else
497 entry.set_n_value(0);
498
499 // add to array
500 _imports.push_back(entry);
501}
502
503template <typename A>
504uint8_t SymbolTableAtom<A>::sectionIndexForStab(const ld::relocatable::File::Stab& stab)
505{
506 // in FUN stabs, n_sect field is 0 for start FUN and 1 for end FUN
507 if ( stab.type == N_FUN )
508 return stab.other;
509 else if ( stab.type == N_GSYM )
510 return 0;
511 else if ( stab.atom != NULL )
512 return stab.atom->machoSection();
513 else
514 return stab.other;
515}
516
517
518template <typename A>
519uint64_t SymbolTableAtom<A>::valueForStab(const ld::relocatable::File::Stab& stab)
520{
521 switch ( stab.type ) {
522 case N_FUN:
523 if ( stab.atom == NULL ) {
524 // <rdar://problem/5591394> Add support to ld64 for N_FUN stabs when used for symbolic constants
525 return stab.value;
526 }
527 if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
528 // end of function N_FUN has size
529 return stab.atom->size();
530 }
531 else {
532 // start of function N_FUN has address
533 return stab.atom->finalAddress();
534 }
535 case N_LBRAC:
536 case N_RBRAC:
537 case N_SLINE:
538 if ( stab.atom == NULL )
539 // some weird assembly files have slines not associated with a function
540 return stab.value;
541 else
542 // all these stab types need their value changed from an offset in the atom to an address
543 return stab.atom->finalAddress() + stab.value;
544 case N_STSYM:
545 case N_LCSYM:
546 case N_BNSYM:
547 // all these need address of atom
548 if ( stab.atom != NULL )
549 return stab.atom->finalAddress();
550 else
551 return 0; // <rdar://problem/7811357> work around for mismatch N_BNSYM
552 case N_ENSYM:
553 return stab.atom->size();
554 case N_SO:
555 if ( stab.atom == NULL ) {
556 return 0;
557 }
558 else {
559 if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
560 // end of translation unit N_SO has address of end of last atom
561 return stab.atom->finalAddress() + stab.atom->size();
562 }
563 else {
564 // start of translation unit N_SO has address of end of first atom
565 return stab.atom->finalAddress();
566 }
567 }
568 break;
569 default:
570 return stab.value;
571 }
572}
573
574template <typename A>
575uint32_t SymbolTableAtom<A>::stringOffsetForStab(const ld::relocatable::File::Stab& stab, StringPoolAtom* pool)
576{
577 switch (stab.type) {
578 case N_SO:
579 if ( (stab.string == NULL) || stab.string[0] == '\0' ) {
580 return pool->emptyString();
581 break;
582 }
583 // fall into uniquing case
584 case N_SOL:
585 case N_BINCL:
586 case N_EXCL:
587 return pool->addUnique(stab.string);
588 break;
589 default:
590 if ( stab.string == NULL )
591 return 0;
592 else if ( stab.string[0] == '\0' )
593 return pool->emptyString();
594 else
595 return pool->add(stab.string);
596 }
597 return 0;
598}
599
600
601
602template <typename A>
603bool SymbolTableAtom<A>::hasStabs(uint32_t& ssos, uint32_t& ssoe, uint32_t& sos, uint32_t& soe)
604{
605 ssos = _stabsStringsOffsetStart;
606 ssoe = _stabsStringsOffsetEnd;
607 sos = _stabsIndexStart * sizeof(macho_nlist<P>);
608 soe = _stabsIndexEnd * sizeof(macho_nlist<P>);
609 return ( (_stabsIndexStart != _stabsIndexEnd) || (_stabsStringsOffsetStart != _stabsStringsOffsetEnd) );
610}
611
612template <typename A>
613void SymbolTableAtom<A>::encode()
614{
615 uint32_t symbolIndex = 0;
616
617 // make nlist entries for all local symbols
618 std::vector<const ld::Atom*>& localAtoms = this->_writer._localAtoms;
619 _locals.reserve(localAtoms.size()+this->_state.stabs.size());
620 this->_writer._localSymbolsStartIndex = 0;
621 // make nlist entries for all debug notes
622 _stabsIndexStart = symbolIndex;
623 _stabsStringsOffsetStart = this->_writer._stringPoolAtom->currentOffset();
624 for (std::vector<ld::relocatable::File::Stab>::const_iterator sit=this->_state.stabs.begin(); sit != this->_state.stabs.end(); ++sit) {
625 macho_nlist<P> entry;
626 entry.set_n_type(sit->type);
627 entry.set_n_sect(sectionIndexForStab(*sit));
628 entry.set_n_desc(sit->desc);
629 entry.set_n_value(valueForStab(*sit));
630 entry.set_n_strx(stringOffsetForStab(*sit, this->_writer._stringPoolAtom));
631 _locals.push_back(entry);
632 ++symbolIndex;
633 }
634 _stabsIndexEnd = symbolIndex;
635 _stabsStringsOffsetEnd = this->_writer._stringPoolAtom->currentOffset();
636 for (std::vector<const ld::Atom*>::const_iterator it=localAtoms.begin(); it != localAtoms.end(); ++it) {
637 const ld::Atom* atom = *it;
638 if ( this->addLocal(atom, this->_writer._stringPoolAtom) )
639 this->_writer._atomToSymbolIndex[atom] = symbolIndex++;
640 }
641 this->_writer._localSymbolsCount = symbolIndex;
642
643
644 // make nlist entries for all global symbols
645 std::vector<const ld::Atom*>& globalAtoms = this->_writer._exportedAtoms;
646 _globals.reserve(globalAtoms.size());
647 this->_writer._globalSymbolsStartIndex = symbolIndex;
648 for (std::vector<const ld::Atom*>::const_iterator it=globalAtoms.begin(); it != globalAtoms.end(); ++it) {
649 const ld::Atom* atom = *it;
650 this->addGlobal(atom, this->_writer._stringPoolAtom);
651 this->_writer._atomToSymbolIndex[atom] = symbolIndex++;
652 }
653 this->_writer._globalSymbolsCount = symbolIndex - this->_writer._globalSymbolsStartIndex;
654
655 // make nlist entries for all undefined (imported) symbols
656 std::vector<const ld::Atom*>& importAtoms = this->_writer._importedAtoms;
657 _imports.reserve(importAtoms.size());
658 this->_writer._importSymbolsStartIndex = symbolIndex;
659 for (std::vector<const ld::Atom*>::const_iterator it=importAtoms.begin(); it != importAtoms.end(); ++it) {
660 this->addImport(*it, this->_writer._stringPoolAtom);
661 this->_writer._atomToSymbolIndex[*it] = symbolIndex++;
662 }
663 this->_writer._importSymbolsCount = symbolIndex - this->_writer._importSymbolsStartIndex;
664}
665
666template <typename A>
667uint64_t SymbolTableAtom<A>::size() const
668{
669 return sizeof(macho_nlist<P>) * (_locals.size() + _globals.size() + _imports.size());
670}
671
672template <typename A>
673void SymbolTableAtom<A>::copyRawContent(uint8_t buffer[]) const
674{
675 memcpy(&buffer[this->_writer._localSymbolsStartIndex*sizeof(macho_nlist<P>)], &_locals[0],
676 this->_writer._localSymbolsCount*sizeof(macho_nlist<P>));
677 memcpy(&buffer[this->_writer._globalSymbolsStartIndex*sizeof(macho_nlist<P>)], &_globals[0],
678 this->_writer._globalSymbolsCount*sizeof(macho_nlist<P>));
679 memcpy(&buffer[this->_writer._importSymbolsStartIndex *sizeof(macho_nlist<P>)], &_imports[0],
680 this->_writer._importSymbolsCount*sizeof(macho_nlist<P>));
681}
682
683
684
685
686class RelocationsAtomAbstract : public ClassicLinkEditAtom
687{
688public:
689 RelocationsAtomAbstract(const Options& opts, ld::Internal& state,
690 OutputFile& writer, const ld::Section& sect,
691 unsigned int pointerSize)
692 : ClassicLinkEditAtom(opts, state, writer, sect, pointerSize) { }
693
694 virtual void addPointerReloc(uint64_t addr, uint32_t symNum) = 0;
695 virtual void addTextReloc(uint64_t addr, ld::Fixup::Kind k, uint64_t targetAddr, uint32_t symNum) = 0;
696 virtual void addExternalPointerReloc(uint64_t addr, const ld::Atom*) = 0;
697 virtual void addExternalCallSiteReloc(uint64_t addr, const ld::Atom*) = 0;
698 virtual uint64_t relocBaseAddress(ld::Internal& state) = 0;
699 virtual void addSectionReloc(ld::Internal::FinalSection* sect, ld::Fixup::Kind,
700 const ld::Atom* inAtom, uint32_t offsetInAtom,
701 bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
702 const ld::Atom* toTarget, uint64_t toAddend,
703 const ld::Atom* fromTarget, uint64_t fromAddend) = 0;
704protected:
705 uint32_t symbolIndex(const ld::Atom* atom) const;
706
707};
708
709
710
711uint32_t RelocationsAtomAbstract::symbolIndex(const ld::Atom* atom) const
712{
713 std::map<const ld::Atom*, uint32_t>::iterator pos = this->_writer._atomToSymbolIndex.find(atom);
714 if ( pos != this->_writer._atomToSymbolIndex.end() )
715 return pos->second;
716 fprintf(stderr, "_atomToSymbolIndex content:\n");
717 for(std::map<const ld::Atom*, uint32_t>::iterator it = this->_writer._atomToSymbolIndex.begin(); it != this->_writer._atomToSymbolIndex.end(); ++it) {
718 fprintf(stderr, "%p(%s) => %d\n", it->first, it->first->name(), it->second);
719 }
720 throwf("internal error: atom not found in symbolIndex(%s)", atom->name());
721}
722
723
724template <typename A>
725class LocalRelocationsAtom : public RelocationsAtomAbstract
726{
727public:
728 LocalRelocationsAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
729 : RelocationsAtomAbstract(opts, state, writer, _s_section, sizeof(pint_t)) { }
730
731 // overrides of ld::Atom
732 virtual const char* name() const { return "local relocations"; }
733 virtual uint64_t size() const;
734 virtual void copyRawContent(uint8_t buffer[]) const;
735 // overrides of ClassicLinkEditAtom
736 virtual void encode() {}
737 // overrides of RelocationsAtomAbstract
738 virtual void addPointerReloc(uint64_t addr, uint32_t symNum);
739 virtual void addExternalPointerReloc(uint64_t addr, const ld::Atom*) {}
740 virtual void addExternalCallSiteReloc(uint64_t addr, const ld::Atom*) {}
741 virtual uint64_t relocBaseAddress(ld::Internal& state);
742 virtual void addTextReloc(uint64_t addr, ld::Fixup::Kind k, uint64_t targetAddr, uint32_t symNum);
743 virtual void addSectionReloc(ld::Internal::FinalSection* sect, ld::Fixup::Kind,
744 const ld::Atom* inAtom, uint32_t offsetInAtom,
745 bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
746 const ld::Atom* toTarget, uint64_t toAddend,
747 const ld::Atom* fromTarget, uint64_t fromAddend) { }
748
749private:
750 typedef typename A::P P;
751 typedef typename A::P::E E;
752 typedef typename A::P::uint_t pint_t;
753
754 std::vector<macho_relocation_info<P> > _relocs;
755
756 static ld::Section _s_section;
757};
758
759template <typename A>
760ld::Section LocalRelocationsAtom<A>::_s_section("__LINKEDIT", "__local_relocs", ld::Section::typeLinkEdit, true);
761
762
763template <>
764uint64_t LocalRelocationsAtom<x86_64>::relocBaseAddress(ld::Internal& state)
765{
766 if ( _options.outputKind() == Options::kKextBundle ) {
767 // for kext bundles the reloc base address starts at __TEXT segment
768 return _options.baseAddress();
769 }
770 // for all other kinds, the x86_64 reloc base address starts at __DATA segment
771 for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
772 ld::Internal::FinalSection* sect = *sit;
773 if ( strcmp(sect->segmentName(), "__DATA") == 0 )
774 return sect->address;
775 }
776 throw "__DATA segment not found";
777}
778
779template <typename A>
780uint64_t LocalRelocationsAtom<A>::relocBaseAddress(ld::Internal& state)
781{
782 return _options.baseAddress();
783}
784
785template <typename A>
786void LocalRelocationsAtom<A>::addPointerReloc(uint64_t addr, uint32_t symNum)
787{
788 macho_relocation_info<P> reloc;
789 reloc.set_r_address(addr);
790 reloc.set_r_symbolnum(symNum);
791 reloc.set_r_pcrel(false);
792 reloc.set_r_length();
793 reloc.set_r_extern(false);
794 reloc.set_r_type(GENERIC_RELOC_VANILLA);
795 _relocs.push_back(reloc);
796}
797
798template <typename A>
799void LocalRelocationsAtom<A>::addTextReloc(uint64_t addr, ld::Fixup::Kind kind, uint64_t targetAddr, uint32_t symNum)
800{
a645023d
A
801}
802
803
804template <typename A>
805uint64_t LocalRelocationsAtom<A>::size() const
806{
807 return _relocs.size() * sizeof(macho_relocation_info<P>);
808}
809
810template <typename A>
811void LocalRelocationsAtom<A>::copyRawContent(uint8_t buffer[]) const
812{
813 memcpy(buffer, &_relocs[0], _relocs.size()*sizeof(macho_relocation_info<P>));
814}
815
816
817
818
819
820
821template <typename A>
822class ExternalRelocationsAtom : public RelocationsAtomAbstract
823{
824public:
825 ExternalRelocationsAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
826 : RelocationsAtomAbstract(opts, state, writer, _s_section, sizeof(pint_t)) { }
827
828 // overrides of ld::Atom
829 virtual const char* name() const { return "external relocations"; }
830 virtual uint64_t size() const;
831 virtual void copyRawContent(uint8_t buffer[]) const;
832 // overrides of ClassicLinkEditAtom
833 virtual void encode() {}
834 // overrides of RelocationsAtomAbstract
835 virtual void addPointerReloc(uint64_t addr, uint32_t symNum) {}
836 virtual void addTextReloc(uint64_t addr, ld::Fixup::Kind k, uint64_t targetAddr, uint32_t symNum) {}
837 virtual void addExternalPointerReloc(uint64_t addr, const ld::Atom*);
838 virtual void addExternalCallSiteReloc(uint64_t addr, const ld::Atom*);
839 virtual uint64_t relocBaseAddress(ld::Internal& state);
840 virtual void addSectionReloc(ld::Internal::FinalSection* sect, ld::Fixup::Kind,
841 const ld::Atom* inAtom, uint32_t offsetInAtom,
842 bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
843 const ld::Atom* toTarget, uint64_t toAddend,
844 const ld::Atom* fromTarget, uint64_t fromAddend) { }
845
846
847private:
848 typedef typename A::P P;
849 typedef typename A::P::E E;
850 typedef typename A::P::uint_t pint_t;
851
852 struct LocAndAtom {
853 LocAndAtom(uint64_t l, const ld::Atom* a) : loc(l), atom(a), symbolIndex(0) {}
854
855 uint64_t loc;
856 const ld::Atom* atom;
857 uint32_t symbolIndex;
858
859 bool operator<(const LocAndAtom& rhs) const {
860 // sort first by symbol number
861 if ( this->symbolIndex != rhs.symbolIndex )
862 return (this->symbolIndex < rhs.symbolIndex);
863 // then sort all uses of the same symbol by address
864 return (this->loc < rhs.loc);
865 }
866
867 };
868
869 static uint32_t pointerReloc();
870 static uint32_t callReloc();
871
872 mutable std::vector<LocAndAtom> _pointerLocations;
873 mutable std::vector<LocAndAtom> _callSiteLocations;
874
875 static ld::Section _s_section;
876};
877
878template <typename A>
879ld::Section ExternalRelocationsAtom<A>::_s_section("__LINKEDIT", "__extrn_relocs", ld::Section::typeLinkEdit, true);
880
881template <>
882uint64_t ExternalRelocationsAtom<x86_64>::relocBaseAddress(ld::Internal& state)
883{
884 // for x86_64 the reloc base address starts at __DATA segment
885 for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
886 ld::Internal::FinalSection* sect = *sit;
887 if ( strcmp(sect->segmentName(), "__DATA") == 0 )
888 return sect->address;
889 }
890 throw "__DATA segment not found";
891}
892
893template <typename A>
894uint64_t ExternalRelocationsAtom<A>::relocBaseAddress(ld::Internal& state)
895{
896 return 0;
897}
898
899template <typename A>
900void ExternalRelocationsAtom<A>::addExternalPointerReloc(uint64_t addr, const ld::Atom* target)
901{
902 _pointerLocations.push_back(LocAndAtom(addr, target));
903}
904
905template <typename A>
906void ExternalRelocationsAtom<A>::addExternalCallSiteReloc(uint64_t addr, const ld::Atom* target)
907{
908 _callSiteLocations.push_back(LocAndAtom(addr, target));
909}
910
911
912template <typename A>
913uint64_t ExternalRelocationsAtom<A>::size() const
914{
915 if ( _options.outputKind() == Options::kStaticExecutable ) {
916 assert(_pointerLocations.size() == 0);
917 assert(_callSiteLocations.size() == 0);
918 }
919 return (_pointerLocations.size() + _callSiteLocations.size()) * sizeof(macho_relocation_info<P>);
920}
921
922template <> uint32_t ExternalRelocationsAtom<arm>::pointerReloc() { return ARM_RELOC_VANILLA; }
923template <> uint32_t ExternalRelocationsAtom<x86>::pointerReloc() { return GENERIC_RELOC_VANILLA; }
a645023d 924template <> uint32_t ExternalRelocationsAtom<x86_64>::pointerReloc() { return X86_64_RELOC_UNSIGNED; }
a645023d
A
925
926
927template <> uint32_t ExternalRelocationsAtom<x86_64>::callReloc() { return X86_64_RELOC_BRANCH; }
928template <> uint32_t ExternalRelocationsAtom<x86>::callReloc() { return GENERIC_RELOC_VANILLA; }
929template <typename A>
930uint32_t ExternalRelocationsAtom<A>::callReloc()
931{
932 assert(0 && "external call relocs not implemented");
933 return 0;
934}
935
936
937template <typename A>
938void ExternalRelocationsAtom<A>::copyRawContent(uint8_t buffer[]) const
939{
940 macho_relocation_info<P>* r = (macho_relocation_info<P>*)buffer;
941
942 // assign symbol index, now that symbol table is built
943 for (typename std::vector<LocAndAtom>::iterator it = _pointerLocations.begin(); it != _pointerLocations.end(); ++it) {
944 it->symbolIndex = symbolIndex(it->atom);
945 }
946 std::sort(_pointerLocations.begin(), _pointerLocations.end());
947 for (typename std::vector<LocAndAtom>::const_iterator it = _pointerLocations.begin(); it != _pointerLocations.end(); ++it, ++r) {
948 r->set_r_address(it->loc);
949 r->set_r_symbolnum(it->symbolIndex);
950 r->set_r_pcrel(false);
951 r->set_r_length();
952 r->set_r_extern(true);
953 r->set_r_type(this->pointerReloc());
954 }
955
956 for (typename std::vector<LocAndAtom>::iterator it = _callSiteLocations.begin(); it != _callSiteLocations.end(); ++it) {
957 it->symbolIndex = symbolIndex(it->atom);
958 }
959 std::sort(_callSiteLocations.begin(), _callSiteLocations.end());
960 for (typename std::vector<LocAndAtom>::const_iterator it = _callSiteLocations.begin(); it != _callSiteLocations.end(); ++it, ++r) {
961 r->set_r_address(it->loc);
962 r->set_r_symbolnum(it->symbolIndex);
963 r->set_r_pcrel(true);
964 r->set_r_length(2);
965 r->set_r_extern(true);
966 r->set_r_type(this->callReloc());
967 }
968}
969
970
971template <typename A>
972class SectionRelocationsAtom : public RelocationsAtomAbstract
973{
974public:
975 SectionRelocationsAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
976 : RelocationsAtomAbstract(opts, state, writer, _s_section, sizeof(pint_t)) { }
977
978 // overrides of ld::Atom
979 virtual const char* name() const { return "section relocations"; }
980 virtual uint64_t size() const;
981 virtual void copyRawContent(uint8_t buffer[]) const;
982 // overrides of ClassicLinkEditAtom
983 virtual void encode();
984 // overrides of RelocationsAtomAbstract
985 virtual void addPointerReloc(uint64_t addr, uint32_t symNum) {}
986 virtual void addTextReloc(uint64_t addr, ld::Fixup::Kind k, uint64_t targetAddr, uint32_t symNum) {}
987 virtual void addExternalPointerReloc(uint64_t addr, const ld::Atom*) {}
988 virtual void addExternalCallSiteReloc(uint64_t addr, const ld::Atom*) {}
989 virtual uint64_t relocBaseAddress(ld::Internal& state) { return 0; }
990 virtual void addSectionReloc(ld::Internal::FinalSection* sect, ld::Fixup::Kind,
991 const ld::Atom* inAtom, uint32_t offsetInAtom,
992 bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
993 const ld::Atom* toTarget, uint64_t toAddend,
994 const ld::Atom* fromTarget, uint64_t fromAddend);
995
996private:
997 typedef typename A::P P;
998 typedef typename A::P::E E;
999 typedef typename A::P::uint_t pint_t;
1000
1001
1002 struct Entry {
1003 ld::Fixup::Kind kind;
1004 bool toTargetUsesExternalReloc;
1005 bool fromTargetUsesExternalReloc;
1006 const ld::Atom* inAtom;
1007 uint32_t offsetInAtom;
1008 const ld::Atom* toTarget;
1009 uint64_t toAddend;
1010 const ld::Atom* fromTarget;
1011 uint64_t fromAddend;
1012 };
1013 uint32_t sectSymNum(bool external, const ld::Atom* target);
1014 void encodeSectionReloc(ld::Internal::FinalSection* sect,
1015 const Entry& entry, std::vector<macho_relocation_info<P> >& relocs);
1016
1017 struct SectionAndEntries {
1018 ld::Internal::FinalSection* sect;
1019 std::vector<Entry> entries;
1020 std::vector<macho_relocation_info<P> > relocs;
1021 };
1022
1023 std::vector<SectionAndEntries> _entriesBySection;
1024
1025 static ld::Section _s_section;
1026};
1027
1028template <typename A>
1029ld::Section SectionRelocationsAtom<A>::_s_section("__LINKEDIT", "__sect_relocs", ld::Section::typeLinkEdit, true);
1030
1031
1032
1033
1034template <typename A>
1035uint64_t SectionRelocationsAtom<A>::size() const
1036{
1037 uint32_t count = 0;
1038 for(typename std::vector<SectionAndEntries>::const_iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
1039 const SectionAndEntries& se = *it;
1040 count += se.relocs.size();
1041 }
1042 return count * sizeof(macho_relocation_info<P>);
1043}
1044
1045template <typename A>
1046void SectionRelocationsAtom<A>::copyRawContent(uint8_t buffer[]) const
1047{
1048 uint32_t offset = 0;
1049 for(typename std::vector<SectionAndEntries>::const_iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
1050 const SectionAndEntries& se = *it;
1051 memcpy(&buffer[offset], &se.relocs[0], se.relocs.size()*sizeof(macho_relocation_info<P>));
1052 offset += (se.relocs.size() * sizeof(macho_relocation_info<P>));
1053 }
1054}
1055
1056
1057template <>
1058void SectionRelocationsAtom<x86_64>::encodeSectionReloc(ld::Internal::FinalSection* sect,
1059 const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
1060{
1061 macho_relocation_info<P> reloc1;
1062 macho_relocation_info<P> reloc2;
1063 uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
1064 bool external = entry.toTargetUsesExternalReloc;
1065 uint32_t symbolNum = sectSymNum(external, entry.toTarget);
1066 bool fromExternal = false;
1067 uint32_t fromSymbolNum = 0;
1068 if ( entry.fromTarget != NULL ) {
1069 fromExternal = entry.fromTargetUsesExternalReloc;
1070 fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget);
1071 }
1072
1073
1074 switch ( entry.kind ) {
1075 case ld::Fixup::kindStoreX86BranchPCRel32:
1076 case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
1077 case ld::Fixup::kindStoreX86DtraceCallSiteNop:
1078 case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
1079 reloc1.set_r_address(address);
1080 reloc1.set_r_symbolnum(symbolNum);
1081 reloc1.set_r_pcrel(true);
1082 reloc1.set_r_length(2);
1083 reloc1.set_r_extern(external);
1084 reloc1.set_r_type(X86_64_RELOC_BRANCH);
1085 relocs.push_back(reloc1);
1086 break;
1087
1088 case ld::Fixup::kindStoreX86BranchPCRel8:
1089 reloc1.set_r_address(address);
1090 reloc1.set_r_symbolnum(symbolNum);
1091 reloc1.set_r_pcrel(true);
1092 reloc1.set_r_length(0);
1093 reloc1.set_r_extern(external);
1094 reloc1.set_r_type(X86_64_RELOC_BRANCH);
1095 relocs.push_back(reloc1);
1096 break;
1097
1098 case ld::Fixup::kindStoreX86PCRel32:
1099 case ld::Fixup::kindStoreTargetAddressX86PCRel32:
1100 reloc1.set_r_address(address);
1101 reloc1.set_r_symbolnum(symbolNum);
1102 reloc1.set_r_pcrel(true);
1103 reloc1.set_r_length(2);
1104 reloc1.set_r_extern(external);
1105 reloc1.set_r_type(X86_64_RELOC_SIGNED);
1106 relocs.push_back(reloc1);
1107 break;
1108
1109 case ld::Fixup::kindStoreX86PCRel32_1:
1110 reloc1.set_r_address(address);
1111 reloc1.set_r_symbolnum(symbolNum);
1112 reloc1.set_r_pcrel(true);
1113 reloc1.set_r_length(2);
1114 reloc1.set_r_extern(external);
1115 reloc1.set_r_type(X86_64_RELOC_SIGNED_1);
1116 relocs.push_back(reloc1);
1117 break;
1118
1119 case ld::Fixup::kindStoreX86PCRel32_2:
1120 reloc1.set_r_address(address);
1121 reloc1.set_r_symbolnum(symbolNum);
1122 reloc1.set_r_pcrel(true);
1123 reloc1.set_r_length(2);
1124 reloc1.set_r_extern(external);
1125 reloc1.set_r_type(X86_64_RELOC_SIGNED_2);
1126 relocs.push_back(reloc1);
1127 break;
1128
1129 case ld::Fixup::kindStoreX86PCRel32_4:
1130 reloc1.set_r_address(address);
1131 reloc1.set_r_symbolnum(symbolNum);
1132 reloc1.set_r_pcrel(true);
1133 reloc1.set_r_length(2);
1134 reloc1.set_r_extern(external);
1135 reloc1.set_r_type(X86_64_RELOC_SIGNED_4);
1136 relocs.push_back(reloc1);
1137 break;
1138
1139 case ld::Fixup::kindStoreX86PCRel32GOTLoad:
1140 case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
1141 reloc1.set_r_address(address);
1142 reloc1.set_r_symbolnum(symbolNum);
1143 reloc1.set_r_pcrel(true);
1144 reloc1.set_r_length(2);
1145 reloc1.set_r_extern(external);
1146 reloc1.set_r_type(X86_64_RELOC_GOT_LOAD);
1147 relocs.push_back(reloc1);
1148 break;
1149
1150 case ld::Fixup::kindStoreX86PCRel32GOT:
1151 reloc1.set_r_address(address);
1152 reloc1.set_r_symbolnum(symbolNum);
1153 reloc1.set_r_pcrel(true);
1154 reloc1.set_r_length(2);
1155 reloc1.set_r_extern(external);
1156 reloc1.set_r_type(X86_64_RELOC_GOT);
1157 relocs.push_back(reloc1);
1158 break;
1159
1160 case ld::Fixup::kindStoreLittleEndian64:
1161 case ld::Fixup::kindStoreTargetAddressLittleEndian64:
1162 if ( entry.fromTarget != NULL ) {
1163 // this is a pointer-diff
1164 reloc1.set_r_address(address);
1165 reloc1.set_r_symbolnum(symbolNum);
1166 reloc1.set_r_pcrel(false);
1167 reloc1.set_r_length(3);
1168 reloc1.set_r_extern(external);
1169 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
1170 reloc2.set_r_address(address);
1171 reloc2.set_r_symbolnum(fromSymbolNum);
1172 reloc2.set_r_pcrel(false);
1173 reloc2.set_r_length(3);
1174 reloc2.set_r_extern(fromExternal);
1175 reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
1176 relocs.push_back(reloc2);
1177 relocs.push_back(reloc1);
1178 }
1179 else {
1180 // regular pointer
1181 reloc1.set_r_address(address);
1182 reloc1.set_r_symbolnum(symbolNum);
1183 reloc1.set_r_pcrel(false);
1184 reloc1.set_r_length(3);
1185 reloc1.set_r_extern(external);
1186 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
1187 relocs.push_back(reloc1);
1188 }
1189 break;
1190
1191 case ld::Fixup::kindStoreLittleEndian32:
1192 case ld::Fixup::kindStoreTargetAddressLittleEndian32:
1193 if ( entry.fromTarget != NULL ) {
1194 // this is a pointer-diff
1195 reloc1.set_r_address(address);
1196 reloc1.set_r_symbolnum(symbolNum);
1197 reloc1.set_r_pcrel(false);
1198 reloc1.set_r_length(2);
1199 reloc1.set_r_extern(external);
1200 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
1201 reloc2.set_r_address(address);
1202 reloc2.set_r_symbolnum(fromSymbolNum);
1203 reloc2.set_r_pcrel(false);
1204 reloc2.set_r_length(2);
1205 reloc2.set_r_extern(fromExternal);
1206 reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
1207 relocs.push_back(reloc2);
1208 relocs.push_back(reloc1);
1209 }
1210 else {
1211 // regular pointer
1212 reloc1.set_r_address(address);
1213 reloc1.set_r_symbolnum(symbolNum);
1214 reloc1.set_r_pcrel(false);
1215 reloc1.set_r_length(2);
1216 reloc1.set_r_extern(external);
1217 reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
1218 relocs.push_back(reloc1);
1219 }
1220 break;
1221 default:
1222 assert(0 && "need to handle -r reloc");
1223
1224 }
1225
1226}
1227
1228
1229
1230template <typename A>
1231uint32_t SectionRelocationsAtom<A>::sectSymNum(bool external, const ld::Atom* target)
1232{
1233 if ( target->definition() == ld::Atom::definitionAbsolute )
1234 return R_ABS;
1235 if ( external )
1236 return this->symbolIndex(target); // in external relocations, r_symbolnum field is symbol index
1237 else
1238 return target->machoSection(); // in non-extern relocations, r_symbolnum is mach-o section index of target
1239}
1240
1241template <>
1242void SectionRelocationsAtom<x86>::encodeSectionReloc(ld::Internal::FinalSection* sect,
1243 const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
1244{
1245 macho_relocation_info<P> reloc1;
1246 macho_relocation_info<P> reloc2;
1247 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
1248 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
1249 uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
1250 bool external = entry.toTargetUsesExternalReloc;
1251 uint32_t symbolNum = sectSymNum(external, entry.toTarget);
1252 bool fromExternal = false;
1253 uint32_t fromSymbolNum = 0;
1254 if ( entry.fromTarget != NULL ) {
1255 fromExternal = entry.fromTargetUsesExternalReloc;
1256 fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget);
1257 }
1258
1259
1260 switch ( entry.kind ) {
1261 case ld::Fixup::kindStoreX86PCRel32:
1262 case ld::Fixup::kindStoreX86BranchPCRel32:
1263 case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
1264 case ld::Fixup::kindStoreX86DtraceCallSiteNop:
1265 case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
1266 if ( !external && (entry.toAddend != 0) ) {
1267 // use scattered reloc is target offset is non-zero
1268 sreloc1->set_r_scattered(true);
1269 sreloc1->set_r_pcrel(true);
1270 sreloc1->set_r_length(2);
1271 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
1272 sreloc1->set_r_address(address);
1273 sreloc1->set_r_value(entry.toTarget->finalAddress());
1274 }
1275 else {
1276 reloc1.set_r_address(address);
1277 reloc1.set_r_symbolnum(symbolNum);
1278 reloc1.set_r_pcrel(true);
1279 reloc1.set_r_length(2);
1280 reloc1.set_r_extern(external);
1281 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
1282 }
1283 relocs.push_back(reloc1);
1284 break;
1285
1286 case ld::Fixup::kindStoreX86BranchPCRel8:
1287 if ( !external && (entry.toAddend != 0) ) {
1288 // use scattered reloc is target offset is non-zero
1289 sreloc1->set_r_scattered(true);
1290 sreloc1->set_r_pcrel(true);
1291 sreloc1->set_r_length(0);
1292 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
1293 sreloc1->set_r_address(address);
1294 sreloc1->set_r_value(entry.toTarget->finalAddress());
1295 }
1296 else {
1297 reloc1.set_r_address(address);
1298 reloc1.set_r_symbolnum(symbolNum);
1299 reloc1.set_r_pcrel(true);
1300 reloc1.set_r_length(0);
1301 reloc1.set_r_extern(external);
1302 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
1303 }
1304 relocs.push_back(reloc1);
1305 break;
1306
1307 case ld::Fixup::kindStoreX86PCRel16:
1308 if ( !external && (entry.toAddend != 0) ) {
1309 // use scattered reloc is target offset is non-zero
1310 sreloc1->set_r_scattered(true);
1311 sreloc1->set_r_pcrel(true);
1312 sreloc1->set_r_length(1);
1313 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
1314 sreloc1->set_r_address(address);
1315 sreloc1->set_r_value(entry.toTarget->finalAddress());
1316 }
1317 else {
1318 reloc1.set_r_address(address);
1319 reloc1.set_r_symbolnum(symbolNum);
1320 reloc1.set_r_pcrel(true);
1321 reloc1.set_r_length(1);
1322 reloc1.set_r_extern(external);
1323 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
1324 }
1325 relocs.push_back(reloc1);
1326 break;
1327
1328 case ld::Fixup::kindStoreLittleEndian32:
1329 case ld::Fixup::kindStoreTargetAddressLittleEndian32:
1330 if ( entry.fromTarget != NULL ) {
1331 // this is a pointer-diff
1332 sreloc1->set_r_scattered(true);
1333 sreloc1->set_r_pcrel(false);
1334 sreloc1->set_r_length(2);
1335 if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit )
1336 sreloc1->set_r_type(GENERIC_RELOC_LOCAL_SECTDIFF);
1337 else
1338 sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
1339 sreloc1->set_r_address(address);
afe874b1
A
1340 if ( entry.toTarget == entry.inAtom ) {
1341 if ( entry.toAddend > entry.toTarget->size() )
1342 sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.offsetInAtom);
1343 else
1344 sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
1345 }
a645023d
A
1346 else
1347 sreloc1->set_r_value(entry.toTarget->finalAddress());
1348 sreloc2->set_r_scattered(true);
1349 sreloc2->set_r_pcrel(false);
1350 sreloc2->set_r_length(2);
1351 sreloc2->set_r_type(GENERIC_RELOC_PAIR);
1352 sreloc2->set_r_address(0);
1353 if ( entry.fromTarget == entry.inAtom ) {
1354 if ( entry.fromAddend > entry.fromTarget->size() )
1355 sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.offsetInAtom);
1356 else
1357 sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
1358 }
1359 else
1360 sreloc2->set_r_value(entry.fromTarget->finalAddress());
1361 relocs.push_back(reloc1);
1362 relocs.push_back(reloc2);
1363 }
1364 else {
1365 // regular pointer
1366 if ( !external && (entry.toAddend != 0) ) {
1367 // use scattered reloc is target offset is non-zero
1368 sreloc1->set_r_scattered(true);
1369 sreloc1->set_r_pcrel(false);
1370 sreloc1->set_r_length(2);
1371 sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
1372 sreloc1->set_r_address(address);
1373 sreloc1->set_r_value(entry.toTarget->finalAddress());
1374 }
1375 else {
1376 reloc1.set_r_address(address);
1377 reloc1.set_r_symbolnum(symbolNum);
1378 reloc1.set_r_pcrel(false);
1379 reloc1.set_r_length(2);
1380 reloc1.set_r_extern(external);
1381 reloc1.set_r_type(GENERIC_RELOC_VANILLA);
1382 }
1383 relocs.push_back(reloc1);
1384 }
1385 break;
1386 default:
1387 assert(0 && "need to handle -r reloc");
1388
1389 }
1390}
1391
1392
1393template <>
1394void SectionRelocationsAtom<arm>::encodeSectionReloc(ld::Internal::FinalSection* sect,
1395 const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
1396{
1397 macho_relocation_info<P> reloc1;
1398 macho_relocation_info<P> reloc2;
1399 macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
1400 macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
1401 uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
1402 bool external = entry.toTargetUsesExternalReloc;
1403 uint32_t symbolNum = sectSymNum(external, entry.toTarget);
1404 bool fromExternal = false;
1405 uint32_t fromSymbolNum = 0;
1406 if ( entry.fromTarget != NULL ) {
1407 fromExternal = entry.fromTargetUsesExternalReloc;
1408 fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget);
1409 }
1410
1411
1412 switch ( entry.kind ) {
1413 case ld::Fixup::kindStoreTargetAddressARMBranch24:
1414 case ld::Fixup::kindStoreARMBranch24:
1415 case ld::Fixup::kindStoreARMDtraceCallSiteNop:
1416 case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
1417 if ( !external && (entry.toAddend != 0) ) {
1418 // use scattered reloc is target offset is non-zero
1419 sreloc1->set_r_scattered(true);
1420 sreloc1->set_r_pcrel(true);
1421 sreloc1->set_r_length(2);
1422 sreloc1->set_r_type(ARM_RELOC_BR24);
1423 sreloc1->set_r_address(address);
1424 sreloc1->set_r_value(entry.toTarget->finalAddress());
1425 }
1426 else {
1427 reloc1.set_r_address(address);
1428 reloc1.set_r_symbolnum(symbolNum);
1429 reloc1.set_r_pcrel(true);
1430 reloc1.set_r_length(2);
1431 reloc1.set_r_extern(external);
1432 reloc1.set_r_type(ARM_RELOC_BR24);
1433 }
1434 relocs.push_back(reloc1);
1435 break;
1436
1437 case ld::Fixup::kindStoreTargetAddressThumbBranch22:
1438 case ld::Fixup::kindStoreThumbBranch22:
1439 case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
1440 case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
1441 if ( !external && (entry.toAddend != 0) ) {
1442 // use scattered reloc is target offset is non-zero
1443 sreloc1->set_r_scattered(true);
1444 sreloc1->set_r_pcrel(true);
1445 sreloc1->set_r_length(2);
1446 sreloc1->set_r_type(ARM_THUMB_RELOC_BR22);
1447 sreloc1->set_r_address(address);
1448 sreloc1->set_r_value(entry.toTarget->finalAddress());
1449 }
1450 else {
1451 reloc1.set_r_address(address);
1452 reloc1.set_r_symbolnum(symbolNum);
1453 reloc1.set_r_pcrel(true);
1454 reloc1.set_r_length(2);
1455 reloc1.set_r_extern(external);
1456 reloc1.set_r_type(ARM_THUMB_RELOC_BR22);
1457 }
1458 relocs.push_back(reloc1);
1459 break;
1460
1461 case ld::Fixup::kindStoreLittleEndian32:
1462 case ld::Fixup::kindStoreTargetAddressLittleEndian32:
1463 if ( entry.fromTarget != NULL ) {
1464 // this is a pointer-diff
1465 sreloc1->set_r_scattered(true);
1466 sreloc1->set_r_pcrel(false);
1467 sreloc1->set_r_length(2);
1468 if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit )
1469 sreloc1->set_r_type(ARM_RELOC_LOCAL_SECTDIFF);
1470 else
1471 sreloc1->set_r_type(ARM_RELOC_SECTDIFF);
1472 sreloc1->set_r_address(address);
afe874b1
A
1473 if ( entry.toTarget == entry.inAtom ) {
1474 if ( entry.toAddend > entry.toTarget->size() )
1475 sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.offsetInAtom);
1476 else
1477 sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
1478 }
1479 else {
a645023d 1480 sreloc1->set_r_value(entry.toTarget->finalAddress());
afe874b1 1481 }
a645023d
A
1482 sreloc2->set_r_scattered(true);
1483 sreloc2->set_r_pcrel(false);
1484 sreloc2->set_r_length(2);
1485 sreloc2->set_r_type(ARM_RELOC_PAIR);
1486 sreloc2->set_r_address(0);
1487 if ( entry.fromTarget == entry.inAtom ) {
1488 //unsigned int pcBaseOffset = entry.inAtom->isThumb() ? 4 : 8;
1489 //if ( entry.fromAddend > pcBaseOffset )
1490 // sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend-pcBaseOffset);
1491 //else
1492 sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
1493 }
1494 else {
1495 sreloc2->set_r_value(entry.fromTarget->finalAddress());
1496 }
1497 relocs.push_back(reloc1);
1498 relocs.push_back(reloc2);
1499 }
1500 else {
1501 // regular pointer
1502 if ( !external && (entry.toAddend != 0) ) {
1503 // use scattered reloc is target offset is non-zero
1504 sreloc1->set_r_scattered(true);
1505 sreloc1->set_r_pcrel(false);
1506 sreloc1->set_r_length(2);
1507 sreloc1->set_r_type(ARM_RELOC_VANILLA);
1508 sreloc1->set_r_address(address);
1509 sreloc1->set_r_value(entry.toTarget->finalAddress());
1510 }
1511 else {
1512 reloc1.set_r_address(address);
1513 reloc1.set_r_symbolnum(symbolNum);
1514 reloc1.set_r_pcrel(false);
1515 reloc1.set_r_length(2);
1516 reloc1.set_r_extern(external);
1517 reloc1.set_r_type(ARM_RELOC_VANILLA);
1518 }
1519 relocs.push_back(reloc1);
1520 }
1521 break;
1522
1523 case ld::Fixup::kindStoreARMLow16:
1524 case ld::Fixup::kindStoreARMHigh16:
1525 case ld::Fixup::kindStoreThumbLow16:
1526 case ld::Fixup::kindStoreThumbHigh16:
1527 {
1528 int len = 0;
1529 uint32_t otherHalf = 0;
1530 uint32_t value = entry.toTarget->finalAddress()+entry.toAddend;
1531 if ( entry.fromTarget != NULL )
1532 value -= (entry.fromTarget->finalAddress()+entry.fromAddend);
1533 switch ( entry.kind ) {
1534 case ld::Fixup::kindStoreARMLow16:
1535 len = 0;
1536 otherHalf = value >> 16;
1537 break;
1538 case ld::Fixup::kindStoreARMHigh16:
1539 len = 1;
1540 otherHalf = value & 0xFFFF;
1541 break;
1542 case ld::Fixup::kindStoreThumbLow16:
1543 len = 2;
1544 otherHalf = value >> 16;
1545 break;
1546 case ld::Fixup::kindStoreThumbHigh16:
1547 len = 3;
1548 otherHalf = value & 0xFFFF;
1549 break;
1550 default:
1551 break;
1552 }
1553 if ( entry.fromTarget != NULL ) {
1554 // this is a sect-diff
1555 sreloc1->set_r_scattered(true);
1556 sreloc1->set_r_pcrel(false);
1557 sreloc1->set_r_length(len);
1558 sreloc1->set_r_type(ARM_RELOC_HALF_SECTDIFF);
1559 sreloc1->set_r_address(address);
1560 sreloc1->set_r_value(entry.toTarget->finalAddress());
1561 sreloc2->set_r_scattered(true);
1562 sreloc2->set_r_pcrel(false);
1563 sreloc2->set_r_length(len);
1564 sreloc2->set_r_type(ARM_RELOC_PAIR);
1565 sreloc2->set_r_address(otherHalf);
1566 if ( entry.fromTarget == entry.inAtom )
1567 sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
1568 else
1569 sreloc2->set_r_value(entry.fromTarget->finalAddress());
1570 relocs.push_back(reloc1);
1571 relocs.push_back(reloc2);
1572 }
1573 else {
1574 // this is absolute address
1575 if ( !external && (entry.toAddend != 0) ) {
1576 // use scattered reloc is target offset is non-zero
1577 sreloc1->set_r_scattered(true);
1578 sreloc1->set_r_pcrel(false);
1579 sreloc1->set_r_length(len);
1580 sreloc1->set_r_type(ARM_RELOC_HALF);
1581 sreloc1->set_r_address(address);
1582 sreloc1->set_r_value(entry.toTarget->finalAddress());
1583 reloc2.set_r_address(otherHalf);
1584 reloc2.set_r_symbolnum(0);
1585 reloc2.set_r_pcrel(false);
1586 reloc2.set_r_length(len);
1587 reloc2.set_r_extern(false);
1588 reloc2.set_r_type(ARM_RELOC_PAIR);
1589 relocs.push_back(reloc1);
1590 relocs.push_back(reloc2);
1591 }
1592 else {
1593 reloc1.set_r_address(address);
1594 reloc1.set_r_symbolnum(symbolNum);
1595 reloc1.set_r_pcrel(false);
1596 reloc1.set_r_length(len);
afe874b1 1597 reloc1.set_r_extern(external);
a645023d
A
1598 reloc1.set_r_type(ARM_RELOC_HALF);
1599 reloc2.set_r_address(otherHalf); // other half
1600 reloc2.set_r_symbolnum(0);
1601 reloc2.set_r_pcrel(false);
1602 reloc2.set_r_length(len);
1603 reloc2.set_r_extern(false);
1604 reloc2.set_r_type(ARM_RELOC_PAIR);
1605 relocs.push_back(reloc1);
1606 relocs.push_back(reloc2);
1607 }
1608 }
1609 }
1610 break;
1611
1612 default:
1613 assert(0 && "need to handle -r reloc");
1614
1615 }
1616}
1617
1618
a645023d
A
1619
1620template <typename A>
1621void SectionRelocationsAtom<A>::addSectionReloc(ld::Internal::FinalSection* sect, ld::Fixup::Kind kind,
1622 const ld::Atom* inAtom, uint32_t offsetInAtom,
1623 bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
1624 const ld::Atom* toTarget, uint64_t toAddend,
1625 const ld::Atom* fromTarget, uint64_t fromAddend)
1626{
1627 Entry entry;
1628 entry.kind = kind;
1629 entry.toTargetUsesExternalReloc = toTargetUsesExternalReloc;
1630 entry.fromTargetUsesExternalReloc = fromTargetExternalReloc;
1631 entry.inAtom = inAtom;
1632 entry.offsetInAtom = offsetInAtom;
1633 entry.toTarget = toTarget;
1634 entry.toAddend = toAddend;
1635 entry.fromTarget = fromTarget;
1636 entry.fromAddend = fromAddend;
1637
1638 static ld::Internal::FinalSection* lastSection = NULL;
1639 static SectionAndEntries* lastSectionAndEntries = NULL;
1640
1641 if ( sect != lastSection ) {
1642 for(typename std::vector<SectionAndEntries>::iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
1643 if ( sect == it->sect ) {
1644 lastSection = sect;
1645 lastSectionAndEntries = &*it;
1646 break;
1647 }
1648 }
1649 if ( sect != lastSection ) {
1650 SectionAndEntries tmp;
1651 tmp.sect = sect;
1652 _entriesBySection.push_back(tmp);
1653 lastSection = sect;
1654 lastSectionAndEntries = &_entriesBySection.back();
1655 }
1656 }
1657 lastSectionAndEntries->entries.push_back(entry);
1658}
1659
1660template <typename A>
1661void SectionRelocationsAtom<A>::encode()
1662{
1663 // convert each Entry record to one or two reloc records
1664 for(typename std::vector<SectionAndEntries>::iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
1665 SectionAndEntries& se = *it;
1666 for(typename std::vector<Entry>::iterator eit=se.entries.begin(); eit != se.entries.end(); ++eit) {
1667 encodeSectionReloc(se.sect, *eit, se.relocs);
1668 }
1669 }
1670
1671 // update sections with start and count or relocs
1672 uint32_t index = 0;
1673 for(typename std::vector<SectionAndEntries>::iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
1674 SectionAndEntries& se = *it;
1675 se.sect->relocStart = index;
1676 se.sect->relocCount = se.relocs.size();
1677 index += se.sect->relocCount;
1678 }
1679
1680}
1681
1682
1683
1684template <typename A>
1685class IndirectSymbolTableAtom : public ClassicLinkEditAtom
1686{
1687public:
1688 IndirectSymbolTableAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
1689 : ClassicLinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
1690
1691 // overrides of ld::Atom
1692 virtual const char* name() const { return "indirect symbol table"; }
1693 virtual uint64_t size() const;
1694 virtual void copyRawContent(uint8_t buffer[]) const;
1695 // overrides of ClassicLinkEditAtom
1696 virtual void encode();
1697
1698private:
1699 typedef typename A::P P;
1700 typedef typename A::P::E E;
1701 typedef typename A::P::uint_t pint_t;
1702
1703 void encodeStubSection(ld::Internal::FinalSection* sect);
1704 void encodeLazyPointerSection(ld::Internal::FinalSection* sect);
1705 void encodeNonLazyPointerSection(ld::Internal::FinalSection* sect);
1706 uint32_t symIndexOfStubAtom(const ld::Atom*);
1707 uint32_t symIndexOfLazyPointerAtom(const ld::Atom*);
1708 uint32_t symIndexOfNonLazyPointerAtom(const ld::Atom*);
1709 uint32_t symbolIndex(const ld::Atom*);
1710 bool kextBundlesDontHaveIndirectSymbolTable();
1711
1712
1713 std::vector<uint32_t> _entries;
1714
1715 static ld::Section _s_section;
1716};
1717
1718template <typename A>
1719ld::Section IndirectSymbolTableAtom<A>::_s_section("__LINKEDIT", "__ind_sym_tab", ld::Section::typeLinkEdit, true);
1720
1721
1722
1723
1724template <typename A>
1725uint32_t IndirectSymbolTableAtom<A>::symbolIndex(const ld::Atom* atom)
1726{
1727 std::map<const ld::Atom*, uint32_t>::iterator pos = this->_writer._atomToSymbolIndex.find(atom);
1728 if ( pos != this->_writer._atomToSymbolIndex.end() )
1729 return pos->second;
1730 //fprintf(stderr, "_atomToSymbolIndex content:\n");
1731 //for(std::map<const ld::Atom*, uint32_t>::iterator it = this->_writer._atomToSymbolIndex.begin(); it != this->_writer._atomToSymbolIndex.end(); ++it) {
1732 // fprintf(stderr, "%p(%s) => %d\n", it->first, it->first->name(), it->second);
1733 //}
1734 throwf("internal error: atom not found in symbolIndex(%s)", atom->name());
1735}
1736
1737template <typename A>
1738uint32_t IndirectSymbolTableAtom<A>::symIndexOfStubAtom(const ld::Atom* stubAtom)
1739{
1740 for (ld::Fixup::iterator fit = stubAtom->fixupsBegin(); fit != stubAtom->fixupsEnd(); ++fit) {
1741 if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
1742 assert((fit->u.target->contentType() == ld::Atom::typeLazyPointer)
1743 || (fit->u.target->contentType() == ld::Atom::typeLazyDylibPointer));
1744 return symIndexOfLazyPointerAtom(fit->u.target);
1745 }
1746 }
1747 throw "internal error: stub missing fixup to lazy pointer";
1748}
1749
1750
1751template <typename A>
1752uint32_t IndirectSymbolTableAtom<A>::symIndexOfLazyPointerAtom(const ld::Atom* lpAtom)
1753{
1754 for (ld::Fixup::iterator fit = lpAtom->fixupsBegin(); fit != lpAtom->fixupsEnd(); ++fit) {
1755 if ( fit->kind == ld::Fixup::kindLazyTarget ) {
1756 assert(fit->binding == ld::Fixup::bindingDirectlyBound);
1757 return symbolIndex(fit->u.target);
1758 }
1759 }
1760 throw "internal error: lazy pointer missing fixupLazyTarget fixup";
1761}
1762
1763template <typename A>
1764uint32_t IndirectSymbolTableAtom<A>::symIndexOfNonLazyPointerAtom(const ld::Atom* nlpAtom)
1765{
1766 //fprintf(stderr, "symIndexOfNonLazyPointerAtom(%p) %s\n", nlpAtom, nlpAtom->name());
1767 for (ld::Fixup::iterator fit = nlpAtom->fixupsBegin(); fit != nlpAtom->fixupsEnd(); ++fit) {
1768 // non-lazy-pointer to a stripped symbol => no symbol index
1769 if ( fit->clusterSize != ld::Fixup::k1of1 )
1770 return INDIRECT_SYMBOL_LOCAL;
1771 const ld::Atom* target;
1772 switch ( fit->binding ) {
1773 case ld::Fixup::bindingDirectlyBound:
1774 target = fit->u.target;
1775 break;
1776 case ld::Fixup::bindingsIndirectlyBound:
1777 target = _state.indirectBindingTable[fit->u.bindingIndex];
1778 break;
1779 default:
1780 throw "internal error: unexpected non-lazy pointer binding";
1781 }
a645023d
A
1782 bool targetIsGlobal = (target->scope() == ld::Atom::scopeGlobal);
1783 switch ( target->definition() ) {
1784 case ld::Atom::definitionRegular:
1785 if ( targetIsGlobal ) {
1786 if ( _options.outputKind() == Options::kObjectFile ) {
1787 // nlpointer to global symbol uses indirect symbol table in .o files
1788 return symbolIndex(target);
1789 }
1790 else if ( target->combine() == ld::Atom::combineByName ) {
1791 // dyld needs to bind nlpointer to global weak def
1792 return symbolIndex(target);
1793 }
1794 else if ( _options.nameSpace() != Options::kTwoLevelNameSpace ) {
1795 // dyld needs to bind nlpointer to global def linked for flat namespace
1796 return symbolIndex(target);
1797 }
1798 }
1799 break;
1800 case ld::Atom::definitionTentative:
1801 case ld::Atom::definitionAbsolute:
1802 if ( _options.outputKind() == Options::kObjectFile ) {
1803 // tentative def in .o file always uses symbol index
1804 return symbolIndex(target);
1805 }
1806 // dyld needs to bind nlpointer to global def linked for flat namespace
1807 if ( targetIsGlobal && _options.nameSpace() != Options::kTwoLevelNameSpace )
1808 return symbolIndex(target);
1809 break;
1810 case ld::Atom::definitionProxy:
1811 // dyld needs to bind nlpointer to something in another dylib
1812 {
1813 const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
1814 if ( (dylib != NULL) && dylib->willBeLazyLoadedDylib() )
1815 throwf("illegal data reference to %s in lazy loaded dylib %s", target->name(), dylib->path());
1816 }
1817 return symbolIndex(target);
1818 }
1819 }
1820 if ( nlpAtom->fixupsBegin() == nlpAtom->fixupsEnd() ) {
1821 // no fixups means this is the ImageLoader cache slot
1822 return INDIRECT_SYMBOL_ABS;
1823 }
1824
1825 // The magic index INDIRECT_SYMBOL_LOCAL tells dyld it should does not need to bind
1826 // this non-lazy pointer.
1827 return INDIRECT_SYMBOL_LOCAL;
1828}
1829
1830
1831
1832template <typename A>
1833void IndirectSymbolTableAtom<A>::encodeStubSection(ld::Internal::FinalSection* sect)
1834{
1835 sect->indirectSymTabStartIndex = _entries.size();
1836 sect->indirectSymTabElementSize = sect->atoms[0]->size();
1837 for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
1838 _entries.push_back(symIndexOfStubAtom(*ait));
1839 }
1840}
1841
1842template <typename A>
1843void IndirectSymbolTableAtom<A>::encodeLazyPointerSection(ld::Internal::FinalSection* sect)
1844{
1845 sect->indirectSymTabStartIndex = _entries.size();
1846 for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
1847 _entries.push_back(symIndexOfLazyPointerAtom(*ait));
1848 }
1849}
1850
1851template <typename A>
1852void IndirectSymbolTableAtom<A>::encodeNonLazyPointerSection(ld::Internal::FinalSection* sect)
1853{
1854 sect->indirectSymTabStartIndex = _entries.size();
1855 for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
1856 _entries.push_back(symIndexOfNonLazyPointerAtom(*ait));
1857 }
1858}
1859
1860template <typename A>
1861bool IndirectSymbolTableAtom<A>::kextBundlesDontHaveIndirectSymbolTable()
1862{
1863 return true;
1864}
1865
1866template <typename A>
1867void IndirectSymbolTableAtom<A>::encode()
1868{
1869 // static executables should not have an indirect symbol table
1870 if ( this->_options.outputKind() == Options::kStaticExecutable )
1871 return;
1872
1873 // x86_64 kext bundles should not have an indirect symbol table
1874 if ( (this->_options.outputKind() == Options::kKextBundle) && kextBundlesDontHaveIndirectSymbolTable() )
1875 return;
1876
1877 // find all special sections that need a range of the indirect symbol table section
1878 for (std::vector<ld::Internal::FinalSection*>::iterator sit = this->_state.sections.begin(); sit != this->_state.sections.end(); ++sit) {
1879 ld::Internal::FinalSection* sect = *sit;
1880 switch ( sect->type() ) {
1881 case ld::Section::typeStub:
1882 case ld::Section::typeStubClose:
1883 this->encodeStubSection(sect);
1884 break;
1885 case ld::Section::typeLazyPointerClose:
1886 case ld::Section::typeLazyPointer:
1887 case ld::Section::typeLazyDylibPointer:
1888 this->encodeLazyPointerSection(sect);
1889 break;
1890 case ld::Section::typeNonLazyPointer:
1891 this->encodeNonLazyPointerSection(sect);
1892 break;
1893 default:
1894 break;
1895 }
1896 }
1897}
1898
1899template <typename A>
1900uint64_t IndirectSymbolTableAtom<A>::size() const
1901{
1902 return _entries.size() * sizeof(uint32_t);
1903}
1904
1905template <typename A>
1906void IndirectSymbolTableAtom<A>::copyRawContent(uint8_t buffer[]) const
1907{
1908 uint32_t* array = (uint32_t*)buffer;
1909 for(unsigned long i=0; i < _entries.size(); ++i) {
1910 E::set32(array[i], _entries[i]);
1911 }
1912}
1913
1914
1915
1916
1917
1918
1919
1920
1921} // namespace tool
1922} // namespace ld
1923
1924#endif // __LINKEDIT_CLASSIC_HPP__