Index: vendor/lld/dist/COFF/DLL.cpp =================================================================== --- vendor/lld/dist/COFF/DLL.cpp (revision 319530) +++ vendor/lld/dist/COFF/DLL.cpp (revision 319531) @@ -1,547 +1,548 @@ //===- DLL.cpp ------------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines various types of chunks for the DLL import or export // descriptor tables. They are inherently Windows-specific. // You need to read Microsoft PE/COFF spec to understand details // about the data structures. // // If you are not particularly interested in linking against Windows // DLL, you can skip this file, and you should still be able to // understand the rest of the linker. // //===----------------------------------------------------------------------===// #include "Chunks.h" #include "DLL.h" #include "llvm/Object/COFF.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Path.h" using namespace llvm; using namespace llvm::object; using namespace llvm::support::endian; using namespace llvm::COFF; namespace lld { namespace coff { namespace { // Import table static int ptrSize() { return Config->is64() ? 8 : 4; } // A chunk for the import descriptor table. class HintNameChunk : public Chunk { public: HintNameChunk(StringRef N, uint16_t H) : Name(N), Hint(H) {} size_t getSize() const override { // Starts with 2 byte Hint field, followed by a null-terminated string, // ends with 0 or 1 byte padding. return alignTo(Name.size() + 3, 2); } void writeTo(uint8_t *Buf) const override { write16le(Buf + OutputSectionOff, Hint); memcpy(Buf + OutputSectionOff + 2, Name.data(), Name.size()); } private: StringRef Name; uint16_t Hint; }; // A chunk for the import descriptor table. class LookupChunk : public Chunk { public: explicit LookupChunk(Chunk *C) : HintName(C) {} size_t getSize() const override { return ptrSize(); } void writeTo(uint8_t *Buf) const override { write32le(Buf + OutputSectionOff, HintName->getRVA()); } Chunk *HintName; }; // A chunk for the import descriptor table. // This chunk represent import-by-ordinal symbols. // See Microsoft PE/COFF spec 7.1. Import Header for details. class OrdinalOnlyChunk : public Chunk { public: explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) {} size_t getSize() const override { return ptrSize(); } void writeTo(uint8_t *Buf) const override { // An import-by-ordinal slot has MSB 1 to indicate that // this is import-by-ordinal (and not import-by-name). if (Config->is64()) { write64le(Buf + OutputSectionOff, (1ULL << 63) | Ordinal); } else { write32le(Buf + OutputSectionOff, (1ULL << 31) | Ordinal); } } uint16_t Ordinal; }; // A chunk for the import descriptor table. class ImportDirectoryChunk : public Chunk { public: explicit ImportDirectoryChunk(Chunk *N) : DLLName(N) {} size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); } void writeTo(uint8_t *Buf) const override { auto *E = (coff_import_directory_table_entry *)(Buf + OutputSectionOff); + E->ImportLookupTableRVA = LookupTab->getRVA(); E->NameRVA = DLLName->getRVA(); - - // The import descriptor table contains two pointers to - // the tables describing dllimported symbols. But the - // Windows loader actually uses only one. So we create - // only one table and set both fields to its address. - E->ImportLookupTableRVA = AddressTab->getRVA(); E->ImportAddressTableRVA = AddressTab->getRVA(); } Chunk *DLLName; + Chunk *LookupTab; Chunk *AddressTab; }; // A chunk representing null terminator in the import table. // Contents of this chunk is always null bytes. class NullChunk : public Chunk { public: explicit NullChunk(size_t N) : Size(N) {} bool hasData() const override { return false; } size_t getSize() const override { return Size; } void setAlign(size_t N) { Align = N; } private: size_t Size; }; static std::vector> binImports(const std::vector &Imports) { // Group DLL-imported symbols by DLL name because that's how // symbols are layed out in the import descriptor table. auto Less = [](const std::string &A, const std::string &B) { return Config->DLLOrder[A] < Config->DLLOrder[B]; }; std::map, bool(*)(const std::string &, const std::string &)> M(Less); for (DefinedImportData *Sym : Imports) M[Sym->getDLLName().lower()].push_back(Sym); std::vector> V; for (auto &KV : M) { // Sort symbols by name for each group. std::vector &Syms = KV.second; std::sort(Syms.begin(), Syms.end(), [](DefinedImportData *A, DefinedImportData *B) { return A->getName() < B->getName(); }); V.push_back(std::move(Syms)); } return V; } // Export table // See Microsoft PE/COFF spec 4.3 for details. // A chunk for the delay import descriptor table etnry. class DelayDirectoryChunk : public Chunk { public: explicit DelayDirectoryChunk(Chunk *N) : DLLName(N) {} size_t getSize() const override { return sizeof(delay_import_directory_table_entry); } void writeTo(uint8_t *Buf) const override { auto *E = (delay_import_directory_table_entry *)(Buf + OutputSectionOff); E->Attributes = 1; E->Name = DLLName->getRVA(); E->ModuleHandle = ModuleHandle->getRVA(); E->DelayImportAddressTable = AddressTab->getRVA(); E->DelayImportNameTable = NameTab->getRVA(); } Chunk *DLLName; Chunk *ModuleHandle; Chunk *AddressTab; Chunk *NameTab; }; // Initial contents for delay-loaded functions. // This code calls __delayLoadHelper2 function to resolve a symbol // and then overwrites its jump table slot with the result // for subsequent function calls. static const uint8_t ThunkX64[] = { 0x51, // push rcx 0x52, // push rdx 0x41, 0x50, // push r8 0x41, 0x51, // push r9 0x48, 0x83, 0xEC, 0x48, // sub rsp, 48h 0x66, 0x0F, 0x7F, 0x04, 0x24, // movdqa xmmword ptr [rsp], xmm0 0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa xmmword ptr [rsp+10h], xmm1 0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm2 0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm3 0x48, 0x8D, 0x15, 0, 0, 0, 0, // lea rdx, [__imp_] 0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...] 0xE8, 0, 0, 0, 0, // call __delayLoadHelper2 0x66, 0x0F, 0x6F, 0x04, 0x24, // movdqa xmm0, xmmword ptr [rsp] 0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa xmm1, xmmword ptr [rsp+10h] 0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa xmm2, xmmword ptr [rsp+20h] 0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa xmm3, xmmword ptr [rsp+30h] 0x48, 0x83, 0xC4, 0x48, // add rsp, 48h 0x41, 0x59, // pop r9 0x41, 0x58, // pop r8 0x5A, // pop rdx 0x59, // pop rcx 0xFF, 0xE0, // jmp rax }; static const uint8_t ThunkX86[] = { 0x51, // push ecx 0x52, // push edx 0x68, 0, 0, 0, 0, // push offset ___imp__ 0x68, 0, 0, 0, 0, // push offset ___DELAY_IMPORT_DESCRIPTOR__dll 0xE8, 0, 0, 0, 0, // call ___delayLoadHelper2@8 0x5A, // pop edx 0x59, // pop ecx 0xFF, 0xE0, // jmp eax }; // A chunk for the delay import thunk. class ThunkChunkX64 : public Chunk { public: ThunkChunkX64(Defined *I, Chunk *D, Defined *H) : Imp(I), Desc(D), Helper(H) {} size_t getSize() const override { return sizeof(ThunkX64); } void writeTo(uint8_t *Buf) const override { memcpy(Buf + OutputSectionOff, ThunkX64, sizeof(ThunkX64)); write32le(Buf + OutputSectionOff + 36, Imp->getRVA() - RVA - 40); write32le(Buf + OutputSectionOff + 43, Desc->getRVA() - RVA - 47); write32le(Buf + OutputSectionOff + 48, Helper->getRVA() - RVA - 52); } Defined *Imp = nullptr; Chunk *Desc = nullptr; Defined *Helper = nullptr; }; class ThunkChunkX86 : public Chunk { public: ThunkChunkX86(Defined *I, Chunk *D, Defined *H) : Imp(I), Desc(D), Helper(H) {} size_t getSize() const override { return sizeof(ThunkX86); } void writeTo(uint8_t *Buf) const override { memcpy(Buf + OutputSectionOff, ThunkX86, sizeof(ThunkX86)); write32le(Buf + OutputSectionOff + 3, Imp->getRVA() + Config->ImageBase); write32le(Buf + OutputSectionOff + 8, Desc->getRVA() + Config->ImageBase); write32le(Buf + OutputSectionOff + 13, Helper->getRVA() - RVA - 17); } void getBaserels(std::vector *Res) override { Res->emplace_back(RVA + 3); Res->emplace_back(RVA + 8); } Defined *Imp = nullptr; Chunk *Desc = nullptr; Defined *Helper = nullptr; }; // A chunk for the import descriptor table. class DelayAddressChunk : public Chunk { public: explicit DelayAddressChunk(Chunk *C) : Thunk(C) {} size_t getSize() const override { return ptrSize(); } void writeTo(uint8_t *Buf) const override { if (Config->is64()) { write64le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase); } else { write32le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase); } } void getBaserels(std::vector *Res) override { Res->emplace_back(RVA); } Chunk *Thunk; }; // Export table // Read Microsoft PE/COFF spec 5.3 for details. // A chunk for the export descriptor table. class ExportDirectoryChunk : public Chunk { public: ExportDirectoryChunk(int I, int J, Chunk *D, Chunk *A, Chunk *N, Chunk *O) : MaxOrdinal(I), NameTabSize(J), DLLName(D), AddressTab(A), NameTab(N), OrdinalTab(O) {} size_t getSize() const override { return sizeof(export_directory_table_entry); } void writeTo(uint8_t *Buf) const override { auto *E = (export_directory_table_entry *)(Buf + OutputSectionOff); E->NameRVA = DLLName->getRVA(); E->OrdinalBase = 0; E->AddressTableEntries = MaxOrdinal + 1; E->NumberOfNamePointers = NameTabSize; E->ExportAddressTableRVA = AddressTab->getRVA(); E->NamePointerRVA = NameTab->getRVA(); E->OrdinalTableRVA = OrdinalTab->getRVA(); } uint16_t MaxOrdinal; uint16_t NameTabSize; Chunk *DLLName; Chunk *AddressTab; Chunk *NameTab; Chunk *OrdinalTab; }; class AddressTableChunk : public Chunk { public: explicit AddressTableChunk(size_t MaxOrdinal) : Size(MaxOrdinal + 1) {} size_t getSize() const override { return Size * 4; } void writeTo(uint8_t *Buf) const override { for (Export &E : Config->Exports) { uint8_t *P = Buf + OutputSectionOff + E.Ordinal * 4; if (E.ForwardChunk) { write32le(P, E.ForwardChunk->getRVA()); } else { write32le(P, cast(E.Sym)->getRVA()); } } } private: size_t Size; }; class NamePointersChunk : public Chunk { public: explicit NamePointersChunk(std::vector &V) : Chunks(V) {} size_t getSize() const override { return Chunks.size() * 4; } void writeTo(uint8_t *Buf) const override { uint8_t *P = Buf + OutputSectionOff; for (Chunk *C : Chunks) { write32le(P, C->getRVA()); P += 4; } } private: std::vector Chunks; }; class ExportOrdinalChunk : public Chunk { public: explicit ExportOrdinalChunk(size_t I) : Size(I) {} size_t getSize() const override { return Size * 2; } void writeTo(uint8_t *Buf) const override { uint8_t *P = Buf + OutputSectionOff; for (Export &E : Config->Exports) { if (E.Noname) continue; write16le(P, E.Ordinal); P += 2; } } private: size_t Size; }; } // anonymous namespace uint64_t IdataContents::getDirSize() { return Dirs.size() * sizeof(ImportDirectoryTableEntry); } uint64_t IdataContents::getIATSize() { return Addresses.size() * ptrSize(); } // Returns a list of .idata contents. // See Microsoft PE/COFF spec 5.4 for details. std::vector IdataContents::getChunks() { create(); // The loader assumes a specific order of data. // Add each type in the correct order. std::vector V; V.insert(V.end(), Dirs.begin(), Dirs.end()); + V.insert(V.end(), Lookups.begin(), Lookups.end()); V.insert(V.end(), Addresses.begin(), Addresses.end()); V.insert(V.end(), Hints.begin(), Hints.end()); V.insert(V.end(), DLLNames.begin(), DLLNames.end()); return V; } void IdataContents::create() { std::vector> V = binImports(Imports); // Create .idata contents for each DLL. for (std::vector &Syms : V) { // Create lookup and address tables. If they have external names, // we need to create HintName chunks to store the names. // If they don't (if they are import-by-ordinals), we store only // ordinal values to the table. - size_t Base = Addresses.size(); + size_t Base = Lookups.size(); for (DefinedImportData *S : Syms) { uint16_t Ord = S->getOrdinal(); if (S->getExternalName().empty()) { + Lookups.push_back(make(Ord)); Addresses.push_back(make(Ord)); continue; } auto *C = make(S->getExternalName(), Ord); + Lookups.push_back(make(C)); Addresses.push_back(make(C)); Hints.push_back(C); } // Terminate with null values. + Lookups.push_back(make(ptrSize())); Addresses.push_back(make(ptrSize())); for (int I = 0, E = Syms.size(); I < E; ++I) Syms[I]->setLocation(Addresses[Base + I]); // Create the import table header. DLLNames.push_back(make(Syms[0]->getDLLName())); auto *Dir = make(DLLNames.back()); + Dir->LookupTab = Lookups[Base]; Dir->AddressTab = Addresses[Base]; Dirs.push_back(Dir); } // Add null terminator. Dirs.push_back(make(sizeof(ImportDirectoryTableEntry))); } std::vector DelayLoadContents::getChunks() { std::vector V; V.insert(V.end(), Dirs.begin(), Dirs.end()); V.insert(V.end(), Names.begin(), Names.end()); V.insert(V.end(), HintNames.begin(), HintNames.end()); V.insert(V.end(), DLLNames.begin(), DLLNames.end()); return V; } std::vector DelayLoadContents::getDataChunks() { std::vector V; V.insert(V.end(), ModuleHandles.begin(), ModuleHandles.end()); V.insert(V.end(), Addresses.begin(), Addresses.end()); return V; } uint64_t DelayLoadContents::getDirSize() { return Dirs.size() * sizeof(delay_import_directory_table_entry); } void DelayLoadContents::create(Defined *H) { Helper = H; std::vector> V = binImports(Imports); // Create .didat contents for each DLL. for (std::vector &Syms : V) { // Create the delay import table header. DLLNames.push_back(make(Syms[0]->getDLLName())); auto *Dir = make(DLLNames.back()); size_t Base = Addresses.size(); for (DefinedImportData *S : Syms) { Chunk *T = newThunkChunk(S, Dir); auto *A = make(T); Addresses.push_back(A); Thunks.push_back(T); StringRef ExtName = S->getExternalName(); if (ExtName.empty()) { Names.push_back(make(S->getOrdinal())); } else { auto *C = make(ExtName, 0); Names.push_back(make(C)); HintNames.push_back(C); } } // Terminate with null values. Addresses.push_back(make(8)); Names.push_back(make(8)); for (int I = 0, E = Syms.size(); I < E; ++I) Syms[I]->setLocation(Addresses[Base + I]); auto *MH = make(8); MH->setAlign(8); ModuleHandles.push_back(MH); // Fill the delay import table header fields. Dir->ModuleHandle = MH; Dir->AddressTab = Addresses[Base]; Dir->NameTab = Names[Base]; Dirs.push_back(Dir); } // Add null terminator. Dirs.push_back(make(sizeof(delay_import_directory_table_entry))); } Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) { switch (Config->Machine) { case AMD64: return make(S, Dir, Helper); case I386: return make(S, Dir, Helper); default: llvm_unreachable("unsupported machine type"); } } EdataContents::EdataContents() { uint16_t MaxOrdinal = 0; for (Export &E : Config->Exports) MaxOrdinal = std::max(MaxOrdinal, E.Ordinal); auto *DLLName = make(sys::path::filename(Config->OutputFile)); auto *AddressTab = make(MaxOrdinal); std::vector Names; for (Export &E : Config->Exports) if (!E.Noname) Names.push_back(make(E.ExportName)); std::vector Forwards; for (Export &E : Config->Exports) { if (E.ForwardTo.empty()) continue; E.ForwardChunk = make(E.ForwardTo); Forwards.push_back(E.ForwardChunk); } auto *NameTab = make(Names); auto *OrdinalTab = make(Names.size()); auto *Dir = make(MaxOrdinal, Names.size(), DLLName, AddressTab, NameTab, OrdinalTab); Chunks.push_back(Dir); Chunks.push_back(DLLName); Chunks.push_back(AddressTab); Chunks.push_back(NameTab); Chunks.push_back(OrdinalTab); Chunks.insert(Chunks.end(), Names.begin(), Names.end()); Chunks.insert(Chunks.end(), Forwards.begin(), Forwards.end()); } } // namespace coff } // namespace lld Index: vendor/lld/dist/COFF/DLL.h =================================================================== --- vendor/lld/dist/COFF/DLL.h (revision 319530) +++ vendor/lld/dist/COFF/DLL.h (revision 319531) @@ -1,83 +1,84 @@ //===- DLL.h ----------------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_COFF_DLL_H #define LLD_COFF_DLL_H #include "Chunks.h" #include "Symbols.h" namespace lld { namespace coff { // Windows-specific. // IdataContents creates all chunks for the DLL import table. // You are supposed to call add() to add symbols and then // call getChunks() to get a list of chunks. class IdataContents { public: void add(DefinedImportData *Sym) { Imports.push_back(Sym); } bool empty() { return Imports.empty(); } std::vector getChunks(); uint64_t getDirRVA() { return Dirs[0]->getRVA(); } uint64_t getDirSize(); uint64_t getIATRVA() { return Addresses[0]->getRVA(); } uint64_t getIATSize(); private: void create(); std::vector Imports; std::vector Dirs; + std::vector Lookups; std::vector Addresses; std::vector Hints; std::vector DLLNames; }; // Windows-specific. // DelayLoadContents creates all chunks for the delay-load DLL import table. class DelayLoadContents { public: void add(DefinedImportData *Sym) { Imports.push_back(Sym); } bool empty() { return Imports.empty(); } void create(Defined *Helper); std::vector getChunks(); std::vector getDataChunks(); ArrayRef getCodeChunks() { return Thunks; } uint64_t getDirRVA() { return Dirs[0]->getRVA(); } uint64_t getDirSize(); private: Chunk *newThunkChunk(DefinedImportData *S, Chunk *Dir); Defined *Helper; std::vector Imports; std::vector Dirs; std::vector ModuleHandles; std::vector Addresses; std::vector Names; std::vector HintNames; std::vector Thunks; std::vector DLLNames; }; // Windows-specific. // EdataContents creates all chunks for the DLL export table. class EdataContents { public: EdataContents(); std::vector Chunks; }; } // namespace coff } // namespace lld #endif Index: vendor/lld/dist/COFF/Driver.cpp =================================================================== --- vendor/lld/dist/COFF/Driver.cpp (revision 319530) +++ vendor/lld/dist/COFF/Driver.cpp (revision 319531) @@ -1,1140 +1,1141 @@ //===- Driver.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Driver.h" #include "Config.h" #include "Error.h" #include "InputFiles.h" #include "Memory.h" #include "SymbolTable.h" #include "Symbols.h" #include "Writer.h" #include "lld/Driver/Driver.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Object/ArchiveWriter.h" #include "llvm/Object/COFFImportFile.h" #include "llvm/Object/COFFModuleDefinition.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ToolDrivers/llvm-lib/LibDriver.h" #include #include #include using namespace llvm; using namespace llvm::object; using namespace llvm::COFF; using llvm::sys::Process; using llvm::sys::fs::file_magic; using llvm::sys::fs::identify_magic; namespace lld { namespace coff { Configuration *Config; LinkerDriver *Driver; BumpPtrAllocator BAlloc; StringSaver Saver{BAlloc}; std::vector SpecificAllocBase::Instances; bool link(ArrayRef Args, raw_ostream &Diag) { ErrorCount = 0; ErrorOS = &Diag; Argv0 = Args[0]; Config = make(); Config->ColorDiagnostics = (ErrorOS == &llvm::errs() && Process::StandardErrHasColors()); Driver = make(); Driver->link(Args); return !ErrorCount; } // Drop directory components and replace extension with ".exe" or ".dll". static std::string getOutputPath(StringRef Path) { auto P = Path.find_last_of("\\/"); StringRef S = (P == StringRef::npos) ? Path : Path.substr(P + 1); const char* E = Config->DLL ? ".dll" : ".exe"; return (S.substr(0, S.rfind('.')) + E).str(); } // ErrorOr is not default constructible, so it cannot be used as the type // parameter of a future. // FIXME: We could open the file in createFutureForFile and avoid needing to // return an error here, but for the moment that would cost us a file descriptor // (a limited resource on Windows) for the duration that the future is pending. typedef std::pair, std::error_code> MBErrPair; // Create a std::future that opens and maps a file using the best strategy for // the host platform. static std::future createFutureForFile(std::string Path) { #if LLVM_ON_WIN32 // On Windows, file I/O is relatively slow so it is best to do this // asynchronously. auto Strategy = std::launch::async; #else auto Strategy = std::launch::deferred; #endif return std::async(Strategy, [=]() { auto MBOrErr = MemoryBuffer::getFile(Path); if (!MBOrErr) return MBErrPair{nullptr, MBOrErr.getError()}; return MBErrPair{std::move(*MBOrErr), std::error_code()}; }); } MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr MB) { MemoryBufferRef MBRef = *MB; make>(std::move(MB)); // take ownership if (Driver->Tar) Driver->Tar->append(relativeToRoot(MBRef.getBufferIdentifier()), MBRef.getBuffer()); return MBRef; } void LinkerDriver::addBuffer(std::unique_ptr MB) { MemoryBufferRef MBRef = takeBuffer(std::move(MB)); // File type is detected by contents, not by file extension. file_magic Magic = identify_magic(MBRef.getBuffer()); if (Magic == file_magic::windows_resource) { Resources.push_back(MBRef); return; } FilePaths.push_back(MBRef.getBufferIdentifier()); if (Magic == file_magic::archive) return Symtab.addFile(make(MBRef)); if (Magic == file_magic::bitcode) return Symtab.addFile(make(MBRef)); if (Magic == file_magic::coff_cl_gl_object) error(MBRef.getBufferIdentifier() + ": is not a native COFF file. " "Recompile without /GL"); else Symtab.addFile(make(MBRef)); } void LinkerDriver::enqueuePath(StringRef Path) { auto Future = std::make_shared>(createFutureForFile(Path)); std::string PathStr = Path; enqueueTask([=]() { auto MBOrErr = Future->get(); if (MBOrErr.second) error("could not open " + PathStr + ": " + MBOrErr.second.message()); else Driver->addBuffer(std::move(MBOrErr.first)); }); } void LinkerDriver::addArchiveBuffer(MemoryBufferRef MB, StringRef SymName, StringRef ParentName) { file_magic Magic = identify_magic(MB.getBuffer()); if (Magic == file_magic::coff_import_library) { Symtab.addFile(make(MB)); return; } InputFile *Obj; if (Magic == file_magic::coff_object) { Obj = make(MB); } else if (Magic == file_magic::bitcode) { Obj = make(MB); } else { error("unknown file type: " + MB.getBufferIdentifier()); return; } Obj->ParentName = ParentName; Symtab.addFile(Obj); log("Loaded " + toString(Obj) + " for " + SymName); } void LinkerDriver::enqueueArchiveMember(const Archive::Child &C, StringRef SymName, StringRef ParentName) { if (!C.getParent()->isThin()) { MemoryBufferRef MB = check( C.getMemoryBufferRef(), "could not get the buffer for the member defining symbol " + SymName); enqueueTask([=]() { Driver->addArchiveBuffer(MB, SymName, ParentName); }); return; } auto Future = std::make_shared>(createFutureForFile( check(C.getFullName(), "could not get the filename for the member defining symbol " + SymName))); enqueueTask([=]() { auto MBOrErr = Future->get(); if (MBOrErr.second) fatal(MBOrErr.second, "could not get the buffer for the member defining " + SymName); Driver->addArchiveBuffer(takeBuffer(std::move(MBOrErr.first)), SymName, ParentName); }); } static bool isDecorated(StringRef Sym) { return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?"); } // Parses .drectve section contents and returns a list of files // specified by /defaultlib. void LinkerDriver::parseDirectives(StringRef S) { opt::InputArgList Args = Parser.parse(S); for (auto *Arg : Args) { switch (Arg->getOption().getID()) { case OPT_alternatename: parseAlternateName(Arg->getValue()); break; case OPT_defaultlib: if (Optional Path = findLib(Arg->getValue())) enqueuePath(*Path); break; case OPT_export: { Export E = parseExport(Arg->getValue()); E.Directives = true; Config->Exports.push_back(E); break; } case OPT_failifmismatch: checkFailIfMismatch(Arg->getValue()); break; case OPT_incl: addUndefined(Arg->getValue()); break; case OPT_merge: parseMerge(Arg->getValue()); break; case OPT_nodefaultlib: Config->NoDefaultLibs.insert(doFindLib(Arg->getValue())); break; case OPT_section: parseSection(Arg->getValue()); break; case OPT_editandcontinue: case OPT_fastfail: case OPT_guardsym: case OPT_throwingnew: break; default: error(Arg->getSpelling() + " is not allowed in .drectve"); } } } // Find file from search paths. You can omit ".obj", this function takes // care of that. Note that the returned path is not guaranteed to exist. StringRef LinkerDriver::doFindFile(StringRef Filename) { bool HasPathSep = (Filename.find_first_of("/\\") != StringRef::npos); if (HasPathSep) return Filename; bool HasExt = (Filename.find('.') != StringRef::npos); for (StringRef Dir : SearchPaths) { SmallString<128> Path = Dir; sys::path::append(Path, Filename); if (sys::fs::exists(Path.str())) return Saver.save(Path.str()); if (!HasExt) { Path.append(".obj"); if (sys::fs::exists(Path.str())) return Saver.save(Path.str()); } } return Filename; } // Resolves a file path. This never returns the same path // (in that case, it returns None). Optional LinkerDriver::findFile(StringRef Filename) { StringRef Path = doFindFile(Filename); bool Seen = !VisitedFiles.insert(Path.lower()).second; if (Seen) return None; return Path; } // Find library file from search path. StringRef LinkerDriver::doFindLib(StringRef Filename) { // Add ".lib" to Filename if that has no file extension. bool HasExt = (Filename.find('.') != StringRef::npos); if (!HasExt) Filename = Saver.save(Filename + ".lib"); return doFindFile(Filename); } // Resolves a library path. /nodefaultlib options are taken into // consideration. This never returns the same path (in that case, // it returns None). Optional LinkerDriver::findLib(StringRef Filename) { if (Config->NoDefaultLibAll) return None; if (!VisitedLibs.insert(Filename.lower()).second) return None; StringRef Path = doFindLib(Filename); if (Config->NoDefaultLibs.count(Path)) return None; if (!VisitedFiles.insert(Path.lower()).second) return None; return Path; } // Parses LIB environment which contains a list of search paths. void LinkerDriver::addLibSearchPaths() { Optional EnvOpt = Process::GetEnv("LIB"); if (!EnvOpt.hasValue()) return; StringRef Env = Saver.save(*EnvOpt); while (!Env.empty()) { StringRef Path; std::tie(Path, Env) = Env.split(';'); SearchPaths.push_back(Path); } } SymbolBody *LinkerDriver::addUndefined(StringRef Name) { SymbolBody *B = Symtab.addUndefined(Name); Config->GCRoot.insert(B); return B; } // Symbol names are mangled by appending "_" prefix on x86. StringRef LinkerDriver::mangle(StringRef Sym) { assert(Config->Machine != IMAGE_FILE_MACHINE_UNKNOWN); if (Config->Machine == I386) return Saver.save("_" + Sym); return Sym; } // Windows specific -- find default entry point name. StringRef LinkerDriver::findDefaultEntry() { // User-defined main functions and their corresponding entry points. static const char *Entries[][2] = { {"main", "mainCRTStartup"}, {"wmain", "wmainCRTStartup"}, {"WinMain", "WinMainCRTStartup"}, {"wWinMain", "wWinMainCRTStartup"}, }; for (auto E : Entries) { StringRef Entry = Symtab.findMangle(mangle(E[0])); if (!Entry.empty() && !isa(Symtab.find(Entry)->body())) return mangle(E[1]); } return ""; } WindowsSubsystem LinkerDriver::inferSubsystem() { if (Config->DLL) return IMAGE_SUBSYSTEM_WINDOWS_GUI; if (Symtab.findUnderscore("main") || Symtab.findUnderscore("wmain")) return IMAGE_SUBSYSTEM_WINDOWS_CUI; if (Symtab.findUnderscore("WinMain") || Symtab.findUnderscore("wWinMain")) return IMAGE_SUBSYSTEM_WINDOWS_GUI; return IMAGE_SUBSYSTEM_UNKNOWN; } static uint64_t getDefaultImageBase() { if (Config->is64()) return Config->DLL ? 0x180000000 : 0x140000000; return Config->DLL ? 0x10000000 : 0x400000; } static std::string createResponseFile(const opt::InputArgList &Args, ArrayRef FilePaths, ArrayRef SearchPaths) { SmallString<0> Data; raw_svector_ostream OS(Data); for (auto *Arg : Args) { switch (Arg->getOption().getID()) { case OPT_linkrepro: case OPT_INPUT: case OPT_defaultlib: case OPT_libpath: break; default: OS << toString(Arg) << "\n"; } } for (StringRef Path : SearchPaths) { std::string RelPath = relativeToRoot(Path); OS << "/libpath:" << quote(RelPath) << "\n"; } for (StringRef Path : FilePaths) OS << quote(relativeToRoot(Path)) << "\n"; return Data.str(); } static unsigned getDefaultDebugType(const opt::InputArgList &Args) { unsigned DebugTypes = static_cast(DebugType::CV); if (Args.hasArg(OPT_driver)) DebugTypes |= static_cast(DebugType::PData); if (Args.hasArg(OPT_profile)) DebugTypes |= static_cast(DebugType::Fixup); return DebugTypes; } static unsigned parseDebugType(StringRef Arg) { SmallVector Types; Arg.split(Types, ',', /*KeepEmpty=*/false); unsigned DebugTypes = static_cast(DebugType::None); for (StringRef Type : Types) DebugTypes |= StringSwitch(Type.lower()) .Case("cv", static_cast(DebugType::CV)) .Case("pdata", static_cast(DebugType::PData)) .Case("fixup", static_cast(DebugType::Fixup)) .Default(0); return DebugTypes; } static std::string getMapFile(const opt::InputArgList &Args) { auto *Arg = Args.getLastArg(OPT_lldmap, OPT_lldmap_file); if (!Arg) return ""; if (Arg->getOption().getID() == OPT_lldmap_file) return Arg->getValue(); assert(Arg->getOption().getID() == OPT_lldmap); StringRef OutFile = Config->OutputFile; return (OutFile.substr(0, OutFile.rfind('.')) + ".map").str(); } static std::string getImplibPath() { if (!Config->Implib.empty()) return Config->Implib; SmallString<128> Out = StringRef(Config->OutputFile); sys::path::replace_extension(Out, ".lib"); return Out.str(); } std::vector createCOFFShortExportFromConfig() { std::vector Exports; for (Export &E1 : Config->Exports) { COFFShortExport E2; - E2.Name = E1.Name; + // Use SymbolName, which will have any stdcall or fastcall qualifiers. + E2.Name = E1.SymbolName; E2.ExtName = E1.ExtName; E2.Ordinal = E1.Ordinal; E2.Noname = E1.Noname; E2.Data = E1.Data; E2.Private = E1.Private; E2.Constant = E1.Constant; Exports.push_back(E2); } return Exports; } static void createImportLibrary() { std::vector Exports = createCOFFShortExportFromConfig(); std::string DLLName = sys::path::filename(Config->OutputFile); std::string Path = getImplibPath(); writeImportLibrary(DLLName, Path, Exports, Config->Machine); } static void parseModuleDefs(StringRef Path) { std::unique_ptr MB = check( MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path); MemoryBufferRef MBRef = MB->getMemBufferRef(); Expected Def = parseCOFFModuleDefinition(MBRef, Config->Machine); if (!Def) fatal(errorToErrorCode(Def.takeError()).message()); COFFModuleDefinition &M = *Def; if (Config->OutputFile.empty()) Config->OutputFile = Saver.save(M.OutputFile); if (M.ImageBase) Config->ImageBase = M.ImageBase; if (M.StackReserve) Config->StackReserve = M.StackReserve; if (M.StackCommit) Config->StackCommit = M.StackCommit; if (M.HeapReserve) Config->HeapReserve = M.HeapReserve; if (M.HeapCommit) Config->HeapCommit = M.HeapCommit; if (M.MajorImageVersion) Config->MajorImageVersion = M.MajorImageVersion; if (M.MinorImageVersion) Config->MinorImageVersion = M.MinorImageVersion; if (M.MajorOSVersion) Config->MajorOSVersion = M.MajorOSVersion; if (M.MinorOSVersion) Config->MinorOSVersion = M.MinorOSVersion; for (COFFShortExport E1 : M.Exports) { Export E2; E2.Name = Saver.save(E1.Name); if (E1.isWeak()) E2.ExtName = Saver.save(E1.ExtName); E2.Ordinal = E1.Ordinal; E2.Noname = E1.Noname; E2.Data = E1.Data; E2.Private = E1.Private; E2.Constant = E1.Constant; Config->Exports.push_back(E2); } } std::vector getArchiveMembers(Archive *File) { std::vector V; Error Err = Error::success(); for (const ErrorOr &COrErr : File->children(Err)) { Archive::Child C = check(COrErr, File->getFileName() + ": could not get the child of the archive"); MemoryBufferRef MBRef = check(C.getMemoryBufferRef(), File->getFileName() + ": could not get the buffer for a child of the archive"); V.push_back(MBRef); } if (Err) fatal(File->getFileName() + ": Archive::children failed: " + toString(std::move(Err))); return V; } // A helper function for filterBitcodeFiles. static bool needsRebuilding(MemoryBufferRef MB) { // The MSVC linker doesn't support thin archives, so if it's a thin // archive, we always need to rebuild it. std::unique_ptr File = check(Archive::create(MB), "Failed to read " + MB.getBufferIdentifier()); if (File->isThin()) return true; // Returns true if the archive contains at least one bitcode file. for (MemoryBufferRef Member : getArchiveMembers(File.get())) if (identify_magic(Member.getBuffer()) == file_magic::bitcode) return true; return false; } // Opens a given path as an archive file and removes bitcode files // from them if exists. This function is to appease the MSVC linker as // their linker doesn't like archive files containing non-native // object files. // // If a given archive doesn't contain bitcode files, the archive path // is returned as-is. Otherwise, a new temporary file is created and // its path is returned. static Optional filterBitcodeFiles(StringRef Path, std::vector &TemporaryFiles) { std::unique_ptr MB = check( MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path); MemoryBufferRef MBRef = MB->getMemBufferRef(); file_magic Magic = identify_magic(MBRef.getBuffer()); if (Magic == file_magic::bitcode) return None; if (Magic != file_magic::archive) return Path.str(); if (!needsRebuilding(MBRef)) return Path.str(); std::unique_ptr File = check(Archive::create(MBRef), MBRef.getBufferIdentifier() + ": failed to parse archive"); std::vector New; for (MemoryBufferRef Member : getArchiveMembers(File.get())) if (identify_magic(Member.getBuffer()) != file_magic::bitcode) New.emplace_back(Member); if (New.empty()) return None; log("Creating a temporary archive for " + Path + " to remove bitcode files"); SmallString<128> S; if (auto EC = sys::fs::createTemporaryFile("lld-" + sys::path::stem(Path), ".lib", S)) fatal(EC, "cannot create a temporary file"); std::string Temp = S.str(); TemporaryFiles.push_back(Temp); std::pair Ret = llvm::writeArchive(Temp, New, /*WriteSymtab=*/true, Archive::Kind::K_GNU, /*Deterministics=*/true, /*Thin=*/false); if (Ret.second) error("failed to create a new archive " + S.str() + ": " + Ret.first); return Temp; } // Create response file contents and invoke the MSVC linker. void LinkerDriver::invokeMSVC(opt::InputArgList &Args) { std::string Rsp = "/nologo\n"; std::vector Temps; // Write out archive members that we used in symbol resolution and pass these // to MSVC before any archives, so that MSVC uses the same objects to satisfy // references. for (const auto *O : Symtab.ObjectFiles) { if (O->ParentName.empty()) continue; SmallString<128> S; int Fd; if (auto EC = sys::fs::createTemporaryFile( "lld-" + sys::path::filename(O->ParentName), ".obj", Fd, S)) fatal(EC, "cannot create a temporary file"); raw_fd_ostream OS(Fd, /*shouldClose*/ true); OS << O->MB.getBuffer(); Temps.push_back(S.str()); Rsp += quote(S) + "\n"; } for (auto *Arg : Args) { switch (Arg->getOption().getID()) { case OPT_linkrepro: case OPT_lldmap: case OPT_lldmap_file: case OPT_lldsavetemps: case OPT_msvclto: // LLD-specific options are stripped. break; case OPT_opt: if (!StringRef(Arg->getValue()).startswith("lld")) Rsp += toString(Arg) + " "; break; case OPT_INPUT: { if (Optional Path = doFindFile(Arg->getValue())) { if (Optional S = filterBitcodeFiles(*Path, Temps)) Rsp += quote(*S) + "\n"; continue; } Rsp += quote(Arg->getValue()) + "\n"; break; } default: Rsp += toString(Arg) + "\n"; } } std::vector ObjectFiles = Symtab.compileBitcodeFiles(); runMSVCLinker(Rsp, ObjectFiles); for (StringRef Path : Temps) sys::fs::remove(Path); } void LinkerDriver::enqueueTask(std::function Task) { TaskQueue.push_back(std::move(Task)); } bool LinkerDriver::run() { bool DidWork = !TaskQueue.empty(); while (!TaskQueue.empty()) { TaskQueue.front()(); TaskQueue.pop_front(); } return DidWork; } void LinkerDriver::link(ArrayRef ArgsArr) { // If the first command line argument is "/lib", link.exe acts like lib.exe. // We call our own implementation of lib.exe that understands bitcode files. if (ArgsArr.size() > 1 && StringRef(ArgsArr[1]).equals_lower("/lib")) { if (llvm::libDriverMain(ArgsArr.slice(1)) != 0) fatal("lib failed"); return; } // Needed for LTO. InitializeAllTargetInfos(); InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmParsers(); InitializeAllAsmPrinters(); InitializeAllDisassemblers(); // Parse command line options. opt::InputArgList Args = Parser.parseLINK(ArgsArr.slice(1)); // Parse and evaluate -mllvm options. std::vector V; V.push_back("lld-link (LLVM option parsing)"); for (auto *Arg : Args.filtered(OPT_mllvm)) V.push_back(Arg->getValue()); cl::ParseCommandLineOptions(V.size(), V.data()); // Handle /errorlimit early, because error() depends on it. if (auto *Arg = Args.getLastArg(OPT_errorlimit)) { int N = 20; StringRef S = Arg->getValue(); if (S.getAsInteger(10, N)) error(Arg->getSpelling() + " number expected, but got " + S); Config->ErrorLimit = N; } // Handle /help if (Args.hasArg(OPT_help)) { printHelp(ArgsArr[0]); return; } if (auto *Arg = Args.getLastArg(OPT_linkrepro)) { SmallString<64> Path = StringRef(Arg->getValue()); sys::path::append(Path, "repro.tar"); Expected> ErrOrWriter = TarWriter::create(Path, "repro"); if (ErrOrWriter) { Tar = std::move(*ErrOrWriter); } else { error("/linkrepro: failed to open " + Path + ": " + toString(ErrOrWriter.takeError())); } } if (!Args.hasArgNoClaim(OPT_INPUT)) fatal("no input files"); // Construct search path list. SearchPaths.push_back(""); for (auto *Arg : Args.filtered(OPT_libpath)) SearchPaths.push_back(Arg->getValue()); addLibSearchPaths(); // Handle /out if (auto *Arg = Args.getLastArg(OPT_out)) Config->OutputFile = Arg->getValue(); // Handle /verbose if (Args.hasArg(OPT_verbose)) Config->Verbose = true; // Handle /force or /force:unresolved if (Args.hasArg(OPT_force) || Args.hasArg(OPT_force_unresolved)) Config->Force = true; // Handle /debug if (Args.hasArg(OPT_debug)) { Config->Debug = true; Config->DebugTypes = Args.hasArg(OPT_debugtype) ? parseDebugType(Args.getLastArg(OPT_debugtype)->getValue()) : getDefaultDebugType(Args); } // Create a dummy PDB file to satisfy build sytem rules. if (auto *Arg = Args.getLastArg(OPT_pdb)) Config->PDBPath = Arg->getValue(); // Handle /noentry if (Args.hasArg(OPT_noentry)) { if (Args.hasArg(OPT_dll)) Config->NoEntry = true; else error("/noentry must be specified with /dll"); } // Handle /dll if (Args.hasArg(OPT_dll)) { Config->DLL = true; Config->ManifestID = 2; } // Handle /fixed if (Args.hasArg(OPT_fixed)) { if (Args.hasArg(OPT_dynamicbase)) { error("/fixed must not be specified with /dynamicbase"); } else { Config->Relocatable = false; Config->DynamicBase = false; } } if (Args.hasArg(OPT_appcontainer)) Config->AppContainer = true; // Handle /machine if (auto *Arg = Args.getLastArg(OPT_machine)) Config->Machine = getMachineType(Arg->getValue()); // Handle /nodefaultlib: for (auto *Arg : Args.filtered(OPT_nodefaultlib)) Config->NoDefaultLibs.insert(doFindLib(Arg->getValue())); // Handle /nodefaultlib if (Args.hasArg(OPT_nodefaultlib_all)) Config->NoDefaultLibAll = true; // Handle /base if (auto *Arg = Args.getLastArg(OPT_base)) parseNumbers(Arg->getValue(), &Config->ImageBase); // Handle /stack if (auto *Arg = Args.getLastArg(OPT_stack)) parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit); // Handle /heap if (auto *Arg = Args.getLastArg(OPT_heap)) parseNumbers(Arg->getValue(), &Config->HeapReserve, &Config->HeapCommit); // Handle /version if (auto *Arg = Args.getLastArg(OPT_version)) parseVersion(Arg->getValue(), &Config->MajorImageVersion, &Config->MinorImageVersion); // Handle /subsystem if (auto *Arg = Args.getLastArg(OPT_subsystem)) parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion, &Config->MinorOSVersion); // Handle /alternatename for (auto *Arg : Args.filtered(OPT_alternatename)) parseAlternateName(Arg->getValue()); // Handle /include for (auto *Arg : Args.filtered(OPT_incl)) addUndefined(Arg->getValue()); // Handle /implib if (auto *Arg = Args.getLastArg(OPT_implib)) Config->Implib = Arg->getValue(); // Handle /opt for (auto *Arg : Args.filtered(OPT_opt)) { std::string Str = StringRef(Arg->getValue()).lower(); SmallVector Vec; StringRef(Str).split(Vec, ','); for (StringRef S : Vec) { if (S == "noref") { Config->DoGC = false; Config->DoICF = false; continue; } if (S == "icf" || StringRef(S).startswith("icf=")) { Config->DoICF = true; continue; } if (S == "noicf") { Config->DoICF = false; continue; } if (StringRef(S).startswith("lldlto=")) { StringRef OptLevel = StringRef(S).substr(7); if (OptLevel.getAsInteger(10, Config->LTOOptLevel) || Config->LTOOptLevel > 3) error("/opt:lldlto: invalid optimization level: " + OptLevel); continue; } if (StringRef(S).startswith("lldltojobs=")) { StringRef Jobs = StringRef(S).substr(11); if (Jobs.getAsInteger(10, Config->LTOJobs) || Config->LTOJobs == 0) error("/opt:lldltojobs: invalid job count: " + Jobs); continue; } if (StringRef(S).startswith("lldltopartitions=")) { StringRef N = StringRef(S).substr(17); if (N.getAsInteger(10, Config->LTOPartitions) || Config->LTOPartitions == 0) error("/opt:lldltopartitions: invalid partition count: " + N); continue; } if (S != "ref" && S != "lbr" && S != "nolbr") error("/opt: unknown option: " + S); } } // Handle /lldsavetemps if (Args.hasArg(OPT_lldsavetemps)) Config->SaveTemps = true; // Handle /failifmismatch for (auto *Arg : Args.filtered(OPT_failifmismatch)) checkFailIfMismatch(Arg->getValue()); // Handle /merge for (auto *Arg : Args.filtered(OPT_merge)) parseMerge(Arg->getValue()); // Handle /section for (auto *Arg : Args.filtered(OPT_section)) parseSection(Arg->getValue()); // Handle /manifest if (auto *Arg = Args.getLastArg(OPT_manifest_colon)) parseManifest(Arg->getValue()); // Handle /manifestuac if (auto *Arg = Args.getLastArg(OPT_manifestuac)) parseManifestUAC(Arg->getValue()); // Handle /manifestdependency if (auto *Arg = Args.getLastArg(OPT_manifestdependency)) Config->ManifestDependency = Arg->getValue(); // Handle /manifestfile if (auto *Arg = Args.getLastArg(OPT_manifestfile)) Config->ManifestFile = Arg->getValue(); // Handle /manifestinput for (auto *Arg : Args.filtered(OPT_manifestinput)) Config->ManifestInput.push_back(Arg->getValue()); // Handle miscellaneous boolean flags. if (Args.hasArg(OPT_allowisolation_no)) Config->AllowIsolation = false; if (Args.hasArg(OPT_dynamicbase_no)) Config->DynamicBase = false; if (Args.hasArg(OPT_nxcompat_no)) Config->NxCompat = false; if (Args.hasArg(OPT_tsaware_no)) Config->TerminalServerAware = false; if (Args.hasArg(OPT_nosymtab)) Config->WriteSymtab = false; Config->DumpPdb = Args.hasArg(OPT_dumppdb); Config->MapFile = getMapFile(Args); if (ErrorCount) return; // Create a list of input files. Files can be given as arguments // for /defaultlib option. std::vector MBs; for (auto *Arg : Args.filtered(OPT_INPUT)) if (Optional Path = findFile(Arg->getValue())) enqueuePath(*Path); for (auto *Arg : Args.filtered(OPT_defaultlib)) if (Optional Path = findLib(Arg->getValue())) enqueuePath(*Path); // Windows specific -- Create a resource file containing a manifest file. if (Config->Manifest == Configuration::Embed) addBuffer(createManifestRes()); // Read all input files given via the command line. run(); // We should have inferred a machine type by now from the input files, but if // not we assume x64. if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) { warn("/machine is not specified. x64 is assumed"); Config->Machine = AMD64; } // Windows specific -- Input files can be Windows resource files (.res files). // We invoke cvtres.exe to convert resource files to a regular COFF file // then link the result file normally. if (!Resources.empty()) addBuffer(convertResToCOFF(Resources)); if (Tar) Tar->append("response.txt", createResponseFile(Args, FilePaths, ArrayRef(SearchPaths).slice(1))); // Handle /largeaddressaware if (Config->is64() || Args.hasArg(OPT_largeaddressaware)) Config->LargeAddressAware = true; // Handle /highentropyva if (Config->is64() && !Args.hasArg(OPT_highentropyva_no)) Config->HighEntropyVA = true; // Handle /entry and /dll if (auto *Arg = Args.getLastArg(OPT_entry)) { Config->Entry = addUndefined(mangle(Arg->getValue())); } else if (Args.hasArg(OPT_dll) && !Config->NoEntry) { StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup@12" : "_DllMainCRTStartup"; Config->Entry = addUndefined(S); } else if (!Config->NoEntry) { // Windows specific -- If entry point name is not given, we need to // infer that from user-defined entry name. StringRef S = findDefaultEntry(); if (S.empty()) fatal("entry point must be defined"); Config->Entry = addUndefined(S); log("Entry name inferred: " + S); } // Handle /export for (auto *Arg : Args.filtered(OPT_export)) { Export E = parseExport(Arg->getValue()); if (Config->Machine == I386) { if (!isDecorated(E.Name)) E.Name = Saver.save("_" + E.Name); if (!E.ExtName.empty() && !isDecorated(E.ExtName)) E.ExtName = Saver.save("_" + E.ExtName); } Config->Exports.push_back(E); } // Handle /def if (auto *Arg = Args.getLastArg(OPT_deffile)) { // parseModuleDefs mutates Config object. parseModuleDefs(Arg->getValue()); } // Handle /delayload for (auto *Arg : Args.filtered(OPT_delayload)) { Config->DelayLoads.insert(StringRef(Arg->getValue()).lower()); if (Config->Machine == I386) { Config->DelayLoadHelper = addUndefined("___delayLoadHelper2@8"); } else { Config->DelayLoadHelper = addUndefined("__delayLoadHelper2"); } } // Set default image name if neither /out or /def set it. if (Config->OutputFile.empty()) { Config->OutputFile = getOutputPath((*Args.filtered(OPT_INPUT).begin())->getValue()); } // Put the PDB next to the image if no /pdb flag was passed. if (Config->Debug && Config->PDBPath.empty()) { Config->PDBPath = Config->OutputFile; sys::path::replace_extension(Config->PDBPath, ".pdb"); } // Disable PDB generation if the user requested it. if (Args.hasArg(OPT_nopdb)) Config->PDBPath = ""; // Set default image base if /base is not given. if (Config->ImageBase == uint64_t(-1)) Config->ImageBase = getDefaultImageBase(); Symtab.addRelative(mangle("__ImageBase"), 0); if (Config->Machine == I386) { Config->SEHTable = Symtab.addRelative("___safe_se_handler_table", 0); Config->SEHCount = Symtab.addAbsolute("___safe_se_handler_count", 0); } // We do not support /guard:cf (control flow protection) yet. // Define CFG symbols anyway so that we can link MSVC 2015 CRT. Symtab.addAbsolute(mangle("__guard_fids_table"), 0); Symtab.addAbsolute(mangle("__guard_fids_count"), 0); Symtab.addAbsolute(mangle("__guard_flags"), 0x100); // This code may add new undefined symbols to the link, which may enqueue more // symbol resolution tasks, so we need to continue executing tasks until we // converge. do { // Windows specific -- if entry point is not found, // search for its mangled names. if (Config->Entry) Symtab.mangleMaybe(Config->Entry); // Windows specific -- Make sure we resolve all dllexported symbols. for (Export &E : Config->Exports) { if (!E.ForwardTo.empty()) continue; E.Sym = addUndefined(E.Name); if (!E.Directives) Symtab.mangleMaybe(E.Sym); } // Add weak aliases. Weak aliases is a mechanism to give remaining // undefined symbols final chance to be resolved successfully. for (auto Pair : Config->AlternateNames) { StringRef From = Pair.first; StringRef To = Pair.second; Symbol *Sym = Symtab.find(From); if (!Sym) continue; if (auto *U = dyn_cast(Sym->body())) if (!U->WeakAlias) U->WeakAlias = Symtab.addUndefined(To); } // Windows specific -- if __load_config_used can be resolved, resolve it. if (Symtab.findUnderscore("_load_config_used")) addUndefined(mangle("_load_config_used")); } while (run()); if (ErrorCount) return; // If /msvclto is given, we use the MSVC linker to link LTO output files. // This is useful because MSVC link.exe can generate complete PDBs. if (Args.hasArg(OPT_msvclto)) { invokeMSVC(Args); exit(0); } // Do LTO by compiling bitcode input files to a set of native COFF files then // link those files. Symtab.addCombinedLTOObjects(); run(); // Make sure we have resolved all symbols. Symtab.reportRemainingUndefines(); // Windows specific -- if no /subsystem is given, we need to infer // that from entry point name. if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) { Config->Subsystem = inferSubsystem(); if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) fatal("subsystem must be defined"); } // Handle /safeseh. if (Args.hasArg(OPT_safeseh)) { for (ObjectFile *File : Symtab.ObjectFiles) if (!File->SEHCompat) error("/safeseh: " + File->getName() + " is not compatible with SEH"); if (ErrorCount) return; } // Windows specific -- when we are creating a .dll file, we also // need to create a .lib file. if (!Config->Exports.empty() || Config->DLL) { fixupExports(); createImportLibrary(); assignExportOrdinals(); } // Windows specific -- Create a side-by-side manifest file. if (Config->Manifest == Configuration::SideBySide) createSideBySideManifest(); // Identify unreferenced COMDAT sections. if (Config->DoGC) markLive(Symtab.getChunks()); // Identify identical COMDAT sections to merge them. if (Config->DoICF) doICF(Symtab.getChunks()); // Write the result. writeResult(&Symtab); // Call exit to avoid calling destructors. exit(0); } } // namespace coff } // namespace lld Index: vendor/lld/dist/COFF/PDB.cpp =================================================================== --- vendor/lld/dist/COFF/PDB.cpp (revision 319530) +++ vendor/lld/dist/COFF/PDB.cpp (revision 319531) @@ -1,232 +1,233 @@ //===- PDB.cpp ------------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "PDB.h" #include "Chunks.h" #include "Config.h" #include "Error.h" #include "SymbolTable.h" #include "Symbols.h" #include "llvm/DebugInfo/CodeView/CVDebugRecord.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" #include "llvm/DebugInfo/CodeView/SymbolDumper.h" #include "llvm/DebugInfo/CodeView/TypeDatabase.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" #include "llvm/Object/COFF.h" #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/Endian.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/ScopedPrinter.h" #include using namespace lld; using namespace lld::coff; using namespace llvm; using namespace llvm::codeview; using namespace llvm::support; using namespace llvm::support::endian; using llvm::object::coff_section; static ExitOnError ExitOnErr; // Returns a list of all SectionChunks. static std::vector getInputSections(SymbolTable *Symtab) { std::vector V; for (Chunk *C : Symtab->getChunks()) if (auto *SC = dyn_cast(C)) V.push_back(*SC->Header); return V; } static SectionChunk *findByName(std::vector &Sections, StringRef Name) { for (SectionChunk *C : Sections) if (C->getSectionName() == Name) return C; return nullptr; } static ArrayRef getDebugSection(ObjectFile *File, StringRef SecName) { SectionChunk *Sec = findByName(File->getDebugChunks(), SecName); if (!Sec) return {}; // First 4 bytes are section magic. ArrayRef Data = Sec->getContents(); if (Data.size() < 4) fatal(SecName + " too short"); if (read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC) fatal(SecName + " has an invalid magic"); return Data.slice(4); } static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder, codeview::TypeTableBuilder &TypeTable) { // Start the TPI or IPI stream header. TpiBuilder.setVersionHeader(pdb::PdbTpiV80); // Flatten the in memory type table. TypeTable.ForEachRecord([&](TypeIndex TI, ArrayRef Rec) { // FIXME: Hash types. TpiBuilder.addTypeRecord(Rec, None); }); } // Merge .debug$T sections into IpiData and TpiData. static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder, codeview::TypeTableBuilder &TypeTable, codeview::TypeTableBuilder &IDTable) { // Follow type servers. If the same type server is encountered more than // once for this instance of `PDBTypeServerHandler` (for example if many // object files reference the same TypeServer), the types from the // TypeServer will only be visited once. pdb::PDBTypeServerHandler Handler; // Visit all .debug$T sections to add them to Builder. for (ObjectFile *File : Symtab->ObjectFiles) { ArrayRef Data = getDebugSection(File, ".debug$T"); if (Data.empty()) continue; BinaryByteStream Stream(Data, support::little); codeview::CVTypeArray Types; BinaryStreamReader Reader(Stream); SmallVector SourceToDest; Handler.addSearchPath(llvm::sys::path::parent_path(File->getName())); if (auto EC = Reader.readArray(Types, Reader.getLength())) fatal(EC, "Reader::readArray failed"); if (auto Err = codeview::mergeTypeAndIdRecords( IDTable, TypeTable, SourceToDest, &Handler, Types)) fatal(Err, "codeview::mergeTypeStreams failed"); } // Construct TPI stream contents. addTypeInfo(Builder.getTpiBuilder(), TypeTable); // Construct IPI stream contents. addTypeInfo(Builder.getIpiBuilder(), IDTable); } static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) { ListScope LS(W, "DebugT"); ArrayRef Data = getDebugSection(File, ".debug$T"); if (Data.empty()) return; LazyRandomTypeCollection Types(Data, 100); TypeDumpVisitor TDV(Types, &W, false); // Use a default implementation that does not follow type servers and instead // just dumps the contents of the TypeServer2 record. if (auto EC = codeview::visitTypeStream(Types, TDV)) fatal(EC, "CVTypeDumper::dump failed"); } static void dumpDebugS(ScopedPrinter &W, ObjectFile *File) { ListScope LS(W, "DebugS"); ArrayRef Data = getDebugSection(File, ".debug$S"); if (Data.empty()) return; BinaryByteStream Stream(Data, llvm::support::little); CVSymbolArray Symbols; BinaryStreamReader Reader(Stream); if (auto EC = Reader.readArray(Symbols, Reader.getLength())) fatal(EC, "StreamReader.readArray failed"); TypeDatabase TDB(0); - CVSymbolDumper SymbolDumper(W, TDB, nullptr, false); + CVSymbolDumper SymbolDumper(W, TDB, CodeViewContainer::ObjectFile, nullptr, + false); if (auto EC = SymbolDumper.dump(Symbols)) fatal(EC, "CVSymbolDumper::dump failed"); } // Dump CodeView debug info. This is for debugging. static void dumpCodeView(SymbolTable *Symtab) { ScopedPrinter W(outs()); for (ObjectFile *File : Symtab->ObjectFiles) { dumpDebugT(W, File); dumpDebugS(W, File); } } // Creates a PDB file. void coff::createPDB(StringRef Path, SymbolTable *Symtab, ArrayRef SectionTable, const llvm::codeview::DebugInfo *DI) { if (Config->DumpPdb) dumpCodeView(Symtab); BumpPtrAllocator Alloc; pdb::PDBFileBuilder Builder(Alloc); ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize // Create streams in MSF for predefined streams, namely // PDB, TPI, DBI and IPI. for (int I = 0; I < (int)pdb::kSpecialStreamCount; ++I) ExitOnErr(Builder.getMsfBuilder().addStream(0)); // Add an Info stream. auto &InfoBuilder = Builder.getInfoBuilder(); InfoBuilder.setAge(DI ? DI->PDB70.Age : 0); pdb::PDB_UniqueId uuid{}; if (DI) memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid)); InfoBuilder.setGuid(uuid); // Should be the current time, but set 0 for reproducibilty. InfoBuilder.setSignature(0); InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70); // Add an empty DPI stream. auto &DbiBuilder = Builder.getDbiBuilder(); DbiBuilder.setVersionHeader(pdb::PdbDbiV110); codeview::TypeTableBuilder TypeTable(BAlloc); codeview::TypeTableBuilder IDTable(BAlloc); mergeDebugT(Symtab, Builder, TypeTable, IDTable); // Add Section Contributions. std::vector Contribs = pdb::DbiStreamBuilder::createSectionContribs(getInputSections(Symtab)); DbiBuilder.setSectionContribs(Contribs); // Add Section Map stream. ArrayRef Sections = { (const object::coff_section *)SectionTable.data(), SectionTable.size() / sizeof(object::coff_section)}; std::vector SectionMap = pdb::DbiStreamBuilder::createSectionMap(Sections); DbiBuilder.setSectionMap(SectionMap); ExitOnErr(DbiBuilder.addModuleInfo("* Linker *")); // Add COFF section header stream. ExitOnErr( DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable)); // Write to a file. ExitOnErr(Builder.commit(Path)); } Index: vendor/lld/dist/ELF/LinkerScript.cpp =================================================================== --- vendor/lld/dist/ELF/LinkerScript.cpp (revision 319530) +++ vendor/lld/dist/ELF/LinkerScript.cpp (revision 319531) @@ -1,1208 +1,1203 @@ //===- LinkerScript.cpp ---------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains the parser/evaluator of the linker script. // //===----------------------------------------------------------------------===// #include "LinkerScript.h" #include "Config.h" #include "InputSection.h" #include "Memory.h" #include "OutputSections.h" #include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Threads.h" #include "Writer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compression.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include #include #include #include #include #include #include #include using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; LinkerScript *elf::Script; uint64_t ExprValue::getValue() const { if (Sec) { if (OutputSection *OS = Sec->getOutputSection()) return alignTo(Sec->getOffset(Val) + OS->Addr, Alignment); error("unable to evaluate expression: input section " + Sec->Name + " has no output section assigned"); } return alignTo(Val, Alignment); } uint64_t ExprValue::getSecAddr() const { if (Sec) return Sec->getOffset(0) + Sec->getOutputSection()->Addr; return 0; } template static SymbolBody *addRegular(SymbolAssignment *Cmd) { Symbol *Sym; uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; std::tie(Sym, std::ignore) = Symtab::X->insert( Cmd->Name, /*Type*/ 0, Visibility, /*CanOmitFromDynSym*/ false, /*File*/ nullptr); Sym->Binding = STB_GLOBAL; ExprValue Value = Cmd->Expression(); SectionBase *Sec = Value.isAbsolute() ? nullptr : Value.Sec; // We want to set symbol values early if we can. This allows us to use symbols // as variables in linker scripts. Doing so allows us to write expressions // like this: `alignment = 16; . = ALIGN(., alignment)` uint64_t SymValue = Value.isAbsolute() ? Value.getValue() : 0; replaceBody(Sym, Cmd->Name, /*IsLocal=*/false, Visibility, STT_NOTYPE, SymValue, 0, Sec, nullptr); return Sym->body(); } OutputSectionCommand * LinkerScript::createOutputSectionCommand(StringRef Name, StringRef Location) { OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name]; OutputSectionCommand *Cmd; if (CmdRef && CmdRef->Location.empty()) { // There was a forward reference. Cmd = CmdRef; } else { Cmd = make(Name); if (!CmdRef) CmdRef = Cmd; } Cmd->Location = Location; return Cmd; } OutputSectionCommand * LinkerScript::getOrCreateOutputSectionCommand(StringRef Name) { OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name]; if (!CmdRef) CmdRef = make(Name); return CmdRef; } void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) { uint64_t Val = E().getValue(); if (Val < Dot) { if (InSec) error(Loc + ": unable to move location counter backward for: " + CurOutSec->Name); else error(Loc + ": unable to move location counter backward"); } Dot = Val; // Update to location counter means update to section size. if (InSec) CurOutSec->Size = Dot - CurOutSec->Addr; } // Sets value of a symbol. Two kinds of symbols are processed: synthetic // symbols, whose value is an offset from beginning of section and regular // symbols whose value is absolute. void LinkerScript::assignSymbol(SymbolAssignment *Cmd, bool InSec) { if (Cmd->Name == ".") { setDot(Cmd->Expression, Cmd->Location, InSec); return; } if (!Cmd->Sym) return; auto *Sym = cast(Cmd->Sym); ExprValue V = Cmd->Expression(); if (V.isAbsolute()) { Sym->Value = V.getValue(); } else { Sym->Section = V.Sec; if (Sym->Section->Flags & SHF_ALLOC) Sym->Value = alignTo(V.Val, V.Alignment); else Sym->Value = V.getValue(); } } static SymbolBody *findSymbol(StringRef S) { switch (Config->EKind) { case ELF32LEKind: return Symtab::X->find(S); case ELF32BEKind: return Symtab::X->find(S); case ELF64LEKind: return Symtab::X->find(S); case ELF64BEKind: return Symtab::X->find(S); default: llvm_unreachable("unknown Config->EKind"); } } static SymbolBody *addRegularSymbol(SymbolAssignment *Cmd) { switch (Config->EKind) { case ELF32LEKind: return addRegular(Cmd); case ELF32BEKind: return addRegular(Cmd); case ELF64LEKind: return addRegular(Cmd); case ELF64BEKind: return addRegular(Cmd); default: llvm_unreachable("unknown Config->EKind"); } } void LinkerScript::addSymbol(SymbolAssignment *Cmd) { if (Cmd->Name == ".") return; // If a symbol was in PROVIDE(), we need to define it only when // it is a referenced undefined symbol. SymbolBody *B = findSymbol(Cmd->Name); if (Cmd->Provide && (!B || B->isDefined())) return; Cmd->Sym = addRegularSymbol(Cmd); } bool SymbolAssignment::classof(const BaseCommand *C) { return C->Kind == AssignmentKind; } bool OutputSectionCommand::classof(const BaseCommand *C) { return C->Kind == OutputSectionKind; } // Fill [Buf, Buf + Size) with Filler. // This is used for linker script "=fillexp" command. static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) { size_t I = 0; for (; I + 4 < Size; I += 4) memcpy(Buf + I, &Filler, 4); memcpy(Buf + I, &Filler, Size - I); } bool InputSectionDescription::classof(const BaseCommand *C) { return C->Kind == InputSectionKind; } bool AssertCommand::classof(const BaseCommand *C) { return C->Kind == AssertKind; } bool BytesDataCommand::classof(const BaseCommand *C) { return C->Kind == BytesDataKind; } static StringRef basename(InputSectionBase *S) { if (S->File) return sys::path::filename(S->File->getName()); return ""; } bool LinkerScript::shouldKeep(InputSectionBase *S) { for (InputSectionDescription *ID : Opt.KeptSections) if (ID->FilePat.match(basename(S))) for (SectionPattern &P : ID->SectionPatterns) if (P.SectionPat.match(S->Name)) return true; return false; } // A helper function for the SORT() command. static std::function getComparator(SortSectionPolicy K) { switch (K) { case SortSectionPolicy::Alignment: return [](InputSectionBase *A, InputSectionBase *B) { // ">" is not a mistake. Sections with larger alignments are placed // before sections with smaller alignments in order to reduce the // amount of padding necessary. This is compatible with GNU. return A->Alignment > B->Alignment; }; case SortSectionPolicy::Name: return [](InputSectionBase *A, InputSectionBase *B) { return A->Name < B->Name; }; case SortSectionPolicy::Priority: return [](InputSectionBase *A, InputSectionBase *B) { return getPriority(A->Name) < getPriority(B->Name); }; default: llvm_unreachable("unknown sort policy"); } } // A helper function for the SORT() command. static bool matchConstraints(ArrayRef Sections, ConstraintKind Kind) { if (Kind == ConstraintKind::NoConstraint) return true; bool IsRW = llvm::any_of(Sections, [](InputSectionBase *Sec) { return static_cast(Sec)->Flags & SHF_WRITE; }); return (IsRW && Kind == ConstraintKind::ReadWrite) || (!IsRW && Kind == ConstraintKind::ReadOnly); } static void sortSections(InputSection **Begin, InputSection **End, SortSectionPolicy K) { if (K != SortSectionPolicy::Default && K != SortSectionPolicy::None) std::stable_sort(Begin, End, getComparator(K)); } // Compute and remember which sections the InputSectionDescription matches. std::vector LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { std::vector Ret; // Collects all sections that satisfy constraints of Cmd. for (const SectionPattern &Pat : Cmd->SectionPatterns) { size_t SizeBefore = Ret.size(); for (InputSectionBase *Sec : InputSections) { if (Sec->Assigned) continue; if (!Sec->Live) { reportDiscarded(Sec); continue; } // For -emit-relocs we have to ignore entries like // .rela.dyn : { *(.rela.data) } // which are common because they are in the default bfd script. if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) continue; StringRef Filename = basename(Sec); if (!Cmd->FilePat.match(Filename) || Pat.ExcludedFilePat.match(Filename) || !Pat.SectionPat.match(Sec->Name)) continue; Ret.push_back(cast(Sec)); Sec->Assigned = true; } // Sort sections as instructed by SORT-family commands and --sort-section // option. Because SORT-family commands can be nested at most two depth // (e.g. SORT_BY_NAME(SORT_BY_ALIGNMENT(.text.*))) and because the command // line option is respected even if a SORT command is given, the exact // behavior we have here is a bit complicated. Here are the rules. // // 1. If two SORT commands are given, --sort-section is ignored. // 2. If one SORT command is given, and if it is not SORT_NONE, // --sort-section is handled as an inner SORT command. // 3. If one SORT command is given, and if it is SORT_NONE, don't sort. // 4. If no SORT command is given, sort according to --sort-section. InputSection **Begin = Ret.data() + SizeBefore; InputSection **End = Ret.data() + Ret.size(); if (Pat.SortOuter != SortSectionPolicy::None) { if (Pat.SortInner == SortSectionPolicy::Default) sortSections(Begin, End, Config->SortSection); else sortSections(Begin, End, Pat.SortInner); sortSections(Begin, End, Pat.SortOuter); } } return Ret; } void LinkerScript::discard(ArrayRef V) { for (InputSectionBase *S : V) { S->Live = false; if (S == InX::ShStrTab) error("discarding .shstrtab section is not allowed"); discard(S->DependentSections); } } std::vector LinkerScript::createInputSectionList(OutputSectionCommand &OutCmd) { std::vector Ret; for (BaseCommand *Base : OutCmd.Commands) { auto *Cmd = dyn_cast(Base); if (!Cmd) continue; Cmd->Sections = computeInputSections(Cmd); Ret.insert(Ret.end(), Cmd->Sections.begin(), Cmd->Sections.end()); } return Ret; } void LinkerScript::processCommands(OutputSectionFactory &Factory) { // A symbol can be assigned before any section is mentioned in the linker // script. In an DSO, the symbol values are addresses, so the only important // section values are: // * SHN_UNDEF // * SHN_ABS // * Any value meaning a regular section. // To handle that, create a dummy aether section that fills the void before // the linker scripts switches to another section. It has an index of one // which will map to whatever the first actual section is. Aether = make("", 0, SHF_ALLOC); Aether->SectionIndex = 1; CurOutSec = Aether; Dot = 0; for (size_t I = 0; I < Opt.Commands.size(); ++I) { // Handle symbol assignments outside of any output section. if (auto *Cmd = dyn_cast(Opt.Commands[I])) { addSymbol(Cmd); continue; } if (auto *Cmd = dyn_cast(Opt.Commands[I])) { std::vector V = createInputSectionList(*Cmd); // The output section name `/DISCARD/' is special. // Any input section assigned to it is discarded. if (Cmd->Name == "/DISCARD/") { discard(V); continue; } // This is for ONLY_IF_RO and ONLY_IF_RW. An output section directive // ".foo : ONLY_IF_R[OW] { ... }" is handled only if all member input // sections satisfy a given constraint. If not, a directive is handled // as if it wasn't present from the beginning. // // Because we'll iterate over Commands many more times, the easiest // way to "make it as if it wasn't present" is to just remove it. if (!matchConstraints(V, Cmd->Constraint)) { for (InputSectionBase *S : V) S->Assigned = false; Opt.Commands.erase(Opt.Commands.begin() + I); --I; continue; } // A directive may contain symbol definitions like this: // ".foo : { ...; bar = .; }". Handle them. for (BaseCommand *Base : Cmd->Commands) if (auto *OutCmd = dyn_cast(Base)) addSymbol(OutCmd); // Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign // is given, input sections are aligned to that value, whether the // given value is larger or smaller than the original section alignment. if (Cmd->SubalignExpr) { uint32_t Subalign = Cmd->SubalignExpr().getValue(); for (InputSectionBase *S : V) S->Alignment = Subalign; } // Add input sections to an output section. for (InputSectionBase *S : V) Factory.addInputSec(S, Cmd->Name, Cmd->Sec); if (OutputSection *Sec = Cmd->Sec) { assert(Sec->SectionIndex == INT_MAX); Sec->SectionIndex = I; SecToCommand[Sec] = Cmd; } } } CurOutSec = nullptr; } void LinkerScript::fabricateDefaultCommands() { std::vector Commands; // Define start address uint64_t StartAddr = Config->ImageBase + elf::getHeaderSize(); // The Sections with -T
have been sorted in order of ascending // address. We must lower StartAddr if the lowest -T
as // calls to setDot() must be monotonically increasing. for (auto& KV : Config->SectionStartMap) StartAddr = std::min(StartAddr, KV.second); Commands.push_back( make(".", [=] { return StartAddr; }, "")); // For each OutputSection that needs a VA fabricate an OutputSectionCommand // with an InputSectionDescription describing the InputSections for (OutputSection *Sec : *OutputSections) { auto *OSCmd = createOutputSectionCommand(Sec->Name, ""); OSCmd->Sec = Sec; SecToCommand[Sec] = OSCmd; // Prefer user supplied address over additional alignment constraint auto I = Config->SectionStartMap.find(Sec->Name); if (I != Config->SectionStartMap.end()) - Commands.push_back( - make(".", [=] { return I->second; }, "")); - else if (Sec->PageAlign) - OSCmd->AddrExpr = [=] { - return alignTo(Script->getDot(), Config->MaxPageSize); - }; + OSCmd->AddrExpr = [=] { return I->second; }; Commands.push_back(OSCmd); if (Sec->Sections.size()) { auto *ISD = make(""); OSCmd->Commands.push_back(ISD); for (InputSection *ISec : Sec->Sections) { ISD->Sections.push_back(ISec); ISec->Assigned = true; } } } // SECTIONS commands run before other non SECTIONS commands Commands.insert(Commands.end(), Opt.Commands.begin(), Opt.Commands.end()); Opt.Commands = std::move(Commands); } // Add sections that didn't match any sections command. void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) { for (InputSectionBase *S : InputSections) { if (!S->Live || S->Parent) continue; StringRef Name = getOutputSectionName(S->Name); auto I = std::find_if( Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) { if (auto *Cmd = dyn_cast(Base)) return Cmd->Name == Name; return false; }); if (I == Opt.Commands.end()) { Factory.addInputSec(S, Name); } else { auto *Cmd = cast(*I); Factory.addInputSec(S, Name, Cmd->Sec); if (OutputSection *Sec = Cmd->Sec) { SecToCommand[Sec] = Cmd; unsigned Index = std::distance(Opt.Commands.begin(), I); assert(Sec->SectionIndex == INT_MAX || Sec->SectionIndex == Index); Sec->SectionIndex = Index; } auto *ISD = make(""); ISD->Sections.push_back(cast(S)); Cmd->Commands.push_back(ISD); } } } uint64_t LinkerScript::advance(uint64_t Size, unsigned Align) { bool IsTbss = (CurOutSec->Flags & SHF_TLS) && CurOutSec->Type == SHT_NOBITS; uint64_t Start = IsTbss ? Dot + ThreadBssOffset : Dot; Start = alignTo(Start, Align); uint64_t End = Start + Size; if (IsTbss) ThreadBssOffset = End - Dot; else Dot = End; return End; } void LinkerScript::output(InputSection *S) { uint64_t Pos = advance(S->getSize(), S->Alignment); S->OutSecOff = Pos - S->getSize() - CurOutSec->Addr; // Update output section size after adding each section. This is so that // SIZEOF works correctly in the case below: // .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) } CurOutSec->Size = Pos - CurOutSec->Addr; // If there is a memory region associated with this input section, then // place the section in that region and update the region index. if (CurMemRegion) { CurMemRegion->Offset += CurOutSec->Size; uint64_t CurSize = CurMemRegion->Offset - CurMemRegion->Origin; if (CurSize > CurMemRegion->Length) { uint64_t OverflowAmt = CurSize - CurMemRegion->Length; error("section '" + CurOutSec->Name + "' will not fit in region '" + CurMemRegion->Name + "': overflowed by " + Twine(OverflowAmt) + " bytes"); } } } void LinkerScript::switchTo(OutputSection *Sec) { if (CurOutSec == Sec) return; CurOutSec = Sec; CurOutSec->Addr = advance(0, CurOutSec->Alignment); // If neither AT nor AT> is specified for an allocatable section, the linker // will set the LMA such that the difference between VMA and LMA for the // section is the same as the preceding output section in the same region // https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html if (LMAOffset) CurOutSec->LMAOffset = LMAOffset(); } void LinkerScript::process(BaseCommand &Base) { // This handles the assignments to symbol or to the dot. if (auto *Cmd = dyn_cast(&Base)) { assignSymbol(Cmd, true); return; } // Handle BYTE(), SHORT(), LONG(), or QUAD(). if (auto *Cmd = dyn_cast(&Base)) { Cmd->Offset = Dot - CurOutSec->Addr; Dot += Cmd->Size; CurOutSec->Size = Dot - CurOutSec->Addr; return; } // Handle ASSERT(). if (auto *Cmd = dyn_cast(&Base)) { Cmd->Expression(); return; } // Handle a single input section description command. // It calculates and assigns the offsets for each section and also // updates the output section size. auto &Cmd = cast(Base); for (InputSection *Sec : Cmd.Sections) { // We tentatively added all synthetic sections at the beginning and removed // empty ones afterwards (because there is no way to know whether they were // going be empty or not other than actually running linker scripts.) // We need to ignore remains of empty sections. if (auto *S = dyn_cast(Sec)) if (S->empty()) continue; if (!Sec->Live) continue; assert(CurOutSec == Sec->getParent()); output(Sec); } } // This function searches for a memory region to place the given output // section in. If found, a pointer to the appropriate memory region is // returned. Otherwise, a nullptr is returned. MemoryRegion *LinkerScript::findMemoryRegion(OutputSectionCommand *Cmd) { // If a memory region name was specified in the output section command, // then try to find that region first. if (!Cmd->MemoryRegionName.empty()) { auto It = Opt.MemoryRegions.find(Cmd->MemoryRegionName); if (It != Opt.MemoryRegions.end()) return &It->second; error("memory region '" + Cmd->MemoryRegionName + "' not declared"); return nullptr; } // If at least one memory region is defined, all sections must // belong to some memory region. Otherwise, we don't need to do // anything for memory regions. if (Opt.MemoryRegions.empty()) return nullptr; OutputSection *Sec = Cmd->Sec; // See if a region can be found by matching section flags. for (auto &Pair : Opt.MemoryRegions) { MemoryRegion &M = Pair.second; if ((M.Flags & Sec->Flags) && (M.NegFlags & Sec->Flags) == 0) return &M; } // Otherwise, no suitable region was found. if (Sec->Flags & SHF_ALLOC) error("no memory region specified for section '" + Sec->Name + "'"); return nullptr; } // This function assigns offsets to input sections and an output section // for a single sections command (e.g. ".text { *(.text); }"). void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) { OutputSection *Sec = Cmd->Sec; if (!Sec) return; if (Cmd->AddrExpr && (Sec->Flags & SHF_ALLOC)) setDot(Cmd->AddrExpr, Cmd->Location, false); if (Cmd->LMAExpr) { uint64_t D = Dot; LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; }; } CurMemRegion = Cmd->MemRegion; if (CurMemRegion) Dot = CurMemRegion->Offset; switchTo(Sec); // We do not support custom layout for compressed debug sectons. // At this point we already know their size and have compressed content. if (CurOutSec->Flags & SHF_COMPRESSED) return; for (BaseCommand *C : Cmd->Commands) process(*C); } void LinkerScript::removeEmptyCommands() { // It is common practice to use very generic linker scripts. So for any // given run some of the output sections in the script will be empty. // We could create corresponding empty output sections, but that would // clutter the output. // We instead remove trivially empty sections. The bfd linker seems even // more aggressive at removing them. auto Pos = std::remove_if( Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) { if (auto *Cmd = dyn_cast(Base)) return std::find(OutputSections->begin(), OutputSections->end(), Cmd->Sec) == OutputSections->end(); return false; }); Opt.Commands.erase(Pos, Opt.Commands.end()); } static bool isAllSectionDescription(const OutputSectionCommand &Cmd) { for (BaseCommand *Base : Cmd.Commands) if (!isa(*Base)) return false; return true; } void LinkerScript::adjustSectionsBeforeSorting() { // If the output section contains only symbol assignments, create a // corresponding output section. The bfd linker seems to only create them if // '.' is assigned to, but creating these section should not have any bad // consequeces and gives us a section to put the symbol in. uint64_t Flags = SHF_ALLOC; for (int I = 0, E = Opt.Commands.size(); I != E; ++I) { auto *Cmd = dyn_cast(Opt.Commands[I]); if (!Cmd) continue; if (OutputSection *Sec = Cmd->Sec) { Flags = Sec->Flags; continue; } if (isAllSectionDescription(*Cmd)) continue; auto *OutSec = make(Cmd->Name, SHT_PROGBITS, Flags); OutSec->SectionIndex = I; OutputSections->push_back(OutSec); Cmd->Sec = OutSec; SecToCommand[OutSec] = Cmd; } } void LinkerScript::adjustSectionsAfterSorting() { placeOrphanSections(); // Try and find an appropriate memory region to assign offsets in. for (BaseCommand *Base : Opt.Commands) { if (auto *Cmd = dyn_cast(Base)) { Cmd->MemRegion = findMemoryRegion(Cmd); // Handle align (e.g. ".foo : ALIGN(16) { ... }"). if (Cmd->AlignExpr) Cmd->Sec->updateAlignment(Cmd->AlignExpr().getValue()); } } // If output section command doesn't specify any segments, // and we haven't previously assigned any section to segment, // then we simply assign section to the very first load segment. // Below is an example of such linker script: // PHDRS { seg PT_LOAD; } // SECTIONS { .aaa : { *(.aaa) } } std::vector DefPhdrs; auto FirstPtLoad = std::find_if(Opt.PhdrsCommands.begin(), Opt.PhdrsCommands.end(), [](const PhdrsCommand &Cmd) { return Cmd.Type == PT_LOAD; }); if (FirstPtLoad != Opt.PhdrsCommands.end()) DefPhdrs.push_back(FirstPtLoad->Name); // Walk the commands and propagate the program headers to commands that don't // explicitly specify them. for (BaseCommand *Base : Opt.Commands) { auto *Cmd = dyn_cast(Base); if (!Cmd) continue; if (Cmd->Phdrs.empty()) Cmd->Phdrs = DefPhdrs; else DefPhdrs = Cmd->Phdrs; } removeEmptyCommands(); } // When placing orphan sections, we want to place them after symbol assignments // so that an orphan after // begin_foo = .; // foo : { *(foo) } // end_foo = .; // doesn't break the intended meaning of the begin/end symbols. // We don't want to go over sections since Writer::sortSections is the // one in charge of deciding the order of the sections. // We don't want to go over alignments, since doing so in // rx_sec : { *(rx_sec) } // . = ALIGN(0x1000); // /* The RW PT_LOAD starts here*/ // rw_sec : { *(rw_sec) } // would mean that the RW PT_LOAD would become unaligned. static bool shouldSkip(BaseCommand *Cmd) { if (isa(Cmd)) return false; if (auto *Assign = dyn_cast(Cmd)) return Assign->Name != "."; return true; } // Orphan sections are sections present in the input files which are // not explicitly placed into the output file by the linker script. // // When the control reaches this function, Opt.Commands contains // output section commands for non-orphan sections only. This function // adds new elements for orphan sections so that all sections are // explicitly handled by Opt.Commands. // // Writer::sortSections has already sorted output sections. // What we need to do is to scan OutputSections vector and // Opt.Commands in parallel to find orphan sections. If there is an // output section that doesn't have a corresponding entry in // Opt.Commands, we will insert a new entry to Opt.Commands. // // There is some ambiguity as to where exactly a new entry should be // inserted, because Opt.Commands contains not only output section // commands but also other types of commands such as symbol assignment // expressions. There's no correct answer here due to the lack of the // formal specification of the linker script. We use heuristics to // determine whether a new output command should be added before or // after another commands. For the details, look at shouldSkip // function. void LinkerScript::placeOrphanSections() { // The OutputSections are already in the correct order. // This loops creates or moves commands as needed so that they are in the // correct order. int CmdIndex = 0; // As a horrible special case, skip the first . assignment if it is before any // section. We do this because it is common to set a load address by starting // the script with ". = 0xabcd" and the expectation is that every section is // after that. auto FirstSectionOrDotAssignment = std::find_if(Opt.Commands.begin(), Opt.Commands.end(), [](BaseCommand *Cmd) { return !shouldSkip(Cmd); }); if (FirstSectionOrDotAssignment != Opt.Commands.end()) { CmdIndex = FirstSectionOrDotAssignment - Opt.Commands.begin(); if (isa(**FirstSectionOrDotAssignment)) ++CmdIndex; } for (OutputSection *Sec : *OutputSections) { StringRef Name = Sec->Name; // Find the last spot where we can insert a command and still get the // correct result. auto CmdIter = Opt.Commands.begin() + CmdIndex; auto E = Opt.Commands.end(); while (CmdIter != E && shouldSkip(*CmdIter)) { ++CmdIter; ++CmdIndex; } // If there is no command corresponding to this output section, // create one and put a InputSectionDescription in it so that both // representations agree on which input sections to use. OutputSectionCommand *Cmd = getCmd(Sec); if (!Cmd) { Cmd = createOutputSectionCommand(Name, ""); Opt.Commands.insert(CmdIter, Cmd); ++CmdIndex; Cmd->Sec = Sec; SecToCommand[Sec] = Cmd; auto *ISD = make(""); for (InputSection *IS : Sec->Sections) ISD->Sections.push_back(IS); Cmd->Commands.push_back(ISD); continue; } // Continue from where we found it. while (*CmdIter != Cmd) { ++CmdIter; ++CmdIndex; } ++CmdIndex; } } void LinkerScript::processNonSectionCommands() { for (BaseCommand *Base : Opt.Commands) { if (auto *Cmd = dyn_cast(Base)) assignSymbol(Cmd, false); else if (auto *Cmd = dyn_cast(Base)) Cmd->Expression(); } } // Do a last effort at synchronizing the linker script "AST" and the section // list. This is needed to account for last minute changes, like adding a // .ARM.exidx terminator and sorting SHF_LINK_ORDER sections. // // FIXME: We should instead create the "AST" earlier and the above changes would // be done directly in the "AST". // // This can only handle new sections being added and sections being reordered. void LinkerScript::synchronize() { for (BaseCommand *Base : Opt.Commands) { auto *Cmd = dyn_cast(Base); if (!Cmd) continue; ArrayRef Sections = Cmd->Sec->Sections; std::vector ScriptSections; DenseSet ScriptSectionsSet; for (BaseCommand *Base : Cmd->Commands) { auto *ISD = dyn_cast(Base); if (!ISD) continue; for (InputSection *&IS : ISD->Sections) { if (IS->Live) { ScriptSections.push_back(&IS); ScriptSectionsSet.insert(IS); } } } std::vector Missing; for (InputSection *IS : Sections) if (!ScriptSectionsSet.count(IS)) Missing.push_back(IS); if (!Missing.empty()) { auto ISD = make(""); ISD->Sections = Missing; Cmd->Commands.push_back(ISD); for (InputSection *&IS : ISD->Sections) if (IS->Live) ScriptSections.push_back(&IS); } assert(ScriptSections.size() == Sections.size()); for (int I = 0, N = Sections.size(); I < N; ++I) *ScriptSections[I] = Sections[I]; } } static bool allocateHeaders(std::vector &Phdrs, ArrayRef OutputSectionCommands, uint64_t Min) { auto FirstPTLoad = std::find_if(Phdrs.begin(), Phdrs.end(), [](const PhdrEntry &E) { return E.p_type == PT_LOAD; }); if (FirstPTLoad == Phdrs.end()) return false; uint64_t HeaderSize = getHeaderSize(); if (HeaderSize <= Min || Script->hasPhdrsCommands()) { Min = alignDown(Min - HeaderSize, Config->MaxPageSize); Out::ElfHeader->Addr = Min; Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size; return true; } assert(FirstPTLoad->First == Out::ElfHeader); OutputSection *ActualFirst = nullptr; for (OutputSectionCommand *Cmd : OutputSectionCommands) { OutputSection *Sec = Cmd->Sec; if (Sec->FirstInPtLoad == Out::ElfHeader) { ActualFirst = Sec; break; } } if (ActualFirst) { for (OutputSectionCommand *Cmd : OutputSectionCommands) { OutputSection *Sec = Cmd->Sec; if (Sec->FirstInPtLoad == Out::ElfHeader) Sec->FirstInPtLoad = ActualFirst; } FirstPTLoad->First = ActualFirst; } else { Phdrs.erase(FirstPTLoad); } auto PhdrI = std::find_if(Phdrs.begin(), Phdrs.end(), [](const PhdrEntry &E) { return E.p_type == PT_PHDR; }); if (PhdrI != Phdrs.end()) Phdrs.erase(PhdrI); return false; } void LinkerScript::assignAddresses( std::vector &Phdrs, ArrayRef OutputSectionCommands) { // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = 0; ErrorOnMissingSection = true; switchTo(Aether); for (BaseCommand *Base : Opt.Commands) { if (auto *Cmd = dyn_cast(Base)) { assignSymbol(Cmd, false); continue; } if (auto *Cmd = dyn_cast(Base)) { Cmd->Expression(); continue; } auto *Cmd = cast(Base); assignOffsets(Cmd); } uint64_t MinVA = std::numeric_limits::max(); for (OutputSectionCommand *Cmd : OutputSectionCommands) { OutputSection *Sec = Cmd->Sec; if (Sec->Flags & SHF_ALLOC) MinVA = std::min(MinVA, Sec->Addr); else Sec->Addr = 0; } allocateHeaders(Phdrs, OutputSectionCommands, MinVA); } // Creates program headers as instructed by PHDRS linker script command. std::vector LinkerScript::createPhdrs() { std::vector Ret; // Process PHDRS and FILEHDR keywords because they are not // real output sections and cannot be added in the following loop. for (const PhdrsCommand &Cmd : Opt.PhdrsCommands) { Ret.emplace_back(Cmd.Type, Cmd.Flags == UINT_MAX ? PF_R : Cmd.Flags); PhdrEntry &Phdr = Ret.back(); if (Cmd.HasFilehdr) Phdr.add(Out::ElfHeader); if (Cmd.HasPhdrs) Phdr.add(Out::ProgramHeaders); if (Cmd.LMAExpr) { Phdr.p_paddr = Cmd.LMAExpr().getValue(); Phdr.HasLMA = true; } } // Add output sections to program headers. for (OutputSection *Sec : *OutputSections) { if (!(Sec->Flags & SHF_ALLOC)) break; // Assign headers specified by linker script for (size_t Id : getPhdrIndices(Sec)) { Ret[Id].add(Sec); if (Opt.PhdrsCommands[Id].Flags == UINT_MAX) Ret[Id].p_flags |= Sec->getPhdrFlags(); } } return Ret; } bool LinkerScript::ignoreInterpSection() { // Ignore .interp section in case we have PHDRS specification // and PT_INTERP isn't listed. if (Opt.PhdrsCommands.empty()) return false; for (PhdrsCommand &Cmd : Opt.PhdrsCommands) if (Cmd.Type == PT_INTERP) return false; return true; } OutputSectionCommand *LinkerScript::getCmd(OutputSection *Sec) const { auto I = SecToCommand.find(Sec); if (I == SecToCommand.end()) return nullptr; return I->second; } uint32_t OutputSectionCommand::getFiller() { if (Filler) return *Filler; if (Sec->Flags & SHF_EXECINSTR) return Target->TrapInstr; return 0; } static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) { if (Size == 1) *Buf = Data; else if (Size == 2) write16(Buf, Data, Config->Endianness); else if (Size == 4) write32(Buf, Data, Config->Endianness); else if (Size == 8) write64(Buf, Data, Config->Endianness); else llvm_unreachable("unsupported Size argument"); } // Compress section contents if this section contains debug info. template void OutputSectionCommand::maybeCompress() { typedef typename ELFT::Chdr Elf_Chdr; // Compress only DWARF debug sections. if (!Config->CompressDebugSections || (Sec->Flags & SHF_ALLOC) || !Name.startswith(".debug_")) return; // Create a section header. Sec->ZDebugHeader.resize(sizeof(Elf_Chdr)); auto *Hdr = reinterpret_cast(Sec->ZDebugHeader.data()); Hdr->ch_type = ELFCOMPRESS_ZLIB; Hdr->ch_size = Sec->Size; Hdr->ch_addralign = Sec->Alignment; // Write section contents to a temporary buffer and compress it. std::vector Buf(Sec->Size); writeTo(Buf.data()); if (Error E = zlib::compress(toStringRef(Buf), Sec->CompressedData)) fatal("compress failed: " + llvm::toString(std::move(E))); // Update section headers. Sec->Size = sizeof(Elf_Chdr) + Sec->CompressedData.size(); Sec->Flags |= SHF_COMPRESSED; } template void OutputSectionCommand::writeTo(uint8_t *Buf) { Sec->Loc = Buf; // We may have already rendered compressed content when using // -compress-debug-sections option. Write it together with header. if (!Sec->CompressedData.empty()) { memcpy(Buf, Sec->ZDebugHeader.data(), Sec->ZDebugHeader.size()); memcpy(Buf + Sec->ZDebugHeader.size(), Sec->CompressedData.data(), Sec->CompressedData.size()); return; } if (Sec->Type == SHT_NOBITS) return; // Write leading padding. std::vector Sections; for (BaseCommand *Cmd : Commands) if (auto *ISD = dyn_cast(Cmd)) for (InputSection *IS : ISD->Sections) if (IS->Live) Sections.push_back(IS); uint32_t Filler = getFiller(); if (Filler) fill(Buf, Sections.empty() ? Sec->Size : Sections[0]->OutSecOff, Filler); parallelForEachN(0, Sections.size(), [=](size_t I) { InputSection *IS = Sections[I]; IS->writeTo(Buf); // Fill gaps between sections. if (Filler) { uint8_t *Start = Buf + IS->OutSecOff + IS->getSize(); uint8_t *End; if (I + 1 == Sections.size()) End = Buf + Sec->Size; else End = Buf + Sections[I + 1]->OutSecOff; fill(Start, End - Start, Filler); } }); // Linker scripts may have BYTE()-family commands with which you // can write arbitrary bytes to the output. Process them if any. for (BaseCommand *Base : Commands) if (auto *Data = dyn_cast(Base)) writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size); } bool LinkerScript::hasLMA(OutputSection *Sec) { if (OutputSectionCommand *Cmd = getCmd(Sec)) if (Cmd->LMAExpr) return true; return false; } ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) { if (S == ".") return {CurOutSec, Dot - CurOutSec->Addr}; if (SymbolBody *B = findSymbol(S)) { if (auto *D = dyn_cast(B)) return {D->Section, D->Value}; if (auto *C = dyn_cast(B)) return {InX::Common, C->Offset}; } error(Loc + ": symbol not found: " + S); return 0; } bool LinkerScript::isDefined(StringRef S) { return findSymbol(S) != nullptr; } // Returns indices of ELF headers containing specific section. Each index is a // zero based number of ELF header listed within PHDRS {} script block. std::vector LinkerScript::getPhdrIndices(OutputSection *Sec) { if (OutputSectionCommand *Cmd = getCmd(Sec)) { std::vector Ret; for (StringRef PhdrName : Cmd->Phdrs) Ret.push_back(getPhdrIndex(Cmd->Location, PhdrName)); return Ret; } return {}; } size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) { size_t I = 0; for (PhdrsCommand &Cmd : Opt.PhdrsCommands) { if (Cmd.Name == PhdrName) return I; ++I; } error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS"); return 0; } template void OutputSectionCommand::writeTo(uint8_t *Buf); template void OutputSectionCommand::writeTo(uint8_t *Buf); template void OutputSectionCommand::writeTo(uint8_t *Buf); template void OutputSectionCommand::writeTo(uint8_t *Buf); template void OutputSectionCommand::maybeCompress(); template void OutputSectionCommand::maybeCompress(); template void OutputSectionCommand::maybeCompress(); template void OutputSectionCommand::maybeCompress(); Index: vendor/lld/dist/ELF/OutputSections.cpp =================================================================== --- vendor/lld/dist/ELF/OutputSections.cpp (revision 319530) +++ vendor/lld/dist/ELF/OutputSections.cpp (revision 319531) @@ -1,411 +1,412 @@ //===- OutputSections.cpp -------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "OutputSections.h" #include "Config.h" #include "LinkerScript.h" #include "Memory.h" #include "Strings.h" #include "SymbolTable.h" #include "SyntheticSections.h" #include "Target.h" #include "Threads.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/SHA1.h" using namespace llvm; using namespace llvm::dwarf; using namespace llvm::object; using namespace llvm::support::endian; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; uint8_t Out::First; OutputSection *Out::Opd; uint8_t *Out::OpdBuf; PhdrEntry *Out::TlsPhdr; OutputSection *Out::DebugInfo; OutputSection *Out::ElfHeader; OutputSection *Out::ProgramHeaders; OutputSection *Out::PreinitArray; OutputSection *Out::InitArray; OutputSection *Out::FiniArray; uint32_t OutputSection::getPhdrFlags() const { uint32_t Ret = PF_R; if (Flags & SHF_WRITE) Ret |= PF_W; if (Flags & SHF_EXECINSTR) Ret |= PF_X; return Ret; } template void OutputSection::writeHeaderTo(typename ELFT::Shdr *Shdr) { Shdr->sh_entsize = Entsize; Shdr->sh_addralign = Alignment; Shdr->sh_type = Type; Shdr->sh_offset = Offset; Shdr->sh_flags = Flags; Shdr->sh_info = Info; Shdr->sh_link = Link; Shdr->sh_addr = Addr; Shdr->sh_size = Size; Shdr->sh_name = ShName; } OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags) : SectionBase(Output, Name, Flags, /*Entsize*/ 0, /*Alignment*/ 1, Type, /*Info*/ 0, /*Link*/ 0), SectionIndex(INT_MAX) {} static bool compareByFilePosition(InputSection *A, InputSection *B) { // Synthetic doesn't have link order dependecy, stable_sort will keep it last if (A->kind() == InputSectionBase::Synthetic || B->kind() == InputSectionBase::Synthetic) return false; InputSection *LA = A->getLinkOrderDep(); InputSection *LB = B->getLinkOrderDep(); OutputSection *AOut = LA->getParent(); OutputSection *BOut = LB->getParent(); if (AOut != BOut) return AOut->SectionIndex < BOut->SectionIndex; return LA->OutSecOff < LB->OutSecOff; } template static void finalizeShtGroup(OutputSection *Sec) { // sh_link field for SHT_GROUP sections should contain the section index of // the symbol table. Sec->Link = InX::SymTab->getParent()->SectionIndex; // sh_info then contain index of an entry in symbol table section which // provides signature of the section group. elf::ObjectFile *Obj = Sec->Sections[0]->getFile(); assert(Config->Relocatable && Sec->Sections.size() == 1); ArrayRef Symbols = Obj->getSymbols(); Sec->Info = InX::SymTab->getSymbolIndex(Symbols[Sec->Sections[0]->Info - 1]); } template void OutputSection::finalize() { if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) { std::sort(Sections.begin(), Sections.end(), compareByFilePosition); assignOffsets(); // We must preserve the link order dependency of sections with the // SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We // need to translate the InputSection sh_link to the OutputSection sh_link, // all InputSections in the OutputSection have the same dependency. if (auto *D = this->Sections.front()->getLinkOrderDep()) this->Link = D->getParent()->SectionIndex; } uint32_t Type = this->Type; if (Type == SHT_GROUP) { finalizeShtGroup(this); return; } if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL)) return; InputSection *First = Sections[0]; if (isa(First)) return; this->Link = InX::SymTab->getParent()->SectionIndex; // sh_info for SHT_REL[A] sections should contain the section header index of // the section to which the relocation applies. InputSectionBase *S = First->getRelocatedSection(); Info = S->getOutputSection()->SectionIndex; + Flags |= SHF_INFO_LINK; } static uint64_t updateOffset(uint64_t Off, InputSection *S) { Off = alignTo(Off, S->Alignment); S->OutSecOff = Off; return Off + S->getSize(); } void OutputSection::addSection(InputSection *S) { assert(S->Live); Sections.push_back(S); S->Parent = this; this->updateAlignment(S->Alignment); // The actual offsets will be computed by assignAddresses. For now, use // crude approximation so that it is at least easy for other code to know the // section order. It is also used to calculate the output section size early // for compressed debug sections. this->Size = updateOffset(Size, S); // If this section contains a table of fixed-size entries, sh_entsize // holds the element size. Consequently, if this contains two or more // input sections, all of them must have the same sh_entsize. However, // you can put different types of input sections into one output // sectin by using linker scripts. I don't know what to do here. // Probably we sholuld handle that as an error. But for now we just // pick the largest sh_entsize. this->Entsize = std::max(this->Entsize, S->Entsize); } // This function is called after we sort input sections // and scan relocations to setup sections' offsets. void OutputSection::assignOffsets() { uint64_t Off = 0; for (InputSection *S : Sections) Off = updateOffset(Off, S); this->Size = Off; } void OutputSection::sort(std::function Order) { typedef std::pair Pair; auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; }; std::vector V; for (InputSection *S : Sections) V.push_back({Order(S), S}); std::stable_sort(V.begin(), V.end(), Comp); Sections.clear(); for (Pair &P : V) Sections.push_back(P.second); } // Sorts input sections by section name suffixes, so that .foo.N comes // before .foo.M if N < M. Used to sort .{init,fini}_array.N sections. // We want to keep the original order if the priorities are the same // because the compiler keeps the original initialization order in a // translation unit and we need to respect that. // For more detail, read the section of the GCC's manual about init_priority. void OutputSection::sortInitFini() { // Sort sections by priority. sort([](InputSectionBase *S) { return getPriority(S->Name); }); } // Returns true if S matches /Filename.?\.o$/. static bool isCrtBeginEnd(StringRef S, StringRef Filename) { if (!S.endswith(".o")) return false; S = S.drop_back(2); if (S.endswith(Filename)) return true; return !S.empty() && S.drop_back().endswith(Filename); } static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); } static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); } // .ctors and .dtors are sorted by this priority from highest to lowest. // // 1. The section was contained in crtbegin (crtbegin contains // some sentinel value in its .ctors and .dtors so that the runtime // can find the beginning of the sections.) // // 2. The section has an optional priority value in the form of ".ctors.N" // or ".dtors.N" where N is a number. Unlike .{init,fini}_array, // they are compared as string rather than number. // // 3. The section is just ".ctors" or ".dtors". // // 4. The section was contained in crtend, which contains an end marker. // // In an ideal world, we don't need this function because .init_array and // .ctors are duplicate features (and .init_array is newer.) However, there // are too many real-world use cases of .ctors, so we had no choice to // support that with this rather ad-hoc semantics. static bool compCtors(const InputSection *A, const InputSection *B) { bool BeginA = isCrtbegin(A->File->getName()); bool BeginB = isCrtbegin(B->File->getName()); if (BeginA != BeginB) return BeginA; bool EndA = isCrtend(A->File->getName()); bool EndB = isCrtend(B->File->getName()); if (EndA != EndB) return EndB; StringRef X = A->Name; StringRef Y = B->Name; assert(X.startswith(".ctors") || X.startswith(".dtors")); assert(Y.startswith(".ctors") || Y.startswith(".dtors")); X = X.substr(6); Y = Y.substr(6); if (X.empty() && Y.empty()) return false; return X < Y; } // Sorts input sections by the special rules for .ctors and .dtors. // Unfortunately, the rules are different from the one for .{init,fini}_array. // Read the comment above. void OutputSection::sortCtorsDtors() { std::stable_sort(Sections.begin(), Sections.end(), compCtors); } static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) { // The ELF spec just says // ---------------------------------------------------------------- // In the first phase, input sections that match in name, type and // attribute flags should be concatenated into single sections. // ---------------------------------------------------------------- // // However, it is clear that at least some flags have to be ignored for // section merging. At the very least SHF_GROUP and SHF_COMPRESSED have to be // ignored. We should not have two output .text sections just because one was // in a group and another was not for example. // // It also seems that that wording was a late addition and didn't get the // necessary scrutiny. // // Merging sections with different flags is expected by some users. One // reason is that if one file has // // int *const bar __attribute__((section(".foo"))) = (int *)0; // // gcc with -fPIC will produce a read only .foo section. But if another // file has // // int zed; // int *const bar __attribute__((section(".foo"))) = (int *)&zed; // // gcc with -fPIC will produce a read write section. // // Last but not least, when using linker script the merge rules are forced by // the script. Unfortunately, linker scripts are name based. This means that // expressions like *(.foo*) can refer to multiple input sections with // different flags. We cannot put them in different output sections or we // would produce wrong results for // // start = .; *(.foo.*) end = .; *(.bar) // // and a mapping of .foo1 and .bar1 to one section and .foo2 and .bar2 to // another. The problem is that there is no way to layout those output // sections such that the .foo sections are the only thing between the start // and end symbols. // // Given the above issues, we instead merge sections by name and error on // incompatible types and flags. uint32_t Alignment = 0; uint64_t Flags = 0; if (Config->Relocatable && (C->Flags & SHF_MERGE)) { Alignment = std::max(C->Alignment, C->Entsize); Flags = C->Flags & (SHF_MERGE | SHF_STRINGS); } return SectionKey{OutsecName, Flags, Alignment}; } OutputSectionFactory::OutputSectionFactory( std::vector &OutputSections) : OutputSections(OutputSections) {} static uint64_t getIncompatibleFlags(uint64_t Flags) { return Flags & (SHF_ALLOC | SHF_TLS); } // We allow sections of types listed below to merged into a // single progbits section. This is typically done by linker // scripts. Merging nobits and progbits will force disk space // to be allocated for nobits sections. Other ones don't require // any special treatment on top of progbits, so there doesn't // seem to be a harm in merging them. static bool canMergeToProgbits(unsigned Type) { return Type == SHT_NOBITS || Type == SHT_PROGBITS || Type == SHT_INIT_ARRAY || Type == SHT_PREINIT_ARRAY || Type == SHT_FINI_ARRAY || Type == SHT_NOTE; } void elf::reportDiscarded(InputSectionBase *IS) { if (!Config->PrintGcSections) return; message("removing unused section from '" + IS->Name + "' in file '" + IS->File->getName()); } void OutputSectionFactory::addInputSec(InputSectionBase *IS, StringRef OutsecName) { SectionKey Key = createKey(IS, OutsecName); OutputSection *&Sec = Map[Key]; return addInputSec(IS, OutsecName, Sec); } void OutputSectionFactory::addInputSec(InputSectionBase *IS, StringRef OutsecName, OutputSection *&Sec) { if (!IS->Live) { reportDiscarded(IS); return; } uint64_t Flags = IS->Flags; if (!Config->Relocatable) Flags &= ~(uint64_t)SHF_GROUP; if (Sec) { if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags)) error("incompatible section flags for " + Sec->Name + "\n>>> " + toString(IS) + ": 0x" + utohexstr(IS->Flags) + "\n>>> output section " + Sec->Name + ": 0x" + utohexstr(Sec->Flags)); if (Sec->Type != IS->Type) { if (canMergeToProgbits(Sec->Type) && canMergeToProgbits(IS->Type)) Sec->Type = SHT_PROGBITS; else error("section type mismatch for " + IS->Name + "\n>>> " + toString(IS) + ": " + getELFSectionTypeName(Config->EMachine, IS->Type) + "\n>>> output section " + Sec->Name + ": " + getELFSectionTypeName(Config->EMachine, Sec->Type)); } Sec->Flags |= Flags; } else { Sec = make(OutsecName, IS->Type, Flags); OutputSections.push_back(Sec); } Sec->addSection(cast(IS)); } OutputSectionFactory::~OutputSectionFactory() {} SectionKey DenseMapInfo::getEmptyKey() { return SectionKey{DenseMapInfo::getEmptyKey(), 0, 0}; } SectionKey DenseMapInfo::getTombstoneKey() { return SectionKey{DenseMapInfo::getTombstoneKey(), 0, 0}; } unsigned DenseMapInfo::getHashValue(const SectionKey &Val) { return hash_combine(Val.Name, Val.Flags, Val.Alignment); } bool DenseMapInfo::isEqual(const SectionKey &LHS, const SectionKey &RHS) { return DenseMapInfo::isEqual(LHS.Name, RHS.Name) && LHS.Flags == RHS.Flags && LHS.Alignment == RHS.Alignment; } uint64_t elf::getHeaderSize() { if (Config->OFormatBinary) return 0; return Out::ElfHeader->Size + Out::ProgramHeaders->Size; } template void OutputSection::writeHeaderTo(ELF32LE::Shdr *Shdr); template void OutputSection::writeHeaderTo(ELF32BE::Shdr *Shdr); template void OutputSection::writeHeaderTo(ELF64LE::Shdr *Shdr); template void OutputSection::writeHeaderTo(ELF64BE::Shdr *Shdr); template void OutputSection::finalize(); template void OutputSection::finalize(); template void OutputSection::finalize(); template void OutputSection::finalize(); Index: vendor/lld/dist/ELF/OutputSections.h =================================================================== --- vendor/lld/dist/ELF/OutputSections.h (revision 319530) +++ vendor/lld/dist/ELF/OutputSections.h (revision 319531) @@ -1,157 +1,153 @@ //===- OutputSections.h -----------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_ELF_OUTPUT_SECTIONS_H #define LLD_ELF_OUTPUT_SECTIONS_H #include "Config.h" #include "InputSection.h" #include "Relocations.h" #include "lld/Core/LLVM.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELF.h" namespace lld { namespace elf { struct PhdrEntry; class SymbolBody; struct EhSectionPiece; class EhInputSection; class InputSection; class InputSectionBase; class MergeInputSection; class OutputSection; template class ObjectFile; template class SharedFile; class SharedSymbol; class DefinedRegular; // This represents a section in an output file. // It is composed of multiple InputSections. // The writer creates multiple OutputSections and assign them unique, // non-overlapping file offsets and VAs. class OutputSection final : public SectionBase { public: OutputSection(StringRef Name, uint32_t Type, uint64_t Flags); static bool classof(const SectionBase *S) { return S->kind() == SectionBase::Output; } uint64_t getLMA() const { return Addr + LMAOffset; } template void writeHeaderTo(typename ELFT::Shdr *SHdr); unsigned SectionIndex; unsigned SortRank; uint32_t getPhdrFlags() const; void updateAlignment(uint32_t Val) { if (Val > Alignment) Alignment = Val; } - // If true, this section will be page aligned on disk. - // Typically the first section of each PT_LOAD segment has this flag. - bool PageAlign = false; - // Pointer to the first section in PT_LOAD segment, which this section // also resides in. This field is used to correctly compute file offset // of a section. When two sections share the same load segment, difference // between their file offsets should be equal to difference between their // virtual addresses. To compute some section offset we use the following // formula: Off = Off_first + VA - VA_first. OutputSection *FirstInPtLoad = nullptr; // The following fields correspond to Elf_Shdr members. uint64_t Size = 0; uint64_t Offset = 0; uint64_t LMAOffset = 0; uint64_t Addr = 0; uint32_t ShName = 0; void addSection(InputSection *S); void sort(std::function Order); void sortInitFini(); void sortCtorsDtors(); template void finalize(); void assignOffsets(); std::vector Sections; // Used for implementation of --compress-debug-sections option. std::vector ZDebugHeader; llvm::SmallVector CompressedData; // Location in the output buffer. uint8_t *Loc = nullptr; }; // All output sections that are handled by the linker specially are // globally accessible. Writer initializes them, so don't use them // until Writer is initialized. struct Out { static uint8_t First; static OutputSection *Opd; static uint8_t *OpdBuf; static PhdrEntry *TlsPhdr; static OutputSection *DebugInfo; static OutputSection *ElfHeader; static OutputSection *ProgramHeaders; static OutputSection *PreinitArray; static OutputSection *InitArray; static OutputSection *FiniArray; }; struct SectionKey { StringRef Name; uint64_t Flags; uint32_t Alignment; }; } } namespace llvm { template <> struct DenseMapInfo { static lld::elf::SectionKey getEmptyKey(); static lld::elf::SectionKey getTombstoneKey(); static unsigned getHashValue(const lld::elf::SectionKey &Val); static bool isEqual(const lld::elf::SectionKey &LHS, const lld::elf::SectionKey &RHS); }; } namespace lld { namespace elf { // This class knows how to create an output section for a given // input section. Output section type is determined by various // factors, including input section's sh_flags, sh_type and // linker scripts. class OutputSectionFactory { public: OutputSectionFactory(std::vector &OutputSections); ~OutputSectionFactory(); void addInputSec(InputSectionBase *IS, StringRef OutsecName); void addInputSec(InputSectionBase *IS, StringRef OutsecName, OutputSection *&Sec); private: llvm::SmallDenseMap Map; std::vector &OutputSections; }; uint64_t getHeaderSize(); void reportDiscarded(InputSectionBase *IS); } // namespace elf } // namespace lld #endif Index: vendor/lld/dist/ELF/Writer.cpp =================================================================== --- vendor/lld/dist/ELF/Writer.cpp (revision 319530) +++ vendor/lld/dist/ELF/Writer.cpp (revision 319531) @@ -1,1851 +1,1861 @@ //===- Writer.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Writer.h" #include "Config.h" #include "Filesystem.h" #include "LinkerScript.h" #include "MapFile.h" #include "Memory.h" #include "OutputSections.h" #include "Relocations.h" #include "Strings.h" #include "SymbolTable.h" #include "SyntheticSections.h" #include "Target.h" #include "Threads.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/raw_ostream.h" #include using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support; using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; namespace { // The writer writes a SymbolTable result to a file. template class Writer { public: typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Ehdr Elf_Ehdr; typedef typename ELFT::Phdr Elf_Phdr; void run(); private: void clearOutputSections(); void createSyntheticSections(); void copyLocalSymbols(); void addSectionSymbols(); void addReservedSymbols(); void createSections(); void forEachRelSec(std::function Fn); void sortSections(); void finalizeSections(); void addPredefinedSections(); std::vector createPhdrs(); void removeEmptyPTLoad(); void addPtArmExid(std::vector &Phdrs); void assignFileOffsets(); void assignFileOffsetsBinary(); void setPhdrs(); void fixSectionAlignments(); void fixPredefinedSymbols(); void openFile(); void writeHeader(); void writeSections(); void writeSectionsBinary(); void writeBuildId(); std::unique_ptr Buffer; std::vector OutputSections; std::vector OutputSectionCommands; OutputSectionFactory Factory{OutputSections}; void addRelIpltSymbols(); void addStartEndSymbols(); void addStartStopSymbols(OutputSection *Sec); uint64_t getEntryAddr(); OutputSection *findSection(StringRef Name); OutputSection *findSectionInScript(StringRef Name); OutputSectionCommand *findSectionCommand(StringRef Name); std::vector Phdrs; uint64_t FileSize; uint64_t SectionHeaderOff; }; } // anonymous namespace StringRef elf::getOutputSectionName(StringRef Name) { if (Config->Relocatable) return Name; // If -emit-relocs is given (which is rare), we need to copy // relocation sections to the output. If input section .foo is // output as .bar, we want to rename .rel.foo .rel.bar as well. if (Config->EmitRelocs) { for (StringRef V : {".rel.", ".rela."}) { if (Name.startswith(V)) { StringRef Inner = getOutputSectionName(Name.substr(V.size() - 1)); return Saver.save(V.drop_back() + Inner); } } } for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.", ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.", ".gcc_except_table.", ".tdata.", ".ARM.exidx."}) { StringRef Prefix = V.drop_back(); if (Name.startswith(V) || Name == Prefix) return Prefix; } // CommonSection is identified as "COMMON" in linker scripts. // By default, it should go to .bss section. if (Name == "COMMON") return ".bss"; // ".zdebug_" is a prefix for ZLIB-compressed sections. // Because we decompressed input sections, we want to remove 'z'. if (Name.startswith(".zdebug_")) return Saver.save("." + Name.substr(2)); return Name; } template static bool needsInterpSection() { return !Symtab::X->getSharedFiles().empty() && !Config->DynamicLinker.empty() && !Script->ignoreInterpSection(); } template void elf::writeResult() { Writer().run(); } template void Writer::removeEmptyPTLoad() { auto I = std::remove_if(Phdrs.begin(), Phdrs.end(), [&](const PhdrEntry &P) { if (P.p_type != PT_LOAD) return false; if (!P.First) return true; uint64_t Size = P.Last->Addr + P.Last->Size - P.First->Addr; return Size == 0; }); Phdrs.erase(I, Phdrs.end()); } // This function scans over the input sections and creates mergeable // synthetic sections. It removes MergeInputSections from array and // adds new synthetic ones. Each synthetic section is added to the // location of the first input section it replaces. static void combineMergableSections() { std::vector MergeSections; for (InputSectionBase *&S : InputSections) { MergeInputSection *MS = dyn_cast(S); if (!MS) continue; // We do not want to handle sections that are not alive, so just remove // them instead of trying to merge. if (!MS->Live) continue; StringRef OutsecName = getOutputSectionName(MS->Name); uint64_t Flags = MS->Flags & ~(uint64_t)SHF_GROUP; uint32_t Alignment = std::max(MS->Alignment, MS->Entsize); auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) { return Sec->Name == OutsecName && Sec->Flags == Flags && Sec->Alignment == Alignment; }); if (I == MergeSections.end()) { MergeSyntheticSection *Syn = make(OutsecName, MS->Type, Flags, Alignment); MergeSections.push_back(Syn); I = std::prev(MergeSections.end()); S = Syn; } else { S = nullptr; } (*I)->addSection(MS); } std::vector &V = InputSections; V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); } template static void combineEhFrameSections() { for (InputSectionBase *&S : InputSections) { EhInputSection *ES = dyn_cast(S); if (!ES || !ES->Live) continue; In::EhFrame->addSection(ES); S = nullptr; } std::vector &V = InputSections; V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); } template void Writer::clearOutputSections() { // Clear the OutputSections to make sure it is not used anymore. Any // code from this point on should be using the linker script // commands. for (OutputSection *Sec : OutputSections) Sec->Sections.clear(); OutputSections.clear(); } // The main function of the writer. template void Writer::run() { // Create linker-synthesized sections such as .got or .plt. // Such sections are of type input section. createSyntheticSections(); combineMergableSections(); if (!Config->Relocatable) combineEhFrameSections(); // We need to create some reserved symbols such as _end. Create them. if (!Config->Relocatable) addReservedSymbols(); // Create output sections. Script->OutputSections = &OutputSections; if (Script->Opt.HasSections) { // If linker script contains SECTIONS commands, let it create sections. Script->processCommands(Factory); // Linker scripts may have left some input sections unassigned. // Assign such sections using the default rule. Script->addOrphanSections(Factory); } else { // If linker script does not contain SECTIONS commands, create // output sections by default rules. We still need to give the // linker script a chance to run, because it might contain // non-SECTIONS commands such as ASSERT. createSections(); Script->processCommands(Factory); } if (Config->Discard != DiscardPolicy::All) copyLocalSymbols(); if (Config->CopyRelocs) addSectionSymbols(); // Now that we have a complete set of output sections. This function // completes section contents. For example, we need to add strings // to the string table, and add entries to .got and .plt. // finalizeSections does that. finalizeSections(); if (ErrorCount) return; - if (!Script->Opt.HasSections) { - if (!Config->Relocatable) - fixSectionAlignments(); + if (!Script->Opt.HasSections) Script->fabricateDefaultCommands(); - } else { + else Script->synchronize(); - } for (BaseCommand *Base : Script->Opt.Commands) if (auto *Cmd = dyn_cast(Base)) OutputSectionCommands.push_back(Cmd); clearOutputSections(); + + if (!Script->Opt.HasSections &&!Config->Relocatable) + fixSectionAlignments(); + // If -compressed-debug-sections is specified, we need to compress // .debug_* sections. Do it right now because it changes the size of // output sections. parallelForEach( OutputSectionCommands.begin(), OutputSectionCommands.end(), [](OutputSectionCommand *Cmd) { Cmd->maybeCompress(); }); if (Config->Relocatable) { assignFileOffsets(); } else { Script->assignAddresses(Phdrs, OutputSectionCommands); // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a // 0 sized region. This has to be done late since only after assignAddresses // we know the size of the sections. removeEmptyPTLoad(); if (!Config->OFormatBinary) assignFileOffsets(); else assignFileOffsetsBinary(); setPhdrs(); fixPredefinedSymbols(); } // It does not make sense try to open the file if we have error already. if (ErrorCount) return; // Write the result down to a file. openFile(); if (ErrorCount) return; if (!Config->OFormatBinary) { writeHeader(); writeSections(); } else { writeSectionsBinary(); } // Backfill .note.gnu.build-id section content. This is done at last // because the content is usually a hash value of the entire output file. writeBuildId(); if (ErrorCount) return; // Handle -Map option. writeMapFile(OutputSectionCommands); if (ErrorCount) return; if (auto EC = Buffer->commit()) error("failed to write to the output file: " + EC.message()); // Flush the output streams and exit immediately. A full shutdown // is a good test that we are keeping track of all allocated memory, // but actually freeing it is a waste of time in a regular linker run. if (Config->ExitEarly) exitLld(0); } // Initialize Out members. template void Writer::createSyntheticSections() { // Initialize all pointers with NULL. This is needed because // you can call lld::elf::main more than once as a library. memset(&Out::First, 0, sizeof(Out)); auto Add = [](InputSectionBase *Sec) { InputSections.push_back(Sec); }; InX::DynStrTab = make(".dynstr", true); InX::Dynamic = make>(); In::RelaDyn = make>( Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc); InX::ShStrTab = make(".shstrtab", false); Out::ElfHeader = make("", 0, SHF_ALLOC); Out::ElfHeader->Size = sizeof(Elf_Ehdr); Out::ProgramHeaders = make("", 0, SHF_ALLOC); Out::ProgramHeaders->updateAlignment(Config->Wordsize); if (needsInterpSection()) { InX::Interp = createInterpSection(); Add(InX::Interp); } else { InX::Interp = nullptr; } if (!Config->Relocatable) Add(createCommentSection()); if (Config->Strip != StripPolicy::All) { InX::StrTab = make(".strtab", false); InX::SymTab = make>(*InX::StrTab); } if (Config->BuildId != BuildIdKind::None) { InX::BuildId = make(); Add(InX::BuildId); } InX::Common = createCommonSection(); if (InX::Common) Add(InX::Common); InX::Bss = make(".bss"); Add(InX::Bss); InX::BssRelRo = make(".bss.rel.ro"); Add(InX::BssRelRo); // Add MIPS-specific sections. bool HasDynSymTab = !Symtab::X->getSharedFiles().empty() || Config->Pic || Config->ExportDynamic; if (Config->EMachine == EM_MIPS) { if (!Config->Shared && HasDynSymTab) { InX::MipsRldMap = make(); Add(InX::MipsRldMap); } if (auto *Sec = MipsAbiFlagsSection::create()) Add(Sec); if (auto *Sec = MipsOptionsSection::create()) Add(Sec); if (auto *Sec = MipsReginfoSection::create()) Add(Sec); } if (HasDynSymTab) { InX::DynSymTab = make>(*InX::DynStrTab); Add(InX::DynSymTab); In::VerSym = make>(); Add(In::VerSym); if (!Config->VersionDefinitions.empty()) { In::VerDef = make>(); Add(In::VerDef); } In::VerNeed = make>(); Add(In::VerNeed); if (Config->GnuHash) { InX::GnuHashTab = make(); Add(InX::GnuHashTab); } if (Config->SysvHash) { In::HashTab = make>(); Add(In::HashTab); } Add(InX::Dynamic); Add(InX::DynStrTab); Add(In::RelaDyn); } // Add .got. MIPS' .got is so different from the other archs, // it has its own class. if (Config->EMachine == EM_MIPS) { InX::MipsGot = make(); Add(InX::MipsGot); } else { InX::Got = make(); Add(InX::Got); } InX::GotPlt = make(); Add(InX::GotPlt); InX::IgotPlt = make(); Add(InX::IgotPlt); if (Config->GdbIndex) { InX::GdbIndex = make(); Add(InX::GdbIndex); } // We always need to add rel[a].plt to output if it has entries. // Even for static linking it can contain R_[*]_IRELATIVE relocations. In::RelaPlt = make>( Config->IsRela ? ".rela.plt" : ".rel.plt", false /*Sort*/); Add(In::RelaPlt); // The RelaIplt immediately follows .rel.plt (.rel.dyn for ARM) to ensure // that the IRelative relocations are processed last by the dynamic loader In::RelaIplt = make>( (Config->EMachine == EM_ARM) ? ".rel.dyn" : In::RelaPlt->Name, false /*Sort*/); Add(In::RelaIplt); InX::Plt = make(Target->PltHeaderSize); Add(InX::Plt); InX::Iplt = make(0); Add(InX::Iplt); if (!Config->Relocatable) { if (Config->EhFrameHdr) { In::EhFrameHdr = make>(); Add(In::EhFrameHdr); } In::EhFrame = make>(); Add(In::EhFrame); } if (InX::SymTab) Add(InX::SymTab); Add(InX::ShStrTab); if (InX::StrTab) Add(InX::StrTab); } static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName, const SymbolBody &B) { if (B.isFile() || B.isSection()) return false; // If sym references a section in a discarded group, don't keep it. if (Sec == &InputSection::Discarded) return false; if (Config->Discard == DiscardPolicy::None) return true; // In ELF assembly .L symbols are normally discarded by the assembler. // If the assembler fails to do so, the linker discards them if // * --discard-locals is used. // * The symbol is in a SHF_MERGE section, which is normally the reason for // the assembler keeping the .L symbol. if (!SymName.startswith(".L") && !SymName.empty()) return true; if (Config->Discard == DiscardPolicy::Locals) return false; return !Sec || !(Sec->Flags & SHF_MERGE); } static bool includeInSymtab(const SymbolBody &B) { if (!B.isLocal() && !B.symbol()->IsUsedInRegularObj) return false; if (auto *D = dyn_cast(&B)) { // Always include absolute symbols. SectionBase *Sec = D->Section; if (!Sec) return true; if (auto *IS = dyn_cast(Sec)) { Sec = IS->Repl; IS = cast(Sec); // Exclude symbols pointing to garbage-collected sections. if (!IS->Live) return false; } if (auto *S = dyn_cast(Sec)) if (!S->getSectionPiece(D->Value)->Live) return false; } return true; } // Local symbols are not in the linker's symbol table. This function scans // each object file's symbol table to copy local symbols to the output. template void Writer::copyLocalSymbols() { if (!InX::SymTab) return; for (elf::ObjectFile *F : Symtab::X->getObjectFiles()) { for (SymbolBody *B : F->getLocalSymbols()) { if (!B->IsLocal) fatal(toString(F) + ": broken object: getLocalSymbols returns a non-local symbol"); auto *DR = dyn_cast(B); // No reason to keep local undefined symbol in symtab. if (!DR) continue; if (!includeInSymtab(*B)) continue; SectionBase *Sec = DR->Section; if (!shouldKeepInSymtab(Sec, B->getName(), *B)) continue; InX::SymTab->addSymbol(B); } } } template void Writer::addSectionSymbols() { // Create one STT_SECTION symbol for each output section we might // have a relocation with. for (OutputSection *Sec : OutputSections) { if (Sec->Sections.empty()) continue; InputSection *IS = Sec->Sections[0]; if (isa(IS) || IS->Type == SHT_REL || IS->Type == SHT_RELA) continue; auto *Sym = make("", /*IsLocal=*/true, /*StOther=*/0, STT_SECTION, /*Value=*/0, /*Size=*/0, IS, nullptr); InX::SymTab->addSymbol(Sym); } } // Today's loaders have a feature to make segments read-only after // processing dynamic relocations to enhance security. PT_GNU_RELRO // is defined for that. // // This function returns true if a section needs to be put into a // PT_GNU_RELRO segment. bool elf::isRelroSection(const OutputSection *Sec) { if (!Config->ZRelro) return false; uint64_t Flags = Sec->Flags; // Non-allocatable or non-writable sections don't need RELRO because // they are not writable or not even mapped to memory in the first place. // RELRO is for sections that are essentially read-only but need to // be writable only at process startup to allow dynamic linker to // apply relocations. if (!(Flags & SHF_ALLOC) || !(Flags & SHF_WRITE)) return false; // Once initialized, TLS data segments are used as data templates // for a thread-local storage. For each new thread, runtime // allocates memory for a TLS and copy templates there. No thread // are supposed to use templates directly. Thus, it can be in RELRO. if (Flags & SHF_TLS) return true; // .init_array, .preinit_array and .fini_array contain pointers to // functions that are executed on process startup or exit. These // pointers are set by the static linker, and they are not expected // to change at runtime. But if you are an attacker, you could do // interesting things by manipulating pointers in .fini_array, for // example. So they are put into RELRO. uint32_t Type = Sec->Type; if (Type == SHT_INIT_ARRAY || Type == SHT_FINI_ARRAY || Type == SHT_PREINIT_ARRAY) return true; // .got contains pointers to external symbols. They are resolved by // the dynamic linker when a module is loaded into memory, and after // that they are not expected to change. So, it can be in RELRO. if (InX::Got && Sec == InX::Got->getParent()) return true; // .got.plt contains pointers to external function symbols. They are // by default resolved lazily, so we usually cannot put it into RELRO. // However, if "-z now" is given, the lazy symbol resolution is // disabled, which enables us to put it into RELRO. if (Sec == InX::GotPlt->getParent()) return Config->ZNow; // .dynamic section contains data for the dynamic linker, and // there's no need to write to it at runtime, so it's better to put // it into RELRO. if (Sec == InX::Dynamic->getParent()) return true; // .bss.rel.ro is used for copy relocations for read-only symbols. // Since the dynamic linker needs to process copy relocations, the // section cannot be read-only, but once initialized, they shouldn't // change. if (Sec == InX::BssRelRo->getParent()) return true; // Sections with some special names are put into RELRO. This is a // bit unfortunate because section names shouldn't be significant in // ELF in spirit. But in reality many linker features depend on // magic section names. StringRef S = Sec->Name; return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" || S == ".eh_frame" || S == ".openbsd.randomdata"; } // We compute a rank for each section. The rank indicates where the // section should be placed in the file. Instead of using simple // numbers (0,1,2...), we use a series of flags. One for each decision // point when placing the section. // Using flags has two key properties: // * It is easy to check if a give branch was taken. // * It is easy two see how similar two ranks are (see getRankProximity). enum RankFlags { RF_NOT_ADDR_SET = 1 << 16, RF_NOT_INTERP = 1 << 15, RF_NOT_ALLOC = 1 << 14, RF_WRITE = 1 << 13, RF_EXEC_WRITE = 1 << 12, RF_EXEC = 1 << 11, RF_NON_TLS_BSS = 1 << 10, RF_NON_TLS_BSS_RO = 1 << 9, RF_NOT_TLS = 1 << 8, RF_BSS = 1 << 7, RF_PPC_NOT_TOCBSS = 1 << 6, RF_PPC_OPD = 1 << 5, RF_PPC_TOCL = 1 << 4, RF_PPC_TOC = 1 << 3, RF_PPC_BRANCH_LT = 1 << 2, RF_MIPS_GPREL = 1 << 1, RF_MIPS_NOT_GOT = 1 << 0 }; static unsigned getSectionRank(const OutputSection *Sec) { unsigned Rank = 0; // We want to put section specified by -T option first, so we // can start assigning VA starting from them later. if (Config->SectionStartMap.count(Sec->Name)) return Rank; Rank |= RF_NOT_ADDR_SET; // Put .interp first because some loaders want to see that section // on the first page of the executable file when loaded into memory. if (Sec->Name == ".interp") return Rank; Rank |= RF_NOT_INTERP; // Allocatable sections go first to reduce the total PT_LOAD size and // so debug info doesn't change addresses in actual code. if (!(Sec->Flags & SHF_ALLOC)) return Rank | RF_NOT_ALLOC; // Sort sections based on their access permission in the following // order: R, RX, RWX, RW. This order is based on the following // considerations: // * Read-only sections come first such that they go in the // PT_LOAD covering the program headers at the start of the file. // * Read-only, executable sections come next, unless the // -no-rosegment option is used. // * Writable, executable sections follow such that .plt on // architectures where it needs to be writable will be placed // between .text and .data. // * Writable sections come last, such that .bss lands at the very // end of the last PT_LOAD. bool IsExec = Sec->Flags & SHF_EXECINSTR; bool IsWrite = Sec->Flags & SHF_WRITE; if (IsExec) { if (IsWrite) Rank |= RF_EXEC_WRITE; else if (!Config->SingleRoRx) Rank |= RF_EXEC; } else { if (IsWrite) Rank |= RF_WRITE; } // If we got here we know that both A and B are in the same PT_LOAD. bool IsTls = Sec->Flags & SHF_TLS; bool IsNoBits = Sec->Type == SHT_NOBITS; // The first requirement we have is to put (non-TLS) nobits sections last. The // reason is that the only thing the dynamic linker will see about them is a // p_memsz that is larger than p_filesz. Seeing that it zeros the end of the // PT_LOAD, so that has to correspond to the nobits sections. bool IsNonTlsNoBits = IsNoBits && !IsTls; if (IsNonTlsNoBits) Rank |= RF_NON_TLS_BSS; // We place nobits RelRo sections before plain r/w ones, and non-nobits RelRo // sections after r/w ones, so that the RelRo sections are contiguous. bool IsRelRo = isRelroSection(Sec); if (IsNonTlsNoBits && !IsRelRo) Rank |= RF_NON_TLS_BSS_RO; if (!IsNonTlsNoBits && IsRelRo) Rank |= RF_NON_TLS_BSS_RO; // The TLS initialization block needs to be a single contiguous block in a R/W // PT_LOAD, so stick TLS sections directly before the other RelRo R/W // sections. The TLS NOBITS sections are placed here as they don't take up // virtual address space in the PT_LOAD. if (!IsTls) Rank |= RF_NOT_TLS; // Within the TLS initialization block, the non-nobits sections need to appear // first. if (IsNoBits) Rank |= RF_BSS; // // Some architectures have additional ordering restrictions for sections // // within the same PT_LOAD. if (Config->EMachine == EM_PPC64) { // PPC64 has a number of special SHT_PROGBITS+SHF_ALLOC+SHF_WRITE sections // that we would like to make sure appear is a specific order to maximize // their coverage by a single signed 16-bit offset from the TOC base // pointer. Conversely, the special .tocbss section should be first among // all SHT_NOBITS sections. This will put it next to the loaded special // PPC64 sections (and, thus, within reach of the TOC base pointer). StringRef Name = Sec->Name; if (Name != ".tocbss") Rank |= RF_PPC_NOT_TOCBSS; if (Name == ".opd") Rank |= RF_PPC_OPD; if (Name == ".toc1") Rank |= RF_PPC_TOCL; if (Name == ".toc") Rank |= RF_PPC_TOC; if (Name == ".branch_lt") Rank |= RF_PPC_BRANCH_LT; } if (Config->EMachine == EM_MIPS) { // All sections with SHF_MIPS_GPREL flag should be grouped together // because data in these sections is addressable with a gp relative address. if (Sec->Flags & SHF_MIPS_GPREL) Rank |= RF_MIPS_GPREL; if (Sec->Name != ".got") Rank |= RF_MIPS_NOT_GOT; } return Rank; } static bool compareSectionsNonScript(const OutputSection *A, const OutputSection *B) { if (A->SortRank != B->SortRank) return A->SortRank < B->SortRank; if (!(A->SortRank & RF_NOT_ADDR_SET)) return Config->SectionStartMap.lookup(A->Name) < Config->SectionStartMap.lookup(B->Name); return false; } // Output section ordering is determined by this function. static bool compareSections(const OutputSection *A, const OutputSection *B) { // For now, put sections mentioned in a linker script // first. Sections not on linker script will have a SectionIndex of // INT_MAX. int AIndex = A->SectionIndex; int BIndex = B->SectionIndex; if (AIndex != BIndex) return AIndex < BIndex; return compareSectionsNonScript(A, B); } void PhdrEntry::add(OutputSection *Sec) { Last = Sec; if (!First) First = Sec; p_align = std::max(p_align, Sec->Alignment); if (p_type == PT_LOAD) Sec->FirstInPtLoad = First; } template static Symbol *addRegular(StringRef Name, SectionBase *Sec, uint64_t Value, uint8_t StOther = STV_HIDDEN, uint8_t Binding = STB_WEAK) { // The linker generated symbols are added as STB_WEAK to allow user defined // ones to override them. return Symtab::X->addRegular(Name, StOther, STT_NOTYPE, Value, /*Size=*/0, Binding, Sec, /*File=*/nullptr); } template static DefinedRegular * addOptionalRegular(StringRef Name, SectionBase *Sec, uint64_t Val, uint8_t StOther = STV_HIDDEN, uint8_t Binding = STB_GLOBAL) { SymbolBody *S = Symtab::X->find(Name); if (!S) return nullptr; if (S->isInCurrentDSO()) return nullptr; return cast( addRegular(Name, Sec, Val, StOther, Binding)->body()); } // The beginning and the ending of .rel[a].plt section are marked // with __rel[a]_iplt_{start,end} symbols if it is a statically linked // executable. The runtime needs these symbols in order to resolve // all IRELATIVE relocs on startup. For dynamic executables, we don't // need these symbols, since IRELATIVE relocs are resolved through GOT // and PLT. For details, see http://www.airs.com/blog/archives/403. template void Writer::addRelIpltSymbols() { if (InX::DynSymTab) return; StringRef S = Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start"; addOptionalRegular(S, In::RelaIplt, 0, STV_HIDDEN, STB_WEAK); S = Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end"; addOptionalRegular(S, In::RelaIplt, -1, STV_HIDDEN, STB_WEAK); } // The linker is expected to define some symbols depending on // the linking result. This function defines such symbols. template void Writer::addReservedSymbols() { if (Config->EMachine == EM_MIPS) { // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer // so that it points to an absolute address which by default is relative // to GOT. Default offset is 0x7ff0. // See "Global Data Symbols" in Chapter 6 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf ElfSym::MipsGp = Symtab::X->addAbsolute("_gp", STV_HIDDEN, STB_LOCAL); // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between // start of function and 'gp' pointer into GOT. if (Symtab::X->find("_gp_disp")) ElfSym::MipsGpDisp = Symtab::X->addAbsolute("_gp_disp", STV_HIDDEN, STB_LOCAL); // The __gnu_local_gp is a magic symbol equal to the current value of 'gp' // pointer. This symbol is used in the code generated by .cpload pseudo-op // in case of using -mno-shared option. // https://sourceware.org/ml/binutils/2004-12/msg00094.html if (Symtab::X->find("__gnu_local_gp")) ElfSym::MipsLocalGp = Symtab::X->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_LOCAL); } // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol // is magical and is used to produce a R_386_GOTPC relocation. // The R_386_GOTPC relocation value doesn't actually depend on the // symbol value, so it could use an index of STN_UNDEF which, according // to the spec, means the symbol value is 0. // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in // the object file. // The situation is even stranger on x86_64 where the assembly doesn't // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as // an undefined symbol in the .o files. // Given that the symbol is effectively unused, we just create a dummy // hidden one to avoid the undefined symbol error. Symtab::X->addIgnored("_GLOBAL_OFFSET_TABLE_"); // __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For // static linking the linker is required to optimize away any references to // __tls_get_addr, so it's not defined anywhere. Create a hidden definition // to avoid the undefined symbol error. if (!InX::DynSymTab) Symtab::X->addIgnored("__tls_get_addr"); // __ehdr_start is the location of ELF file headers. Note that we define // this symbol unconditionally even when using a linker script, which // differs from the behavior implemented by GNU linker which only define // this symbol if ELF headers are in the memory mapped segment. addOptionalRegular("__ehdr_start", Out::ElfHeader, 0, STV_HIDDEN); // If linker script do layout we do not need to create any standart symbols. if (Script->Opt.HasSections) return; auto Add = [](StringRef S) { return addOptionalRegular(S, Out::ElfHeader, 0, STV_DEFAULT); }; ElfSym::Bss = Add("__bss_start"); ElfSym::End1 = Add("end"); ElfSym::End2 = Add("_end"); ElfSym::Etext1 = Add("etext"); ElfSym::Etext2 = Add("_etext"); ElfSym::Edata1 = Add("edata"); ElfSym::Edata2 = Add("_edata"); } // Sort input sections by section name suffixes for // __attribute__((init_priority(N))). static void sortInitFini(OutputSection *S) { if (S) reinterpret_cast(S)->sortInitFini(); } // Sort input sections by the special rule for .ctors and .dtors. static void sortCtorsDtors(OutputSection *S) { if (S) reinterpret_cast(S)->sortCtorsDtors(); } // Sort input sections using the list provided by --symbol-ordering-file. template static void sortBySymbolsOrder(ArrayRef OutputSections) { if (Config->SymbolOrderingFile.empty()) return; // Build a map from symbols to their priorities. Symbols that didn't // appear in the symbol ordering file have the lowest priority 0. // All explicitly mentioned symbols have negative (higher) priorities. DenseMap SymbolOrder; int Priority = -Config->SymbolOrderingFile.size(); for (StringRef S : Config->SymbolOrderingFile) SymbolOrder.insert({S, Priority++}); // Build a map from sections to their priorities. DenseMap SectionOrder; for (elf::ObjectFile *File : Symtab::X->getObjectFiles()) { for (SymbolBody *Body : File->getSymbols()) { auto *D = dyn_cast(Body); if (!D || !D->Section) continue; int &Priority = SectionOrder[D->Section]; Priority = std::min(Priority, SymbolOrder.lookup(D->getName())); } } // Sort sections by priority. for (OutputSection *Base : OutputSections) if (auto *Sec = dyn_cast(Base)) Sec->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); }); } template void Writer::forEachRelSec(std::function Fn) { for (InputSectionBase *IS : InputSections) { if (!IS->Live) continue; // Scan all relocations. Each relocation goes through a series // of tests to determine if it needs special treatment, such as // creating GOT, PLT, copy relocations, etc. // Note that relocations for non-alloc sections are directly // processed by InputSection::relocateNonAlloc. if (!(IS->Flags & SHF_ALLOC)) continue; if (isa(IS) || isa(IS)) Fn(*IS); } if (!Config->Relocatable) { for (EhInputSection *ES : In::EhFrame->Sections) Fn(*ES); } } template void Writer::createSections() { for (InputSectionBase *IS : InputSections) if (IS) Factory.addInputSec(IS, getOutputSectionName(IS->Name)); sortBySymbolsOrder(OutputSections); sortInitFini(findSection(".init_array")); sortInitFini(findSection(".fini_array")); sortCtorsDtors(findSection(".ctors")); sortCtorsDtors(findSection(".dtors")); for (OutputSection *Sec : OutputSections) Sec->assignOffsets(); } // We want to find how similar two ranks are. // The more branches in getSectionRank that match, the more similar they are. // Since each branch corresponds to a bit flag, we can just use // countLeadingZeros. static unsigned getRankProximity(OutputSection *A, OutputSection *B) { return countLeadingZeros(A->SortRank ^ B->SortRank); } // We want to place orphan sections so that they share as much // characteristics with their neighbors as possible. For example, if // both are rw, or both are tls. template static std::vector::iterator findOrphanPos(std::vector::iterator B, std::vector::iterator E) { OutputSection *Sec = *E; // Find the first element that has as close a rank as possible. auto I = std::max_element(B, E, [=](OutputSection *A, OutputSection *B) { return getRankProximity(Sec, A) < getRankProximity(Sec, B); }); if (I == E) return E; // Consider all existing sections with the same proximity. unsigned Proximity = getRankProximity(Sec, *I); while (I != E && getRankProximity(Sec, *I) == Proximity && Sec->SortRank >= (*I)->SortRank) ++I; return I; } template void Writer::sortSections() { // Don't sort if using -r. It is not necessary and we want to preserve the // relative order for SHF_LINK_ORDER sections. if (Config->Relocatable) return; if (Script->Opt.HasSections) Script->adjustSectionsBeforeSorting(); for (OutputSection *Sec : OutputSections) Sec->SortRank = getSectionRank(Sec); if (!Script->Opt.HasSections) { std::stable_sort(OutputSections.begin(), OutputSections.end(), compareSectionsNonScript); return; } // The order of the sections in the script is arbitrary and may not agree with // compareSectionsNonScript. This means that we cannot easily define a // strict weak ordering. To see why, consider a comparison of a section in the // script and one not in the script. We have a two simple options: // * Make them equivalent (a is not less than b, and b is not less than a). // The problem is then that equivalence has to be transitive and we can // have sections a, b and c with only b in a script and a less than c // which breaks this property. // * Use compareSectionsNonScript. Given that the script order doesn't have // to match, we can end up with sections a, b, c, d where b and c are in the // script and c is compareSectionsNonScript less than b. In which case d // can be equivalent to c, a to b and d < a. As a concrete example: // .a (rx) # not in script // .b (rx) # in script // .c (ro) # in script // .d (ro) # not in script // // The way we define an order then is: // * First put script sections at the start and sort the script sections. // * Move each non-script section to its preferred position. We try // to put each section in the last position where it it can share // a PT_LOAD. std::stable_sort(OutputSections.begin(), OutputSections.end(), compareSections); auto I = OutputSections.begin(); auto E = OutputSections.end(); auto NonScriptI = std::find_if(OutputSections.begin(), E, [](OutputSection *S) { return S->SectionIndex == INT_MAX; }); while (NonScriptI != E) { auto Pos = findOrphanPos(I, NonScriptI); // As an optimization, find all sections with the same sort rank // and insert them with one rotate. unsigned Rank = (*NonScriptI)->SortRank; auto End = std::find_if(NonScriptI + 1, E, [=](OutputSection *Sec) { return Sec->SortRank != Rank; }); std::rotate(Pos, NonScriptI, End); NonScriptI = End; } Script->adjustSectionsAfterSorting(); } static void applySynthetic(const std::vector &Sections, std::function Fn) { for (SyntheticSection *SS : Sections) if (SS && SS->getParent() && !SS->empty()) { Fn(SS); SS->getParent()->assignOffsets(); } } // We need to add input synthetic sections early in createSyntheticSections() // to make them visible from linkescript side. But not all sections are always // required to be in output. For example we don't need dynamic section content // sometimes. This function filters out such unused sections from the output. static void removeUnusedSyntheticSections(std::vector &V) { // All input synthetic sections that can be empty are placed after // all regular ones. We iterate over them all and exit at first // non-synthetic. for (InputSectionBase *S : llvm::reverse(InputSections)) { SyntheticSection *SS = dyn_cast(S); if (!SS) return; OutputSection *OS = SS->getParent(); if (!SS->empty() || !OS) continue; OS->Sections.erase(std::find(OS->Sections.begin(), OS->Sections.end(), SS)); SS->Live = false; // If there are no other sections in the output section, remove it from the // output. if (OS->Sections.empty()) V.erase(std::find(V.begin(), V.end(), OS)); } } // Create output section objects and add them to OutputSections. template void Writer::finalizeSections() { Out::DebugInfo = findSection(".debug_info"); Out::PreinitArray = findSection(".preinit_array"); Out::InitArray = findSection(".init_array"); Out::FiniArray = findSection(".fini_array"); // The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop // symbols for sections, so that the runtime can get the start and end // addresses of each section by section name. Add such symbols. if (!Config->Relocatable) { addStartEndSymbols(); for (OutputSection *Sec : OutputSections) addStartStopSymbols(Sec); } // Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type. // It should be okay as no one seems to care about the type. // Even the author of gold doesn't remember why gold behaves that way. // https://sourceware.org/ml/binutils/2002-03/msg00360.html if (InX::DynSymTab) addRegular("_DYNAMIC", InX::Dynamic, 0); // Define __rel[a]_iplt_{start,end} symbols if needed. addRelIpltSymbols(); // This responsible for splitting up .eh_frame section into // pieces. The relocation scan uses those pieces, so this has to be // earlier. applySynthetic({In::EhFrame}, [](SyntheticSection *SS) { SS->finalizeContents(); }); // Scan relocations. This must be done after every symbol is declared so that // we can correctly decide if a dynamic relocation is needed. forEachRelSec(scanRelocations); if (InX::Plt && !InX::Plt->empty()) InX::Plt->addSymbols(); if (InX::Iplt && !InX::Iplt->empty()) InX::Iplt->addSymbols(); // Now that we have defined all possible global symbols including linker- // synthesized ones. Visit all symbols to give the finishing touches. for (Symbol *S : Symtab::X->getSymbols()) { SymbolBody *Body = S->body(); if (!includeInSymtab(*Body)) continue; if (InX::SymTab) InX::SymTab->addSymbol(Body); if (InX::DynSymTab && S->includeInDynsym()) { InX::DynSymTab->addSymbol(Body); if (auto *SS = dyn_cast(Body)) if (cast>(SS->File)->isNeeded()) In::VerNeed->addSymbol(SS); } } // Do not proceed if there was an undefined symbol. if (ErrorCount) return; addPredefinedSections(); removeUnusedSyntheticSections(OutputSections); sortSections(); // This is a bit of a hack. A value of 0 means undef, so we set it // to 1 t make __ehdr_start defined. The section number is not // particularly relevant. Out::ElfHeader->SectionIndex = 1; unsigned I = 1; for (OutputSection *Sec : OutputSections) { Sec->SectionIndex = I++; Sec->ShName = InX::ShStrTab->addString(Sec->Name); } // Binary and relocatable output does not have PHDRS. // The headers have to be created before finalize as that can influence the // image base and the dynamic section on mips includes the image base. if (!Config->Relocatable && !Config->OFormatBinary) { Phdrs = Script->hasPhdrsCommands() ? Script->createPhdrs() : createPhdrs(); addPtArmExid(Phdrs); Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size(); } // Dynamic section must be the last one in this list and dynamic // symbol table section (DynSymTab) must be the first one. applySynthetic({InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab, In::HashTab, InX::SymTab, InX::ShStrTab, InX::StrTab, In::VerDef, InX::DynStrTab, InX::GdbIndex, InX::Got, InX::MipsGot, InX::IgotPlt, InX::GotPlt, In::RelaDyn, In::RelaIplt, In::RelaPlt, InX::Plt, InX::Iplt, In::EhFrameHdr, In::VerSym, In::VerNeed, InX::Dynamic}, [](SyntheticSection *SS) { SS->finalizeContents(); }); // Some architectures use small displacements for jump instructions. // It is linker's responsibility to create thunks containing long // jump instructions if jump targets are too far. Create thunks. if (Target->NeedsThunks) { // FIXME: only ARM Interworking and Mips LA25 Thunks are implemented, // these // do not require address information. To support range extension Thunks // we need to assign addresses so that we can tell if jump instructions // are out of range. This will need to turn into a loop that converges // when no more Thunks are added ThunkCreator TC; if (TC.createThunks(OutputSections)) applySynthetic({InX::MipsGot}, [](SyntheticSection *SS) { SS->updateAllocSize(); }); } // Fill other section headers. The dynamic table is finalized // at the end because some tags like RELSZ depend on result // of finalizing other sections. for (OutputSection *Sec : OutputSections) Sec->finalize(); // createThunks may have added local symbols to the static symbol table applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab}, [](SyntheticSection *SS) { SS->postThunkContents(); }); } template void Writer::addPredefinedSections() { // ARM ABI requires .ARM.exidx to be terminated by some piece of data. // We have the terminater synthetic section class. Add that at the end. auto *OS = dyn_cast_or_null(findSection(".ARM.exidx")); if (!OS || OS->Sections.empty() || Config->Relocatable) return; auto *Sentinel = make(); OS->addSection(Sentinel); // If there are linker script commands existing at this point then add the // sentinel to the last of these too. if (OutputSectionCommand *C = Script->getCmd(OS)) { auto ISD = std::find_if(C->Commands.rbegin(), C->Commands.rend(), [](const BaseCommand *Base) { return isa(Base); }); cast(*ISD)->Sections.push_back(Sentinel); } } // The linker is expected to define SECNAME_start and SECNAME_end // symbols for a few sections. This function defines them. template void Writer::addStartEndSymbols() { auto Define = [&](StringRef Start, StringRef End, OutputSection *OS) { // These symbols resolve to the image base if the section does not exist. // A special value -1 indicates end of the section. if (OS) { addOptionalRegular(Start, OS, 0); addOptionalRegular(End, OS, -1); } else { if (Config->Pic) OS = Out::ElfHeader; addOptionalRegular(Start, OS, 0); addOptionalRegular(End, OS, 0); } }; Define("__preinit_array_start", "__preinit_array_end", Out::PreinitArray); Define("__init_array_start", "__init_array_end", Out::InitArray); Define("__fini_array_start", "__fini_array_end", Out::FiniArray); if (OutputSection *Sec = findSection(".ARM.exidx")) Define("__exidx_start", "__exidx_end", Sec); } // If a section name is valid as a C identifier (which is rare because of // the leading '.'), linkers are expected to define __start_ and // __stop_ symbols. They are at beginning and end of the section, // respectively. This is not requested by the ELF standard, but GNU ld and // gold provide the feature, and used by many programs. template void Writer::addStartStopSymbols(OutputSection *Sec) { StringRef S = Sec->Name; if (!isValidCIdentifier(S)) return; addOptionalRegular(Saver.save("__start_" + S), Sec, 0, STV_DEFAULT); addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT); } template OutputSectionCommand *Writer::findSectionCommand(StringRef Name) { for (OutputSectionCommand *Cmd : OutputSectionCommands) if (Cmd->Name == Name) return Cmd; return nullptr; } template OutputSection *Writer::findSectionInScript(StringRef Name) { if (OutputSectionCommand *Cmd = findSectionCommand(Name)) return Cmd->Sec; return nullptr; } template OutputSection *Writer::findSection(StringRef Name) { for (OutputSection *Sec : OutputSections) if (Sec->Name == Name) return Sec; return nullptr; } static bool needsPtLoad(OutputSection *Sec) { if (!(Sec->Flags & SHF_ALLOC)) return false; // Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is // responsible for allocating space for them, not the PT_LOAD that // contains the TLS initialization image. if (Sec->Flags & SHF_TLS && Sec->Type == SHT_NOBITS) return false; return true; } // Linker scripts are responsible for aligning addresses. Unfortunately, most // linker scripts are designed for creating two PT_LOADs only, one RX and one // RW. This means that there is no alignment in the RO to RX transition and we // cannot create a PT_LOAD there. static uint64_t computeFlags(uint64_t Flags) { if (Config->Omagic) return PF_R | PF_W | PF_X; if (Config->SingleRoRx && !(Flags & PF_W)) return Flags | PF_X; return Flags; } // Decide which program headers to create and which sections to include in each // one. template std::vector Writer::createPhdrs() { std::vector Ret; auto AddHdr = [&](unsigned Type, unsigned Flags) -> PhdrEntry * { Ret.emplace_back(Type, Flags); return &Ret.back(); }; // The first phdr entry is PT_PHDR which describes the program header itself. AddHdr(PT_PHDR, PF_R)->add(Out::ProgramHeaders); // PT_INTERP must be the second entry if exists. if (OutputSection *Sec = findSection(".interp")) AddHdr(PT_INTERP, Sec->getPhdrFlags())->add(Sec); // Add the first PT_LOAD segment for regular output sections. uint64_t Flags = computeFlags(PF_R); PhdrEntry *Load = AddHdr(PT_LOAD, Flags); // Add the headers. We will remove them if they don't fit. Load->add(Out::ElfHeader); Load->add(Out::ProgramHeaders); for (OutputSection *Sec : OutputSections) { if (!(Sec->Flags & SHF_ALLOC)) break; if (!needsPtLoad(Sec)) continue; // Segments are contiguous memory regions that has the same attributes // (e.g. executable or writable). There is one phdr for each segment. // Therefore, we need to create a new phdr when the next section has // different flags or is loaded at a discontiguous address using AT linker // script command. uint64_t NewFlags = computeFlags(Sec->getPhdrFlags()); if (Script->hasLMA(Sec) || Flags != NewFlags) { Load = AddHdr(PT_LOAD, NewFlags); Flags = NewFlags; } Load->add(Sec); } // Add a TLS segment if any. PhdrEntry TlsHdr(PT_TLS, PF_R); for (OutputSection *Sec : OutputSections) if (Sec->Flags & SHF_TLS) TlsHdr.add(Sec); if (TlsHdr.First) Ret.push_back(std::move(TlsHdr)); // Add an entry for .dynamic. if (InX::DynSymTab) AddHdr(PT_DYNAMIC, InX::Dynamic->getParent()->getPhdrFlags()) ->add(InX::Dynamic->getParent()); // PT_GNU_RELRO includes all sections that should be marked as // read-only by dynamic linker after proccessing relocations. PhdrEntry RelRo(PT_GNU_RELRO, PF_R); for (OutputSection *Sec : OutputSections) if (needsPtLoad(Sec) && isRelroSection(Sec)) RelRo.add(Sec); if (RelRo.First) Ret.push_back(std::move(RelRo)); // PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr. if (!In::EhFrame->empty() && In::EhFrameHdr && In::EhFrame->getParent() && In::EhFrameHdr->getParent()) AddHdr(PT_GNU_EH_FRAME, In::EhFrameHdr->getParent()->getPhdrFlags()) ->add(In::EhFrameHdr->getParent()); // PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes // the dynamic linker fill the segment with random data. if (OutputSection *Sec = findSection(".openbsd.randomdata")) AddHdr(PT_OPENBSD_RANDOMIZE, Sec->getPhdrFlags())->add(Sec); // PT_GNU_STACK is a special section to tell the loader to make the // pages for the stack non-executable. If you really want an executable // stack, you can pass -z execstack, but that's not recommended for // security reasons. unsigned Perm; if (Config->ZExecstack) Perm = PF_R | PF_W | PF_X; else Perm = PF_R | PF_W; AddHdr(PT_GNU_STACK, Perm)->p_memsz = Config->ZStackSize; // PT_OPENBSD_WXNEEDED is a OpenBSD-specific header to mark the executable // is expected to perform W^X violations, such as calling mprotect(2) or // mmap(2) with PROT_WRITE | PROT_EXEC, which is prohibited by default on // OpenBSD. if (Config->ZWxneeded) AddHdr(PT_OPENBSD_WXNEEDED, PF_X); // Create one PT_NOTE per a group of contiguous .note sections. PhdrEntry *Note = nullptr; for (OutputSection *Sec : OutputSections) { if (Sec->Type == SHT_NOTE) { if (!Note || Script->hasLMA(Sec)) Note = AddHdr(PT_NOTE, PF_R); Note->add(Sec); } else { Note = nullptr; } } return Ret; } template void Writer::addPtArmExid(std::vector &Phdrs) { if (Config->EMachine != EM_ARM) return; auto I = std::find_if( OutputSections.begin(), OutputSections.end(), [](OutputSection *Sec) { return Sec->Type == SHT_ARM_EXIDX; }); if (I == OutputSections.end()) return; // PT_ARM_EXIDX is the ARM EHABI equivalent of PT_GNU_EH_FRAME PhdrEntry ARMExidx(PT_ARM_EXIDX, PF_R); ARMExidx.add(*I); Phdrs.push_back(ARMExidx); } // The first section of each PT_LOAD, the first section in PT_GNU_RELRO and the // first section after PT_GNU_RELRO have to be page aligned so that the dynamic // linker can set the permissions. template void Writer::fixSectionAlignments() { + auto PageAlign = [](OutputSection *Sec) { + OutputSectionCommand *Cmd = Script->getCmd(Sec); + if (Cmd && !Cmd->AddrExpr) + Cmd->AddrExpr = [=] { + return alignTo(Script->getDot(), Config->MaxPageSize); + }; + }; + for (const PhdrEntry &P : Phdrs) if (P.p_type == PT_LOAD && P.First) - P.First->PageAlign = true; + PageAlign(P.First); for (const PhdrEntry &P : Phdrs) { if (P.p_type != PT_GNU_RELRO) continue; if (P.First) - P.First->PageAlign = true; + PageAlign(P.First); // Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we // have to align it to a page. - auto End = OutputSections.end(); - auto I = std::find(OutputSections.begin(), End, P.Last); + auto End = OutputSectionCommands.end(); + auto I = + std::find(OutputSectionCommands.begin(), End, Script->getCmd(P.Last)); if (I == End || (I + 1) == End) continue; - OutputSection *Sec = *(I + 1); + OutputSection *Sec = (*(I + 1))->Sec; if (needsPtLoad(Sec)) - Sec->PageAlign = true; + PageAlign(Sec); } } // Adjusts the file alignment for a given output section and returns // its new file offset. The file offset must be the same with its // virtual address (modulo the page size) so that the loader can load // executables without any address adjustment. static uint64_t getFileAlignment(uint64_t Off, OutputSection *Sec) { OutputSection *First = Sec->FirstInPtLoad; // If the section is not in a PT_LOAD, we just have to align it. if (!First) return alignTo(Off, Sec->Alignment); // The first section in a PT_LOAD has to have congruent offset and address // module the page size. if (Sec == First) return alignTo(Off, Config->MaxPageSize, Sec->Addr); // If two sections share the same PT_LOAD the file offset is calculated // using this formula: Off2 = Off1 + (VA2 - VA1). return First->Offset + Sec->Addr - First->Addr; } static uint64_t setOffset(OutputSection *Sec, uint64_t Off) { if (Sec->Type == SHT_NOBITS) { Sec->Offset = Off; return Off; } Off = getFileAlignment(Off, Sec); Sec->Offset = Off; return Off + Sec->Size; } template void Writer::assignFileOffsetsBinary() { uint64_t Off = 0; for (OutputSectionCommand *Cmd : OutputSectionCommands) { OutputSection *Sec = Cmd->Sec; if (Sec->Flags & SHF_ALLOC) Off = setOffset(Sec, Off); } FileSize = alignTo(Off, Config->Wordsize); } // Assign file offsets to output sections. template void Writer::assignFileOffsets() { uint64_t Off = 0; Off = setOffset(Out::ElfHeader, Off); Off = setOffset(Out::ProgramHeaders, Off); for (OutputSectionCommand *Cmd : OutputSectionCommands) Off = setOffset(Cmd->Sec, Off); SectionHeaderOff = alignTo(Off, Config->Wordsize); FileSize = SectionHeaderOff + (OutputSectionCommands.size() + 1) * sizeof(Elf_Shdr); } // Finalize the program headers. We call this function after we assign // file offsets and VAs to all sections. template void Writer::setPhdrs() { for (PhdrEntry &P : Phdrs) { OutputSection *First = P.First; OutputSection *Last = P.Last; if (First) { P.p_filesz = Last->Offset - First->Offset; if (Last->Type != SHT_NOBITS) P.p_filesz += Last->Size; P.p_memsz = Last->Addr + Last->Size - First->Addr; P.p_offset = First->Offset; P.p_vaddr = First->Addr; if (!P.HasLMA) P.p_paddr = First->getLMA(); } if (P.p_type == PT_LOAD) P.p_align = Config->MaxPageSize; else if (P.p_type == PT_GNU_RELRO) { P.p_align = 1; // The glibc dynamic loader rounds the size down, so we need to round up // to protect the last page. This is a no-op on FreeBSD which always // rounds up. P.p_memsz = alignTo(P.p_memsz, Target->PageSize); } // The TLS pointer goes after PT_TLS. At least glibc will align it, // so round up the size to make sure the offsets are correct. if (P.p_type == PT_TLS) { Out::TlsPhdr = &P; if (P.p_memsz) P.p_memsz = alignTo(P.p_memsz, P.p_align); } } } // The entry point address is chosen in the following ways. // // 1. the '-e' entry command-line option; // 2. the ENTRY(symbol) command in a linker control script; // 3. the value of the symbol start, if present; // 4. the address of the first byte of the .text section, if present; // 5. the address 0. template uint64_t Writer::getEntryAddr() { // Case 1, 2 or 3. As a special case, if the symbol is actually // a number, we'll use that number as an address. if (SymbolBody *B = Symtab::X->find(Config->Entry)) return B->getVA(); uint64_t Addr; if (to_integer(Config->Entry, Addr)) return Addr; // Case 4 if (OutputSection *Sec = findSectionInScript(".text")) { if (Config->WarnMissingEntry) warn("cannot find entry symbol " + Config->Entry + "; defaulting to 0x" + utohexstr(Sec->Addr)); return Sec->Addr; } // Case 5 if (Config->WarnMissingEntry) warn("cannot find entry symbol " + Config->Entry + "; not setting start address"); return 0; } static uint16_t getELFType() { if (Config->Pic) return ET_DYN; if (Config->Relocatable) return ET_REL; return ET_EXEC; } // This function is called after we have assigned address and size // to each section. This function fixes some predefined // symbol values that depend on section address and size. template void Writer::fixPredefinedSymbols() { // _etext is the first location after the last read-only loadable segment. // _edata is the first location after the last read-write loadable segment. // _end is the first location after the uninitialized data region. PhdrEntry *Last = nullptr; PhdrEntry *LastRO = nullptr; PhdrEntry *LastRW = nullptr; for (PhdrEntry &P : Phdrs) { if (P.p_type != PT_LOAD) continue; Last = &P; if (P.p_flags & PF_W) LastRW = &P; else LastRO = &P; } auto Set = [](DefinedRegular *S, OutputSection *Sec, uint64_t Value) { if (S) { S->Section = Sec; S->Value = Value; } }; if (Last) { Set(ElfSym::End1, Last->First, Last->p_memsz); Set(ElfSym::End2, Last->First, Last->p_memsz); } if (LastRO) { Set(ElfSym::Etext1, LastRO->First, LastRO->p_filesz); Set(ElfSym::Etext2, LastRO->First, LastRO->p_filesz); } if (LastRW) { Set(ElfSym::Edata1, LastRW->First, LastRW->p_filesz); Set(ElfSym::Edata2, LastRW->First, LastRW->p_filesz); } if (ElfSym::Bss) ElfSym::Bss->Section = findSectionInScript(".bss"); // Setup MIPS _gp_disp/__gnu_local_gp symbols which should // be equal to the _gp symbol's value. if (Config->EMachine == EM_MIPS && !ElfSym::MipsGp->Value) { // Find GP-relative section with the lowest address // and use this address to calculate default _gp value. for (const OutputSectionCommand *Cmd : OutputSectionCommands) { OutputSection *OS = Cmd->Sec; if (OS->Flags & SHF_MIPS_GPREL) { ElfSym::MipsGp->Value = OS->Addr + 0x7ff0; break; } } } } template void Writer::writeHeader() { uint8_t *Buf = Buffer->getBufferStart(); memcpy(Buf, "\177ELF", 4); // Write the ELF header. auto *EHdr = reinterpret_cast(Buf); EHdr->e_ident[EI_CLASS] = Config->Is64 ? ELFCLASS64 : ELFCLASS32; EHdr->e_ident[EI_DATA] = Config->IsLE ? ELFDATA2LSB : ELFDATA2MSB; EHdr->e_ident[EI_VERSION] = EV_CURRENT; EHdr->e_ident[EI_OSABI] = Config->OSABI; EHdr->e_type = getELFType(); EHdr->e_machine = Config->EMachine; EHdr->e_version = EV_CURRENT; EHdr->e_entry = getEntryAddr(); EHdr->e_shoff = SectionHeaderOff; EHdr->e_ehsize = sizeof(Elf_Ehdr); EHdr->e_phnum = Phdrs.size(); EHdr->e_shentsize = sizeof(Elf_Shdr); EHdr->e_shnum = OutputSectionCommands.size() + 1; EHdr->e_shstrndx = InX::ShStrTab->getParent()->SectionIndex; if (Config->EMachine == EM_ARM) // We don't currently use any features incompatible with EF_ARM_EABI_VER5, // but we don't have any firm guarantees of conformance. Linux AArch64 // kernels (as of 2016) require an EABI version to be set. EHdr->e_flags = EF_ARM_EABI_VER5; else if (Config->EMachine == EM_MIPS) EHdr->e_flags = getMipsEFlags(); if (!Config->Relocatable) { EHdr->e_phoff = sizeof(Elf_Ehdr); EHdr->e_phentsize = sizeof(Elf_Phdr); } // Write the program header table. auto *HBuf = reinterpret_cast(Buf + EHdr->e_phoff); for (PhdrEntry &P : Phdrs) { HBuf->p_type = P.p_type; HBuf->p_flags = P.p_flags; HBuf->p_offset = P.p_offset; HBuf->p_vaddr = P.p_vaddr; HBuf->p_paddr = P.p_paddr; HBuf->p_filesz = P.p_filesz; HBuf->p_memsz = P.p_memsz; HBuf->p_align = P.p_align; ++HBuf; } // Write the section header table. Note that the first table entry is null. auto *SHdrs = reinterpret_cast(Buf + EHdr->e_shoff); for (OutputSectionCommand *Cmd : OutputSectionCommands) Cmd->Sec->writeHeaderTo(++SHdrs); } // Open a result file. template void Writer::openFile() { if (!Config->Is64 && FileSize > UINT32_MAX) { error("output file too large: " + Twine(FileSize) + " bytes"); return; } unlinkAsync(Config->OutputFile); ErrorOr> BufferOrErr = FileOutputBuffer::create(Config->OutputFile, FileSize, FileOutputBuffer::F_executable); if (auto EC = BufferOrErr.getError()) error("failed to open " + Config->OutputFile + ": " + EC.message()); else Buffer = std::move(*BufferOrErr); } template void Writer::writeSectionsBinary() { uint8_t *Buf = Buffer->getBufferStart(); for (OutputSectionCommand *Cmd : OutputSectionCommands) { OutputSection *Sec = Cmd->Sec; if (Sec->Flags & SHF_ALLOC) Cmd->writeTo(Buf + Sec->Offset); } } // Write section contents to a mmap'ed file. template void Writer::writeSections() { uint8_t *Buf = Buffer->getBufferStart(); // PPC64 needs to process relocations in the .opd section // before processing relocations in code-containing sections. if (auto *OpdCmd = findSectionCommand(".opd")) { Out::Opd = OpdCmd->Sec; Out::OpdBuf = Buf + Out::Opd->Offset; OpdCmd->template writeTo(Buf + Out::Opd->Offset); } OutputSection *EhFrameHdr = (In::EhFrameHdr && !In::EhFrameHdr->empty()) ? In::EhFrameHdr->getParent() : nullptr; // In -r or -emit-relocs mode, write the relocation sections first as in // ELf_Rel targets we might find out that we need to modify the relocated // section while doing it. for (OutputSectionCommand *Cmd : OutputSectionCommands) { OutputSection *Sec = Cmd->Sec; if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) Cmd->writeTo(Buf + Sec->Offset); } for (OutputSectionCommand *Cmd : OutputSectionCommands) { OutputSection *Sec = Cmd->Sec; if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA) Cmd->writeTo(Buf + Sec->Offset); } // The .eh_frame_hdr depends on .eh_frame section contents, therefore // it should be written after .eh_frame is written. if (EhFrameHdr) { OutputSectionCommand *Cmd = Script->getCmd(EhFrameHdr); Cmd->writeTo(Buf + EhFrameHdr->Offset); } } template void Writer::writeBuildId() { if (!InX::BuildId || !InX::BuildId->getParent()) return; // Compute a hash of all sections of the output file. uint8_t *Start = Buffer->getBufferStart(); uint8_t *End = Start + FileSize; InX::BuildId->writeBuildId({Start, End}); } template void elf::writeResult(); template void elf::writeResult(); template void elf::writeResult(); template void elf::writeResult(); Index: vendor/lld/dist/test/COFF/armnt-imports.test =================================================================== --- vendor/lld/dist/test/COFF/armnt-imports.test (revision 319530) +++ vendor/lld/dist/test/COFF/armnt-imports.test (revision 319531) @@ -1,51 +1,51 @@ # RUN: yaml2obj < %s > %t.obj # RUN: lld-link /out:%t.exe /subsystem:console %t.obj \ # RUN: /entry:mainCRTStartup %p/Inputs/library.lib # RUN: llvm-readobj -coff-imports %t.exe | FileCheck %s # CHECK: Import { # CHECK: Name: library.dll # CHECK: ImportLookupTableRVA: 0x2028 -# CHECK: ImportAddressTableRVA: 0x2028 +# CHECK: ImportAddressTableRVA: 0x2030 # CHECK: Symbol: function (0) # CHECK: } --- !COFF header: Machine: IMAGE_FILE_MACHINE_ARMNT Characteristics: [ ] sections: - Name: .text Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_16BIT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] Alignment: 4 SectionData: 40F20000C0F2000000680047 Relocations: - VirtualAddress: 0 SymbolName: __imp_function Type: 17 symbols: - Name: .text Value: 0 SectionNumber: 1 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC SectionDefinition: Length: 12 NumberOfRelocations: 1 NumberOfLinenumbers: 0 CheckSum: 0 Number: 1 - Name: mainCRTStartup Value: 0 SectionNumber: 1 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_FUNCTION StorageClass: IMAGE_SYM_CLASS_EXTERNAL - Name: __imp_function Value: 0 SectionNumber: 0 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_EXTERNAL ... Index: vendor/lld/dist/test/COFF/def-export-stdcall.s =================================================================== --- vendor/lld/dist/test/COFF/def-export-stdcall.s (nonexistent) +++ vendor/lld/dist/test/COFF/def-export-stdcall.s (revision 319531) @@ -0,0 +1,25 @@ +# RUN: llvm-mc -filetype=obj -triple=i686-windows-msvc %s -o %t.obj +# RUN: echo -e "LIBRARY foo\nEXPORTS\n stdcall" > %t.def +# RUN: lld-link -entry:dllmain -dll -def:%t.def %t.obj -out:%t.dll -implib:%t.lib +# RUN: llvm-nm %t.lib | FileCheck %s +# CHECK: __imp__stdcall@8 +# CHECK: _stdcall@8 + + .def _stdcall@8; + .scl 2; + .type 32; + .endef + .globl _stdcall@8 +_stdcall@8: + movl 8(%esp), %eax + addl 4(%esp), %eax + retl $8 + + .def _dllmain; + .scl 2; + .type 32; + .endef + .globl _dllmain +_dllmain: + retl + Property changes on: vendor/lld/dist/test/COFF/def-export-stdcall.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/COFF/hello32.test =================================================================== --- vendor/lld/dist/test/COFF/hello32.test (revision 319530) +++ vendor/lld/dist/test/COFF/hello32.test (revision 319531) @@ -1,131 +1,131 @@ # RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj # RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \ # RUN: /entry:main@0 /out:%t.exe /appcontainer # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s # RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s HEADER: Format: COFF-i386 HEADER-NEXT: Arch: i386 HEADER-NEXT: AddressSize: 32bit HEADER-NEXT: ImageFileHeader { HEADER-NEXT: Machine: IMAGE_FILE_MACHINE_I386 (0x14C) HEADER-NEXT: SectionCount: 4 HEADER-NEXT: TimeDateStamp: 1970-01-01 00:00:00 (0x0) HEADER-NEXT: PointerToSymbolTable: 0x0 HEADER-NEXT: SymbolCount: 0 HEADER-NEXT: OptionalHeaderSize: 224 HEADER-NEXT: Characteristics [ (0x102) HEADER-NEXT: IMAGE_FILE_32BIT_MACHINE (0x100) HEADER-NEXT: IMAGE_FILE_EXECUTABLE_IMAGE (0x2) HEADER-NEXT: ] HEADER-NEXT: } HEADER-NEXT: ImageOptionalHeader { HEADER-NEXT: MajorLinkerVersion: 0 HEADER-NEXT: MinorLinkerVersion: 0 HEADER-NEXT: SizeOfCode: 512 HEADER-NEXT: SizeOfInitializedData: 1536 HEADER-NEXT: SizeOfUninitializedData: 0 HEADER-NEXT: AddressOfEntryPoint: 0x2000 HEADER-NEXT: BaseOfCode: 0x2000 HEADER-NEXT: BaseOfData: 0x0 HEADER-NEXT: ImageBase: 0x400000 HEADER-NEXT: SectionAlignment: 4096 HEADER-NEXT: FileAlignment: 512 HEADER-NEXT: MajorOperatingSystemVersion: 6 HEADER-NEXT: MinorOperatingSystemVersion: 0 HEADER-NEXT: MajorImageVersion: 0 HEADER-NEXT: MinorImageVersion: 0 HEADER-NEXT: MajorSubsystemVersion: 6 HEADER-NEXT: MinorSubsystemVersion: 0 HEADER-NEXT: SizeOfImage: 16896 HEADER-NEXT: SizeOfHeaders: 512 HEADER-NEXT: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3) HEADER-NEXT: Characteristics [ (0x9940) HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_APPCONTAINER (0x1000) HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE (0x40) HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_NO_BIND (0x800) HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT (0x100) HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE (0x8000) HEADER-NEXT: ] HEADER-NEXT: SizeOfStackReserve: 1048576 HEADER-NEXT: SizeOfStackCommit: 4096 HEADER-NEXT: SizeOfHeapReserve: 1048576 HEADER-NEXT: SizeOfHeapCommit: 4096 HEADER-NEXT: NumberOfRvaAndSize: 16 HEADER-NEXT: DataDirectory { HEADER-NEXT: ExportTableRVA: 0x0 HEADER-NEXT: ExportTableSize: 0x0 HEADER-NEXT: ImportTableRVA: 0x3000 HEADER-NEXT: ImportTableSize: 0x28 HEADER-NEXT: ResourceTableRVA: 0x0 HEADER-NEXT: ResourceTableSize: 0x0 HEADER-NEXT: ExceptionTableRVA: 0x0 HEADER-NEXT: ExceptionTableSize: 0x0 HEADER-NEXT: CertificateTableRVA: 0x0 HEADER-NEXT: CertificateTableSize: 0x0 HEADER-NEXT: BaseRelocationTableRVA: 0x4000 HEADER-NEXT: BaseRelocationTableSize: 0x10 HEADER-NEXT: DebugRVA: 0x0 HEADER-NEXT: DebugSize: 0x0 HEADER-NEXT: ArchitectureRVA: 0x0 HEADER-NEXT: ArchitectureSize: 0x0 HEADER-NEXT: GlobalPtrRVA: 0x0 HEADER-NEXT: GlobalPtrSize: 0x0 HEADER-NEXT: TLSTableRVA: 0x0 HEADER-NEXT: TLSTableSize: 0x0 HEADER-NEXT: LoadConfigTableRVA: 0x0 HEADER-NEXT: LoadConfigTableSize: 0x0 HEADER-NEXT: BoundImportRVA: 0x0 HEADER-NEXT: BoundImportSize: 0x0 -HEADER-NEXT: IATRVA: 0x3028 +HEADER-NEXT: IATRVA: 0x3034 HEADER-NEXT: IATSize: 0xC HEADER-NEXT: DelayImportDescriptorRVA: 0x0 HEADER-NEXT: DelayImportDescriptorSize: 0x0 HEADER-NEXT: CLRRuntimeHeaderRVA: 0x0 HEADER-NEXT: CLRRuntimeHeaderSize: 0x0 HEADER-NEXT: ReservedRVA: 0x0 HEADER-NEXT: ReservedSize: 0x0 HEADER-NEXT: } HEADER-NEXT: } HEADER-NEXT: DOSHeader { HEADER-NEXT: Magic: MZ HEADER-NEXT: UsedBytesInTheLastPage: 0 HEADER-NEXT: FileSizeInPages: 0 HEADER-NEXT: NumberOfRelocationItems: 0 HEADER-NEXT: HeaderSizeInParagraphs: 0 HEADER-NEXT: MinimumExtraParagraphs: 0 HEADER-NEXT: MaximumExtraParagraphs: 0 HEADER-NEXT: InitialRelativeSS: 0 HEADER-NEXT: InitialSP: 0 HEADER-NEXT: Checksum: 0 HEADER-NEXT: InitialIP: 0 HEADER-NEXT: InitialRelativeCS: 0 HEADER-NEXT: AddressOfRelocationTable: 64 HEADER-NEXT: OverlayNumber: 0 HEADER-NEXT: OEMid: 0 HEADER-NEXT: OEMinfo: 0 HEADER-NEXT: AddressOfNewExeHeader: 64 HEADER-NEXT: } IMPORTS: Format: COFF-i386 IMPORTS: Arch: i386 IMPORTS: AddressSize: 32bit IMPORTS: Import { IMPORTS: Name: std32.dll IMPORTS: ImportLookupTableRVA: 0x3028 -IMPORTS: ImportAddressTableRVA: 0x3028 +IMPORTS: ImportAddressTableRVA: 0x3034 IMPORTS: Symbol: ExitProcess (0) IMPORTS: Symbol: MessageBoxA (1) IMPORTS: } BASEREL: BaseReloc [ BASEREL: Entry { BASEREL: Type: HIGHLOW BASEREL: Address: 0x2005 BASEREL: } BASEREL: Entry { BASEREL: Type: HIGHLOW BASEREL: Address: 0x200C BASEREL: } BASEREL: ] Index: vendor/lld/dist/test/COFF/imports.test =================================================================== --- vendor/lld/dist/test/COFF/imports.test (revision 319530) +++ vendor/lld/dist/test/COFF/imports.test (revision 319531) @@ -1,35 +1,35 @@ # Verify that the lld can handle .lib files and emit .idata sections. # # RUN: lld-link /out:%t.exe /entry:main /subsystem:console \ # RUN: %p/Inputs/hello64.obj %p/Inputs/std64.lib # RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=TEXT %s # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s # RUN: lld-link /out:%t.exe /entry:main /subsystem:console \ # RUN: %p/Inputs/hello64.obj %p/Inputs/std64.lib /include:ExitProcess # RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=TEXT %s # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s TEXT: Disassembly of section .text: TEXT-NEXT: .text: TEXT-NEXT: subq $40, %rsp TEXT-NEXT: movq $0, %rcx TEXT-NEXT: leaq -4108(%rip), %rdx TEXT-NEXT: leaq -4121(%rip), %r8 TEXT-NEXT: movl $0, %r9d TEXT-NEXT: callq 60 TEXT-NEXT: movl $0, %ecx TEXT-NEXT: callq 18 TEXT-NEXT: callq 29 -TEXT: jmpq *4066(%rip) -TEXT: jmpq *4058(%rip) -TEXT: jmpq *4050(%rip) +TEXT: jmpq *4098(%rip) +TEXT: jmpq *4090(%rip) +TEXT: jmpq *4082(%rip) IMPORT: Import { IMPORT-NEXT: Name: std64.dll IMPORT-NEXT: ImportLookupTableRVA: 0x3028 -IMPORT-NEXT: ImportAddressTableRVA: 0x3028 +IMPORT-NEXT: ImportAddressTableRVA: 0x3048 IMPORT-NEXT: Symbol: ExitProcess (0) IMPORT-NEXT: Symbol: (50) IMPORT-NEXT: Symbol: MessageBoxA (1) IMPORT-NEXT: } Index: vendor/lld/dist/test/ELF/emit-relocs.s =================================================================== --- vendor/lld/dist/test/ELF/emit-relocs.s (revision 319530) +++ vendor/lld/dist/test/ELF/emit-relocs.s (revision 319531) @@ -1,99 +1,106 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o # RUN: ld.lld --emit-relocs %t1.o -o %t -# RUN: llvm-readobj -t -r %t | FileCheck %s +# RUN: llvm-readobj -t -r -s %t | FileCheck %s ## Check single dash form. # RUN: ld.lld -emit-relocs %t1.o -o %t1 -# RUN: llvm-readobj -t -r %t1 | FileCheck %s +# RUN: llvm-readobj -t -r -s %t1 | FileCheck %s ## Check alias. # RUN: ld.lld -q %t1.o -o %t2 -# RUN: llvm-readobj -t -r %t2 | FileCheck %s +# RUN: llvm-readobj -t -r -s %t2 | FileCheck %s +# CHECK: Section { +# CHECK: Index: 2 +# CHECK-NEXT: Name: .rela.text +# CHECK-NEXT: Type: SHT_RELA +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_INFO_LINK +# CHECK-NEXT: ] # CHECK: Relocations [ # CHECK-NEXT: Section ({{.*}}) .rela.text { # CHECK-NEXT: 0x201002 R_X86_64_32 .text 0x1 # CHECK-NEXT: 0x201007 R_X86_64_PLT32 fn 0xFFFFFFFFFFFFFFFC # CHECK-NEXT: 0x20100E R_X86_64_32 .text 0xD # CHECK-NEXT: 0x201013 R_X86_64_PLT32 fn2 0xFFFFFFFFFFFFFFFC # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: Symbols [ # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: # CHECK-NEXT: Value: 0x0 # CHECK-NEXT: Size: 0 # CHECK-NEXT: Binding: Local # CHECK-NEXT: Type: None # CHECK-NEXT: Other: 0 # CHECK-NEXT: Section: Undefined # CHECK-NEXT: } # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: bar # CHECK-NEXT: Value: 0x201001 # CHECK-NEXT: Size: 0 # CHECK-NEXT: Binding: Local # CHECK-NEXT: Type: None # CHECK-NEXT: Other: 0 # CHECK-NEXT: Section: .text # CHECK-NEXT: } # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: foo # CHECK-NEXT: Value: 0x20100D # CHECK-NEXT: Size: 0 # CHECK-NEXT: Binding: Local # CHECK-NEXT: Type: None # CHECK-NEXT: Other: 0 # CHECK-NEXT: Section: .text # CHECK-NEXT: } # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: # CHECK-NEXT: Value: 0x201000 # CHECK-NEXT: Size: 0 # CHECK-NEXT: Binding: Local # CHECK-NEXT: Type: Section # CHECK-NEXT: Other: 0 # CHECK-NEXT: Section: .text # CHECK-NEXT: } # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: fn # CHECK-NEXT: Value: 0x201000 # CHECK-NEXT: Size: 0 # CHECK-NEXT: Binding: Global # CHECK-NEXT: Type: Function # CHECK-NEXT: Other: 0 # CHECK-NEXT: Section: .text # CHECK-NEXT: } # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: fn2 # CHECK-NEXT: Value: 0x20100C # CHECK-NEXT: Size: 0 # CHECK-NEXT: Binding: Global # CHECK-NEXT: Type: Function # CHECK-NEXT: Other: 0 # CHECK-NEXT: Section: .text # CHECK-NEXT: } # CHECK-NEXT: ] .section .text,"ax",@progbits,unique,0 .globl fn .type fn,@function fn: nop bar: movl $bar, %edx callq fn@PLT nop .section .text,"ax",@progbits,unique,1 .globl fn2 .type fn2,@function fn2: nop foo: movl $foo, %edx callq fn2@PLT nop