1 //===- SyntheticSections.cpp ---------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "SyntheticSections.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"
20 #include "lld/Common/ErrorHandler.h"
21 #include "lld/Common/Memory.h"
22 #include "llvm/Support/EndianStream.h"
23 #include "llvm/Support/LEB128.h"
26 using namespace llvm::support
;
27 using namespace llvm::support::endian
;
29 using namespace lld::macho
;
32 std::vector
<SyntheticSection
*> macho::syntheticSections
;
34 SyntheticSection::SyntheticSection(const char *segname
, const char *name
)
35 : OutputSection(SyntheticKind
, name
), segname(segname
) {
36 syntheticSections
.push_back(this);
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
) {}
44 void MachHeaderSection::addLoadCommand(LoadCommand
*lc
) {
45 loadCommands
.push_back(lc
);
46 sizeOfCmds
+= lc
->getSize();
49 uint64_t MachHeaderSection::getSize() const {
50 return sizeof(MachO::mach_header_64
) + sizeOfCmds
+ config
->headerPad
;
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
;
63 if (config
->outputType
== MachO::MH_DYLIB
&& !config
->hasReexports
)
64 hdr
->flags
|= MachO::MH_NO_REEXPORTED_DYLIBS
;
66 if (config
->outputType
== MachO::MH_EXECUTE
&& config
->isPic
)
67 hdr
->flags
|= MachO::MH_PIE
;
69 if (in
.exports
->hasWeakSymbol
|| in
.weakBinding
->hasNonWeakDefinition())
70 hdr
->flags
|= MachO::MH_WEAK_DEFINES
;
72 if (in
.exports
->hasWeakSymbol
|| in
.weakBinding
->hasEntry())
73 hdr
->flags
|= MachO::MH_BINDS_TO_WEAK
;
75 for (OutputSegment
*seg
: outputSegments
) {
76 for (OutputSection
*osec
: seg
->getSections()) {
77 if (isThreadLocalVariables(osec
->flags
)) {
78 hdr
->flags
|= MachO::MH_HAS_TLV_DESCRIPTORS
;
84 uint8_t *p
= reinterpret_cast<uint8_t *>(hdr
+ 1);
85 for (LoadCommand
*lc
: loadCommands
) {
91 PageZeroSection::PageZeroSection()
92 : SyntheticSection(segment_names::pageZero
, section_names::pageZero
) {}
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
;
100 RebaseSection::RebaseSection()
101 : LinkEditSection(segment_names::linkEdit
, section_names::rebase
) {}
105 OutputSegment
*segment
= nullptr;
107 uint64_t consecutiveCount
= 0;
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
);
121 os
<< static_cast<uint8_t>(REBASE_OPCODE_DO_REBASE_ULEB_TIMES
);
122 encodeULEB128(rebase
.consecutiveCount
, os
);
124 rebase
.consecutiveCount
= 0;
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
);
136 if (lastRebase
.segment
!= seg
) {
137 os
<< static_cast<uint8_t>(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
|
139 encodeULEB128(offset
, os
);
140 lastRebase
.segment
= seg
;
141 lastRebase
.offset
= offset
;
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
;
149 ++lastRebase
.consecutiveCount
;
150 // DO_REBASE causes dyld to both perform the binding and increment the offset
151 lastRebase
.offset
+= WordSize
;
154 void RebaseSection::finalizeContents() {
155 using namespace llvm::MachO
;
156 if (locations
.empty())
159 raw_svector_ostream os
{contents
};
162 os
<< static_cast<uint8_t>(REBASE_OPCODE_SET_TYPE_IMM
| REBASE_TYPE_POINTER
);
164 llvm::sort(locations
, [](const Location
&a
, const Location
&b
) {
165 return a
.getVA() < b
.getVA();
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
);
171 const auto *osec
= loc
.section
.get
<const OutputSection
*>();
172 encodeRebase(osec
, loc
.offset
, lastRebase
, os
);
175 if (lastRebase
.consecutiveCount
!= 0)
176 encodeDoRebase(lastRebase
, os
);
178 os
<< static_cast<uint8_t>(REBASE_OPCODE_DONE
);
181 void RebaseSection::writeTo(uint8_t *buf
) const {
182 memcpy(buf
, contents
.data(), contents
.size());
185 NonLazyPointerSectionBase::NonLazyPointerSectionBase(const char *segname
,
187 : SyntheticSection(segname
, name
) {
189 flags
= MachO::S_NON_LAZY_SYMBOL_POINTERS
;
192 void NonLazyPointerSectionBase::addEntry(Symbol
*sym
) {
193 if (entries
.insert(sym
)) {
194 assert(!sym
->isInGot());
195 sym
->gotIndex
= entries
.size() - 1;
197 addNonLazyBindingEntries(sym
, this, sym
->gotIndex
* WordSize
);
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());
207 BindingSection::BindingSection()
208 : LinkEditSection(segment_names::linkEdit
, section_names::binding
) {}
212 OutputSegment
*segment
= nullptr;
219 // Encode a sequence of opcodes that tell dyld to write the address of symbol +
220 // addend at osec->addr + outSecOff.
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
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
|
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
;
243 if (lastBinding
.addend
!= addend
) {
244 os
<< static_cast<uint8_t>(BIND_OPCODE_SET_ADDEND_SLEB
);
245 encodeSLEB128(addend
, os
);
246 lastBinding
.addend
= addend
;
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
;
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
);
266 os
<< static_cast<uint8_t>(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
);
267 encodeULEB128(dysym
->file
->ordinal
, os
);
269 lastBinding
.ordinal
= dysym
->file
->ordinal
;
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';
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
287 // * symbol library ordinal (the index of its library's LC_LOAD_DYLIB command)
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
};
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();
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
);
310 auto *osec
= b
.target
.section
.get
<const OutputSection
*>();
311 encodeBinding(b
.dysym
, osec
, b
.target
.offset
, b
.addend
, lastBinding
, os
);
314 if (!bindings
.empty())
315 os
<< static_cast<uint8_t>(MachO::BIND_OPCODE_DONE
);
318 void BindingSection::writeTo(uint8_t *buf
) const {
319 memcpy(buf
, contents
.data(), contents
.size());
322 WeakBindingSection::WeakBindingSection()
323 : LinkEditSection(segment_names::linkEdit
, section_names::weakBinding
) {}
325 void WeakBindingSection::finalizeContents() {
326 raw_svector_ostream os
{contents
};
329 for (const Defined
*defined
: definitions
)
330 encodeWeakOverride(defined
, os
);
332 // Since bindings are delta-encoded, sorting them allows for a more compact
335 [](const WeakBindingEntry
&a
, const WeakBindingEntry
&b
) {
336 return a
.target
.getVA() < b
.target
.getVA();
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
);
343 auto *osec
= b
.target
.section
.get
<const OutputSection
*>();
344 encodeBinding(b
.symbol
, osec
, b
.target
.offset
, b
.addend
, lastBinding
, os
);
347 if (!bindings
.empty() || !definitions
.empty())
348 os
<< static_cast<uint8_t>(MachO::BIND_OPCODE_DONE
);
351 void WeakBindingSection::writeTo(uint8_t *buf
) const {
352 memcpy(buf
, contents
.data(), contents
.size());
355 bool macho::needsBinding(const Symbol
*sym
) {
356 if (isa
<DylibSymbol
>(sym
)) {
358 } else if (const auto *defined
= dyn_cast
<Defined
>(sym
)) {
359 if (defined
->isWeakDef() && defined
->isExternal())
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
);
379 // Undefined symbols are filtered out in scanRelocations(); we should never
381 llvm_unreachable("cannot bind to an undefined symbol");
385 StubsSection::StubsSection()
386 : SyntheticSection(segment_names::text
, "__stubs") {
387 flags
= MachO::S_SYMBOL_STUBS
;
388 reserved2
= target
->stubSize
;
391 uint64_t StubsSection::getSize() const {
392 return entries
.size() * target
->stubSize
;
395 void StubsSection::writeTo(uint8_t *buf
) const {
397 for (const Symbol
*sym
: entries
) {
398 target
->writeStub(buf
+ off
, *sym
);
399 off
+= target
->stubSize
;
403 bool StubsSection::addEntry(Symbol
*sym
) {
404 bool inserted
= entries
.insert(sym
);
406 sym
->stubsIndex
= entries
.size() - 1;
410 StubHelperSection::StubHelperSection()
411 : SyntheticSection(segment_names::text
, "__stub_helper") {}
413 uint64_t StubHelperSection::getSize() const {
414 return target
->stubHelperHeaderSize
+
415 in
.lazyBinding
->getEntries().size() * target
->stubHelperEntrySize
;
418 bool StubHelperSection::isNeeded() const { return in
.lazyBinding
->isNeeded(); }
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
;
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.");
436 in
.got
->addEntry(stubBinder
);
438 inputSections
.push_back(in
.imageLoaderCache
);
439 symtab
->addDefined("__dyld_private", in
.imageLoaderCache
, 0,
440 /*isWeakDef=*/false);
443 ImageLoaderCacheSection::ImageLoaderCacheSection() {
444 segname
= segment_names::data
;
446 uint8_t *arr
= bAlloc
.Allocate
<uint8_t>(WordSize
);
447 memset(arr
, 0, WordSize
);
448 data
= {arr
, WordSize
};
451 LazyPointerSection::LazyPointerSection()
452 : SyntheticSection(segment_names::data
, "__la_symbol_ptr") {
454 flags
= MachO::S_LAZY_SYMBOL_POINTERS
;
457 uint64_t LazyPointerSection::getSize() const {
458 return in
.stubs
->getEntries().size() * WordSize
;
461 bool LazyPointerSection::isNeeded() const {
462 return !in
.stubs
->getEntries().empty();
465 void LazyPointerSection::writeTo(uint8_t *buf
) const {
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
);
476 write64le(buf
+ off
, sym
->getVA());
482 LazyBindingSection::LazyBindingSection()
483 : LinkEditSection(segment_names::linkEdit
, section_names::lazyBinding
) {}
485 void LazyBindingSection::finalizeContents() {
486 // TODO: Just precompute output size here instead of writing to a temporary
488 for (DylibSymbol
*sym
: entries
)
489 sym
->lazyBindOffset
= encode(*sym
);
492 void LazyBindingSection::writeTo(uint8_t *buf
) const {
493 memcpy(buf
, contents
.data(), contents
.size());
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
);
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
|
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
|
521 os
<< static_cast<uint8_t>(MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
);
522 encodeULEB128(sym
.file
->ordinal
, os
);
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
;
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
);
541 in
.lazyBinding
->addEntry(dysym
);
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
);
555 ExportSection::ExportSection()
556 : LinkEditSection(segment_names::linkEdit
, section_names::export_
) {}
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();
567 size
= trieBuilder
.build();
570 void ExportSection::writeTo(uint8_t *buf
) const { trieBuilder
.writeTo(buf
); }
572 SymtabSection::SymtabSection(StringTableSection
&stringTableSection
)
573 : LinkEditSection(segment_names::linkEdit
, section_names::symbolTable
),
574 stringTableSection(stringTableSection
) {}
576 uint64_t SymtabSection::getRawSize() const {
577 return symbols
.size() * sizeof(structs::nlist_64
);
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())});
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
;
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();
607 nList
->n_desc
|= defined
->isWeakDef() ? MachO::N_WEAK_DEF
: 0;
613 IndirectSymtabSection::IndirectSymtabSection()
614 : LinkEditSection(segment_names::linkEdit
,
615 section_names::indirectSymbolTable
) {}
617 uint32_t IndirectSymtabSection::getNumSymbols() const {
618 return in
.got
->getEntries().size() + in
.tlvPointers
->getEntries().size() +
619 in
.stubs
->getEntries().size();
622 bool IndirectSymtabSection::isNeeded() const {
623 return in
.got
->isNeeded() || in
.tlvPointers
->isNeeded() ||
624 in
.stubs
->isNeeded();
627 void IndirectSymtabSection::finalizeContents() {
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
;
638 void IndirectSymtabSection::writeTo(uint8_t *buf
) const {
640 for (const Symbol
*sym
: in
.got
->getEntries()) {
641 write32le(buf
+ off
* sizeof(uint32_t), sym
->symtabIndex
);
644 for (const Symbol
*sym
: in
.tlvPointers
->getEntries()) {
645 write32le(buf
+ off
* sizeof(uint32_t), sym
->symtabIndex
);
648 for (const Symbol
*sym
: in
.stubs
->getEntries()) {
649 write32le(buf
+ off
* sizeof(uint32_t), sym
->symtabIndex
);
654 StringTableSection::StringTableSection()
655 : LinkEditSection(segment_names::linkEdit
, section_names::stringTable
) {}
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
664 void StringTableSection::writeTo(uint8_t *buf
) const {
666 for (StringRef str
: strings
) {
667 memcpy(buf
+ off
, str
.data(), str
.size());
668 off
+= str
.size() + 1; // account for null terminator