1 //===- SyntheticSections.cpp ---------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "SyntheticSections.h"
10 #include "Config.h"
11 #include "ExportTrie.h"
12 #include "InputFiles.h"
13 #include "MachOStructs.h"
14 #include "MergedOutputSection.h"
15 #include "OutputSegment.h"
16 #include "SymbolTable.h"
17 #include "Symbols.h"
18 #include "Writer.h"
19 
20 #include "lld/Common/ErrorHandler.h"
21 #include "lld/Common/Memory.h"
22 #include "llvm/Support/EndianStream.h"
23 #include "llvm/Support/LEB128.h"
24 
25 using namespace llvm;
26 using namespace llvm::support;
27 using namespace llvm::support::endian;
28 using namespace lld;
29 using namespace lld::macho;
30 
31 InStruct macho::in;
32 std::vector<SyntheticSection *> macho::syntheticSections;
33 
34 SyntheticSection::SyntheticSection(const char *segname, const char *name)
35     : OutputSection(SyntheticKind, name), segname(segname) {
36   syntheticSections.push_back(this);
37 }
38 
39 // dyld3's MachOLoaded::getSlide() assumes that the __TEXT segment starts
40 // from the beginning of the file (i.e. the header).
41 MachHeaderSection::MachHeaderSection()
42     : SyntheticSection(segment_names::text, section_names::header) {}
43 
44 void MachHeaderSection::addLoadCommand(LoadCommand *lc) {
45   loadCommands.push_back(lc);
46   sizeOfCmds += lc->getSize();
47 }
48 
49 uint64_t MachHeaderSection::getSize() const {
50   return sizeof(MachO::mach_header_64) + sizeOfCmds + config->headerPad;
51 }
52 
53 void MachHeaderSection::writeTo(uint8_t *buf) const {
54   auto *hdr = reinterpret_cast<MachO::mach_header_64 *>(buf);
55   hdr->magic = MachO::MH_MAGIC_64;
56   hdr->cputype = MachO::CPU_TYPE_X86_64;
57   hdr->cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL | MachO::CPU_SUBTYPE_LIB64;
58   hdr->filetype = config->outputType;
59   hdr->ncmds = loadCommands.size();
60   hdr->sizeofcmds = sizeOfCmds;
61   hdr->flags = MachO::MH_NOUNDEFS | MachO::MH_DYLDLINK | MachO::MH_TWOLEVEL;
62 
63   if (config->outputType == MachO::MH_DYLIB && !config->hasReexports)
64     hdr->flags |= MachO::MH_NO_REEXPORTED_DYLIBS;
65 
66   if (config->outputType == MachO::MH_EXECUTE && config->isPic)
67     hdr->flags |= MachO::MH_PIE;
68 
69   if (in.exports->hasWeakSymbol || in.weakBinding->hasNonWeakDefinition())
70     hdr->flags |= MachO::MH_WEAK_DEFINES;
71 
72   if (in.exports->hasWeakSymbol || in.weakBinding->hasEntry())
73     hdr->flags |= MachO::MH_BINDS_TO_WEAK;
74 
75   for (OutputSegment *seg : outputSegments) {
76     for (OutputSection *osec : seg->getSections()) {
77       if (isThreadLocalVariables(osec->flags)) {
78         hdr->flags |= MachO::MH_HAS_TLV_DESCRIPTORS;
79         break;
80       }
81     }
82   }
83 
84   uint8_t *p = reinterpret_cast<uint8_t *>(hdr + 1);
85   for (LoadCommand *lc : loadCommands) {
86     lc->writeTo(p);
87     p += lc->getSize();
88   }
89 }
90 
91 PageZeroSection::PageZeroSection()
92     : SyntheticSection(segment_names::pageZero, section_names::pageZero) {}
93 
94 uint64_t Location::getVA() const {
95   if (const auto *isec = section.dyn_cast<const InputSection *>())
96     return isec->getVA() + offset;
97   return section.get<const OutputSection *>()->addr + offset;
98 }
99 
100 RebaseSection::RebaseSection()
101     : LinkEditSection(segment_names::linkEdit, section_names::rebase) {}
102 
103 namespace {
104 struct Rebase {
105   OutputSegment *segment = nullptr;
106   uint64_t offset = 0;
107   uint64_t consecutiveCount = 0;
108 };
109 } // namespace
110 
111 // Rebase opcodes allow us to describe a contiguous sequence of rebase location
112 // using a single DO_REBASE opcode. To take advantage of it, we delay emitting
113 // `DO_REBASE` until we have reached the end of a contiguous sequence.
114 static void encodeDoRebase(Rebase &rebase, raw_svector_ostream &os) {
115   using namespace llvm::MachO;
116   assert(rebase.consecutiveCount != 0);
117   if (rebase.consecutiveCount <= REBASE_IMMEDIATE_MASK) {
118     os << static_cast<uint8_t>(REBASE_OPCODE_DO_REBASE_IMM_TIMES |
119                                rebase.consecutiveCount);
120   } else {
121     os << static_cast<uint8_t>(REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
122     encodeULEB128(rebase.consecutiveCount, os);
123   }
124   rebase.consecutiveCount = 0;
125 }
126 
127 static void encodeRebase(const OutputSection *osec, uint64_t outSecOff,
128                          Rebase &lastRebase, raw_svector_ostream &os) {
129   using namespace llvm::MachO;
130   OutputSegment *seg = osec->parent;
131   uint64_t offset = osec->getSegmentOffset() + outSecOff;
132   if (lastRebase.segment != seg || lastRebase.offset != offset) {
133     if (lastRebase.consecutiveCount != 0)
134       encodeDoRebase(lastRebase, os);
135 
136     if (lastRebase.segment != seg) {
137       os << static_cast<uint8_t>(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB |
138                                  seg->index);
139       encodeULEB128(offset, os);
140       lastRebase.segment = seg;
141       lastRebase.offset = offset;
142     } else {
143       assert(lastRebase.offset != offset);
144       os << static_cast<uint8_t>(REBASE_OPCODE_ADD_ADDR_ULEB);
145       encodeULEB128(offset - lastRebase.offset, os);
146       lastRebase.offset = offset;
147     }
148   }
149   ++lastRebase.consecutiveCount;
150   // DO_REBASE causes dyld to both perform the binding and increment the offset
151   lastRebase.offset += WordSize;
152 }
153 
154 void RebaseSection::finalizeContents() {
155   using namespace llvm::MachO;
156   if (locations.empty())
157     return;
158 
159   raw_svector_ostream os{contents};
160   Rebase lastRebase;
161 
162   os << static_cast<uint8_t>(REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER);
163 
164   llvm::sort(locations, [](const Location &a, const Location &b) {
165     return a.getVA() < b.getVA();
166   });
167   for (const Location &loc : locations) {
168     if (const auto *isec = loc.section.dyn_cast<const InputSection *>()) {
169       encodeRebase(isec->parent, isec->outSecOff + loc.offset, lastRebase, os);
170     } else {
171       const auto *osec = loc.section.get<const OutputSection *>();
172       encodeRebase(osec, loc.offset, lastRebase, os);
173     }
174   }
175   if (lastRebase.consecutiveCount != 0)
176     encodeDoRebase(lastRebase, os);
177 
178   os << static_cast<uint8_t>(REBASE_OPCODE_DONE);
179 }
180 
181 void RebaseSection::writeTo(uint8_t *buf) const {
182   memcpy(buf, contents.data(), contents.size());
183 }
184 
185 NonLazyPointerSectionBase::NonLazyPointerSectionBase(const char *segname,
186                                                      const char *name)
187     : SyntheticSection(segname, name) {
188   align = 8;
189   flags = MachO::S_NON_LAZY_SYMBOL_POINTERS;
190 }
191 
192 void NonLazyPointerSectionBase::addEntry(Symbol *sym) {
193   if (entries.insert(sym)) {
194     assert(!sym->isInGot());
195     sym->gotIndex = entries.size() - 1;
196 
197     addNonLazyBindingEntries(sym, this, sym->gotIndex * WordSize);
198   }
199 }
200 
201 void NonLazyPointerSectionBase::writeTo(uint8_t *buf) const {
202   for (size_t i = 0, n = entries.size(); i < n; ++i)
203     if (auto *defined = dyn_cast<Defined>(entries[i]))
204       write64le(&buf[i * WordSize], defined->getVA());
205 }
206 
207 BindingSection::BindingSection()
208     : LinkEditSection(segment_names::linkEdit, section_names::binding) {}
209 
210 namespace {
211 struct Binding {
212   OutputSegment *segment = nullptr;
213   uint64_t offset = 0;
214   int64_t addend = 0;
215   uint8_t ordinal = 0;
216 };
217 } // namespace
218 
219 // Encode a sequence of opcodes that tell dyld to write the address of symbol +
220 // addend at osec->addr + outSecOff.
221 //
222 // The bind opcode "interpreter" remembers the values of each binding field, so
223 // we only need to encode the differences between bindings. Hence the use of
224 // lastBinding.
225 static void encodeBinding(const Symbol *sym, const OutputSection *osec,
226                           uint64_t outSecOff, int64_t addend,
227                           Binding &lastBinding, raw_svector_ostream &os) {
228   using namespace llvm::MachO;
229   OutputSegment *seg = osec->parent;
230   uint64_t offset = osec->getSegmentOffset() + outSecOff;
231   if (lastBinding.segment != seg) {
232     os << static_cast<uint8_t>(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB |
233                                seg->index);
234     encodeULEB128(offset, os);
235     lastBinding.segment = seg;
236     lastBinding.offset = offset;
237   } else if (lastBinding.offset != offset) {
238     os << static_cast<uint8_t>(BIND_OPCODE_ADD_ADDR_ULEB);
239     encodeULEB128(offset - lastBinding.offset, os);
240     lastBinding.offset = offset;
241   }
242 
243   if (lastBinding.addend != addend) {
244     os << static_cast<uint8_t>(BIND_OPCODE_SET_ADDEND_SLEB);
245     encodeSLEB128(addend, os);
246     lastBinding.addend = addend;
247   }
248 
249   os << static_cast<uint8_t>(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM)
250      << sym->getName() << '\0'
251      << static_cast<uint8_t>(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER)
252      << static_cast<uint8_t>(BIND_OPCODE_DO_BIND);
253   // DO_BIND causes dyld to both perform the binding and increment the offset
254   lastBinding.offset += WordSize;
255 }
256 
257 // Non-weak bindings need to have their dylib ordinal encoded as well.
258 static void encodeDylibOrdinal(const DylibSymbol *dysym, Binding &lastBinding,
259                                raw_svector_ostream &os) {
260   using namespace llvm::MachO;
261   if (lastBinding.ordinal != dysym->file->ordinal) {
262     if (dysym->file->ordinal <= BIND_IMMEDIATE_MASK) {
263       os << static_cast<uint8_t>(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM |
264                                  dysym->file->ordinal);
265     } else {
266       os << static_cast<uint8_t>(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
267       encodeULEB128(dysym->file->ordinal, os);
268     }
269     lastBinding.ordinal = dysym->file->ordinal;
270   }
271 }
272 
273 static void encodeWeakOverride(const Defined *defined,
274                                raw_svector_ostream &os) {
275   using namespace llvm::MachO;
276   os << static_cast<uint8_t>(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM |
277                              BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION)
278      << defined->getName() << '\0';
279 }
280 
281 // Emit bind opcodes, which are a stream of byte-sized opcodes that dyld
282 // interprets to update a record with the following fields:
283 //  * segment index (of the segment to write the symbol addresses to, typically
284 //    the __DATA_CONST segment which contains the GOT)
285 //  * offset within the segment, indicating the next location to write a binding
286 //  * symbol type
287 //  * symbol library ordinal (the index of its library's LC_LOAD_DYLIB command)
288 //  * symbol name
289 //  * addend
290 // When dyld sees BIND_OPCODE_DO_BIND, it uses the current record state to bind
291 // a symbol in the GOT, and increments the segment offset to point to the next
292 // entry. It does *not* clear the record state after doing the bind, so
293 // subsequent opcodes only need to encode the differences between bindings.
294 void BindingSection::finalizeContents() {
295   raw_svector_ostream os{contents};
296   Binding lastBinding;
297 
298   // Since bindings are delta-encoded, sorting them allows for a more compact
299   // result. Note that sorting by address alone ensures that bindings for the
300   // same segment / section are located together.
301   llvm::sort(bindings, [](const BindingEntry &a, const BindingEntry &b) {
302     return a.target.getVA() < b.target.getVA();
303   });
304   for (const BindingEntry &b : bindings) {
305     encodeDylibOrdinal(b.dysym, lastBinding, os);
306     if (auto *isec = b.target.section.dyn_cast<const InputSection *>()) {
307       encodeBinding(b.dysym, isec->parent, isec->outSecOff + b.target.offset,
308                     b.addend, lastBinding, os);
309     } else {
310       auto *osec = b.target.section.get<const OutputSection *>();
311       encodeBinding(b.dysym, osec, b.target.offset, b.addend, lastBinding, os);
312     }
313   }
314   if (!bindings.empty())
315     os << static_cast<uint8_t>(MachO::BIND_OPCODE_DONE);
316 }
317 
318 void BindingSection::writeTo(uint8_t *buf) const {
319   memcpy(buf, contents.data(), contents.size());
320 }
321 
322 WeakBindingSection::WeakBindingSection()
323     : LinkEditSection(segment_names::linkEdit, section_names::weakBinding) {}
324 
325 void WeakBindingSection::finalizeContents() {
326   raw_svector_ostream os{contents};
327   Binding lastBinding;
328 
329   for (const Defined *defined : definitions)
330     encodeWeakOverride(defined, os);
331 
332   // Since bindings are delta-encoded, sorting them allows for a more compact
333   // result.
334   llvm::sort(bindings,
335              [](const WeakBindingEntry &a, const WeakBindingEntry &b) {
336                return a.target.getVA() < b.target.getVA();
337              });
338   for (const WeakBindingEntry &b : bindings) {
339     if (auto *isec = b.target.section.dyn_cast<const InputSection *>()) {
340       encodeBinding(b.symbol, isec->parent, isec->outSecOff + b.target.offset,
341                     b.addend, lastBinding, os);
342     } else {
343       auto *osec = b.target.section.get<const OutputSection *>();
344       encodeBinding(b.symbol, osec, b.target.offset, b.addend, lastBinding, os);
345     }
346   }
347   if (!bindings.empty() || !definitions.empty())
348     os << static_cast<uint8_t>(MachO::BIND_OPCODE_DONE);
349 }
350 
351 void WeakBindingSection::writeTo(uint8_t *buf) const {
352   memcpy(buf, contents.data(), contents.size());
353 }
354 
355 bool macho::needsBinding(const Symbol *sym) {
356   if (isa<DylibSymbol>(sym)) {
357     return true;
358   } else if (const auto *defined = dyn_cast<Defined>(sym)) {
359     if (defined->isWeakDef() && defined->isExternal())
360       return true;
361   }
362   return false;
363 }
364 
365 void macho::addNonLazyBindingEntries(const Symbol *sym,
366                                      SectionPointerUnion section,
367                                      uint64_t offset, int64_t addend) {
368   if (auto *dysym = dyn_cast<DylibSymbol>(sym)) {
369     in.binding->addEntry(dysym, section, offset, addend);
370     if (dysym->isWeakDef())
371       in.weakBinding->addEntry(sym, section, offset, addend);
372   } else if (auto *defined = dyn_cast<Defined>(sym)) {
373     in.rebase->addEntry(section, offset);
374     if (defined->isWeakDef() && defined->isExternal())
375       in.weakBinding->addEntry(sym, section, offset, addend);
376   } else if (isa<DSOHandle>(sym)) {
377     error("cannot bind to " + DSOHandle::name);
378   } else {
379     // Undefined symbols are filtered out in scanRelocations(); we should never
380     // get here
381     llvm_unreachable("cannot bind to an undefined symbol");
382   }
383 }
384 
385 StubsSection::StubsSection()
386     : SyntheticSection(segment_names::text, "__stubs") {
387   flags = MachO::S_SYMBOL_STUBS;
388   reserved2 = target->stubSize;
389 }
390 
391 uint64_t StubsSection::getSize() const {
392   return entries.size() * target->stubSize;
393 }
394 
395 void StubsSection::writeTo(uint8_t *buf) const {
396   size_t off = 0;
397   for (const Symbol *sym : entries) {
398     target->writeStub(buf + off, *sym);
399     off += target->stubSize;
400   }
401 }
402 
403 bool StubsSection::addEntry(Symbol *sym) {
404   bool inserted = entries.insert(sym);
405   if (inserted)
406     sym->stubsIndex = entries.size() - 1;
407   return inserted;
408 }
409 
410 StubHelperSection::StubHelperSection()
411     : SyntheticSection(segment_names::text, "__stub_helper") {}
412 
413 uint64_t StubHelperSection::getSize() const {
414   return target->stubHelperHeaderSize +
415          in.lazyBinding->getEntries().size() * target->stubHelperEntrySize;
416 }
417 
418 bool StubHelperSection::isNeeded() const { return in.lazyBinding->isNeeded(); }
419 
420 void StubHelperSection::writeTo(uint8_t *buf) const {
421   target->writeStubHelperHeader(buf);
422   size_t off = target->stubHelperHeaderSize;
423   for (const DylibSymbol *sym : in.lazyBinding->getEntries()) {
424     target->writeStubHelperEntry(buf + off, *sym, addr + off);
425     off += target->stubHelperEntrySize;
426   }
427 }
428 
429 void StubHelperSection::setup() {
430   stubBinder = dyn_cast_or_null<DylibSymbol>(symtab->find("dyld_stub_binder"));
431   if (stubBinder == nullptr) {
432     error("symbol dyld_stub_binder not found (normally in libSystem.dylib). "
433           "Needed to perform lazy binding.");
434     return;
435   }
436   in.got->addEntry(stubBinder);
437 
438   inputSections.push_back(in.imageLoaderCache);
439   symtab->addDefined("__dyld_private", in.imageLoaderCache, 0,
440                      /*isWeakDef=*/false);
441 }
442 
443 ImageLoaderCacheSection::ImageLoaderCacheSection() {
444   segname = segment_names::data;
445   name = "__data";
446   uint8_t *arr = bAlloc.Allocate<uint8_t>(WordSize);
447   memset(arr, 0, WordSize);
448   data = {arr, WordSize};
449 }
450 
451 LazyPointerSection::LazyPointerSection()
452     : SyntheticSection(segment_names::data, "__la_symbol_ptr") {
453   align = 8;
454   flags = MachO::S_LAZY_SYMBOL_POINTERS;
455 }
456 
457 uint64_t LazyPointerSection::getSize() const {
458   return in.stubs->getEntries().size() * WordSize;
459 }
460 
461 bool LazyPointerSection::isNeeded() const {
462   return !in.stubs->getEntries().empty();
463 }
464 
465 void LazyPointerSection::writeTo(uint8_t *buf) const {
466   size_t off = 0;
467   for (const Symbol *sym : in.stubs->getEntries()) {
468     if (const auto *dysym = dyn_cast<DylibSymbol>(sym)) {
469       if (dysym->hasStubsHelper()) {
470         uint64_t stubHelperOffset =
471             target->stubHelperHeaderSize +
472             dysym->stubsHelperIndex * target->stubHelperEntrySize;
473         write64le(buf + off, in.stubHelper->addr + stubHelperOffset);
474       }
475     } else {
476       write64le(buf + off, sym->getVA());
477     }
478     off += WordSize;
479   }
480 }
481 
482 LazyBindingSection::LazyBindingSection()
483     : LinkEditSection(segment_names::linkEdit, section_names::lazyBinding) {}
484 
485 void LazyBindingSection::finalizeContents() {
486   // TODO: Just precompute output size here instead of writing to a temporary
487   // buffer
488   for (DylibSymbol *sym : entries)
489     sym->lazyBindOffset = encode(*sym);
490 }
491 
492 void LazyBindingSection::writeTo(uint8_t *buf) const {
493   memcpy(buf, contents.data(), contents.size());
494 }
495 
496 void LazyBindingSection::addEntry(DylibSymbol *dysym) {
497   if (entries.insert(dysym)) {
498     dysym->stubsHelperIndex = entries.size() - 1;
499     in.rebase->addEntry(in.lazyPointers, dysym->stubsIndex * WordSize);
500   }
501 }
502 
503 // Unlike the non-lazy binding section, the bind opcodes in this section aren't
504 // interpreted all at once. Rather, dyld will start interpreting opcodes at a
505 // given offset, typically only binding a single symbol before it finds a
506 // BIND_OPCODE_DONE terminator. As such, unlike in the non-lazy-binding case,
507 // we cannot encode just the differences between symbols; we have to emit the
508 // complete bind information for each symbol.
509 uint32_t LazyBindingSection::encode(const DylibSymbol &sym) {
510   uint32_t opstreamOffset = contents.size();
511   OutputSegment *dataSeg = in.lazyPointers->parent;
512   os << static_cast<uint8_t>(MachO::BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB |
513                              dataSeg->index);
514   uint64_t offset = in.lazyPointers->addr - dataSeg->firstSection()->addr +
515                     sym.stubsIndex * WordSize;
516   encodeULEB128(offset, os);
517   if (sym.file->ordinal <= MachO::BIND_IMMEDIATE_MASK) {
518     os << static_cast<uint8_t>(MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_IMM |
519                                sym.file->ordinal);
520   } else {
521     os << static_cast<uint8_t>(MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
522     encodeULEB128(sym.file->ordinal, os);
523   }
524 
525   os << static_cast<uint8_t>(MachO::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM)
526      << sym.getName() << '\0'
527      << static_cast<uint8_t>(MachO::BIND_OPCODE_DO_BIND)
528      << static_cast<uint8_t>(MachO::BIND_OPCODE_DONE);
529   return opstreamOffset;
530 }
531 
532 void macho::prepareBranchTarget(Symbol *sym) {
533   if (auto *dysym = dyn_cast<DylibSymbol>(sym)) {
534     if (in.stubs->addEntry(dysym)) {
535       if (sym->isWeakDef()) {
536         in.binding->addEntry(dysym, in.lazyPointers,
537                              sym->stubsIndex * WordSize);
538         in.weakBinding->addEntry(sym, in.lazyPointers,
539                                  sym->stubsIndex * WordSize);
540       } else {
541         in.lazyBinding->addEntry(dysym);
542       }
543     }
544   } else if (auto *defined = dyn_cast<Defined>(sym)) {
545     if (defined->isWeakDef() && defined->isExternal()) {
546       if (in.stubs->addEntry(sym)) {
547         in.rebase->addEntry(in.lazyPointers, sym->stubsIndex * WordSize);
548         in.weakBinding->addEntry(sym, in.lazyPointers,
549                                  sym->stubsIndex * WordSize);
550       }
551     }
552   }
553 }
554 
555 ExportSection::ExportSection()
556     : LinkEditSection(segment_names::linkEdit, section_names::export_) {}
557 
558 void ExportSection::finalizeContents() {
559   trieBuilder.setImageBase(in.header->addr);
560   // TODO: We should check symbol visibility.
561   for (const Symbol *sym : symtab->getSymbols()) {
562     if (const auto *defined = dyn_cast<Defined>(sym)) {
563       trieBuilder.addSymbol(*defined);
564       hasWeakSymbol = hasWeakSymbol || sym->isWeakDef();
565     }
566   }
567   size = trieBuilder.build();
568 }
569 
570 void ExportSection::writeTo(uint8_t *buf) const { trieBuilder.writeTo(buf); }
571 
572 SymtabSection::SymtabSection(StringTableSection &stringTableSection)
573     : LinkEditSection(segment_names::linkEdit, section_names::symbolTable),
574       stringTableSection(stringTableSection) {}
575 
576 uint64_t SymtabSection::getRawSize() const {
577   return symbols.size() * sizeof(structs::nlist_64);
578 }
579 
580 void SymtabSection::finalizeContents() {
581   // TODO support other symbol types
582   for (Symbol *sym : symtab->getSymbols()) {
583     if (isa<Defined>(sym) || sym->isInGot() || sym->isInStubs()) {
584       sym->symtabIndex = symbols.size();
585       symbols.push_back({sym, stringTableSection.addString(sym->getName())});
586     }
587   }
588 }
589 
590 void SymtabSection::writeTo(uint8_t *buf) const {
591   auto *nList = reinterpret_cast<structs::nlist_64 *>(buf);
592   for (const SymtabEntry &entry : symbols) {
593     nList->n_strx = entry.strx;
594     // TODO support other symbol types
595     // TODO populate n_desc with more flags
596     if (auto *defined = dyn_cast<Defined>(entry.sym)) {
597       if (defined->isAbsolute()) {
598         nList->n_type = MachO::N_EXT | MachO::N_ABS;
599         nList->n_sect = MachO::NO_SECT;
600         nList->n_value = defined->value;
601       } else {
602         nList->n_type = MachO::N_EXT | MachO::N_SECT;
603         nList->n_sect = defined->isec->parent->index;
604         // For the N_SECT symbol type, n_value is the address of the symbol
605         nList->n_value = defined->value + defined->isec->getVA();
606       }
607       nList->n_desc |= defined->isWeakDef() ? MachO::N_WEAK_DEF : 0;
608     }
609     ++nList;
610   }
611 }
612 
613 IndirectSymtabSection::IndirectSymtabSection()
614     : LinkEditSection(segment_names::linkEdit,
615                       section_names::indirectSymbolTable) {}
616 
617 uint32_t IndirectSymtabSection::getNumSymbols() const {
618   return in.got->getEntries().size() + in.tlvPointers->getEntries().size() +
619          in.stubs->getEntries().size();
620 }
621 
622 bool IndirectSymtabSection::isNeeded() const {
623   return in.got->isNeeded() || in.tlvPointers->isNeeded() ||
624          in.stubs->isNeeded();
625 }
626 
627 void IndirectSymtabSection::finalizeContents() {
628   uint32_t off = 0;
629   in.got->reserved1 = off;
630   off += in.got->getEntries().size();
631   in.tlvPointers->reserved1 = off;
632   off += in.tlvPointers->getEntries().size();
633   // There is a 1:1 correspondence between stubs and LazyPointerSection
634   // entries, so they can share the same sub-array in the table.
635   in.stubs->reserved1 = in.lazyPointers->reserved1 = off;
636 }
637 
638 void IndirectSymtabSection::writeTo(uint8_t *buf) const {
639   uint32_t off = 0;
640   for (const Symbol *sym : in.got->getEntries()) {
641     write32le(buf + off * sizeof(uint32_t), sym->symtabIndex);
642     ++off;
643   }
644   for (const Symbol *sym : in.tlvPointers->getEntries()) {
645     write32le(buf + off * sizeof(uint32_t), sym->symtabIndex);
646     ++off;
647   }
648   for (const Symbol *sym : in.stubs->getEntries()) {
649     write32le(buf + off * sizeof(uint32_t), sym->symtabIndex);
650     ++off;
651   }
652 }
653 
654 StringTableSection::StringTableSection()
655     : LinkEditSection(segment_names::linkEdit, section_names::stringTable) {}
656 
657 uint32_t StringTableSection::addString(StringRef str) {
658   uint32_t strx = size;
659   strings.push_back(str);
660   size += str.size() + 1; // account for null terminator
661   return strx;
662 }
663 
664 void StringTableSection::writeTo(uint8_t *buf) const {
665   uint32_t off = 0;
666   for (StringRef str : strings) {
667     memcpy(buf + off, str.data(), str.size());
668     off += str.size() + 1; // account for null terminator
669   }
670 }
671