blob: 8ec46581cc9518ef41a924bfd8738e1daf209b23 [file] [log] [blame]
Nick Kledzike34182f2013-11-06 21:36:55 +00001//===- lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp ------------===//
2//
3// The LLVM Linker
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10///
11/// \file Converts from in-memory Atoms to in-memory normalized mach-o.
12///
13/// +------------+
14/// | normalized |
15/// +------------+
16/// ^
17/// |
18/// |
19/// +-------+
20/// | Atoms |
21/// +-------+
22
23#include "MachONormalizedFile.h"
24#include "ReferenceKinds.h"
25
26#include "lld/Core/Error.h"
27#include "lld/Core/LLVM.h"
28
29#include "llvm/ADT/StringRef.h"
30#include "llvm/ADT/StringSwitch.h"
31#include "llvm/Support/Casting.h"
32#include "llvm/Support/Debug.h"
33#include "llvm/Support/ErrorHandling.h"
34#include "llvm/Support/Format.h"
35#include "llvm/Support/MachO.h"
36#include "llvm/Support/system_error.h"
37
38#include <map>
39
40using llvm::StringRef;
41using llvm::dyn_cast;
42using llvm::isa;
43using namespace llvm::MachO;
44using namespace lld::mach_o::normalized;
45using namespace lld;
46
47namespace {
48
49struct AtomInfo {
50 const DefinedAtom *atom;
51 uint64_t offsetInSection;
52};
53
54struct SectionInfo {
55 SectionInfo(StringRef seg, StringRef sect, SectionType type, uint32_t attr=0);
56
57 StringRef segmentName;
58 StringRef sectionName;
59 SectionType type;
60 uint32_t attributes;
61 uint64_t address;
62 uint64_t size;
63 uint32_t alignment;
64 std::vector<AtomInfo> atomsAndOffsets;
65 uint32_t normalizedSectionIndex;
66 uint32_t finalSectionIndex;
67};
68
69SectionInfo::SectionInfo(StringRef sg, StringRef sct, SectionType t, uint32_t a)
70 : segmentName(sg), sectionName(sct), type(t), attributes(a),
71 address(0), size(0), alignment(0),
72 normalizedSectionIndex(0), finalSectionIndex(0) {
73}
74
75struct SegmentInfo {
76 SegmentInfo(StringRef name);
77
78 StringRef name;
79 uint64_t address;
80 uint64_t size;
81 uint32_t access;
82 std::vector<SectionInfo*> sections;
83};
84
85SegmentInfo::SegmentInfo(StringRef n)
86 : name(n), address(0), size(0), access(0) {
87}
88
89
90class Util {
91public:
92 Util(const MachOLinkingContext &ctxt) : _context(ctxt), _entryAtom(nullptr) {}
93
94 void assignAtomsToSections(const lld::File &atomFile);
95 void organizeSections();
96 void assignAddressesToSections();
97 uint32_t fileFlags();
98 void copySegmentInfo(NormalizedFile &file);
99 void copySections(NormalizedFile &file);
100 void buildAtomToAddressMap();
101 void addSymbols(const lld::File &atomFile, NormalizedFile &file);
102 void addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file);
103 void addRebaseAndBindingInfo(const lld::File &, NormalizedFile &file);
104 void addSectionRelocs(const lld::File &, NormalizedFile &file);
105 void addDependentDylibs(const lld::File &, NormalizedFile &file);
106 void copyEntryPointAddress(NormalizedFile &file);
107
108private:
109 typedef std::map<DefinedAtom::ContentType, SectionInfo*> TypeToSection;
110 typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
111
112 struct DylibInfo { int ordinal; bool hasWeak; bool hasNonWeak; };
113 typedef llvm::StringMap<DylibInfo> DylibPathToInfo;
114
115 SectionInfo *sectionForAtom(const DefinedAtom*);
116 SectionInfo *makeSection(DefinedAtom::ContentType);
117 void appendAtom(SectionInfo *sect, const DefinedAtom *atom);
118 SegmentInfo *segmentForName(StringRef segName);
119 void layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr);
120 void layoutSectionsInTextSegment(SegmentInfo *seg, uint64_t &addr);
121 void copySectionContent(SectionInfo *si, ContentBytes &content);
122 uint8_t scopeBits(const DefinedAtom* atom);
123 int dylibOrdinal(const SharedLibraryAtom *sa);
124 void segIndexForSection(const SectionInfo *sect,
125 uint8_t &segmentIndex, uint64_t &segmentStartAddr);
126 const Atom *targetOfLazyPointer(const DefinedAtom *lpAtom);
127 const Atom *targetOfStub(const DefinedAtom *stubAtom);
128 bool belongsInGlobalSymbolsSection(const DefinedAtom* atom);
129 void appendSection(SectionInfo *si, NormalizedFile &file);
130 void appendReloc(const DefinedAtom *atom, const Reference *ref,
131 Relocations &relocations);
132
133 static uint64_t alignTo(uint64_t value, uint8_t align2);
134 typedef llvm::DenseMap<const Atom*, uint32_t> AtomToIndex;
135 struct AtomAndIndex { const Atom *atom; uint32_t index; };
136 struct AtomSorter {
137 bool operator()(const AtomAndIndex &left, const AtomAndIndex &right);
138 };
139 struct SegmentSorter {
140 bool operator()(const SegmentInfo *left, const SegmentInfo *right);
141 static unsigned weight(const SegmentInfo *);
142 };
143 struct TextSectionSorter {
144 bool operator()(const SectionInfo *left, const SectionInfo *right);
145 static unsigned weight(const SectionInfo *);
146 };
147
148 const MachOLinkingContext &_context;
149 llvm::BumpPtrAllocator _allocator;
150 std::vector<SectionInfo*> _sectionInfos;
151 std::vector<SegmentInfo*> _segmentInfos;
152 TypeToSection _sectionMap;
153 AtomToAddress _atomToAddress;
154 DylibPathToInfo _dylibInfo;
155 const DefinedAtom *_entryAtom;
156 AtomToIndex _atomToSymbolIndex;
157};
158
159SectionInfo *Util::makeSection(DefinedAtom::ContentType type) {
160 switch ( type ) {
161 case DefinedAtom::typeCode:
162 return new (_allocator) SectionInfo("__TEXT", "__text",
163 S_REGULAR, S_ATTR_PURE_INSTRUCTIONS
164 | S_ATTR_SOME_INSTRUCTIONS);
165 case DefinedAtom::typeCString:
166 return new (_allocator) SectionInfo("__TEXT", "__cstring",
167 S_CSTRING_LITERALS);
168 case DefinedAtom::typeStub:
169 return new (_allocator) SectionInfo("__TEXT", "__stubs",
170 S_SYMBOL_STUBS, S_ATTR_PURE_INSTRUCTIONS);
171 case DefinedAtom::typeStubHelper:
172 return new (_allocator) SectionInfo("__TEXT", "__stub_helper",
173 S_REGULAR, S_ATTR_PURE_INSTRUCTIONS);
174 case DefinedAtom::typeLazyPointer:
175 return new (_allocator) SectionInfo("__DATA", "__la_symbol_ptr",
176 S_LAZY_SYMBOL_POINTERS);
177 case DefinedAtom::typeGOT:
178 return new (_allocator) SectionInfo("__DATA", "__got",
179 S_NON_LAZY_SYMBOL_POINTERS);
180 default:
181 llvm_unreachable("TO DO: add support for more sections");
182 break;
183 }
184}
185
186
187
188SectionInfo *Util::sectionForAtom(const DefinedAtom *atom) {
189 DefinedAtom::ContentType type = atom->contentType();
190 auto pos = _sectionMap.find(type);
191 if ( pos != _sectionMap.end() )
192 return pos->second;
193 SectionInfo *si = makeSection(type);
194 _sectionInfos.push_back(si);
195 _sectionMap[type] = si;
196 return si;
197}
198
199
200void Util::appendAtom(SectionInfo *sect, const DefinedAtom *atom) {
201 // Figure out offset for atom in this section given alignment constraints.
202 uint64_t offset = sect->size;
203 DefinedAtom::Alignment atomAlign = atom->alignment();
204 uint64_t align2 = 1 << atomAlign.powerOf2;
205 uint64_t requiredModulus = atomAlign.modulus;
206 uint64_t currentModulus = (offset % align2);
207 if ( currentModulus != requiredModulus ) {
208 if ( requiredModulus > currentModulus )
209 offset += requiredModulus-currentModulus;
210 else
211 offset += align2+requiredModulus-currentModulus;
212 }
213 // Record max alignment of any atom in this section.
214 if ( atomAlign.powerOf2 > sect->alignment )
215 sect->alignment = atomAlign.powerOf2;
216 // Assign atom to this section with this offset.
217 AtomInfo ai = {atom, offset};
218 sect->atomsAndOffsets.push_back(ai);
219 // Update section size to include this atom.
220 sect->size = offset + atom->size();
221}
222
223void Util::assignAtomsToSections(const lld::File &atomFile) {
224 for (const DefinedAtom *atom : atomFile.defined()) {
225 appendAtom(sectionForAtom(atom), atom);
226 }
227}
228
229SegmentInfo *Util::segmentForName(StringRef segName) {
230 for (SegmentInfo *si : _segmentInfos) {
231 if ( si->name.equals(segName) )
232 return si;
233 }
234 SegmentInfo *info = new (_allocator) SegmentInfo(segName);
235 if (segName.equals("__TEXT"))
236 info->access = VM_PROT_READ | VM_PROT_EXECUTE;
237 else if (segName.equals("__DATA"))
238 info->access = VM_PROT_READ | VM_PROT_WRITE;
239 else if (segName.equals("__PAGEZERO"))
240 info->access = 0;
241 _segmentInfos.push_back(info);
242 return info;
243}
244
245unsigned Util::SegmentSorter::weight(const SegmentInfo *seg) {
246 return llvm::StringSwitch<unsigned>(seg->name)
247 .Case("__PAGEZERO", 1)
248 .Case("__TEXT", 2)
249 .Case("__DATA", 3)
250 .Default(100);
251}
252
253bool Util::SegmentSorter::operator()(const SegmentInfo *left,
254 const SegmentInfo *right) {
255 return (weight(left) < weight(right));
256}
257
258unsigned Util::TextSectionSorter::weight(const SectionInfo *sect) {
259 return llvm::StringSwitch<unsigned>(sect->sectionName)
260 .Case("__text", 1)
261 .Case("__stubs", 2)
262 .Case("__stub_helper", 3)
263 .Case("__const", 4)
264 .Case("__cstring", 5)
265 .Case("__unwind_info", 98)
266 .Case("__eh_frame", 99)
267 .Default(10);
268}
269
270bool Util::TextSectionSorter::operator()(const SectionInfo *left,
271 const SectionInfo *right) {
272 return (weight(left) < weight(right));
273}
274
275
276void Util::organizeSections() {
277 if (_context.outputFileType() == llvm::MachO::MH_OBJECT) {
278 // Leave sections ordered as normalized file specified.
279 uint32_t sectionIndex = 1;
280 for (SectionInfo *si : _sectionInfos) {
281 si->finalSectionIndex = sectionIndex++;
282 }
283 } else {
284 // Main executables, need a zero-page segment
285 if (_context.outputFileType() == llvm::MachO::MH_EXECUTE)
286 segmentForName("__PAGEZERO");
287 // Group sections into segments.
288 for (SectionInfo *si : _sectionInfos) {
289 SegmentInfo *seg = segmentForName(si->segmentName);
290 seg->sections.push_back(si);
291 }
292 // Sort segments.
293 std::sort(_segmentInfos.begin(), _segmentInfos.end(), SegmentSorter());
294
295 // Sort sections within segments.
296 for (SegmentInfo *seg : _segmentInfos) {
297 if (seg->name.equals("__TEXT")) {
298 std::sort(seg->sections.begin(), seg->sections.end(),
299 TextSectionSorter());
300 }
301 }
302
303 // Record final section indexes.
304 uint32_t sectionIndex = 1;
305 for (SegmentInfo *seg : _segmentInfos) {
306 for (SectionInfo *sect : seg->sections) {
307 sect->finalSectionIndex = sectionIndex++;
308 }
309 }
310 }
311
312}
313
314uint64_t Util::alignTo(uint64_t value, uint8_t align2) {
315 return llvm::RoundUpToAlignment(value, 1 << align2);
316}
317
318
319void Util::layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr) {
320 seg->address = addr;
321 for (SectionInfo *sect : seg->sections) {
322 sect->address = alignTo(addr, sect->alignment);
323 addr += sect->size;
324 }
325 seg->size = llvm::RoundUpToAlignment(addr - seg->address,_context.pageSize());
326}
327
328
329// __TEXT segment lays out backwards so padding is at front after load commands.
330void Util::layoutSectionsInTextSegment(SegmentInfo *seg, uint64_t &addr) {
331 seg->address = addr;
332 // Walks sections starting at end to calculate padding for start.
333 int64_t taddr = 0;
334 for (auto it = seg->sections.rbegin(); it != seg->sections.rend(); ++it) {
335 SectionInfo *sect = *it;
336 taddr -= sect->size;
337 taddr = taddr & (0 - (1 << sect->alignment));
338 }
339 int64_t padding = taddr;
340 while (padding < 0)
341 padding += _context.pageSize();
342 // Start assigning section address starting at padded offset.
343 addr += padding;
344 for (SectionInfo *sect : seg->sections) {
345 sect->address = alignTo(addr, sect->alignment);
346 addr = sect->address + sect->size;
347 }
348 seg->size = llvm::RoundUpToAlignment(addr - seg->address,_context.pageSize());
349}
350
351
352void Util::assignAddressesToSections() {
353 uint64_t address = 0; // FIXME
354 if (_context.outputFileType() != llvm::MachO::MH_OBJECT) {
355 for (SegmentInfo *seg : _segmentInfos) {
356 if (seg->name.equals("__PAGEZERO")) {
357 seg->size = _context.pageZeroSize();
358 address += seg->size;
359 }
360 else if (seg->name.equals("__TEXT"))
361 layoutSectionsInTextSegment(seg, address);
362 else
363 layoutSectionsInSegment(seg, address);
364 }
365 DEBUG_WITH_TYPE("WriterMachO-norm",
366 llvm::dbgs() << "assignAddressesToSections()\n");
367 for (SegmentInfo *sgi : _segmentInfos) {
368 DEBUG_WITH_TYPE("WriterMachO-norm", llvm::dbgs()
369 << " address=" << llvm::format("0x%08llX", sgi->address)
370 << ", size=" << llvm::format("0x%08llX", sgi->size)
371 << ", segment-name='" << sgi->name
372 << "'\n");
373 for (SectionInfo *si : sgi->sections) {
374 DEBUG_WITH_TYPE("WriterMachO-norm", llvm::dbgs()
375 << " addr=" << llvm::format("0x%08llX", si->address)
376 << ", size=" << llvm::format("0x%08llX", si->size)
377 << ", section-name='" << si->sectionName
378 << "\n");
379 }
380 }
381 } else {
382 for (SectionInfo *sect : _sectionInfos) {
383 sect->address = alignTo(address, sect->alignment);
384 address = sect->address + sect->size;
385 }
386 DEBUG_WITH_TYPE("WriterMachO-norm",
387 llvm::dbgs() << "assignAddressesToSections()\n");
388 for (SectionInfo *si : _sectionInfos) {
389 DEBUG_WITH_TYPE("WriterMachO-norm", llvm::dbgs()
390 << " section=" << si->sectionName
391 << " address= " << llvm::format("0x%08X", si->address)
392 << " size= " << llvm::format("0x%08X", si->size)
393 << "\n");
394 }
395 }
396
397}
398
399
400void Util::copySegmentInfo(NormalizedFile &file) {
401 for (SegmentInfo *sgi : _segmentInfos) {
402 Segment seg;
403 seg.name = sgi->name;
404 seg.address = sgi->address;
405 seg.size = sgi->size;
406 seg.access = sgi->access;
407 file.segments.push_back(seg);
408 }
409}
410
411void Util::appendSection(SectionInfo *si, NormalizedFile &file) {
412 // Add new empty section to end of file.sections.
413 Section temp;
414 file.sections.push_back(std::move(temp));
415 Section* normSect = &file.sections.back();
416 // Copy fields to normalized section.
417 normSect->segmentName = si->segmentName;
418 normSect->sectionName = si->sectionName;
419 normSect->type = si->type;
420 normSect->attributes = si->attributes;
421 normSect->address = si->address;
422 normSect->alignment = si->alignment;
423 // Record where normalized section is.
424 si->normalizedSectionIndex = file.sections.size()-1;
425 // Copy content from atoms to content buffer for section.
426 // FIXME: zerofill atoms/sections should not take up content space.
427 normSect->content.resize(si->size);
428 Hex8 *sectionContent = normSect->content.data();
429 for (AtomInfo &ai : si->atomsAndOffsets) {
430 // Copy raw bytes.
431 uint8_t *atomContent = reinterpret_cast<uint8_t*>
432 (&sectionContent[ai.offsetInSection]);
433 memcpy(atomContent, ai.atom->rawContent().data(), ai.atom->size());
434 // Apply fix-ups.
435 for (const Reference *ref : *ai.atom) {
436 uint32_t offset = ref->offsetInAtom();
437 uint64_t targetAddress = 0;
438 if ( ref->target() != nullptr )
439 targetAddress = _atomToAddress[ref->target()];
440 uint64_t fixupAddress = _atomToAddress[ai.atom] + offset;
441 _context.kindHandler().applyFixup(ref->kind(), ref->addend(),
442 &atomContent[offset], fixupAddress,
443 targetAddress);
444 }
445 }
446}
447
448void Util::copySections(NormalizedFile &file) {
449 file.sections.reserve(_sectionInfos.size());
450 // For final linked images, write sections grouped by segment.
451 if (_context.outputFileType() != llvm::MachO::MH_OBJECT) {
452 for (SegmentInfo *sgi : _segmentInfos) {
453 for (SectionInfo *si : sgi->sections) {
454 appendSection(si, file);
455 }
456 }
457 } else {
458 // Object files write sections in default order.
459 for (SectionInfo *si : _sectionInfos) {
460 appendSection(si, file);
461 }
462 }
463}
464
465void Util::copyEntryPointAddress(NormalizedFile &nFile) {
466 if (_context.outputTypeHasEntry()) {
467 nFile.entryAddress = _atomToAddress[_entryAtom];
468 }
469}
470
471void Util::buildAtomToAddressMap() {
472 DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
473 << "assign atom addresses:\n");
474 const bool lookForEntry = _context.outputTypeHasEntry();
475 for (SectionInfo *sect : _sectionInfos) {
476 for (const AtomInfo &info : sect->atomsAndOffsets) {
477 _atomToAddress[info.atom] = sect->address + info.offsetInSection;
478 if (lookForEntry && (info.atom->contentType() == DefinedAtom::typeCode) &&
479 (info.atom->size() != 0) &&
480 info.atom->name() == _context.entrySymbolName()) {
481 _entryAtom = info.atom;
482 }
483 DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
484 << " address="
485 << llvm::format("0x%016X", _atomToAddress[info.atom])
486 << " atom=" << info.atom
487 << " name=" << info.atom->name() << "\n");
488 }
489 }
490}
491
492uint8_t Util::scopeBits(const DefinedAtom* atom) {
493 switch (atom->scope()) {
494 case Atom::scopeTranslationUnit:
495 return 0;
496 case Atom::scopeLinkageUnit:
497 return N_PEXT | N_EXT;
498 case Atom::scopeGlobal:
499 return N_EXT;
500 }
501}
502
503bool Util::AtomSorter::operator()(const AtomAndIndex &left,
504 const AtomAndIndex &right) {
505 return (left.atom->name().compare(right.atom->name()) < 0);
506}
507
508
509bool Util::belongsInGlobalSymbolsSection(const DefinedAtom* atom) {
510 return (atom->scope() == Atom::scopeGlobal);
511}
512
513void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) {
514 // Mach-O symbol table has three regions: locals, globals, undefs.
515
516 // Add all local (non-global) symbols in address order
517 std::vector<AtomAndIndex> globals;
518 globals.reserve(512);
519 for (SectionInfo *sect : _sectionInfos) {
520 for (const AtomInfo &info : sect->atomsAndOffsets) {
521 const DefinedAtom *atom = info.atom;
522 if (!atom->name().empty()) {
523 if (belongsInGlobalSymbolsSection(atom)) {
524 AtomAndIndex ai = { atom, sect->finalSectionIndex };
525 globals.push_back(ai);
526 } else {
527 Symbol sym;
528 sym.name = atom->name();
529 sym.type = N_SECT;
530 sym.scope = scopeBits(atom);
531 sym.sect = sect->finalSectionIndex;
532 sym.desc = 0;
533 sym.value = _atomToAddress[atom];
534 file.localSymbols.push_back(sym);
535 }
536 }
537 }
538 }
539
540 // Sort global symbol alphabetically, then add to symbol table.
541 std::sort(globals.begin(), globals.end(), AtomSorter());
542 for (AtomAndIndex &ai : globals) {
543 Symbol sym;
544 sym.name = ai.atom->name();
545 sym.type = N_SECT;
546 sym.scope = scopeBits(static_cast<const DefinedAtom*>(ai.atom));
547 sym.sect = ai.index;
548 sym.desc = 0;
549 sym.value = _atomToAddress[ai.atom];
550 file.globalSymbols.push_back(sym);
551 }
552
553
554 // Sort undefined symbol alphabetically, then add to symbol table.
555 std::vector<AtomAndIndex> undefs;
556 undefs.reserve(128);
557 for (const UndefinedAtom *atom : atomFile.undefined()) {
558 AtomAndIndex ai = { atom, 0 };
559 undefs.push_back(ai);
560 }
561 for (const SharedLibraryAtom *atom : atomFile.sharedLibrary()) {
562 AtomAndIndex ai = { atom, 0 };
563 undefs.push_back(ai);
564 }
565 std::sort(undefs.begin(), undefs.end(), AtomSorter());
566 const uint32_t start = file.globalSymbols.size() + file.localSymbols.size();
567 for (AtomAndIndex &ai : undefs) {
568 Symbol sym;
569 sym.name = ai.atom->name();
570 sym.type = N_UNDF;
571 sym.scope = N_EXT;
572 sym.sect = 0;
573 sym.desc = 0;
574 sym.value = 0;
575 _atomToSymbolIndex[ai.atom] = file.undefinedSymbols.size() + start;
576 file.undefinedSymbols.push_back(sym);
577 }
578}
579
580const Atom *Util::targetOfLazyPointer(const DefinedAtom *lpAtom) {
581 for (const Reference *ref : *lpAtom) {
582 if (_context.kindHandler().isLazyTarget(ref->kind())) {
583 return ref->target();
584 }
585 }
586 return nullptr;
587}
588
589const Atom *Util::targetOfStub(const DefinedAtom *stubAtom) {
590 for (const Reference *ref : *stubAtom) {
591 if (const Atom *ta = ref->target()) {
592 if (const DefinedAtom *lpAtom = dyn_cast<DefinedAtom>(ta)) {
593 const Atom *target = targetOfLazyPointer(lpAtom);
594 if (target)
595 return target;
596 }
597 }
598 }
599 return nullptr;
600}
601
602
603void Util::addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file) {
604 for (SectionInfo *si : _sectionInfos) {
605 Section &normSect = file.sections[si->normalizedSectionIndex];
606 switch (si->type) {
607 case llvm::MachO::S_NON_LAZY_SYMBOL_POINTERS:
608 for (const AtomInfo &info : si->atomsAndOffsets) {
609 bool foundTarget = false;
610 for (const Reference *ref : *info.atom) {
611 const Atom *target = ref->target();
612 if (target) {
613 if (isa<const SharedLibraryAtom>(target)) {
614 uint32_t index = _atomToSymbolIndex[target];
615 normSect.indirectSymbols.push_back(index);
616 foundTarget = true;
617 } else {
618 normSect.indirectSymbols.push_back(
619 llvm::MachO::INDIRECT_SYMBOL_LOCAL);
620 }
621 }
622 }
623 if (!foundTarget) {
624 normSect.indirectSymbols.push_back(
625 llvm::MachO::INDIRECT_SYMBOL_ABS);
626 }
627 }
628 break;
629 case llvm::MachO::S_LAZY_SYMBOL_POINTERS:
630 for (const AtomInfo &info : si->atomsAndOffsets) {
631 const Atom *target = targetOfLazyPointer(info.atom);
632 if (target) {
633 uint32_t index = _atomToSymbolIndex[target];
634 normSect.indirectSymbols.push_back(index);
635 }
636 }
637 break;
638 case llvm::MachO::S_SYMBOL_STUBS:
639 for (const AtomInfo &info : si->atomsAndOffsets) {
640 const Atom *target = targetOfStub(info.atom);
641 if (target) {
642 uint32_t index = _atomToSymbolIndex[target];
643 normSect.indirectSymbols.push_back(index);
644 }
645 }
646 break;
647 default:
648 break;
649 }
650 }
651
652}
653
654void Util::addDependentDylibs(const lld::File &atomFile,NormalizedFile &nFile) {
655 // Scan all imported symbols and build up list of dylibs they are from.
656 int ordinal = 1;
657 for (const SharedLibraryAtom *slAtom : atomFile.sharedLibrary()) {
658 StringRef loadPath = slAtom->loadName();
659 DylibPathToInfo::iterator pos = _dylibInfo.find(loadPath);
660 if (pos == _dylibInfo.end()) {
661 DylibInfo info;
662 info.ordinal = ordinal++;
663 info.hasWeak = slAtom->canBeNullAtRuntime();
664 info.hasNonWeak = !info.hasWeak;
665 _dylibInfo[loadPath] = info;
666 DependentDylib depInfo;
667 depInfo.path = loadPath;
668 depInfo.kind = llvm::MachO::LC_LOAD_DYLIB;
669 nFile.dependentDylibs.push_back(depInfo);
670 } else {
671 if ( slAtom->canBeNullAtRuntime() )
672 pos->second.hasWeak = true;
673 else
674 pos->second.hasNonWeak = true;
675 }
676 }
677 // Automatically weak link dylib in which all symbols are weak (canBeNull).
678 for (DependentDylib &dep : nFile.dependentDylibs) {
679 DylibInfo &info = _dylibInfo[dep.path];
680 if (info.hasWeak && !info.hasNonWeak)
681 dep.kind = llvm::MachO::LC_LOAD_WEAK_DYLIB;
682 }
683}
684
685
686int Util::dylibOrdinal(const SharedLibraryAtom *sa) {
687 return _dylibInfo[sa->loadName()].ordinal;
688}
689
690void Util::segIndexForSection(const SectionInfo *sect, uint8_t &segmentIndex,
691 uint64_t &segmentStartAddr) {
692 segmentIndex = 0;
693 for (const SegmentInfo *seg : _segmentInfos) {
694 if ((seg->address <= sect->address)
695 && (seg->address+seg->size >= sect->address+sect->size)) {
696 segmentStartAddr = seg->address;
697 return;
698 }
699 ++segmentIndex;
700 }
701 llvm_unreachable("section not in any segment");
702}
703
704
705void Util::appendReloc(const DefinedAtom *atom, const Reference *ref,
706 Relocations &relocations) {
707 // TODO: convert Reference to normalized relocation
708}
709
710void Util::addSectionRelocs(const lld::File &, NormalizedFile &file) {
711 if (_context.outputFileType() != llvm::MachO::MH_OBJECT)
712 return;
713
714 for (SectionInfo *si : _sectionInfos) {
715 Section &normSect = file.sections[si->normalizedSectionIndex];
716 for (const AtomInfo &info : si->atomsAndOffsets) {
717 const DefinedAtom *atom = info.atom;
718 for (const Reference *ref : *atom) {
719 appendReloc(atom, ref, normSect.relocations);
720 }
721 }
722 }
723}
724
725void Util::addRebaseAndBindingInfo(const lld::File &atomFile,
726 NormalizedFile &nFile) {
727 if (_context.outputFileType() == llvm::MachO::MH_OBJECT)
728 return;
729
730 uint8_t segmentIndex;
731 uint64_t segmentStartAddr;
732 for (SectionInfo *sect : _sectionInfos) {
733 segIndexForSection(sect, segmentIndex, segmentStartAddr);
734 for (const AtomInfo &info : sect->atomsAndOffsets) {
735 const DefinedAtom *atom = info.atom;
736 for (const Reference *ref : *atom) {
737 uint64_t segmentOffset = _atomToAddress[atom] + ref->offsetInAtom()
738 - segmentStartAddr;
739 const Atom* targ = ref->target();
740 if (_context.kindHandler().isPointer(ref->kind())) {
741 // A pointer to a DefinedAtom requires rebasing.
742 if (dyn_cast<DefinedAtom>(targ)) {
743 RebaseLocation rebase;
744 rebase.segIndex = segmentIndex;
745 rebase.segOffset = segmentOffset;
746 rebase.kind = llvm::MachO::REBASE_TYPE_POINTER;
747 nFile.rebasingInfo.push_back(rebase);
748 }
749 // A pointer to an SharedLibraryAtom requires binding.
750 if (const SharedLibraryAtom *sa = dyn_cast<SharedLibraryAtom>(targ)) {
751 BindLocation bind;
752 bind.segIndex = segmentIndex;
753 bind.segOffset = segmentOffset;
754 bind.kind = llvm::MachO::BIND_TYPE_POINTER;
755 bind.canBeNull = sa->canBeNullAtRuntime();
756 bind.ordinal = dylibOrdinal(sa);
757 bind.symbolName = targ->name();
758 bind.addend = ref->addend();
759 nFile.bindingInfo.push_back(bind);
760 }
761 }
762 if (_context.kindHandler().isLazyTarget(ref->kind())) {
763 BindLocation bind;
764 bind.segIndex = segmentIndex;
765 bind.segOffset = segmentOffset;
766 bind.kind = llvm::MachO::BIND_TYPE_POINTER;
767 bind.canBeNull = false; //sa->canBeNullAtRuntime();
768 bind.ordinal = 1;
769 bind.symbolName = targ->name();
770 bind.addend = ref->addend();
771 nFile.lazyBindingInfo.push_back(bind);
772 }
773 }
774 }
775 }
776}
777
778uint32_t Util::fileFlags() {
779 return 0; //FIX ME
780}
781
782} // end anonymous namespace
783
784
785namespace lld {
786namespace mach_o {
787namespace normalized {
788
789/// Convert a set of Atoms into a normalized mach-o file.
790ErrorOr<std::unique_ptr<NormalizedFile>>
791normalizedFromAtoms(const lld::File &atomFile,
792 const MachOLinkingContext &context) {
793 // The util object buffers info until the normalized file can be made.
794 Util util(context);
795 util.assignAtomsToSections(atomFile);
796 util.organizeSections();
797 util.assignAddressesToSections();
798 util.buildAtomToAddressMap();
799
800 std::unique_ptr<NormalizedFile> f(new NormalizedFile());
801 NormalizedFile &normFile = *f.get();
802 f->arch = context.arch();
803 f->fileType = context.outputFileType();
804 f->flags = util.fileFlags();
805 util.copySegmentInfo(normFile);
806 util.copySections(normFile);
807 util.addDependentDylibs(atomFile, normFile);
808 util.addSymbols(atomFile, normFile);
809 util.addIndirectSymbols(atomFile, normFile);
810 util.addRebaseAndBindingInfo(atomFile, normFile);
811 util.addSectionRelocs(atomFile, normFile);
812 util.copyEntryPointAddress(normFile);
813
814 return std::move(f);
815}
816
817
818} // namespace normalized
819} // namespace mach_o
820} // namespace lld
821