blob: b5b571898ee996aaffc4e71309eda87730693bb4 [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/// |
Shankar Easwaran3d8de472014-01-27 03:09:26 +000019/// +-------+
Nick Kledzike34182f2013-11-06 21:36:55 +000020/// | Atoms |
Shankar Easwaran3d8de472014-01-27 03:09:26 +000021/// +-------+
Nick Kledzike34182f2013-11-06 21:36:55 +000022
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;
Nick Kledzike34182f2013-11-06 21:36:55 +000041using llvm::isa;
42using namespace llvm::MachO;
43using namespace lld::mach_o::normalized;
44using namespace lld;
45
46namespace {
47
48struct AtomInfo {
49 const DefinedAtom *atom;
50 uint64_t offsetInSection;
51};
52
53struct SectionInfo {
54 SectionInfo(StringRef seg, StringRef sect, SectionType type, uint32_t attr=0);
Shankar Easwaran3d8de472014-01-27 03:09:26 +000055
Nick Kledzike34182f2013-11-06 21:36:55 +000056 StringRef segmentName;
57 StringRef sectionName;
58 SectionType type;
59 uint32_t attributes;
60 uint64_t address;
61 uint64_t size;
62 uint32_t alignment;
63 std::vector<AtomInfo> atomsAndOffsets;
64 uint32_t normalizedSectionIndex;
65 uint32_t finalSectionIndex;
66};
67
Shankar Easwaran3d8de472014-01-27 03:09:26 +000068SectionInfo::SectionInfo(StringRef sg, StringRef sct, SectionType t, uint32_t a)
69 : segmentName(sg), sectionName(sct), type(t), attributes(a),
70 address(0), size(0), alignment(0),
Nick Kledzike34182f2013-11-06 21:36:55 +000071 normalizedSectionIndex(0), finalSectionIndex(0) {
72}
73
74struct SegmentInfo {
75 SegmentInfo(StringRef name);
Shankar Easwaran3d8de472014-01-27 03:09:26 +000076
Nick Kledzike34182f2013-11-06 21:36:55 +000077 StringRef name;
78 uint64_t address;
79 uint64_t size;
80 uint32_t access;
81 std::vector<SectionInfo*> sections;
82};
83
Shankar Easwaran3d8de472014-01-27 03:09:26 +000084SegmentInfo::SegmentInfo(StringRef n)
Nick Kledzike34182f2013-11-06 21:36:55 +000085 : name(n), address(0), size(0), access(0) {
86}
87
88
89class Util {
90public:
91 Util(const MachOLinkingContext &ctxt) : _context(ctxt), _entryAtom(nullptr) {}
92
93 void assignAtomsToSections(const lld::File &atomFile);
94 void organizeSections();
95 void assignAddressesToSections();
96 uint32_t fileFlags();
97 void copySegmentInfo(NormalizedFile &file);
98 void copySections(NormalizedFile &file);
99 void buildAtomToAddressMap();
100 void addSymbols(const lld::File &atomFile, NormalizedFile &file);
101 void addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file);
102 void addRebaseAndBindingInfo(const lld::File &, NormalizedFile &file);
103 void addSectionRelocs(const lld::File &, NormalizedFile &file);
104 void addDependentDylibs(const lld::File &, NormalizedFile &file);
105 void copyEntryPointAddress(NormalizedFile &file);
106
107private:
108 typedef std::map<DefinedAtom::ContentType, SectionInfo*> TypeToSection;
109 typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000110
Nick Kledzike34182f2013-11-06 21:36:55 +0000111 struct DylibInfo { int ordinal; bool hasWeak; bool hasNonWeak; };
112 typedef llvm::StringMap<DylibInfo> DylibPathToInfo;
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000113
Nick Kledzike34182f2013-11-06 21:36:55 +0000114 SectionInfo *sectionForAtom(const DefinedAtom*);
115 SectionInfo *makeSection(DefinedAtom::ContentType);
116 void appendAtom(SectionInfo *sect, const DefinedAtom *atom);
117 SegmentInfo *segmentForName(StringRef segName);
118 void layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr);
119 void layoutSectionsInTextSegment(SegmentInfo *seg, uint64_t &addr);
120 void copySectionContent(SectionInfo *si, ContentBytes &content);
121 uint8_t scopeBits(const DefinedAtom* atom);
122 int dylibOrdinal(const SharedLibraryAtom *sa);
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000123 void segIndexForSection(const SectionInfo *sect,
Nick Kledzike34182f2013-11-06 21:36:55 +0000124 uint8_t &segmentIndex, uint64_t &segmentStartAddr);
125 const Atom *targetOfLazyPointer(const DefinedAtom *lpAtom);
126 const Atom *targetOfStub(const DefinedAtom *stubAtom);
127 bool belongsInGlobalSymbolsSection(const DefinedAtom* atom);
128 void appendSection(SectionInfo *si, NormalizedFile &file);
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000129 void appendReloc(const DefinedAtom *atom, const Reference *ref,
Nick Kledzike34182f2013-11-06 21:36:55 +0000130 Relocations &relocations);
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000131
Nick Kledzike34182f2013-11-06 21:36:55 +0000132 static uint64_t alignTo(uint64_t value, uint8_t align2);
133 typedef llvm::DenseMap<const Atom*, uint32_t> AtomToIndex;
134 struct AtomAndIndex { const Atom *atom; uint32_t index; };
Joey Gouly9d263e02013-12-25 19:39:08 +0000135 struct AtomSorter {
136 bool operator()(const AtomAndIndex &left, const AtomAndIndex &right);
Nick Kledzike34182f2013-11-06 21:36:55 +0000137 };
Joey Gouly9d263e02013-12-25 19:39:08 +0000138 struct SegmentSorter {
139 bool operator()(const SegmentInfo *left, const SegmentInfo *right);
Nick Kledzike34182f2013-11-06 21:36:55 +0000140 static unsigned weight(const SegmentInfo *);
141 };
Joey Gouly9d263e02013-12-25 19:39:08 +0000142 struct TextSectionSorter {
143 bool operator()(const SectionInfo *left, const SectionInfo *right);
Nick Kledzike34182f2013-11-06 21:36:55 +0000144 static unsigned weight(const SectionInfo *);
145 };
146
147 const MachOLinkingContext &_context;
148 llvm::BumpPtrAllocator _allocator;
149 std::vector<SectionInfo*> _sectionInfos;
150 std::vector<SegmentInfo*> _segmentInfos;
151 TypeToSection _sectionMap;
152 AtomToAddress _atomToAddress;
153 DylibPathToInfo _dylibInfo;
154 const DefinedAtom *_entryAtom;
155 AtomToIndex _atomToSymbolIndex;
156};
157
158SectionInfo *Util::makeSection(DefinedAtom::ContentType type) {
159 switch ( type ) {
160 case DefinedAtom::typeCode:
161 return new (_allocator) SectionInfo("__TEXT", "__text",
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000162 S_REGULAR, S_ATTR_PURE_INSTRUCTIONS
Nick Kledzike34182f2013-11-06 21:36:55 +0000163 | S_ATTR_SOME_INSTRUCTIONS);
164 case DefinedAtom::typeCString:
165 return new (_allocator) SectionInfo("__TEXT", "__cstring",
166 S_CSTRING_LITERALS);
167 case DefinedAtom::typeStub:
168 return new (_allocator) SectionInfo("__TEXT", "__stubs",
169 S_SYMBOL_STUBS, S_ATTR_PURE_INSTRUCTIONS);
170 case DefinedAtom::typeStubHelper:
171 return new (_allocator) SectionInfo("__TEXT", "__stub_helper",
172 S_REGULAR, S_ATTR_PURE_INSTRUCTIONS);
173 case DefinedAtom::typeLazyPointer:
174 return new (_allocator) SectionInfo("__DATA", "__la_symbol_ptr",
175 S_LAZY_SYMBOL_POINTERS);
176 case DefinedAtom::typeGOT:
177 return new (_allocator) SectionInfo("__DATA", "__got",
178 S_NON_LAZY_SYMBOL_POINTERS);
Nick Kledzik61fdef62014-05-15 20:59:23 +0000179 case DefinedAtom::typeZeroFill:
180 return new (_allocator) SectionInfo("__DATA", "__bss",
181 S_ZEROFILL);
Nick Kledzike34182f2013-11-06 21:36:55 +0000182 default:
183 llvm_unreachable("TO DO: add support for more sections");
184 break;
185 }
186}
187
188
189
190SectionInfo *Util::sectionForAtom(const DefinedAtom *atom) {
191 DefinedAtom::ContentType type = atom->contentType();
192 auto pos = _sectionMap.find(type);
193 if ( pos != _sectionMap.end() )
194 return pos->second;
195 SectionInfo *si = makeSection(type);
196 _sectionInfos.push_back(si);
197 _sectionMap[type] = si;
198 return si;
199}
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000200
Nick Kledzike34182f2013-11-06 21:36:55 +0000201
202void Util::appendAtom(SectionInfo *sect, const DefinedAtom *atom) {
203 // Figure out offset for atom in this section given alignment constraints.
204 uint64_t offset = sect->size;
205 DefinedAtom::Alignment atomAlign = atom->alignment();
206 uint64_t align2 = 1 << atomAlign.powerOf2;
207 uint64_t requiredModulus = atomAlign.modulus;
208 uint64_t currentModulus = (offset % align2);
209 if ( currentModulus != requiredModulus ) {
210 if ( requiredModulus > currentModulus )
211 offset += requiredModulus-currentModulus;
212 else
213 offset += align2+requiredModulus-currentModulus;
214 }
215 // Record max alignment of any atom in this section.
216 if ( atomAlign.powerOf2 > sect->alignment )
217 sect->alignment = atomAlign.powerOf2;
218 // Assign atom to this section with this offset.
219 AtomInfo ai = {atom, offset};
220 sect->atomsAndOffsets.push_back(ai);
221 // Update section size to include this atom.
222 sect->size = offset + atom->size();
223}
224
225void Util::assignAtomsToSections(const lld::File &atomFile) {
226 for (const DefinedAtom *atom : atomFile.defined()) {
227 appendAtom(sectionForAtom(atom), atom);
228 }
229}
230
231SegmentInfo *Util::segmentForName(StringRef segName) {
232 for (SegmentInfo *si : _segmentInfos) {
233 if ( si->name.equals(segName) )
234 return si;
235 }
236 SegmentInfo *info = new (_allocator) SegmentInfo(segName);
237 if (segName.equals("__TEXT"))
238 info->access = VM_PROT_READ | VM_PROT_EXECUTE;
239 else if (segName.equals("__DATA"))
240 info->access = VM_PROT_READ | VM_PROT_WRITE;
241 else if (segName.equals("__PAGEZERO"))
242 info->access = 0;
243 _segmentInfos.push_back(info);
244 return info;
245}
246
247unsigned Util::SegmentSorter::weight(const SegmentInfo *seg) {
248 return llvm::StringSwitch<unsigned>(seg->name)
249 .Case("__PAGEZERO", 1)
250 .Case("__TEXT", 2)
251 .Case("__DATA", 3)
252 .Default(100);
253}
254
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000255bool Util::SegmentSorter::operator()(const SegmentInfo *left,
Nick Kledzike34182f2013-11-06 21:36:55 +0000256 const SegmentInfo *right) {
257 return (weight(left) < weight(right));
258}
259
260unsigned Util::TextSectionSorter::weight(const SectionInfo *sect) {
261 return llvm::StringSwitch<unsigned>(sect->sectionName)
262 .Case("__text", 1)
263 .Case("__stubs", 2)
264 .Case("__stub_helper", 3)
265 .Case("__const", 4)
266 .Case("__cstring", 5)
267 .Case("__unwind_info", 98)
268 .Case("__eh_frame", 99)
269 .Default(10);
270}
271
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000272bool Util::TextSectionSorter::operator()(const SectionInfo *left,
Nick Kledzike34182f2013-11-06 21:36:55 +0000273 const SectionInfo *right) {
274 return (weight(left) < weight(right));
275}
276
277
278void Util::organizeSections() {
279 if (_context.outputFileType() == llvm::MachO::MH_OBJECT) {
280 // Leave sections ordered as normalized file specified.
281 uint32_t sectionIndex = 1;
282 for (SectionInfo *si : _sectionInfos) {
283 si->finalSectionIndex = sectionIndex++;
284 }
285 } else {
286 // Main executables, need a zero-page segment
287 if (_context.outputFileType() == llvm::MachO::MH_EXECUTE)
288 segmentForName("__PAGEZERO");
289 // Group sections into segments.
290 for (SectionInfo *si : _sectionInfos) {
291 SegmentInfo *seg = segmentForName(si->segmentName);
292 seg->sections.push_back(si);
293 }
294 // Sort segments.
295 std::sort(_segmentInfos.begin(), _segmentInfos.end(), SegmentSorter());
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000296
Nick Kledzike34182f2013-11-06 21:36:55 +0000297 // Sort sections within segments.
298 for (SegmentInfo *seg : _segmentInfos) {
299 if (seg->name.equals("__TEXT")) {
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000300 std::sort(seg->sections.begin(), seg->sections.end(),
Nick Kledzike34182f2013-11-06 21:36:55 +0000301 TextSectionSorter());
302 }
303 }
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000304
Nick Kledzike34182f2013-11-06 21:36:55 +0000305 // Record final section indexes.
306 uint32_t sectionIndex = 1;
307 for (SegmentInfo *seg : _segmentInfos) {
308 for (SectionInfo *sect : seg->sections) {
309 sect->finalSectionIndex = sectionIndex++;
310 }
311 }
312 }
313
314}
315
316uint64_t Util::alignTo(uint64_t value, uint8_t align2) {
317 return llvm::RoundUpToAlignment(value, 1 << align2);
318}
319
320
321void Util::layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr) {
322 seg->address = addr;
323 for (SectionInfo *sect : seg->sections) {
324 sect->address = alignTo(addr, sect->alignment);
325 addr += sect->size;
326 }
327 seg->size = llvm::RoundUpToAlignment(addr - seg->address,_context.pageSize());
328}
329
330
331// __TEXT segment lays out backwards so padding is at front after load commands.
332void Util::layoutSectionsInTextSegment(SegmentInfo *seg, uint64_t &addr) {
333 seg->address = addr;
334 // Walks sections starting at end to calculate padding for start.
335 int64_t taddr = 0;
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000336 for (auto it = seg->sections.rbegin(); it != seg->sections.rend(); ++it) {
Nick Kledzike34182f2013-11-06 21:36:55 +0000337 SectionInfo *sect = *it;
338 taddr -= sect->size;
339 taddr = taddr & (0 - (1 << sect->alignment));
340 }
341 int64_t padding = taddr;
342 while (padding < 0)
343 padding += _context.pageSize();
344 // Start assigning section address starting at padded offset.
345 addr += padding;
346 for (SectionInfo *sect : seg->sections) {
347 sect->address = alignTo(addr, sect->alignment);
348 addr = sect->address + sect->size;
349 }
350 seg->size = llvm::RoundUpToAlignment(addr - seg->address,_context.pageSize());
351}
352
353
354void Util::assignAddressesToSections() {
355 uint64_t address = 0; // FIXME
356 if (_context.outputFileType() != llvm::MachO::MH_OBJECT) {
357 for (SegmentInfo *seg : _segmentInfos) {
358 if (seg->name.equals("__PAGEZERO")) {
359 seg->size = _context.pageZeroSize();
360 address += seg->size;
361 }
362 else if (seg->name.equals("__TEXT"))
363 layoutSectionsInTextSegment(seg, address);
364 else
365 layoutSectionsInSegment(seg, address);
366 }
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000367 DEBUG_WITH_TYPE("WriterMachO-norm",
Nick Kledzik020a49c2013-11-06 21:57:52 +0000368 llvm::dbgs() << "assignAddressesToSections()\n";
369 for (SegmentInfo *sgi : _segmentInfos) {
370 llvm::dbgs() << " address=" << llvm::format("0x%08llX", sgi->address)
Nick Kledzike34182f2013-11-06 21:36:55 +0000371 << ", size=" << llvm::format("0x%08llX", sgi->size)
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000372 << ", segment-name='" << sgi->name
Nick Kledzik020a49c2013-11-06 21:57:52 +0000373 << "'\n";
374 for (SectionInfo *si : sgi->sections) {
375 llvm::dbgs()<< " addr=" << llvm::format("0x%08llX", si->address)
Nick Kledzike34182f2013-11-06 21:36:55 +0000376 << ", size=" << llvm::format("0x%08llX", si->size)
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000377 << ", section-name='" << si->sectionName
Nick Kledzik020a49c2013-11-06 21:57:52 +0000378 << "\n";
379 }
Nick Kledzike34182f2013-11-06 21:36:55 +0000380 }
Nick Kledzik020a49c2013-11-06 21:57:52 +0000381 );
Nick Kledzike34182f2013-11-06 21:36:55 +0000382 } else {
383 for (SectionInfo *sect : _sectionInfos) {
384 sect->address = alignTo(address, sect->alignment);
385 address = sect->address + sect->size;
386 }
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000387 DEBUG_WITH_TYPE("WriterMachO-norm",
Nick Kledzik020a49c2013-11-06 21:57:52 +0000388 llvm::dbgs() << "assignAddressesToSections()\n";
389 for (SectionInfo *si : _sectionInfos) {
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000390 llvm::dbgs() << " section=" << si->sectionName
Nick Kledzike34182f2013-11-06 21:36:55 +0000391 << " address= " << llvm::format("0x%08X", si->address)
392 << " size= " << llvm::format("0x%08X", si->size)
Nick Kledzik020a49c2013-11-06 21:57:52 +0000393 << "\n";
394 }
395 );
Nick Kledzike34182f2013-11-06 21:36:55 +0000396 }
Nick Kledzike34182f2013-11-06 21:36:55 +0000397}
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.
Nick Kledzik61fdef62014-05-15 20:59:23 +0000426 if (si->type == llvm::MachO::S_ZEROFILL)
427 return;
Nick Kledzik6edd7222014-01-11 01:07:43 +0000428 uint8_t *sectionContent = file.ownedAllocations.Allocate<uint8_t>(si->size);
429 normSect->content = llvm::makeArrayRef(sectionContent, si->size);
Nick Kledzike34182f2013-11-06 21:36:55 +0000430 for (AtomInfo &ai : si->atomsAndOffsets) {
431 // Copy raw bytes.
432 uint8_t *atomContent = reinterpret_cast<uint8_t*>
433 (&sectionContent[ai.offsetInSection]);
434 memcpy(atomContent, ai.atom->rawContent().data(), ai.atom->size());
435 // Apply fix-ups.
436 for (const Reference *ref : *ai.atom) {
437 uint32_t offset = ref->offsetInAtom();
438 uint64_t targetAddress = 0;
439 if ( ref->target() != nullptr )
440 targetAddress = _atomToAddress[ref->target()];
441 uint64_t fixupAddress = _atomToAddress[ai.atom] + offset;
Rui Ueyama170a1a82013-12-20 07:48:29 +0000442 _context.kindHandler().applyFixup(
443 ref->kindNamespace(), ref->kindArch(), ref->kindValue(),
444 ref->addend(), &atomContent[offset], fixupAddress, targetAddress);
Nick Kledzike34182f2013-11-06 21:36:55 +0000445 }
446 }
447}
448
449void Util::copySections(NormalizedFile &file) {
450 file.sections.reserve(_sectionInfos.size());
451 // For final linked images, write sections grouped by segment.
452 if (_context.outputFileType() != llvm::MachO::MH_OBJECT) {
453 for (SegmentInfo *sgi : _segmentInfos) {
454 for (SectionInfo *si : sgi->sections) {
455 appendSection(si, file);
456 }
457 }
458 } else {
459 // Object files write sections in default order.
460 for (SectionInfo *si : _sectionInfos) {
461 appendSection(si, file);
462 }
463 }
464}
465
466void Util::copyEntryPointAddress(NormalizedFile &nFile) {
467 if (_context.outputTypeHasEntry()) {
468 nFile.entryAddress = _atomToAddress[_entryAtom];
469 }
470}
471
472void Util::buildAtomToAddressMap() {
473 DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
474 << "assign atom addresses:\n");
475 const bool lookForEntry = _context.outputTypeHasEntry();
476 for (SectionInfo *sect : _sectionInfos) {
477 for (const AtomInfo &info : sect->atomsAndOffsets) {
478 _atomToAddress[info.atom] = sect->address + info.offsetInSection;
479 if (lookForEntry && (info.atom->contentType() == DefinedAtom::typeCode) &&
480 (info.atom->size() != 0) &&
481 info.atom->name() == _context.entrySymbolName()) {
482 _entryAtom = info.atom;
483 }
484 DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
485 << " address="
486 << llvm::format("0x%016X", _atomToAddress[info.atom])
487 << " atom=" << info.atom
488 << " name=" << info.atom->name() << "\n");
489 }
490 }
491}
492
493uint8_t Util::scopeBits(const DefinedAtom* atom) {
494 switch (atom->scope()) {
495 case Atom::scopeTranslationUnit:
496 return 0;
497 case Atom::scopeLinkageUnit:
498 return N_PEXT | N_EXT;
499 case Atom::scopeGlobal:
500 return N_EXT;
501 }
Nick Kledzik020fa7f2013-11-06 22:18:09 +0000502 llvm_unreachable("Unknown scope");
Nick Kledzike34182f2013-11-06 21:36:55 +0000503}
504
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000505bool Util::AtomSorter::operator()(const AtomAndIndex &left,
Nick Kledzike34182f2013-11-06 21:36:55 +0000506 const AtomAndIndex &right) {
507 return (left.atom->name().compare(right.atom->name()) < 0);
508}
509
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000510
Nick Kledzike34182f2013-11-06 21:36:55 +0000511bool Util::belongsInGlobalSymbolsSection(const DefinedAtom* atom) {
512 return (atom->scope() == Atom::scopeGlobal);
513}
514
515void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) {
516 // Mach-O symbol table has three regions: locals, globals, undefs.
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000517
Nick Kledzike34182f2013-11-06 21:36:55 +0000518 // Add all local (non-global) symbols in address order
519 std::vector<AtomAndIndex> globals;
520 globals.reserve(512);
521 for (SectionInfo *sect : _sectionInfos) {
522 for (const AtomInfo &info : sect->atomsAndOffsets) {
523 const DefinedAtom *atom = info.atom;
524 if (!atom->name().empty()) {
525 if (belongsInGlobalSymbolsSection(atom)) {
526 AtomAndIndex ai = { atom, sect->finalSectionIndex };
527 globals.push_back(ai);
528 } else {
529 Symbol sym;
530 sym.name = atom->name();
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000531 sym.type = N_SECT;
Nick Kledzike34182f2013-11-06 21:36:55 +0000532 sym.scope = scopeBits(atom);
533 sym.sect = sect->finalSectionIndex;
534 sym.desc = 0;
535 sym.value = _atomToAddress[atom];
536 file.localSymbols.push_back(sym);
537 }
538 }
539 }
540 }
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000541
Nick Kledzike34182f2013-11-06 21:36:55 +0000542 // Sort global symbol alphabetically, then add to symbol table.
543 std::sort(globals.begin(), globals.end(), AtomSorter());
544 for (AtomAndIndex &ai : globals) {
545 Symbol sym;
546 sym.name = ai.atom->name();
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000547 sym.type = N_SECT;
Nick Kledzike34182f2013-11-06 21:36:55 +0000548 sym.scope = scopeBits(static_cast<const DefinedAtom*>(ai.atom));
549 sym.sect = ai.index;
550 sym.desc = 0;
551 sym.value = _atomToAddress[ai.atom];
552 file.globalSymbols.push_back(sym);
553 }
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000554
555
Nick Kledzike34182f2013-11-06 21:36:55 +0000556 // Sort undefined symbol alphabetically, then add to symbol table.
557 std::vector<AtomAndIndex> undefs;
558 undefs.reserve(128);
559 for (const UndefinedAtom *atom : atomFile.undefined()) {
560 AtomAndIndex ai = { atom, 0 };
561 undefs.push_back(ai);
562 }
563 for (const SharedLibraryAtom *atom : atomFile.sharedLibrary()) {
564 AtomAndIndex ai = { atom, 0 };
565 undefs.push_back(ai);
566 }
567 std::sort(undefs.begin(), undefs.end(), AtomSorter());
568 const uint32_t start = file.globalSymbols.size() + file.localSymbols.size();
569 for (AtomAndIndex &ai : undefs) {
570 Symbol sym;
571 sym.name = ai.atom->name();
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000572 sym.type = N_UNDF;
Nick Kledzike34182f2013-11-06 21:36:55 +0000573 sym.scope = N_EXT;
574 sym.sect = 0;
575 sym.desc = 0;
576 sym.value = 0;
577 _atomToSymbolIndex[ai.atom] = file.undefinedSymbols.size() + start;
578 file.undefinedSymbols.push_back(sym);
579 }
580}
581
582const Atom *Util::targetOfLazyPointer(const DefinedAtom *lpAtom) {
583 for (const Reference *ref : *lpAtom) {
Nick Kledzike5552772013-12-19 21:58:00 +0000584 if (_context.kindHandler().isLazyTarget(*ref)) {
Nick Kledzike34182f2013-11-06 21:36:55 +0000585 return ref->target();
586 }
587 }
588 return nullptr;
589}
590
591const Atom *Util::targetOfStub(const DefinedAtom *stubAtom) {
592 for (const Reference *ref : *stubAtom) {
593 if (const Atom *ta = ref->target()) {
594 if (const DefinedAtom *lpAtom = dyn_cast<DefinedAtom>(ta)) {
595 const Atom *target = targetOfLazyPointer(lpAtom);
596 if (target)
597 return target;
598 }
599 }
600 }
601 return nullptr;
602}
603
604
605void Util::addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file) {
606 for (SectionInfo *si : _sectionInfos) {
607 Section &normSect = file.sections[si->normalizedSectionIndex];
608 switch (si->type) {
609 case llvm::MachO::S_NON_LAZY_SYMBOL_POINTERS:
610 for (const AtomInfo &info : si->atomsAndOffsets) {
611 bool foundTarget = false;
612 for (const Reference *ref : *info.atom) {
613 const Atom *target = ref->target();
614 if (target) {
615 if (isa<const SharedLibraryAtom>(target)) {
616 uint32_t index = _atomToSymbolIndex[target];
617 normSect.indirectSymbols.push_back(index);
618 foundTarget = true;
619 } else {
620 normSect.indirectSymbols.push_back(
621 llvm::MachO::INDIRECT_SYMBOL_LOCAL);
622 }
623 }
624 }
625 if (!foundTarget) {
626 normSect.indirectSymbols.push_back(
627 llvm::MachO::INDIRECT_SYMBOL_ABS);
628 }
629 }
630 break;
631 case llvm::MachO::S_LAZY_SYMBOL_POINTERS:
632 for (const AtomInfo &info : si->atomsAndOffsets) {
633 const Atom *target = targetOfLazyPointer(info.atom);
634 if (target) {
635 uint32_t index = _atomToSymbolIndex[target];
636 normSect.indirectSymbols.push_back(index);
637 }
638 }
639 break;
640 case llvm::MachO::S_SYMBOL_STUBS:
641 for (const AtomInfo &info : si->atomsAndOffsets) {
642 const Atom *target = targetOfStub(info.atom);
643 if (target) {
644 uint32_t index = _atomToSymbolIndex[target];
645 normSect.indirectSymbols.push_back(index);
646 }
647 }
648 break;
649 default:
650 break;
651 }
652 }
653
654}
655
656void Util::addDependentDylibs(const lld::File &atomFile,NormalizedFile &nFile) {
657 // Scan all imported symbols and build up list of dylibs they are from.
658 int ordinal = 1;
659 for (const SharedLibraryAtom *slAtom : atomFile.sharedLibrary()) {
660 StringRef loadPath = slAtom->loadName();
661 DylibPathToInfo::iterator pos = _dylibInfo.find(loadPath);
662 if (pos == _dylibInfo.end()) {
663 DylibInfo info;
664 info.ordinal = ordinal++;
665 info.hasWeak = slAtom->canBeNullAtRuntime();
666 info.hasNonWeak = !info.hasWeak;
667 _dylibInfo[loadPath] = info;
668 DependentDylib depInfo;
669 depInfo.path = loadPath;
670 depInfo.kind = llvm::MachO::LC_LOAD_DYLIB;
671 nFile.dependentDylibs.push_back(depInfo);
672 } else {
673 if ( slAtom->canBeNullAtRuntime() )
674 pos->second.hasWeak = true;
675 else
676 pos->second.hasNonWeak = true;
677 }
678 }
679 // Automatically weak link dylib in which all symbols are weak (canBeNull).
680 for (DependentDylib &dep : nFile.dependentDylibs) {
681 DylibInfo &info = _dylibInfo[dep.path];
682 if (info.hasWeak && !info.hasNonWeak)
683 dep.kind = llvm::MachO::LC_LOAD_WEAK_DYLIB;
684 }
685}
686
687
688int Util::dylibOrdinal(const SharedLibraryAtom *sa) {
689 return _dylibInfo[sa->loadName()].ordinal;
690}
691
692void Util::segIndexForSection(const SectionInfo *sect, uint8_t &segmentIndex,
693 uint64_t &segmentStartAddr) {
694 segmentIndex = 0;
695 for (const SegmentInfo *seg : _segmentInfos) {
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000696 if ((seg->address <= sect->address)
Nick Kledzike34182f2013-11-06 21:36:55 +0000697 && (seg->address+seg->size >= sect->address+sect->size)) {
698 segmentStartAddr = seg->address;
699 return;
700 }
701 ++segmentIndex;
702 }
703 llvm_unreachable("section not in any segment");
704}
705
706
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000707void Util::appendReloc(const DefinedAtom *atom, const Reference *ref,
Nick Kledzike34182f2013-11-06 21:36:55 +0000708 Relocations &relocations) {
709 // TODO: convert Reference to normalized relocation
710}
711
712void Util::addSectionRelocs(const lld::File &, NormalizedFile &file) {
713 if (_context.outputFileType() != llvm::MachO::MH_OBJECT)
714 return;
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000715
Nick Kledzike34182f2013-11-06 21:36:55 +0000716 for (SectionInfo *si : _sectionInfos) {
717 Section &normSect = file.sections[si->normalizedSectionIndex];
718 for (const AtomInfo &info : si->atomsAndOffsets) {
719 const DefinedAtom *atom = info.atom;
720 for (const Reference *ref : *atom) {
721 appendReloc(atom, ref, normSect.relocations);
722 }
723 }
724 }
725}
726
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000727void Util::addRebaseAndBindingInfo(const lld::File &atomFile,
Nick Kledzike34182f2013-11-06 21:36:55 +0000728 NormalizedFile &nFile) {
729 if (_context.outputFileType() == llvm::MachO::MH_OBJECT)
730 return;
731
732 uint8_t segmentIndex;
733 uint64_t segmentStartAddr;
734 for (SectionInfo *sect : _sectionInfos) {
735 segIndexForSection(sect, segmentIndex, segmentStartAddr);
736 for (const AtomInfo &info : sect->atomsAndOffsets) {
737 const DefinedAtom *atom = info.atom;
738 for (const Reference *ref : *atom) {
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000739 uint64_t segmentOffset = _atomToAddress[atom] + ref->offsetInAtom()
Nick Kledzike34182f2013-11-06 21:36:55 +0000740 - segmentStartAddr;
741 const Atom* targ = ref->target();
Nick Kledzike5552772013-12-19 21:58:00 +0000742 if (_context.kindHandler().isPointer(*ref)) {
Nick Kledzike34182f2013-11-06 21:36:55 +0000743 // A pointer to a DefinedAtom requires rebasing.
744 if (dyn_cast<DefinedAtom>(targ)) {
745 RebaseLocation rebase;
746 rebase.segIndex = segmentIndex;
747 rebase.segOffset = segmentOffset;
748 rebase.kind = llvm::MachO::REBASE_TYPE_POINTER;
749 nFile.rebasingInfo.push_back(rebase);
750 }
751 // A pointer to an SharedLibraryAtom requires binding.
752 if (const SharedLibraryAtom *sa = dyn_cast<SharedLibraryAtom>(targ)) {
753 BindLocation bind;
754 bind.segIndex = segmentIndex;
755 bind.segOffset = segmentOffset;
756 bind.kind = llvm::MachO::BIND_TYPE_POINTER;
757 bind.canBeNull = sa->canBeNullAtRuntime();
758 bind.ordinal = dylibOrdinal(sa);
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000759 bind.symbolName = targ->name();
Nick Kledzike34182f2013-11-06 21:36:55 +0000760 bind.addend = ref->addend();
761 nFile.bindingInfo.push_back(bind);
762 }
763 }
Nick Kledzike5552772013-12-19 21:58:00 +0000764 if (_context.kindHandler().isLazyTarget(*ref)) {
Nick Kledzike34182f2013-11-06 21:36:55 +0000765 BindLocation bind;
766 bind.segIndex = segmentIndex;
767 bind.segOffset = segmentOffset;
768 bind.kind = llvm::MachO::BIND_TYPE_POINTER;
769 bind.canBeNull = false; //sa->canBeNullAtRuntime();
770 bind.ordinal = 1;
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000771 bind.symbolName = targ->name();
Nick Kledzike34182f2013-11-06 21:36:55 +0000772 bind.addend = ref->addend();
773 nFile.lazyBindingInfo.push_back(bind);
774 }
775 }
776 }
777 }
778}
779
780uint32_t Util::fileFlags() {
781 return 0; //FIX ME
782}
783
784} // end anonymous namespace
785
786
787namespace lld {
788namespace mach_o {
789namespace normalized {
790
791/// Convert a set of Atoms into a normalized mach-o file.
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000792ErrorOr<std::unique_ptr<NormalizedFile>>
793normalizedFromAtoms(const lld::File &atomFile,
Nick Kledzike34182f2013-11-06 21:36:55 +0000794 const MachOLinkingContext &context) {
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000795 // The util object buffers info until the normalized file can be made.
Nick Kledzike34182f2013-11-06 21:36:55 +0000796 Util util(context);
797 util.assignAtomsToSections(atomFile);
798 util.organizeSections();
799 util.assignAddressesToSections();
800 util.buildAtomToAddressMap();
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000801
Nick Kledzike34182f2013-11-06 21:36:55 +0000802 std::unique_ptr<NormalizedFile> f(new NormalizedFile());
803 NormalizedFile &normFile = *f.get();
804 f->arch = context.arch();
805 f->fileType = context.outputFileType();
806 f->flags = util.fileFlags();
807 util.copySegmentInfo(normFile);
808 util.copySections(normFile);
809 util.addDependentDylibs(atomFile, normFile);
810 util.addSymbols(atomFile, normFile);
811 util.addIndirectSymbols(atomFile, normFile);
812 util.addRebaseAndBindingInfo(atomFile, normFile);
813 util.addSectionRelocs(atomFile, normFile);
814 util.copyEntryPointAddress(normFile);
Shankar Easwaran3d8de472014-01-27 03:09:26 +0000815
Nick Kledzike34182f2013-11-06 21:36:55 +0000816 return std::move(f);
817}
818
819
820} // namespace normalized
821} // namespace mach_o
822} // namespace lld
823