Optional<coff_symbol16> Writer::createSymbol(Defined *Def) { // Relative symbols are unrepresentable in a COFF symbol table. if (isa<DefinedSynthetic>(Def)) return None; if (auto *D = dyn_cast<DefinedRegular>(Def)) { // Don't write dead symbols or symbols in codeview sections to the symbol // table. if (!D->getChunk()->isLive() || D->getChunk()->isCodeView()) return None; } if (auto *Sym = dyn_cast<DefinedImportData>(Def)) if (!Sym->File->Live) return None; if (auto *Sym = dyn_cast<DefinedImportThunk>(Def)) if (!Sym->WrappedSym->File->Live) return None; coff_symbol16 Sym; StringRef Name = Def->getName(); if (Name.size() > COFF::NameSize) { Sym.Name.Offset.Zeroes = 0; Sym.Name.Offset.Offset = addEntryToStringTable(Name); } else { memset(Sym.Name.ShortName, 0, COFF::NameSize); memcpy(Sym.Name.ShortName, Name.data(), Name.size()); } if (auto *D = dyn_cast<DefinedCOFF>(Def)) { COFFSymbolRef Ref = D->getCOFFSymbol(); Sym.Type = Ref.getType(); Sym.StorageClass = Ref.getStorageClass(); } else { Sym.Type = IMAGE_SYM_TYPE_NULL; Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; } Sym.NumberOfAuxSymbols = 0; switch (Def->kind()) { case SymbolBody::DefinedAbsoluteKind: Sym.Value = Def->getRVA(); Sym.SectionNumber = IMAGE_SYM_ABSOLUTE; break; default: { uint64_t RVA = Def->getRVA(); OutputSection *Sec = nullptr; for (OutputSection *S : OutputSections) { if (S->getRVA() > RVA) break; Sec = S; } Sym.Value = RVA - Sec->getRVA(); Sym.SectionNumber = Sec->SectionIndex; break; } } return Sym; }
void Writer::createExportTable() { if (Config->Exports.empty()) return; OutputSection *Sec = createSection(".edata"); for (std::unique_ptr<Chunk> &C : Edata.Chunks) Sec->addChunk(C.get()); }
// Create relocations sections in the final output. // These are only created when relocatable output is requested. void Writer::createRelocSections() { log("createRelocSections"); // Don't use iterator here since we are adding to OutputSection size_t OrigSize = OutputSections.size(); for (size_t I = 0; I < OrigSize; I++) { OutputSection *OSec = OutputSections[I]; uint32_t Count = OSec->numRelocations(); if (!Count) continue; StringRef Name; if (OSec->Type == WASM_SEC_DATA) Name = "reloc.DATA"; else if (OSec->Type == WASM_SEC_CODE) Name = "reloc.CODE"; else if (OSec->Type == WASM_SEC_CUSTOM) Name = Saver.save("reloc." + OSec->Name); else llvm_unreachable( "relocations only supported for code, data, or custom sections"); SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, Name); raw_ostream &OS = Section->getStream(); writeUleb128(OS, I, "reloc section"); writeUleb128(OS, Count, "reloc count"); OSec->writeRelocations(OS); } }
void Writer::createExportTable() { if (Config->Exports.empty()) return; OutputSection *Sec = createSection(".edata"); for (Chunk *C : Edata.Chunks) Sec->addChunk(C); }
void Writer::createMiscChunks() { OutputSection *RData = createSection(".rdata"); // Create thunks for locally-dllimported symbols. if (!Symtab->LocalImportChunks.empty()) { for (Chunk *C : Symtab->LocalImportChunks) RData->addChunk(C); } // Create Debug Information Chunks if (Config->Debug) { DebugDirectory = make<DebugDirectoryChunk>(DebugRecords); // TODO(compnerd) create a coffgrp entry if DebugType::CV is not enabled if (Config->DebugTypes & static_cast<unsigned>(coff::DebugType::CV)) { auto *Chunk = make<CVDebugRecordChunk>(); BuildId = Chunk; DebugRecords.push_back(Chunk); } RData->addChunk(DebugDirectory); for (Chunk *C : DebugRecords) RData->addChunk(C); } // Create SEH table. x86-only. if (Config->Machine != I386) return; std::set<Defined *> Handlers; for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) { if (!File->SEHCompat) return; for (SymbolBody *B : File->SEHandlers) { // Make sure the handler is still live. Assume all handlers are regular // symbols. auto *D = dyn_cast<DefinedRegular>(B); if (D && D->getChunk()->isLive()) Handlers.insert(D); } } if (!Handlers.empty()) { SEHTable = make<SEHTableChunk>(Handlers); RData->addChunk(SEHTable); } }
Optional<coff_symbol16> Writer::createSymbol(Defined *Def) { if (auto *D = dyn_cast<DefinedRegular>(Def)) if (!D->getChunk()->isLive()) return None; coff_symbol16 Sym; StringRef Name = Def->getName(); if (Name.size() > COFF::NameSize) { Sym.Name.Offset.Zeroes = 0; Sym.Name.Offset.Offset = addEntryToStringTable(Name); } else { memset(Sym.Name.ShortName, 0, COFF::NameSize); memcpy(Sym.Name.ShortName, Name.data(), Name.size()); } if (auto *D = dyn_cast<DefinedCOFF>(Def)) { COFFSymbolRef Ref = D->getCOFFSymbol(); Sym.Type = Ref.getType(); Sym.StorageClass = Ref.getStorageClass(); } else { Sym.Type = IMAGE_SYM_TYPE_NULL; Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; } Sym.NumberOfAuxSymbols = 0; switch (Def->kind()) { case SymbolBody::DefinedAbsoluteKind: case SymbolBody::DefinedRelativeKind: Sym.Value = Def->getRVA(); Sym.SectionNumber = IMAGE_SYM_ABSOLUTE; break; default: { uint64_t RVA = Def->getRVA(); OutputSection *Sec = nullptr; for (OutputSection *S : OutputSections) { if (S->getRVA() > RVA) break; Sec = S; } Sym.Value = RVA - Sec->getRVA(); Sym.SectionNumber = Sec->SectionIndex; break; } } return Sym; }
// Create .idata section for the DLL-imported symbol table. // The format of this section is inherently Windows-specific. // IdataContents class abstracted away the details for us, // so we just let it create chunks and add them to the section. void Writer::createImportTables() { if (Symtab->ImportFiles.empty()) return; // Initialize DLLOrder so that import entries are ordered in // the same order as in the command line. (That affects DLL // initialization order, and this ordering is MSVC-compatible.) for (ImportFile *File : Symtab->ImportFiles) { if (!File->Live) continue; std::string DLL = StringRef(File->DLLName).lower(); if (Config->DLLOrder.count(DLL) == 0) Config->DLLOrder[DLL] = Config->DLLOrder.size(); } OutputSection *Text = createSection(".text"); for (ImportFile *File : Symtab->ImportFiles) { if (!File->Live) continue; if (DefinedImportThunk *Thunk = File->ThunkSym) Text->addChunk(Thunk->getChunk()); if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) { if (!File->ThunkSym) fatal("cannot delay-load " + toString(File) + " due to import of data: " + toString(*File->ImpSym)); DelayIdata.add(File->ImpSym); } else { Idata.add(File->ImpSym); } } if (!Idata.empty()) { OutputSection *Sec = createSection(".idata"); for (Chunk *C : Idata.getChunks()) Sec->addChunk(C); } if (!DelayIdata.empty()) { Defined *Helper = cast<Defined>(Config->DelayLoadHelper); DelayIdata.create(Helper); OutputSection *Sec = createSection(".didat"); for (Chunk *C : DelayIdata.getChunks()) Sec->addChunk(C); Sec = createSection(".data"); for (Chunk *C : DelayIdata.getDataChunks()) Sec->addChunk(C); Sec = createSection(".text"); for (Chunk *C : DelayIdata.getCodeChunks()) Sec->addChunk(C); } }
void Writer::createMiscChunks() { // Create thunks for locally-dllimported symbols. if (!Symtab->LocalImportChunks.empty()) { OutputSection *Sec = createSection(".rdata"); for (Chunk *C : Symtab->LocalImportChunks) Sec->addChunk(C); } // Create SEH table. x86-only. if (Config->Machine != I386) return; std::set<Defined *> Handlers; for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) { if (!File->SEHCompat) return; for (SymbolBody *B : File->SEHandlers) Handlers.insert(cast<Defined>(B->repl())); } SEHTable.reset(new SEHTableChunk(Handlers)); createSection(".rdata")->addChunk(SEHTable.get()); }
// Sort .pdata section contents according to PE/COFF spec 5.5. void Writer::sortExceptionTable() { OutputSection *Sec = findSection(".pdata"); if (!Sec) return; // We assume .pdata contains function table entries only. uint8_t *Begin = Buffer->getBufferStart() + Sec->getFileOff(); uint8_t *End = Begin + Sec->getVirtualSize(); if (Config->Machine == AMD64) { struct Entry { ulittle32_t Begin, End, Unwind; }; sort(parallel::par, (Entry *)Begin, (Entry *)End, [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; }); return; } if (Config->Machine == ARMNT) { struct Entry { ulittle32_t Begin, Unwind; }; sort(parallel::par, (Entry *)Begin, (Entry *)End, [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; }); return; } errs() << "warning: don't know how to handle .pdata.\n"; }
void Writer::createSymbolAndStringTable() { if (!Config->Debug || !Config->WriteSymtab) return; // Name field in the section table is 8 byte long. Longer names need // to be written to the string table. First, construct string table. for (OutputSection *Sec : OutputSections) { StringRef Name = Sec->getName(); if (Name.size() <= COFF::NameSize) continue; Sec->setStringTableOff(addEntryToStringTable(Name)); } for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) { for (SymbolBody *B : File->getSymbols()) { auto *D = dyn_cast<Defined>(B); if (!D || D->WrittenToSymtab) continue; D->WrittenToSymtab = true; if (Optional<coff_symbol16> Sym = createSymbol(D)) OutputSymtab.push_back(*Sym); } } OutputSection *LastSection = OutputSections.back(); // We position the symbol table to be adjacent to the end of the last section. uint64_t FileOff = LastSection->getFileOff() + alignTo(LastSection->getRawSize(), SectorSize); if (!OutputSymtab.empty()) { PointerToSymbolTable = FileOff; FileOff += OutputSymtab.size() * sizeof(coff_symbol16); } if (!Strtab.empty()) FileOff += Strtab.size() + 4; FileSize = alignTo(FileOff, SectorSize); }
static OutputSection *createSection(InputSectionBase *IS, StringRef OutsecName) { OutputSection *Sec = Script->createOutputSection(OutsecName, "<internal>"); Sec->addSection(cast<InputSection>(IS)); return Sec; }