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