Index: vendor/lld/dist/ELF/InputFiles.h =================================================================== --- vendor/lld/dist/ELF/InputFiles.h (revision 313062) +++ vendor/lld/dist/ELF/InputFiles.h (revision 313063) @@ -1,342 +1,338 @@ //===- InputFiles.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_INPUT_FILES_H #define LLD_ELF_INPUT_FILES_H #include "Config.h" #include "InputSection.h" #include "Error.h" #include "Symbols.h" #include "lld/Core/LLVM.h" #include "lld/Core/Reproduce.h" #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/IR/Comdat.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ELF.h" #include "llvm/Object/IRObjectFile.h" #include namespace llvm { class DWARFDebugLine; class TarWriter; namespace lto { class InputFile; } } namespace lld { namespace elf { class InputFile; } // Returns "(internal)", "foo.a(bar.o)" or "baz.o". std::string toString(const elf::InputFile *F); namespace elf { using llvm::object::Archive; class Lazy; class SymbolBody; // If -reproduce option is given, all input files are written // to this tar archive. extern llvm::TarWriter *Tar; // Opens a given file. llvm::Optional readFile(StringRef Path); // The root class of input files. class InputFile { public: enum Kind { ObjectKind, SharedKind, LazyObjectKind, ArchiveKind, BitcodeKind, BinaryKind, }; Kind kind() const { return FileKind; } StringRef getName() const { return MB.getBufferIdentifier(); } MemoryBufferRef MB; // Filename of .a which contained this file. If this file was // not in an archive file, it is the empty string. We use this // string for creating error messages. StringRef ArchiveName; // If this file is in an archive, the member contains the offset of // the file in the archive. Otherwise, it's just zero. We store this // field so that we can pass it to lib/LTO in order to disambiguate // between objects. uint64_t OffsetInArchive; // If this is an architecture-specific file, the following members // have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type. ELFKind EKind = ELFNoneKind; uint16_t EMachine = llvm::ELF::EM_NONE; uint8_t OSABI = 0; protected: InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} private: const Kind FileKind; }; template class ELFFileBase : public InputFile { public: typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::Word Elf_Word; typedef typename ELFT::SymRange Elf_Sym_Range; ELFFileBase(Kind K, MemoryBufferRef M); static bool classof(const InputFile *F) { Kind K = F->kind(); return K == ObjectKind || K == SharedKind; } llvm::object::ELFFile getObj() const { return llvm::object::ELFFile(MB.getBuffer()); } StringRef getStringTable() const { return StringTable; } uint32_t getSectionIndex(const Elf_Sym &Sym) const; Elf_Sym_Range getGlobalSymbols(); protected: ArrayRef Symbols; uint32_t FirstNonLocal = 0; ArrayRef SymtabSHNDX; StringRef StringTable; void initSymtab(ArrayRef Sections, const Elf_Shdr *Symtab); }; // .o file. template class ObjectFile : public ELFFileBase { typedef ELFFileBase Base; typedef typename ELFT::Rel Elf_Rel; typedef typename ELFT::Rela Elf_Rela; typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::SymRange Elf_Sym_Range; typedef typename ELFT::Word Elf_Word; typedef typename ELFT::uint uintX_t; StringRef getShtGroupSignature(ArrayRef Sections, const Elf_Shdr &Sec); ArrayRef getShtGroupEntries(const Elf_Shdr &Sec); public: static bool classof(const InputFile *F) { return F->kind() == Base::ObjectKind; } ArrayRef getSymbols(); ArrayRef getLocalSymbols(); ArrayRef getNonLocalSymbols(); explicit ObjectFile(MemoryBufferRef M); void parse(llvm::DenseSet &ComdatGroups); ArrayRef *> getSections() const { return Sections; } InputSectionBase *getSection(const Elf_Sym &Sym) const; SymbolBody &getSymbolBody(uint32_t SymbolIndex) const { if (SymbolIndex >= SymbolBodies.size()) fatal(toString(this) + ": invalid symbol index"); return *SymbolBodies[SymbolIndex]; } template SymbolBody &getRelocTargetSym(const RelT &Rel) const { uint32_t SymIndex = Rel.getSymbol(Config->Mips64EL); return getSymbolBody(SymIndex); } // Returns source line information for a given offset. // If no information is available, returns "". std::string getLineInfo(InputSectionBase *S, uintX_t Offset); // MIPS GP0 value defined by this file. This value represents the gp value // used to create the relocatable object and required to support // R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations. uint32_t MipsGp0 = 0; - // The number is the offset in the string table. It will be used as the - // st_name of the symbol. - std::vector *, unsigned>> KeptLocalSyms; - // Name of source file obtained from STT_FILE symbol value, // or empty string if there is no such symbol in object file // symbol table. StringRef SourceFile; private: void initializeSections(llvm::DenseSet &ComdatGroups); void initializeSymbols(); void initializeDwarfLine(); InputSectionBase *getRelocTarget(const Elf_Shdr &Sec); InputSectionBase *createInputSection(const Elf_Shdr &Sec, StringRef SectionStringTable); bool shouldMerge(const Elf_Shdr &Sec); SymbolBody *createSymbolBody(const Elf_Sym *Sym); // List of all sections defined by this file. std::vector *> Sections; // List of all symbols referenced or defined by this file. std::vector SymbolBodies; // Debugging information to retrieve source file and line for error // reporting. Linker may find reasonable number of errors in a // single object file, so we cache debugging information in order to // parse it only once for each object file we link. std::unique_ptr DwarfLine; }; // LazyObjectFile is analogous to ArchiveFile in the sense that // the file contains lazy symbols. The difference is that // LazyObjectFile wraps a single file instead of multiple files. // // This class is used for --start-lib and --end-lib options which // instruct the linker to link object files between them with the // archive file semantics. class LazyObjectFile : public InputFile { public: explicit LazyObjectFile(MemoryBufferRef M) : InputFile(LazyObjectKind, M) {} static bool classof(const InputFile *F) { return F->kind() == LazyObjectKind; } template void parse(); MemoryBufferRef getBuffer(); private: std::vector getSymbols(); template std::vector getElfSymbols(); std::vector getBitcodeSymbols(); bool Seen = false; }; // An ArchiveFile object represents a .a file. class ArchiveFile : public InputFile { public: explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } template void parse(); // Returns a memory buffer for a given symbol and the offset in the archive // for the member. An empty memory buffer and an offset of zero // is returned if we have already returned the same memory buffer. // (So that we don't instantiate same members more than once.) std::pair getMember(const Archive::Symbol *Sym); private: std::unique_ptr File; llvm::DenseSet Seen; }; class BitcodeFile : public InputFile { public: explicit BitcodeFile(MemoryBufferRef M); static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } template void parse(llvm::DenseSet &ComdatGroups); ArrayRef getSymbols() { return Symbols; } std::unique_ptr Obj; private: std::vector Symbols; }; // .so file. template class SharedFile : public ELFFileBase { typedef ELFFileBase Base; typedef typename ELFT::Dyn Elf_Dyn; typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::SymRange Elf_Sym_Range; typedef typename ELFT::Verdef Elf_Verdef; typedef typename ELFT::Versym Elf_Versym; typedef typename ELFT::Word Elf_Word; typedef typename ELFT::uint uintX_t; std::vector Undefs; StringRef SoName; const Elf_Shdr *VersymSec = nullptr; const Elf_Shdr *VerdefSec = nullptr; public: StringRef getSoName() const { return SoName; } const Elf_Shdr *getSection(const Elf_Sym &Sym) const; llvm::ArrayRef getUndefinedSymbols() { return Undefs; } static bool classof(const InputFile *F) { return F->kind() == Base::SharedKind; } explicit SharedFile(MemoryBufferRef M); void parseSoName(); void parseRest(); std::vector parseVerdefs(const Elf_Versym *&Versym); struct NeededVer { // The string table offset of the version name in the output file. size_t StrTab; // The version identifier for this version name. uint16_t Index; }; // Mapping from Elf_Verdef data structures to information about Elf_Vernaux // data structures in the output file. std::map VerdefMap; // Used for --as-needed bool AsNeeded = false; bool IsUsed = false; bool isNeeded() const { return !AsNeeded || IsUsed; } }; class BinaryFile : public InputFile { public: explicit BinaryFile(MemoryBufferRef M) : InputFile(BinaryKind, M) {} static bool classof(const InputFile *F) { return F->kind() == BinaryKind; } template void parse(); ArrayRef getSections() const { return Sections; } private: std::vector Sections; }; InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "", uint64_t OffsetInArchive = 0); InputFile *createSharedFile(MemoryBufferRef MB); } // namespace elf } // namespace lld #endif Index: vendor/lld/dist/ELF/InputSection.cpp =================================================================== --- vendor/lld/dist/ELF/InputSection.cpp (revision 313062) +++ vendor/lld/dist/ELF/InputSection.cpp (revision 313063) @@ -1,801 +1,802 @@ //===- InputSection.cpp ---------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "InputSection.h" #include "Config.h" #include "EhFrame.h" #include "Error.h" #include "InputFiles.h" #include "LinkerScript.h" #include "Memory.h" #include "OutputSections.h" #include "Relocations.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" #include "llvm/Object/Decompressor.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Endian.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; // Returns a string to construct an error message. template std::string lld::toString(const InputSectionBase *Sec) { // File can be absent if section is synthetic. std::string FileName = Sec->getFile() ? Sec->getFile()->getName() : ""; return (FileName + ":(" + Sec->Name + ")").str(); } template static ArrayRef getSectionContents(elf::ObjectFile *File, const typename ELFT::Shdr *Hdr) { if (!File || Hdr->sh_type == SHT_NOBITS) return makeArrayRef(nullptr, Hdr->sh_size); return check(File->getObj().getSectionContents(Hdr)); } template InputSectionBase::InputSectionBase(elf::ObjectFile *File, uintX_t Flags, uint32_t Type, uintX_t Entsize, uint32_t Link, uint32_t Info, uintX_t Addralign, ArrayRef Data, StringRef Name, Kind SectionKind) : InputSectionData(SectionKind, Name, Data, !Config->GcSections || !(Flags & SHF_ALLOC)), File(File), Flags(Flags), Entsize(Entsize), Type(Type), Link(Link), Info(Info), Repl(this) { NumRelocations = 0; AreRelocsRela = false; // The ELF spec states that a value of 0 means the section has // no alignment constraits. uint64_t V = std::max(Addralign, 1); if (!isPowerOf2_64(V)) fatal(toString(File) + ": section sh_addralign is not a power of 2"); // We reject object files having insanely large alignments even though // they are allowed by the spec. I think 4GB is a reasonable limitation. // We might want to relax this in the future. if (V > UINT32_MAX) fatal(toString(File) + ": section sh_addralign is too large"); Alignment = V; // If it is not a mergeable section, overwrite the flag so that the flag // is consistent with the class. This inconsistency could occur when // string merging is disabled using -O0 flag. if (!Config->Relocatable && !isa>(this)) this->Flags &= ~(SHF_MERGE | SHF_STRINGS); } template InputSectionBase::InputSectionBase(elf::ObjectFile *File, const Elf_Shdr *Hdr, StringRef Name, Kind SectionKind) : InputSectionBase(File, Hdr->sh_flags & ~SHF_INFO_LINK, Hdr->sh_type, Hdr->sh_entsize, Hdr->sh_link, Hdr->sh_info, Hdr->sh_addralign, getSectionContents(File, Hdr), Name, SectionKind) { this->Offset = Hdr->sh_offset; } template size_t InputSectionBase::getSize() const { if (auto *S = dyn_cast>(this)) return S->getSize(); if (auto *D = dyn_cast>(this)) if (D->getThunksSize() > 0) return D->getThunkOff() + D->getThunksSize(); return Data.size(); } template typename ELFT::uint InputSectionBase::getOffset(uintX_t Offset) const { switch (kind()) { case Regular: return cast>(this)->OutSecOff + Offset; case Synthetic: // For synthetic sections we treat offset -1 as the end of the section. // The same approach is used for synthetic symbols (DefinedSynthetic). return cast>(this)->OutSecOff + (Offset == uintX_t(-1) ? getSize() : Offset); case EHFrame: // The file crtbeginT.o has relocations pointing to the start of an empty // .eh_frame that is known to be the first in the link. It does that to // identify the start of the output .eh_frame. return Offset; case Merge: return cast>(this)->getOffset(Offset); } llvm_unreachable("invalid section kind"); } // Uncompress section contents. Note that this function is called // from parallel_for_each, so it must be thread-safe. template void InputSectionBase::uncompress() { Decompressor Decompressor = check(Decompressor::create( Name, toStringRef(Data), ELFT::TargetEndianness == llvm::support::little, ELFT::Is64Bits)); size_t Size = Decompressor.getDecompressedSize(); char *OutputBuf; { static std::mutex Mu; std::lock_guard Lock(Mu); OutputBuf = BAlloc.Allocate(Size); } if (Error E = Decompressor.decompress({OutputBuf, Size})) fatal(E, toString(this)); Data = ArrayRef((uint8_t *)OutputBuf, Size); } template typename ELFT::uint InputSectionBase::getOffset(const DefinedRegular &Sym) const { return getOffset(Sym.Value); } template InputSectionBase *InputSectionBase::getLinkOrderDep() const { if ((Flags & SHF_LINK_ORDER) && Link != 0) return getFile()->getSections()[Link]; return nullptr; } // Returns a source location string. Used to construct an error message. template std::string InputSectionBase::getLocation(typename ELFT::uint Offset) { // First check if we can get desired values from debugging information. std::string LineInfo = File->getLineInfo(this, Offset); if (!LineInfo.empty()) return LineInfo; // File->SourceFile contains STT_FILE symbol that contains a // source file name. If it's missing, we use an object file name. std::string SrcFile = File->SourceFile; if (SrcFile.empty()) SrcFile = toString(File); // Find a function symbol that encloses a given location. for (SymbolBody *B : File->getSymbols()) if (auto *D = dyn_cast>(B)) if (D->Section == this && D->Type == STT_FUNC) if (D->Value <= Offset && Offset < D->Value + D->Size) return SrcFile + ":(function " + toString(*D) + ")"; // If there's no symbol, print out the offset in the section. return (SrcFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")").str(); } template InputSection::InputSection() : InputSectionBase() {} template InputSection::InputSection(uintX_t Flags, uint32_t Type, uintX_t Addralign, ArrayRef Data, StringRef Name, Kind K) : InputSectionBase(nullptr, Flags, Type, /*Entsize*/ 0, /*Link*/ 0, /*Info*/ 0, Addralign, Data, Name, K) {} template InputSection::InputSection(elf::ObjectFile *F, const Elf_Shdr *Header, StringRef Name) : InputSectionBase(F, Header, Name, Base::Regular) {} template bool InputSection::classof(const InputSectionData *S) { return S->kind() == Base::Regular || S->kind() == Base::Synthetic; } template InputSectionBase *InputSection::getRelocatedSection() { assert(this->Type == SHT_RELA || this->Type == SHT_REL); ArrayRef *> Sections = this->File->getSections(); return Sections[this->Info]; } template void InputSection::addThunk(const Thunk *T) { Thunks.push_back(T); } template uint64_t InputSection::getThunkOff() const { return this->Data.size(); } template uint64_t InputSection::getThunksSize() const { uint64_t Total = 0; for (const Thunk *T : Thunks) Total += T->size(); return Total; } // This is used for -r. We can't use memcpy to copy relocations because we need // to update symbol table offset and section index for each relocation. So we // copy relocations one by one. template template void InputSection::copyRelocations(uint8_t *Buf, ArrayRef Rels) { InputSectionBase *RelocatedSection = getRelocatedSection(); for (const RelTy &Rel : Rels) { uint32_t Type = Rel.getType(Config->Mips64EL); SymbolBody &Body = this->File->getRelocTargetSym(Rel); Elf_Rela *P = reinterpret_cast(Buf); Buf += sizeof(RelTy); if (Config->Rela) P->r_addend = getAddend(Rel); P->r_offset = RelocatedSection->getOffset(Rel.r_offset); - P->setSymbolAndType(Body.DynsymIndex, Type, Config->Mips64EL); + P->setSymbolAndType(In::SymTab->getSymbolIndex(&Body), Type, + Config->Mips64EL); } } static uint32_t getARMUndefinedRelativeWeakVA(uint32_t Type, uint32_t A, uint32_t P) { switch (Type) { case R_ARM_THM_JUMP11: return P + 2; case R_ARM_CALL: case R_ARM_JUMP24: case R_ARM_PC24: case R_ARM_PLT32: case R_ARM_PREL31: case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP24: return P + 4; case R_ARM_THM_CALL: // We don't want an interworking BLX to ARM return P + 5; default: return A; } } static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A, uint64_t P) { switch (Type) { case R_AARCH64_CALL26: case R_AARCH64_CONDBR19: case R_AARCH64_JUMP26: case R_AARCH64_TSTBR14: return P + 4; default: return A; } } template static typename ELFT::uint getRelocTargetVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P, const SymbolBody &Body, RelExpr Expr) { switch (Expr) { case R_HINT: case R_TLSDESC_CALL: llvm_unreachable("cannot relocate hint relocs"); case R_TLSLD: return In::Got->getTlsIndexOff() + A - In::Got->getSize(); case R_TLSLD_PC: return In::Got->getTlsIndexVA() + A - P; case R_THUNK_ABS: return Body.getThunkVA() + A; case R_THUNK_PC: case R_THUNK_PLT_PC: return Body.getThunkVA() + A - P; case R_PPC_TOC: return getPPC64TocBase() + A; case R_TLSGD: return In::Got->getGlobalDynOffset(Body) + A - In::Got->getSize(); case R_TLSGD_PC: return In::Got->getGlobalDynAddr(Body) + A - P; case R_TLSDESC: return In::Got->getGlobalDynAddr(Body) + A; case R_TLSDESC_PAGE: return getAArch64Page(In::Got->getGlobalDynAddr(Body) + A) - getAArch64Page(P); case R_PLT: return Body.getPltVA() + A; case R_PLT_PC: case R_PPC_PLT_OPD: return Body.getPltVA() + A - P; case R_SIZE: return Body.getSize() + A; case R_GOTREL: return Body.getVA(A) - In::Got->getVA(); case R_GOTREL_FROM_END: return Body.getVA(A) - In::Got->getVA() - In::Got->getSize(); case R_RELAX_TLS_GD_TO_IE_END: case R_GOT_FROM_END: return Body.getGotOffset() + A - In::Got->getSize(); case R_RELAX_TLS_GD_TO_IE_ABS: case R_GOT: return Body.getGotVA() + A; case R_RELAX_TLS_GD_TO_IE_PAGE_PC: case R_GOT_PAGE_PC: return getAArch64Page(Body.getGotVA() + A) - getAArch64Page(P); case R_RELAX_TLS_GD_TO_IE: case R_GOT_PC: return Body.getGotVA() + A - P; case R_GOTONLY_PC: return In::Got->getVA() + A - P; case R_GOTONLY_PC_FROM_END: return In::Got->getVA() + A - P + In::Got->getSize(); case R_RELAX_TLS_LD_TO_LE: case R_RELAX_TLS_IE_TO_LE: case R_RELAX_TLS_GD_TO_LE: case R_TLS: // A weak undefined TLS symbol resolves to the base of the TLS // block, i.e. gets a value of zero. If we pass --gc-sections to // lld and .tbss is not referenced, it gets reclaimed and we don't // create a TLS program header. Therefore, we resolve this // statically to zero. if (Body.isTls() && (Body.isLazy() || Body.isUndefined()) && Body.symbol()->isWeak()) return 0; if (Target->TcbSize) return Body.getVA(A) + alignTo(Target->TcbSize, Out::TlsPhdr->p_align); return Body.getVA(A) - Out::TlsPhdr->p_memsz; case R_RELAX_TLS_GD_TO_LE_NEG: case R_NEG_TLS: return Out::TlsPhdr->p_memsz - Body.getVA(A); case R_ABS: case R_RELAX_GOT_PC_NOPIC: return Body.getVA(A); case R_GOT_OFF: return Body.getGotOffset() + A; case R_MIPS_GOT_LOCAL_PAGE: // If relocation against MIPS local symbol requires GOT entry, this entry // should be initialized by 'page address'. This address is high 16-bits // of sum the symbol's value and the addend. return In::MipsGot->getVA() + In::MipsGot->getPageEntryOffset(Body, A) - In::MipsGot->getGp(); case R_MIPS_GOT_OFF: case R_MIPS_GOT_OFF32: // In case of MIPS if a GOT relocation has non-zero addend this addend // should be applied to the GOT entry content not to the GOT entry offset. // That is why we use separate expression type. return In::MipsGot->getVA() + In::MipsGot->getBodyEntryOffset(Body, A) - In::MipsGot->getGp(); case R_MIPS_GOTREL: return Body.getVA(A) - In::MipsGot->getGp(); case R_MIPS_TLSGD: return In::MipsGot->getVA() + In::MipsGot->getTlsOffset() + In::MipsGot->getGlobalDynOffset(Body) - In::MipsGot->getGp(); case R_MIPS_TLSLD: return In::MipsGot->getVA() + In::MipsGot->getTlsOffset() + In::MipsGot->getTlsIndexOff() - In::MipsGot->getGp(); case R_PPC_OPD: { uint64_t SymVA = Body.getVA(A); // If we have an undefined weak symbol, we might get here with a symbol // address of zero. That could overflow, but the code must be unreachable, // so don't bother doing anything at all. if (!SymVA) return 0; if (Out::Opd) { // If this is a local call, and we currently have the address of a // function-descriptor, get the underlying code address instead. uint64_t OpdStart = Out::Opd->Addr; uint64_t OpdEnd = OpdStart + Out::Opd->Size; bool InOpd = OpdStart <= SymVA && SymVA < OpdEnd; if (InOpd) SymVA = read64be(&Out::OpdBuf[SymVA - OpdStart]); } return SymVA - P; } case R_PC: if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) { // On ARM and AArch64 a branch to an undefined weak resolves to the // next instruction, otherwise the place. if (Config->EMachine == EM_ARM) return getARMUndefinedRelativeWeakVA(Type, A, P); if (Config->EMachine == EM_AARCH64) return getAArch64UndefinedRelativeWeakVA(Type, A, P); } case R_RELAX_GOT_PC: return Body.getVA(A) - P; case R_PLT_PAGE_PC: case R_PAGE_PC: if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) return getAArch64Page(A); return getAArch64Page(Body.getVA(A)) - getAArch64Page(P); } llvm_unreachable("Invalid expression"); } // This function applies relocations to sections without SHF_ALLOC bit. // Such sections are never mapped to memory at runtime. Debug sections are // an example. Relocations in non-alloc sections are much easier to // handle than in allocated sections because it will never need complex // treatement such as GOT or PLT (because at runtime no one refers them). // So, we handle relocations for non-alloc sections directly in this // function as a performance optimization. template template void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef Rels) { for (const RelTy &Rel : Rels) { uint32_t Type = Rel.getType(Config->Mips64EL); uintX_t Offset = this->getOffset(Rel.r_offset); uint8_t *BufLoc = Buf + Offset; uintX_t Addend = getAddend(Rel); if (!RelTy::IsRela) Addend += Target->getImplicitAddend(BufLoc, Type); SymbolBody &Sym = this->File->getRelocTargetSym(Rel); if (Target->getRelExpr(Type, Sym) != R_ABS) { error(this->getLocation(Offset) + ": has non-ABS reloc"); return; } uintX_t AddrLoc = this->OutSec->Addr + Offset; uint64_t SymVA = 0; if (!Sym.isTls() || Out::TlsPhdr) SymVA = SignExtend64( getRelocTargetVA(Type, Addend, AddrLoc, Sym, R_ABS)); Target->relocateOne(BufLoc, Type, SymVA); } } template void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) { // scanReloc function in Writer.cpp constructs Relocations // vector only for SHF_ALLOC'ed sections. For other sections, // we handle relocations directly here. auto *IS = dyn_cast>(this); if (IS && !(IS->Flags & SHF_ALLOC)) { if (IS->AreRelocsRela) IS->relocateNonAlloc(Buf, IS->relas()); else IS->relocateNonAlloc(Buf, IS->rels()); return; } const unsigned Bits = sizeof(uintX_t) * 8; for (const Relocation &Rel : Relocations) { uintX_t Offset = getOffset(Rel.Offset); uint8_t *BufLoc = Buf + Offset; uint32_t Type = Rel.Type; uintX_t A = Rel.Addend; uintX_t AddrLoc = OutSec->Addr + Offset; RelExpr Expr = Rel.Expr; uint64_t TargetVA = SignExtend64( getRelocTargetVA(Type, A, AddrLoc, *Rel.Sym, Expr)); switch (Expr) { case R_RELAX_GOT_PC: case R_RELAX_GOT_PC_NOPIC: Target->relaxGot(BufLoc, TargetVA); break; case R_RELAX_TLS_IE_TO_LE: Target->relaxTlsIeToLe(BufLoc, Type, TargetVA); break; case R_RELAX_TLS_LD_TO_LE: Target->relaxTlsLdToLe(BufLoc, Type, TargetVA); break; case R_RELAX_TLS_GD_TO_LE: case R_RELAX_TLS_GD_TO_LE_NEG: Target->relaxTlsGdToLe(BufLoc, Type, TargetVA); break; case R_RELAX_TLS_GD_TO_IE: case R_RELAX_TLS_GD_TO_IE_ABS: case R_RELAX_TLS_GD_TO_IE_PAGE_PC: case R_RELAX_TLS_GD_TO_IE_END: Target->relaxTlsGdToIe(BufLoc, Type, TargetVA); break; case R_PPC_PLT_OPD: // Patch a nop (0x60000000) to a ld. if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == 0x60000000) write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1) // fallthrough default: Target->relocateOne(BufLoc, Type, TargetVA); break; } } } template void InputSection::writeTo(uint8_t *Buf) { if (this->Type == SHT_NOBITS) return; if (auto *S = dyn_cast>(this)) { S->writeTo(Buf + OutSecOff); return; } // If -r is given, then an InputSection may be a relocation section. if (this->Type == SHT_RELA) { copyRelocations(Buf + OutSecOff, this->template getDataAs()); return; } if (this->Type == SHT_REL) { copyRelocations(Buf + OutSecOff, this->template getDataAs()); return; } // Copy section contents from source object file to output file. ArrayRef Data = this->Data; memcpy(Buf + OutSecOff, Data.data(), Data.size()); // Iterate over all relocation sections that apply to this section. uint8_t *BufEnd = Buf + OutSecOff + Data.size(); this->relocate(Buf, BufEnd); // The section might have a data/code generated by the linker and need // to be written after the section. Usually these are thunks - small piece // of code used to jump between "incompatible" functions like PIC and non-PIC // or if the jump target too far and its address does not fit to the short // jump istruction. if (!Thunks.empty()) { Buf += OutSecOff + getThunkOff(); for (const Thunk *T : Thunks) { T->writeTo(Buf); Buf += T->size(); } } } template void InputSection::replace(InputSection *Other) { this->Alignment = std::max(this->Alignment, Other->Alignment); Other->Repl = this->Repl; Other->Live = false; } template EhInputSection::EhInputSection(elf::ObjectFile *F, const Elf_Shdr *Header, StringRef Name) : InputSectionBase(F, Header, Name, InputSectionBase::EHFrame) { // Mark .eh_frame sections as live by default because there are // usually no relocations that point to .eh_frames. Otherwise, // the garbage collector would drop all .eh_frame sections. this->Live = true; } template bool EhInputSection::classof(const InputSectionData *S) { return S->kind() == InputSectionBase::EHFrame; } // Returns the index of the first relocation that points to a region between // Begin and Begin+Size. template static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef &Rels, unsigned &RelocI) { // Start search from RelocI for fast access. That works because the // relocations are sorted in .eh_frame. for (unsigned N = Rels.size(); RelocI < N; ++RelocI) { const RelTy &Rel = Rels[RelocI]; if (Rel.r_offset < Begin) continue; if (Rel.r_offset < Begin + Size) return RelocI; return -1; } return -1; } // .eh_frame is a sequence of CIE or FDE records. // This function splits an input section into records and returns them. template void EhInputSection::split() { // Early exit if already split. if (!this->Pieces.empty()) return; if (this->NumRelocations) { if (this->AreRelocsRela) split(this->relas()); else split(this->rels()); return; } split(makeArrayRef(nullptr, nullptr)); } template template void EhInputSection::split(ArrayRef Rels) { ArrayRef Data = this->Data; unsigned RelI = 0; for (size_t Off = 0, End = Data.size(); Off != End;) { size_t Size = readEhRecordSize(this, Off); this->Pieces.emplace_back(Off, this, Size, getReloc(Off, Size, Rels, RelI)); // The empty record is the end marker. if (Size == 4) break; Off += Size; } } static size_t findNull(ArrayRef A, size_t EntSize) { // Optimize the common case. StringRef S((const char *)A.data(), A.size()); if (EntSize == 1) return S.find(0); for (unsigned I = 0, N = S.size(); I != N; I += EntSize) { const char *B = S.begin() + I; if (std::all_of(B, B + EntSize, [](char C) { return C == 0; })) return I; } return StringRef::npos; } // Split SHF_STRINGS section. Such section is a sequence of // null-terminated strings. template void MergeInputSection::splitStrings(ArrayRef Data, size_t EntSize) { size_t Off = 0; bool IsAlloc = this->Flags & SHF_ALLOC; while (!Data.empty()) { size_t End = findNull(Data, EntSize); if (End == StringRef::npos) fatal(toString(this) + ": string is not null terminated"); size_t Size = End + EntSize; Pieces.emplace_back(Off, !IsAlloc); Hashes.push_back(hash_value(toStringRef(Data.slice(0, Size)))); Data = Data.slice(Size); Off += Size; } } // Split non-SHF_STRINGS section. Such section is a sequence of // fixed size records. template void MergeInputSection::splitNonStrings(ArrayRef Data, size_t EntSize) { size_t Size = Data.size(); assert((Size % EntSize) == 0); bool IsAlloc = this->Flags & SHF_ALLOC; for (unsigned I = 0, N = Size; I != N; I += EntSize) { Hashes.push_back(hash_value(toStringRef(Data.slice(I, EntSize)))); Pieces.emplace_back(I, !IsAlloc); } } template MergeInputSection::MergeInputSection(elf::ObjectFile *F, const Elf_Shdr *Header, StringRef Name) : InputSectionBase(F, Header, Name, InputSectionBase::Merge) {} // This function is called after we obtain a complete list of input sections // that need to be linked. This is responsible to split section contents // into small chunks for further processing. // // Note that this function is called from parallel_for_each. This must be // thread-safe (i.e. no memory allocation from the pools). template void MergeInputSection::splitIntoPieces() { ArrayRef Data = this->Data; uintX_t EntSize = this->Entsize; if (this->Flags & SHF_STRINGS) splitStrings(Data, EntSize); else splitNonStrings(Data, EntSize); if (Config->GcSections && (this->Flags & SHF_ALLOC)) for (uintX_t Off : LiveOffsets) this->getSectionPiece(Off)->Live = true; } template bool MergeInputSection::classof(const InputSectionData *S) { return S->kind() == InputSectionBase::Merge; } // Do binary search to get a section piece at a given input offset. template SectionPiece *MergeInputSection::getSectionPiece(uintX_t Offset) { auto *This = static_cast *>(this); return const_cast(This->getSectionPiece(Offset)); } template static It fastUpperBound(It First, It Last, const T &Value, Compare Comp) { size_t Size = std::distance(First, Last); assert(Size != 0); while (Size != 1) { size_t H = Size / 2; const It MI = First + H; Size -= H; First = Comp(Value, *MI) ? First : First + H; } return Comp(Value, *First) ? First : First + 1; } template const SectionPiece * MergeInputSection::getSectionPiece(uintX_t Offset) const { uintX_t Size = this->Data.size(); if (Offset >= Size) fatal(toString(this) + ": entry is past the end of the section"); // Find the element this offset points to. auto I = fastUpperBound( Pieces.begin(), Pieces.end(), Offset, [](const uintX_t &A, const SectionPiece &B) { return A < B.InputOff; }); --I; return &*I; } // Returns the offset in an output section for a given input offset. // Because contents of a mergeable section is not contiguous in output, // it is not just an addition to a base output offset. template typename ELFT::uint MergeInputSection::getOffset(uintX_t Offset) const { // Initialize OffsetMap lazily. std::call_once(InitOffsetMap, [&] { OffsetMap.reserve(Pieces.size()); for (const SectionPiece &Piece : Pieces) OffsetMap[Piece.InputOff] = Piece.OutputOff; }); // Find a string starting at a given offset. auto It = OffsetMap.find(Offset); if (It != OffsetMap.end()) return It->second; if (!this->Live) return 0; // If Offset is not at beginning of a section piece, it is not in the map. // In that case we need to search from the original section piece vector. const SectionPiece &Piece = *this->getSectionPiece(Offset); if (!Piece.Live) return 0; uintX_t Addend = Offset - Piece.InputOff; return Piece.OutputOff + Addend; } template class elf::InputSectionBase; template class elf::InputSectionBase; template class elf::InputSectionBase; template class elf::InputSectionBase; template class elf::InputSection; template class elf::InputSection; template class elf::InputSection; template class elf::InputSection; template class elf::EhInputSection; template class elf::EhInputSection; template class elf::EhInputSection; template class elf::EhInputSection; template class elf::MergeInputSection; template class elf::MergeInputSection; template class elf::MergeInputSection; template class elf::MergeInputSection; template std::string lld::toString(const InputSectionBase *); template std::string lld::toString(const InputSectionBase *); template std::string lld::toString(const InputSectionBase *); template std::string lld::toString(const InputSectionBase *); Index: vendor/lld/dist/ELF/SyntheticSections.cpp =================================================================== --- vendor/lld/dist/ELF/SyntheticSections.cpp (revision 313062) +++ vendor/lld/dist/ELF/SyntheticSections.cpp (revision 313063) @@ -1,1981 +1,1995 @@ //===- SyntheticSections.cpp ----------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains linker-synthesized sections. Currently, // synthetic sections are created either output sections or input sections, // but we are rewriting code so that all synthetic sections are created as // input sections. // //===----------------------------------------------------------------------===// #include "SyntheticSections.h" #include "Config.h" #include "Error.h" #include "InputFiles.h" #include "LinkerScript.h" #include "Memory.h" #include "OutputSections.h" #include "Strings.h" #include "SymbolTable.h" #include "Target.h" #include "Threads.h" #include "Writer.h" #include "lld/Config/Version.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/Endian.h" #include "llvm/Support/MD5.h" #include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Support/SHA1.h" #include "llvm/Support/xxhash.h" #include using namespace llvm; using namespace llvm::dwarf; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support; using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; template static std::vector getCommonSymbols() { std::vector V; for (Symbol *S : Symtab::X->getSymbols()) if (auto *B = dyn_cast(S->body())) V.push_back(B); return V; } // Find all common symbols and allocate space for them. template InputSection *elf::createCommonSection() { auto *Ret = make>(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, 1, ArrayRef(), "COMMON"); Ret->Live = true; // Sort the common symbols by alignment as an heuristic to pack them better. std::vector Syms = getCommonSymbols(); std::stable_sort(Syms.begin(), Syms.end(), [](const DefinedCommon *A, const DefinedCommon *B) { return A->Alignment > B->Alignment; }); // Assign offsets to symbols. size_t Size = 0; size_t Alignment = 1; for (DefinedCommon *Sym : Syms) { Alignment = std::max(Alignment, Sym->Alignment); Size = alignTo(Size, Sym->Alignment); // Compute symbol offset relative to beginning of input section. Sym->Offset = Size; Size += Sym->Size; } Ret->Alignment = Alignment; Ret->Data = makeArrayRef(nullptr, Size); return Ret; } // Returns an LLD version string. static ArrayRef getVersion() { // Check LLD_VERSION first for ease of testing. // You can get consitent output by using the environment variable. // This is only for testing. StringRef S = getenv("LLD_VERSION"); if (S.empty()) S = Saver.save(Twine("Linker: ") + getLLDVersion()); // +1 to include the terminating '\0'. return {(const uint8_t *)S.data(), S.size() + 1}; } // Creates a .comment section containing LLD version info. // With this feature, you can identify LLD-generated binaries easily // by "objdump -s -j .comment ". // The returned object is a mergeable string section. template MergeInputSection *elf::createCommentSection() { typename ELFT::Shdr Hdr = {}; Hdr.sh_flags = SHF_MERGE | SHF_STRINGS; Hdr.sh_type = SHT_PROGBITS; Hdr.sh_entsize = 1; Hdr.sh_addralign = 1; auto *Ret = make>(/*file=*/nullptr, &Hdr, ".comment"); Ret->Data = getVersion(); Ret->splitIntoPieces(); return Ret; } // .MIPS.abiflags section. template MipsAbiFlagsSection::MipsAbiFlagsSection(Elf_Mips_ABIFlags Flags) : SyntheticSection(SHF_ALLOC, SHT_MIPS_ABIFLAGS, 8, ".MIPS.abiflags"), Flags(Flags) {} template void MipsAbiFlagsSection::writeTo(uint8_t *Buf) { memcpy(Buf, &Flags, sizeof(Flags)); } template MipsAbiFlagsSection *MipsAbiFlagsSection::create() { Elf_Mips_ABIFlags Flags = {}; bool Create = false; for (InputSectionBase *Sec : Symtab::X->Sections) { if (!Sec->Live || Sec->Type != SHT_MIPS_ABIFLAGS) continue; Sec->Live = false; Create = true; std::string Filename = toString(Sec->getFile()); const size_t Size = Sec->Data.size(); // Older version of BFD (such as the default FreeBSD linker) concatenate // .MIPS.abiflags instead of merging. To allow for this case (or potential // zero padding) we ignore everything after the first Elf_Mips_ABIFlags if (Size < sizeof(Elf_Mips_ABIFlags)) { error(Filename + ": invalid size of .MIPS.abiflags section: got " + Twine(Size) + " instead of " + Twine(sizeof(Elf_Mips_ABIFlags))); return nullptr; } auto *S = reinterpret_cast(Sec->Data.data()); if (S->version != 0) { error(Filename + ": unexpected .MIPS.abiflags version " + Twine(S->version)); return nullptr; } // LLD checks ISA compatibility in getMipsEFlags(). Here we just // select the highest number of ISA/Rev/Ext. Flags.isa_level = std::max(Flags.isa_level, S->isa_level); Flags.isa_rev = std::max(Flags.isa_rev, S->isa_rev); Flags.isa_ext = std::max(Flags.isa_ext, S->isa_ext); Flags.gpr_size = std::max(Flags.gpr_size, S->gpr_size); Flags.cpr1_size = std::max(Flags.cpr1_size, S->cpr1_size); Flags.cpr2_size = std::max(Flags.cpr2_size, S->cpr2_size); Flags.ases |= S->ases; Flags.flags1 |= S->flags1; Flags.flags2 |= S->flags2; Flags.fp_abi = elf::getMipsFpAbiFlag(Flags.fp_abi, S->fp_abi, Filename); }; if (Create) return make>(Flags); return nullptr; } // .MIPS.options section. template MipsOptionsSection::MipsOptionsSection(Elf_Mips_RegInfo Reginfo) : SyntheticSection(SHF_ALLOC, SHT_MIPS_OPTIONS, 8, ".MIPS.options"), Reginfo(Reginfo) {} template void MipsOptionsSection::writeTo(uint8_t *Buf) { auto *Options = reinterpret_cast(Buf); Options->kind = ODK_REGINFO; Options->size = getSize(); if (!Config->Relocatable) Reginfo.ri_gp_value = In::MipsGot->getGp(); memcpy(Buf + sizeof(Elf_Mips_Options), &Reginfo, sizeof(Reginfo)); } template MipsOptionsSection *MipsOptionsSection::create() { // N64 ABI only. if (!ELFT::Is64Bits) return nullptr; Elf_Mips_RegInfo Reginfo = {}; bool Create = false; for (InputSectionBase *Sec : Symtab::X->Sections) { if (!Sec->Live || Sec->Type != SHT_MIPS_OPTIONS) continue; Sec->Live = false; Create = true; std::string Filename = toString(Sec->getFile()); ArrayRef D = Sec->Data; while (!D.empty()) { if (D.size() < sizeof(Elf_Mips_Options)) { error(Filename + ": invalid size of .MIPS.options section"); break; } auto *Opt = reinterpret_cast(D.data()); if (Opt->kind == ODK_REGINFO) { if (Config->Relocatable && Opt->getRegInfo().ri_gp_value) error(Filename + ": unsupported non-zero ri_gp_value"); Reginfo.ri_gprmask |= Opt->getRegInfo().ri_gprmask; Sec->getFile()->MipsGp0 = Opt->getRegInfo().ri_gp_value; break; } if (!Opt->size) fatal(Filename + ": zero option descriptor size"); D = D.slice(Opt->size); } }; if (Create) return make>(Reginfo); return nullptr; } // MIPS .reginfo section. template MipsReginfoSection::MipsReginfoSection(Elf_Mips_RegInfo Reginfo) : SyntheticSection(SHF_ALLOC, SHT_MIPS_REGINFO, 4, ".reginfo"), Reginfo(Reginfo) {} template void MipsReginfoSection::writeTo(uint8_t *Buf) { if (!Config->Relocatable) Reginfo.ri_gp_value = In::MipsGot->getGp(); memcpy(Buf, &Reginfo, sizeof(Reginfo)); } template MipsReginfoSection *MipsReginfoSection::create() { // Section should be alive for O32 and N32 ABIs only. if (ELFT::Is64Bits) return nullptr; Elf_Mips_RegInfo Reginfo = {}; bool Create = false; for (InputSectionBase *Sec : Symtab::X->Sections) { if (!Sec->Live || Sec->Type != SHT_MIPS_REGINFO) continue; Sec->Live = false; Create = true; if (Sec->Data.size() != sizeof(Elf_Mips_RegInfo)) { error(toString(Sec->getFile()) + ": invalid size of .reginfo section"); return nullptr; } auto *R = reinterpret_cast(Sec->Data.data()); if (Config->Relocatable && R->ri_gp_value) error(toString(Sec->getFile()) + ": unsupported non-zero ri_gp_value"); Reginfo.ri_gprmask |= R->ri_gprmask; Sec->getFile()->MipsGp0 = R->ri_gp_value; }; if (Create) return make>(Reginfo); return nullptr; } template InputSection *elf::createInterpSection() { auto *Ret = make>(SHF_ALLOC, SHT_PROGBITS, 1, ArrayRef(), ".interp"); Ret->Live = true; // StringSaver guarantees that the returned string ends with '\0'. StringRef S = Saver.save(Config->DynamicLinker); Ret->Data = {(const uint8_t *)S.data(), S.size() + 1}; return Ret; } static size_t getHashSize() { switch (Config->BuildId) { case BuildIdKind::Fast: return 8; case BuildIdKind::Md5: case BuildIdKind::Uuid: return 16; case BuildIdKind::Sha1: return 20; case BuildIdKind::Hexstring: return Config->BuildIdVector.size(); default: llvm_unreachable("unknown BuildIdKind"); } } template BuildIdSection::BuildIdSection() : SyntheticSection(SHF_ALLOC, SHT_NOTE, 1, ".note.gnu.build-id"), HashSize(getHashSize()) {} template void BuildIdSection::writeTo(uint8_t *Buf) { const endianness E = ELFT::TargetEndianness; write32(Buf, 4); // Name size write32(Buf + 4, HashSize); // Content size write32(Buf + 8, NT_GNU_BUILD_ID); // Type memcpy(Buf + 12, "GNU", 4); // Name string HashBuf = Buf + 16; } // Split one uint8 array into small pieces of uint8 arrays. static std::vector> split(ArrayRef Arr, size_t ChunkSize) { std::vector> Ret; while (Arr.size() > ChunkSize) { Ret.push_back(Arr.take_front(ChunkSize)); Arr = Arr.drop_front(ChunkSize); } if (!Arr.empty()) Ret.push_back(Arr); return Ret; } // Computes a hash value of Data using a given hash function. // In order to utilize multiple cores, we first split data into 1MB // chunks, compute a hash for each chunk, and then compute a hash value // of the hash values. template void BuildIdSection::computeHash( llvm::ArrayRef Data, std::function Arr)> HashFn) { std::vector> Chunks = split(Data, 1024 * 1024); std::vector Hashes(Chunks.size() * HashSize); // Compute hash values. forLoop(0, Chunks.size(), [&](size_t I) { HashFn(Hashes.data() + I * HashSize, Chunks[I]); }); // Write to the final output buffer. HashFn(HashBuf, Hashes); } template void BuildIdSection::writeBuildId(ArrayRef Buf) { switch (Config->BuildId) { case BuildIdKind::Fast: computeHash(Buf, [](uint8_t *Dest, ArrayRef Arr) { write64le(Dest, xxHash64(toStringRef(Arr))); }); break; case BuildIdKind::Md5: computeHash(Buf, [](uint8_t *Dest, ArrayRef Arr) { memcpy(Dest, MD5::hash(Arr).data(), 16); }); break; case BuildIdKind::Sha1: computeHash(Buf, [](uint8_t *Dest, ArrayRef Arr) { memcpy(Dest, SHA1::hash(Arr).data(), 20); }); break; case BuildIdKind::Uuid: if (getRandomBytes(HashBuf, HashSize)) error("entropy source failure"); break; case BuildIdKind::Hexstring: memcpy(HashBuf, Config->BuildIdVector.data(), Config->BuildIdVector.size()); break; default: llvm_unreachable("unknown BuildIdKind"); } } template GotSection::GotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Target->GotEntrySize, ".got") {} template void GotSection::addEntry(SymbolBody &Sym) { Sym.GotIndex = NumEntries; ++NumEntries; } template bool GotSection::addDynTlsEntry(SymbolBody &Sym) { if (Sym.GlobalDynIndex != -1U) return false; Sym.GlobalDynIndex = NumEntries; // Global Dynamic TLS entries take two GOT slots. NumEntries += 2; return true; } // Reserves TLS entries for a TLS module ID and a TLS block offset. // In total it takes two GOT slots. template bool GotSection::addTlsIndex() { if (TlsIndexOff != uint32_t(-1)) return false; TlsIndexOff = NumEntries * sizeof(uintX_t); NumEntries += 2; return true; } template typename GotSection::uintX_t GotSection::getGlobalDynAddr(const SymbolBody &B) const { return this->getVA() + B.GlobalDynIndex * sizeof(uintX_t); } template typename GotSection::uintX_t GotSection::getGlobalDynOffset(const SymbolBody &B) const { return B.GlobalDynIndex * sizeof(uintX_t); } template void GotSection::finalize() { Size = NumEntries * sizeof(uintX_t); } template bool GotSection::empty() const { // If we have a relocation that is relative to GOT (such as GOTOFFREL), // we need to emit a GOT even if it's empty. return NumEntries == 0 && !HasGotOffRel; } template void GotSection::writeTo(uint8_t *Buf) { this->relocate(Buf, Buf + Size); } template MipsGotSection::MipsGotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, Target->GotEntrySize, ".got") {} template void MipsGotSection::addEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr) { // For "true" local symbols which can be referenced from the same module // only compiler creates two instructions for address loading: // // lw $8, 0($gp) # R_MIPS_GOT16 // addi $8, $8, 0 # R_MIPS_LO16 // // The first instruction loads high 16 bits of the symbol address while // the second adds an offset. That allows to reduce number of required // GOT entries because only one global offset table entry is necessary // for every 64 KBytes of local data. So for local symbols we need to // allocate number of GOT entries to hold all required "page" addresses. // // All global symbols (hidden and regular) considered by compiler uniformly. // It always generates a single `lw` instruction and R_MIPS_GOT16 relocation // to load address of the symbol. So for each such symbol we need to // allocate dedicated GOT entry to store its address. // // If a symbol is preemptible we need help of dynamic linker to get its // final address. The corresponding GOT entries are allocated in the // "global" part of GOT. Entries for non preemptible global symbol allocated // in the "local" part of GOT. // // See "Global Offset Table" in Chapter 5: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf if (Expr == R_MIPS_GOT_LOCAL_PAGE) { // At this point we do not know final symbol value so to reduce number // of allocated GOT entries do the following trick. Save all output // sections referenced by GOT relocations. Then later in the `finalize` // method calculate number of "pages" required to cover all saved output // section and allocate appropriate number of GOT entries. PageIndexMap.insert({cast>(&Sym)->Section->OutSec, 0}); return; } if (Sym.isTls()) { // GOT entries created for MIPS TLS relocations behave like // almost GOT entries from other ABIs. They go to the end // of the global offset table. Sym.GotIndex = TlsEntries.size(); TlsEntries.push_back(&Sym); return; } auto AddEntry = [&](SymbolBody &S, uintX_t A, GotEntries &Items) { if (S.isInGot() && !A) return; size_t NewIndex = Items.size(); if (!EntryIndexMap.insert({{&S, A}, NewIndex}).second) return; Items.emplace_back(&S, A); if (!A) S.GotIndex = NewIndex; }; if (Sym.isPreemptible()) { // Ignore addends for preemptible symbols. They got single GOT entry anyway. AddEntry(Sym, 0, GlobalEntries); Sym.IsInGlobalMipsGot = true; } else if (Expr == R_MIPS_GOT_OFF32) { AddEntry(Sym, Addend, LocalEntries32); Sym.Is32BitMipsGot = true; } else { // Hold local GOT entries accessed via a 16-bit index separately. // That allows to write them in the beginning of the GOT and keep // their indexes as less as possible to escape relocation's overflow. AddEntry(Sym, Addend, LocalEntries); } } template bool MipsGotSection::addDynTlsEntry(SymbolBody &Sym) { if (Sym.GlobalDynIndex != -1U) return false; Sym.GlobalDynIndex = TlsEntries.size(); // Global Dynamic TLS entries take two GOT slots. TlsEntries.push_back(nullptr); TlsEntries.push_back(&Sym); return true; } // Reserves TLS entries for a TLS module ID and a TLS block offset. // In total it takes two GOT slots. template bool MipsGotSection::addTlsIndex() { if (TlsIndexOff != uint32_t(-1)) return false; TlsIndexOff = TlsEntries.size() * sizeof(uintX_t); TlsEntries.push_back(nullptr); TlsEntries.push_back(nullptr); return true; } static uint64_t getMipsPageAddr(uint64_t Addr) { return (Addr + 0x8000) & ~0xffff; } static uint64_t getMipsPageCount(uint64_t Size) { return (Size + 0xfffe) / 0xffff + 1; } template typename MipsGotSection::uintX_t MipsGotSection::getPageEntryOffset(const SymbolBody &B, uintX_t Addend) const { const OutputSectionBase *OutSec = cast>(&B)->Section->OutSec; uintX_t SecAddr = getMipsPageAddr(OutSec->Addr); uintX_t SymAddr = getMipsPageAddr(B.getVA(Addend)); uintX_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff; assert(Index < PageEntriesNum); return (HeaderEntriesNum + Index) * sizeof(uintX_t); } template typename MipsGotSection::uintX_t MipsGotSection::getBodyEntryOffset(const SymbolBody &B, uintX_t Addend) const { // Calculate offset of the GOT entries block: TLS, global, local. uintX_t Index = HeaderEntriesNum + PageEntriesNum; if (B.isTls()) Index += LocalEntries.size() + LocalEntries32.size() + GlobalEntries.size(); else if (B.IsInGlobalMipsGot) Index += LocalEntries.size() + LocalEntries32.size(); else if (B.Is32BitMipsGot) Index += LocalEntries.size(); // Calculate offset of the GOT entry in the block. if (B.isInGot()) Index += B.GotIndex; else { auto It = EntryIndexMap.find({&B, Addend}); assert(It != EntryIndexMap.end()); Index += It->second; } return Index * sizeof(uintX_t); } template typename MipsGotSection::uintX_t MipsGotSection::getTlsOffset() const { return (getLocalEntriesNum() + GlobalEntries.size()) * sizeof(uintX_t); } template typename MipsGotSection::uintX_t MipsGotSection::getGlobalDynOffset(const SymbolBody &B) const { return B.GlobalDynIndex * sizeof(uintX_t); } template const SymbolBody *MipsGotSection::getFirstGlobalEntry() const { return GlobalEntries.empty() ? nullptr : GlobalEntries.front().first; } template unsigned MipsGotSection::getLocalEntriesNum() const { return HeaderEntriesNum + PageEntriesNum + LocalEntries.size() + LocalEntries32.size(); } template void MipsGotSection::finalize() { PageEntriesNum = 0; for (std::pair &P : PageIndexMap) { // For each output section referenced by GOT page relocations calculate // and save into PageIndexMap an upper bound of MIPS GOT entries required // to store page addresses of local symbols. We assume the worst case - // each 64kb page of the output section has at least one GOT relocation // against it. And take in account the case when the section intersects // page boundaries. P.second = PageEntriesNum; PageEntriesNum += getMipsPageCount(P.first->Size); } Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) * sizeof(uintX_t); } template bool MipsGotSection::empty() const { // We add the .got section to the result for dynamic MIPS target because // its address and properties are mentioned in the .dynamic section. return Config->Relocatable; } template typename MipsGotSection::uintX_t MipsGotSection::getGp() const { return ElfSym::MipsGp->template getVA(0); } template static void writeUint(uint8_t *Buf, typename ELFT::uint Val) { typedef typename ELFT::uint uintX_t; write(Buf, Val); } template void MipsGotSection::writeTo(uint8_t *Buf) { // Set the MSB of the second GOT slot. This is not required by any // MIPS ABI documentation, though. // // There is a comment in glibc saying that "The MSB of got[1] of a // gnu object is set to identify gnu objects," and in GNU gold it // says "the second entry will be used by some runtime loaders". // But how this field is being used is unclear. // // We are not really willing to mimic other linkers behaviors // without understanding why they do that, but because all files // generated by GNU tools have this special GOT value, and because // we've been doing this for years, it is probably a safe bet to // keep doing this for now. We really need to revisit this to see // if we had to do this. auto *P = reinterpret_cast(Buf); P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31); Buf += HeaderEntriesNum * sizeof(uintX_t); // Write 'page address' entries to the local part of the GOT. for (std::pair &L : PageIndexMap) { size_t PageCount = getMipsPageCount(L.first->Size); uintX_t FirstPageAddr = getMipsPageAddr(L.first->Addr); for (size_t PI = 0; PI < PageCount; ++PI) { uint8_t *Entry = Buf + (L.second + PI) * sizeof(uintX_t); writeUint(Entry, FirstPageAddr + PI * 0x10000); } } Buf += PageEntriesNum * sizeof(uintX_t); auto AddEntry = [&](const GotEntry &SA) { uint8_t *Entry = Buf; Buf += sizeof(uintX_t); const SymbolBody *Body = SA.first; uintX_t VA = Body->template getVA(SA.second); writeUint(Entry, VA); }; std::for_each(std::begin(LocalEntries), std::end(LocalEntries), AddEntry); std::for_each(std::begin(LocalEntries32), std::end(LocalEntries32), AddEntry); std::for_each(std::begin(GlobalEntries), std::end(GlobalEntries), AddEntry); // Initialize TLS-related GOT entries. If the entry has a corresponding // dynamic relocations, leave it initialized by zero. Write down adjusted // TLS symbol's values otherwise. To calculate the adjustments use offsets // for thread-local storage. // https://www.linux-mips.org/wiki/NPTL if (TlsIndexOff != -1U && !Config->Pic) writeUint(Buf + TlsIndexOff, 1); for (const SymbolBody *B : TlsEntries) { if (!B || B->isPreemptible()) continue; uintX_t VA = B->getVA(); if (B->GotIndex != -1U) { uint8_t *Entry = Buf + B->GotIndex * sizeof(uintX_t); writeUint(Entry, VA - 0x7000); } if (B->GlobalDynIndex != -1U) { uint8_t *Entry = Buf + B->GlobalDynIndex * sizeof(uintX_t); writeUint(Entry, 1); Entry += sizeof(uintX_t); writeUint(Entry, VA - 0x8000); } } } template GotPltSection::GotPltSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Target->GotPltEntrySize, ".got.plt") {} template void GotPltSection::addEntry(SymbolBody &Sym) { Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size(); Entries.push_back(&Sym); } template size_t GotPltSection::getSize() const { return (Target->GotPltHeaderEntriesNum + Entries.size()) * Target->GotPltEntrySize; } template void GotPltSection::writeTo(uint8_t *Buf) { Target->writeGotPltHeader(Buf); Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize; for (const SymbolBody *B : Entries) { Target->writeGotPlt(Buf, *B); Buf += sizeof(uintX_t); } } // On ARM the IgotPltSection is part of the GotSection, on other Targets it is // part of the .got.plt template IgotPltSection::IgotPltSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Target->GotPltEntrySize, Config->EMachine == EM_ARM ? ".got" : ".got.plt") { } template void IgotPltSection::addEntry(SymbolBody &Sym) { Sym.IsInIgot = true; Sym.GotPltIndex = Entries.size(); Entries.push_back(&Sym); } template size_t IgotPltSection::getSize() const { return Entries.size() * Target->GotPltEntrySize; } template void IgotPltSection::writeTo(uint8_t *Buf) { for (const SymbolBody *B : Entries) { Target->writeIgotPlt(Buf, *B); Buf += sizeof(uintX_t); } } template StringTableSection::StringTableSection(StringRef Name, bool Dynamic) : SyntheticSection(Dynamic ? (uintX_t)SHF_ALLOC : 0, SHT_STRTAB, 1, Name), Dynamic(Dynamic) {} // Adds a string to the string table. If HashIt is true we hash and check for // duplicates. It is optional because the name of global symbols are already // uniqued and hashing them again has a big cost for a small value: uniquing // them with some other string that happens to be the same. template unsigned StringTableSection::addString(StringRef S, bool HashIt) { if (HashIt) { auto R = StringMap.insert(std::make_pair(S, this->Size)); if (!R.second) return R.first->second; } unsigned Ret = this->Size; this->Size = this->Size + S.size() + 1; Strings.push_back(S); return Ret; } template void StringTableSection::writeTo(uint8_t *Buf) { // ELF string tables start with NUL byte, so advance the pointer by one. ++Buf; for (StringRef S : Strings) { memcpy(Buf, S.data(), S.size()); Buf += S.size() + 1; } } // Returns the number of version definition entries. Because the first entry // is for the version definition itself, it is the number of versioned symbols // plus one. Note that we don't support multiple versions yet. static unsigned getVerDefNum() { return Config->VersionDefinitions.size() + 1; } template DynamicSection::DynamicSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_DYNAMIC, sizeof(uintX_t), ".dynamic") { this->Entsize = ELFT::Is64Bits ? 16 : 8; // .dynamic section is not writable on MIPS. // See "Special Section" in Chapter 4 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf if (Config->EMachine == EM_MIPS) this->Flags = SHF_ALLOC; addEntries(); } // There are some dynamic entries that don't depend on other sections. // Such entries can be set early. template void DynamicSection::addEntries() { // Add strings to .dynstr early so that .dynstr's size will be // fixed early. for (StringRef S : Config->AuxiliaryList) add({DT_AUXILIARY, In::DynStrTab->addString(S)}); if (!Config->RPath.empty()) add({Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH, In::DynStrTab->addString(Config->RPath)}); for (SharedFile *F : Symtab::X->getSharedFiles()) if (F->isNeeded()) add({DT_NEEDED, In::DynStrTab->addString(F->getSoName())}); if (!Config->SoName.empty()) add({DT_SONAME, In::DynStrTab->addString(Config->SoName)}); // Set DT_FLAGS and DT_FLAGS_1. uint32_t DtFlags = 0; uint32_t DtFlags1 = 0; if (Config->Bsymbolic) DtFlags |= DF_SYMBOLIC; if (Config->ZNodelete) DtFlags1 |= DF_1_NODELETE; if (Config->ZNow) { DtFlags |= DF_BIND_NOW; DtFlags1 |= DF_1_NOW; } if (Config->ZOrigin) { DtFlags |= DF_ORIGIN; DtFlags1 |= DF_1_ORIGIN; } if (DtFlags) add({DT_FLAGS, DtFlags}); if (DtFlags1) add({DT_FLAGS_1, DtFlags1}); if (!Config->Shared && !Config->Relocatable) add({DT_DEBUG, (uint64_t)0}); } // Add remaining entries to complete .dynamic contents. template void DynamicSection::finalize() { if (this->Size) return; // Already finalized. this->Link = In::DynStrTab->OutSec->SectionIndex; if (In::RelaDyn->OutSec->Size > 0) { bool IsRela = Config->Rela; add({IsRela ? DT_RELA : DT_REL, In::RelaDyn}); add({IsRela ? DT_RELASZ : DT_RELSZ, In::RelaDyn->OutSec->Size}); add({IsRela ? DT_RELAENT : DT_RELENT, uintX_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))}); // MIPS dynamic loader does not support RELCOUNT tag. // The problem is in the tight relation between dynamic // relocations and GOT. So do not emit this tag on MIPS. if (Config->EMachine != EM_MIPS) { size_t NumRelativeRels = In::RelaDyn->getRelativeRelocCount(); if (Config->ZCombreloc && NumRelativeRels) add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels}); } } if (In::RelaPlt->OutSec->Size > 0) { add({DT_JMPREL, In::RelaPlt}); add({DT_PLTRELSZ, In::RelaPlt->OutSec->Size}); add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT, In::GotPlt}); add({DT_PLTREL, uint64_t(Config->Rela ? DT_RELA : DT_REL)}); } add({DT_SYMTAB, In::DynSymTab}); add({DT_SYMENT, sizeof(Elf_Sym)}); add({DT_STRTAB, In::DynStrTab}); add({DT_STRSZ, In::DynStrTab->getSize()}); if (In::GnuHashTab) add({DT_GNU_HASH, In::GnuHashTab}); if (In::HashTab) add({DT_HASH, In::HashTab}); if (Out::PreinitArray) { add({DT_PREINIT_ARRAY, Out::PreinitArray}); add({DT_PREINIT_ARRAYSZ, Out::PreinitArray, Entry::SecSize}); } if (Out::InitArray) { add({DT_INIT_ARRAY, Out::InitArray}); add({DT_INIT_ARRAYSZ, Out::InitArray, Entry::SecSize}); } if (Out::FiniArray) { add({DT_FINI_ARRAY, Out::FiniArray}); add({DT_FINI_ARRAYSZ, Out::FiniArray, Entry::SecSize}); } if (SymbolBody *B = Symtab::X->findInCurrentDSO(Config->Init)) add({DT_INIT, B}); if (SymbolBody *B = Symtab::X->findInCurrentDSO(Config->Fini)) add({DT_FINI, B}); bool HasVerNeed = In::VerNeed->getNeedNum() != 0; if (HasVerNeed || In::VerDef) add({DT_VERSYM, In::VerSym}); if (In::VerDef) { add({DT_VERDEF, In::VerDef}); add({DT_VERDEFNUM, getVerDefNum()}); } if (HasVerNeed) { add({DT_VERNEED, In::VerNeed}); add({DT_VERNEEDNUM, In::VerNeed->getNeedNum()}); } if (Config->EMachine == EM_MIPS) { add({DT_MIPS_RLD_VERSION, 1}); add({DT_MIPS_FLAGS, RHF_NOTPOT}); add({DT_MIPS_BASE_ADDRESS, Config->ImageBase}); add({DT_MIPS_SYMTABNO, In::DynSymTab->getNumSymbols()}); add({DT_MIPS_LOCAL_GOTNO, In::MipsGot->getLocalEntriesNum()}); if (const SymbolBody *B = In::MipsGot->getFirstGlobalEntry()) add({DT_MIPS_GOTSYM, B->DynsymIndex}); else add({DT_MIPS_GOTSYM, In::DynSymTab->getNumSymbols()}); add({DT_PLTGOT, In::MipsGot}); if (In::MipsRldMap) add({DT_MIPS_RLD_MAP, In::MipsRldMap}); } this->OutSec->Entsize = this->Entsize; this->OutSec->Link = this->Link; // +1 for DT_NULL this->Size = (Entries.size() + 1) * this->Entsize; } template void DynamicSection::writeTo(uint8_t *Buf) { auto *P = reinterpret_cast(Buf); for (const Entry &E : Entries) { P->d_tag = E.Tag; switch (E.Kind) { case Entry::SecAddr: P->d_un.d_ptr = E.OutSec->Addr; break; case Entry::InSecAddr: P->d_un.d_ptr = E.InSec->OutSec->Addr + E.InSec->OutSecOff; break; case Entry::SecSize: P->d_un.d_val = E.OutSec->Size; break; case Entry::SymAddr: P->d_un.d_ptr = E.Sym->template getVA(); break; case Entry::PlainInt: P->d_un.d_val = E.Val; break; } ++P; } } template typename ELFT::uint DynamicReloc::getOffset() const { if (OutputSec) return OutputSec->Addr + OffsetInSec; return InputSec->OutSec->Addr + InputSec->getOffset(OffsetInSec); } template typename ELFT::uint DynamicReloc::getAddend() const { if (UseSymVA) return Sym->getVA(Addend); return Addend; } template uint32_t DynamicReloc::getSymIndex() const { if (Sym && !UseSymVA) return Sym->DynsymIndex; return 0; } template RelocationSection::RelocationSection(StringRef Name, bool Sort) : SyntheticSection(SHF_ALLOC, Config->Rela ? SHT_RELA : SHT_REL, sizeof(uintX_t), Name), Sort(Sort) { this->Entsize = Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); } template void RelocationSection::addReloc(const DynamicReloc &Reloc) { if (Reloc.Type == Target->RelativeRel) ++NumRelativeRelocs; Relocs.push_back(Reloc); } template static bool compRelocations(const RelTy &A, const RelTy &B) { bool AIsRel = A.getType(Config->Mips64EL) == Target->RelativeRel; bool BIsRel = B.getType(Config->Mips64EL) == Target->RelativeRel; if (AIsRel != BIsRel) return AIsRel; return A.getSymbol(Config->Mips64EL) < B.getSymbol(Config->Mips64EL); } template void RelocationSection::writeTo(uint8_t *Buf) { uint8_t *BufBegin = Buf; for (const DynamicReloc &Rel : Relocs) { auto *P = reinterpret_cast(Buf); Buf += Config->Rela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); if (Config->Rela) P->r_addend = Rel.getAddend(); P->r_offset = Rel.getOffset(); if (Config->EMachine == EM_MIPS && Rel.getInputSec() == In::MipsGot) // Dynamic relocation against MIPS GOT section make deal TLS entries // allocated in the end of the GOT. We need to adjust the offset to take // in account 'local' and 'global' GOT entries. P->r_offset += In::MipsGot->getTlsOffset(); P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->Mips64EL); } if (Sort) { if (Config->Rela) std::stable_sort((Elf_Rela *)BufBegin, (Elf_Rela *)BufBegin + Relocs.size(), compRelocations); else std::stable_sort((Elf_Rel *)BufBegin, (Elf_Rel *)BufBegin + Relocs.size(), compRelocations); } } template unsigned RelocationSection::getRelocOffset() { return this->Entsize * Relocs.size(); } template void RelocationSection::finalize() { this->Link = In::DynSymTab ? In::DynSymTab->OutSec->SectionIndex : In::SymTab->OutSec->SectionIndex; // Set required output section properties. this->OutSec->Link = this->Link; this->OutSec->Entsize = this->Entsize; } template SymbolTableSection::SymbolTableSection( StringTableSection &StrTabSec) : SyntheticSection(StrTabSec.isDynamic() ? (uintX_t)SHF_ALLOC : 0, StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB, sizeof(uintX_t), StrTabSec.isDynamic() ? ".dynsym" : ".symtab"), StrTabSec(StrTabSec) { this->Entsize = sizeof(Elf_Sym); } // Orders symbols according to their positions in the GOT, // in compliance with MIPS ABI rules. // See "Global Offset Table" in Chapter 5 in the following document // for detailed description: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf static bool sortMipsSymbols(const SymbolBody *L, const SymbolBody *R) { // Sort entries related to non-local preemptible symbols by GOT indexes. // All other entries go to the first part of GOT in arbitrary order. bool LIsInLocalGot = !L->IsInGlobalMipsGot; bool RIsInLocalGot = !R->IsInGlobalMipsGot; if (LIsInLocalGot || RIsInLocalGot) return !RIsInLocalGot; return L->GotIndex < R->GotIndex; } template void SymbolTableSection::finalize() { this->OutSec->Link = this->Link = StrTabSec.OutSec->SectionIndex; this->OutSec->Info = this->Info = NumLocals + 1; this->OutSec->Entsize = this->Entsize; - if (Config->Relocatable) { - size_t I = NumLocals; - for (const SymbolTableEntry &S : Symbols) - S.Symbol->DynsymIndex = ++I; + if (Config->Relocatable) return; - } if (!StrTabSec.isDynamic()) { - std::stable_sort( - Symbols.begin(), Symbols.end(), - [](const SymbolTableEntry &L, const SymbolTableEntry &R) { - return L.Symbol->symbol()->computeBinding() == STB_LOCAL && - R.Symbol->symbol()->computeBinding() != STB_LOCAL; + auto GlobBegin = Symbols.begin() + NumLocals; + auto It = std::stable_partition( + GlobBegin, Symbols.end(), [](const SymbolTableEntry &S) { + return S.Symbol->symbol()->computeBinding() == STB_LOCAL; }); + // update sh_info with number of Global symbols output with computed + // binding of STB_LOCAL + this->OutSec->Info = this->Info = 1 + It - Symbols.begin(); return; } + if (In::GnuHashTab) // NB: It also sorts Symbols to meet the GNU hash table requirements. In::GnuHashTab->addSymbols(Symbols); else if (Config->EMachine == EM_MIPS) std::stable_sort(Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &L, const SymbolTableEntry &R) { return sortMipsSymbols(L.Symbol, R.Symbol); }); size_t I = 0; for (const SymbolTableEntry &S : Symbols) S.Symbol->DynsymIndex = ++I; } -template void SymbolTableSection::addSymbol(SymbolBody *B) { +template void SymbolTableSection::addGlobal(SymbolBody *B) { Symbols.push_back({B, StrTabSec.addString(B->getName(), false)}); } +template void SymbolTableSection::addLocal(SymbolBody *B) { + assert(!StrTabSec.isDynamic()); + ++NumLocals; + Symbols.push_back({B, StrTabSec.addString(B->getName())}); +} + +template +size_t SymbolTableSection::getSymbolIndex(SymbolBody *Body) { + auto I = llvm::find_if( + Symbols, [&](const SymbolTableEntry &E) { return E.Symbol == Body; }); + if (I == Symbols.end()) + return 0; + return I - Symbols.begin() + 1; +} + template void SymbolTableSection::writeTo(uint8_t *Buf) { Buf += sizeof(Elf_Sym); // All symbols with STB_LOCAL binding precede the weak and global symbols. // .dynsym only contains global symbols. if (Config->Discard != DiscardPolicy::All && !StrTabSec.isDynamic()) writeLocalSymbols(Buf); writeGlobalSymbols(Buf); } template void SymbolTableSection::writeLocalSymbols(uint8_t *&Buf) { // Iterate over all input object files to copy their local symbols // to the output symbol table pointed by Buf. - for (ObjectFile *File : Symtab::X->getObjectFiles()) { - for (const std::pair *, size_t> &P : - File->KeptLocalSyms) { - const DefinedRegular &Body = *P.first; - InputSectionBase *Section = Body.Section; - auto *ESym = reinterpret_cast(Buf); - if (!Section) { - ESym->st_shndx = SHN_ABS; - ESym->st_value = Body.Value; - } else { - const OutputSectionBase *OutSec = Section->OutSec; - ESym->st_shndx = OutSec->SectionIndex; - ESym->st_value = OutSec->Addr + Section->getOffset(Body); - } - ESym->st_name = P.second; - ESym->st_size = Body.template getSize(); - ESym->setBindingAndType(STB_LOCAL, Body.Type); - Buf += sizeof(*ESym); + for (auto I = Symbols.begin(); I != Symbols.begin() + NumLocals; ++I) { + const DefinedRegular &Body = *cast>(I->Symbol); + InputSectionBase *Section = Body.Section; + auto *ESym = reinterpret_cast(Buf); + + if (!Section) { + ESym->st_shndx = SHN_ABS; + ESym->st_value = Body.Value; + } else { + const OutputSectionBase *OutSec = Section->OutSec; + ESym->st_shndx = OutSec->SectionIndex; + ESym->st_value = OutSec->Addr + Section->getOffset(Body); } + ESym->st_name = I->StrTabOffset; + ESym->st_size = Body.template getSize(); + ESym->setBindingAndType(STB_LOCAL, Body.Type); + Buf += sizeof(*ESym); } } template void SymbolTableSection::writeGlobalSymbols(uint8_t *Buf) { // Write the internal symbol table contents to the output symbol table // pointed by Buf. auto *ESym = reinterpret_cast(Buf); - for (const SymbolTableEntry &S : Symbols) { + + for (auto I = Symbols.begin() + NumLocals; I != Symbols.end(); ++I) { + const SymbolTableEntry &S = *I; SymbolBody *Body = S.Symbol; size_t StrOff = S.StrTabOffset; uint8_t Type = Body->Type; uintX_t Size = Body->getSize(); ESym->setBindingAndType(Body->symbol()->computeBinding(), Type); ESym->st_size = Size; ESym->st_name = StrOff; ESym->setVisibility(Body->symbol()->Visibility); ESym->st_value = Body->getVA(); if (const OutputSectionBase *OutSec = getOutputSection(Body)) ESym->st_shndx = OutSec->SectionIndex; else if (isa>(Body)) ESym->st_shndx = SHN_ABS; if (Config->EMachine == EM_MIPS) { // On MIPS we need to mark symbol which has a PLT entry and requires // pointer equality by STO_MIPS_PLT flag. That is necessary to help // dynamic linker distinguish such symbols and MIPS lazy-binding stubs. // https://sourceware.org/ml/binutils/2008-07/txt00000.txt if (Body->isInPlt() && Body->NeedsCopyOrPltAddr) ESym->st_other |= STO_MIPS_PLT; if (Config->Relocatable) { auto *D = dyn_cast>(Body); if (D && D->isMipsPIC()) ESym->st_other |= STO_MIPS_PIC; } } ++ESym; } } template const OutputSectionBase * SymbolTableSection::getOutputSection(SymbolBody *Sym) { switch (Sym->kind()) { case SymbolBody::DefinedSyntheticKind: return cast(Sym)->Section; case SymbolBody::DefinedRegularKind: { auto &D = cast>(*Sym); if (D.Section) return D.Section->OutSec; break; } case SymbolBody::DefinedCommonKind: return In::Common->OutSec; case SymbolBody::SharedKind: { auto &SS = cast>(*Sym); if (SS.needsCopy()) return SS.getBssSectionForCopy(); break; } case SymbolBody::UndefinedKind: case SymbolBody::LazyArchiveKind: case SymbolBody::LazyObjectKind: break; } return nullptr; } template GnuHashTableSection::GnuHashTableSection() : SyntheticSection(SHF_ALLOC, SHT_GNU_HASH, sizeof(uintX_t), ".gnu.hash") { this->Entsize = ELFT::Is64Bits ? 0 : 4; } template unsigned GnuHashTableSection::calcNBuckets(unsigned NumHashed) { if (!NumHashed) return 0; // These values are prime numbers which are not greater than 2^(N-1) + 1. // In result, for any particular NumHashed we return a prime number // which is not greater than NumHashed. static const unsigned Primes[] = { 1, 1, 3, 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071}; return Primes[std::min(Log2_32_Ceil(NumHashed), array_lengthof(Primes) - 1)]; } // Bloom filter estimation: at least 8 bits for each hashed symbol. // GNU Hash table requirement: it should be a power of 2, // the minimum value is 1, even for an empty table. // Expected results for a 32-bit target: // calcMaskWords(0..4) = 1 // calcMaskWords(5..8) = 2 // calcMaskWords(9..16) = 4 // For a 64-bit target: // calcMaskWords(0..8) = 1 // calcMaskWords(9..16) = 2 // calcMaskWords(17..32) = 4 template unsigned GnuHashTableSection::calcMaskWords(unsigned NumHashed) { if (!NumHashed) return 1; return NextPowerOf2((NumHashed - 1) / sizeof(Elf_Off)); } template void GnuHashTableSection::finalize() { unsigned NumHashed = Symbols.size(); NBuckets = calcNBuckets(NumHashed); MaskWords = calcMaskWords(NumHashed); // Second hash shift estimation: just predefined values. Shift2 = ELFT::Is64Bits ? 6 : 5; this->OutSec->Entsize = this->Entsize; this->OutSec->Link = this->Link = In::DynSymTab->OutSec->SectionIndex; this->Size = sizeof(Elf_Word) * 4 // Header + sizeof(Elf_Off) * MaskWords // Bloom Filter + sizeof(Elf_Word) * NBuckets // Hash Buckets + sizeof(Elf_Word) * NumHashed; // Hash Values } template void GnuHashTableSection::writeTo(uint8_t *Buf) { writeHeader(Buf); if (Symbols.empty()) return; writeBloomFilter(Buf); writeHashTable(Buf); } template void GnuHashTableSection::writeHeader(uint8_t *&Buf) { auto *P = reinterpret_cast(Buf); *P++ = NBuckets; *P++ = In::DynSymTab->getNumSymbols() - Symbols.size(); *P++ = MaskWords; *P++ = Shift2; Buf = reinterpret_cast(P); } template void GnuHashTableSection::writeBloomFilter(uint8_t *&Buf) { unsigned C = sizeof(Elf_Off) * 8; auto *Masks = reinterpret_cast(Buf); for (const SymbolData &Sym : Symbols) { size_t Pos = (Sym.Hash / C) & (MaskWords - 1); uintX_t V = (uintX_t(1) << (Sym.Hash % C)) | (uintX_t(1) << ((Sym.Hash >> Shift2) % C)); Masks[Pos] |= V; } Buf += sizeof(Elf_Off) * MaskWords; } template void GnuHashTableSection::writeHashTable(uint8_t *Buf) { Elf_Word *Buckets = reinterpret_cast(Buf); Elf_Word *Values = Buckets + NBuckets; int PrevBucket = -1; int I = 0; for (const SymbolData &Sym : Symbols) { int Bucket = Sym.Hash % NBuckets; assert(PrevBucket <= Bucket); if (Bucket != PrevBucket) { Buckets[Bucket] = Sym.Body->DynsymIndex; PrevBucket = Bucket; if (I > 0) Values[I - 1] |= 1; } Values[I] = Sym.Hash & ~1; ++I; } if (I > 0) Values[I - 1] |= 1; } static uint32_t hashGnu(StringRef Name) { uint32_t H = 5381; for (uint8_t C : Name) H = (H << 5) + H + C; return H; } // Add symbols to this symbol hash table. Note that this function // destructively sort a given vector -- which is needed because // GNU-style hash table places some sorting requirements. template void GnuHashTableSection::addSymbols(std::vector &V) { // Ideally this will just be 'auto' but GCC 6.1 is not able // to deduce it correctly. std::vector::iterator Mid = std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) { return S.Symbol->isUndefined(); }); if (Mid == V.end()) return; for (auto I = Mid, E = V.end(); I != E; ++I) { SymbolBody *B = I->Symbol; size_t StrOff = I->StrTabOffset; Symbols.push_back({B, StrOff, hashGnu(B->getName())}); } unsigned NBuckets = calcNBuckets(Symbols.size()); std::stable_sort(Symbols.begin(), Symbols.end(), [&](const SymbolData &L, const SymbolData &R) { return L.Hash % NBuckets < R.Hash % NBuckets; }); V.erase(Mid, V.end()); for (const SymbolData &Sym : Symbols) V.push_back({Sym.Body, Sym.STName}); } template HashTableSection::HashTableSection() : SyntheticSection(SHF_ALLOC, SHT_HASH, sizeof(Elf_Word), ".hash") { this->Entsize = sizeof(Elf_Word); } template void HashTableSection::finalize() { this->OutSec->Link = this->Link = In::DynSymTab->OutSec->SectionIndex; this->OutSec->Entsize = this->Entsize; unsigned NumEntries = 2; // nbucket and nchain. NumEntries += In::DynSymTab->getNumSymbols(); // The chain entries. // Create as many buckets as there are symbols. // FIXME: This is simplistic. We can try to optimize it, but implementing // support for SHT_GNU_HASH is probably even more profitable. NumEntries += In::DynSymTab->getNumSymbols(); this->Size = NumEntries * sizeof(Elf_Word); } template void HashTableSection::writeTo(uint8_t *Buf) { unsigned NumSymbols = In::DynSymTab->getNumSymbols(); auto *P = reinterpret_cast(Buf); *P++ = NumSymbols; // nbucket *P++ = NumSymbols; // nchain Elf_Word *Buckets = P; Elf_Word *Chains = P + NumSymbols; for (const SymbolTableEntry &S : In::DynSymTab->getSymbols()) { SymbolBody *Body = S.Symbol; StringRef Name = Body->getName(); unsigned I = Body->DynsymIndex; uint32_t Hash = hashSysV(Name) % NumSymbols; Chains[I] = Buckets[Hash]; Buckets[Hash] = I; } } template PltSection::PltSection() : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt") {} template void PltSection::writeTo(uint8_t *Buf) { // At beginning of PLT, we have code to call the dynamic linker // to resolve dynsyms at runtime. Write such code. Target->writePltHeader(Buf); size_t Off = Target->PltHeaderSize; for (auto &I : Entries) { const SymbolBody *B = I.first; unsigned RelOff = I.second; uint64_t Got = B->getGotPltVA(); uint64_t Plt = this->getVA() + Off; Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff); Off += Target->PltEntrySize; } } template void PltSection::addEntry(SymbolBody &Sym) { Sym.PltIndex = Entries.size(); unsigned RelOff = In::RelaPlt->getRelocOffset(); Entries.push_back(std::make_pair(&Sym, RelOff)); } template size_t PltSection::getSize() const { return Target->PltHeaderSize + Entries.size() * Target->PltEntrySize; } template IpltSection::IpltSection() : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt") {} template void IpltSection::writeTo(uint8_t *Buf) { // The IRelative relocations do not support lazy binding so no header is // needed size_t Off = 0; for (auto &I : Entries) { const SymbolBody *B = I.first; unsigned RelOff = I.second + In::Plt->getSize(); uint64_t Got = B->getGotPltVA(); uint64_t Plt = this->getVA() + Off; Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff); Off += Target->PltEntrySize; } } template void IpltSection::addEntry(SymbolBody &Sym) { Sym.PltIndex = Entries.size(); Sym.IsInIplt = true; unsigned RelOff = In::RelaIplt->getRelocOffset(); Entries.push_back(std::make_pair(&Sym, RelOff)); } template size_t IpltSection::getSize() const { return Entries.size() * Target->PltEntrySize; } template GdbIndexSection::GdbIndexSection() : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"), StringPool(llvm::StringTableBuilder::ELF) {} template void GdbIndexSection::parseDebugSections() { for (InputSectionBase *S : Symtab::X->Sections) if (InputSection *IS = dyn_cast>(S)) if (IS->OutSec && IS->Name == ".debug_info") readDwarf(IS); } // Iterative hash function for symbol's name is described in .gdb_index format // specification. Note that we use one for version 5 to 7 here, it is different // for version 4. static uint32_t hash(StringRef Str) { uint32_t R = 0; for (uint8_t C : Str) R = R * 67 + tolower(C) - 113; return R; } template void GdbIndexSection::readDwarf(InputSection *I) { GdbIndexBuilder Builder(I); if (ErrorCount) return; size_t CuId = CompilationUnits.size(); std::vector> CuList = Builder.readCUList(); CompilationUnits.insert(CompilationUnits.end(), CuList.begin(), CuList.end()); std::vector> AddrArea = Builder.readAddressArea(CuId); AddressArea.insert(AddressArea.end(), AddrArea.begin(), AddrArea.end()); std::vector> NamesAndTypes = Builder.readPubNamesAndTypes(); for (std::pair &Pair : NamesAndTypes) { uint32_t Hash = hash(Pair.first); size_t Offset = StringPool.add(Pair.first); bool IsNew; GdbSymbol *Sym; std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset); if (IsNew) { Sym->CuVectorIndex = CuVectors.size(); CuVectors.push_back({{CuId, Pair.second}}); continue; } std::vector> &CuVec = CuVectors[Sym->CuVectorIndex]; CuVec.push_back({CuId, Pair.second}); } } template void GdbIndexSection::finalize() { if (Finalized) return; Finalized = true; parseDebugSections(); // GdbIndex header consist from version fields // and 5 more fields with different kinds of offsets. CuTypesOffset = CuListOffset + CompilationUnits.size() * CompilationUnitSize; SymTabOffset = CuTypesOffset + AddressArea.size() * AddressEntrySize; ConstantPoolOffset = SymTabOffset + SymbolTable.getCapacity() * SymTabEntrySize; for (std::vector> &CuVec : CuVectors) { CuVectorsOffset.push_back(CuVectorsSize); CuVectorsSize += OffsetTypeSize * (CuVec.size() + 1); } StringPoolOffset = ConstantPoolOffset + CuVectorsSize; StringPool.finalizeInOrder(); } template size_t GdbIndexSection::getSize() const { const_cast *>(this)->finalize(); return StringPoolOffset + StringPool.getSize(); } template void GdbIndexSection::writeTo(uint8_t *Buf) { write32le(Buf, 7); // Write version. write32le(Buf + 4, CuListOffset); // CU list offset. write32le(Buf + 8, CuTypesOffset); // Types CU list offset. write32le(Buf + 12, CuTypesOffset); // Address area offset. write32le(Buf + 16, SymTabOffset); // Symbol table offset. write32le(Buf + 20, ConstantPoolOffset); // Constant pool offset. Buf += 24; // Write the CU list. for (std::pair CU : CompilationUnits) { write64le(Buf, CU.first); write64le(Buf + 8, CU.second); Buf += 16; } // Write the address area. for (AddressEntry &E : AddressArea) { uintX_t BaseAddr = E.Section->OutSec->Addr + E.Section->getOffset(0); write64le(Buf, BaseAddr + E.LowAddress); write64le(Buf + 8, BaseAddr + E.HighAddress); write32le(Buf + 16, E.CuIndex); Buf += 20; } // Write the symbol table. for (size_t I = 0; I < SymbolTable.getCapacity(); ++I) { GdbSymbol *Sym = SymbolTable.getSymbol(I); if (Sym) { size_t NameOffset = Sym->NameOffset + StringPoolOffset - ConstantPoolOffset; size_t CuVectorOffset = CuVectorsOffset[Sym->CuVectorIndex]; write32le(Buf, NameOffset); write32le(Buf + 4, CuVectorOffset); } Buf += 8; } // Write the CU vectors into the constant pool. for (std::vector> &CuVec : CuVectors) { write32le(Buf, CuVec.size()); Buf += 4; for (std::pair &P : CuVec) { uint32_t Index = P.first; uint8_t Flags = P.second; Index |= Flags << 24; write32le(Buf, Index); Buf += 4; } } StringPool.write(Buf); } template bool GdbIndexSection::empty() const { return !Out::DebugInfo; } template EhFrameHeader::EhFrameHeader() : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame_hdr") {} // .eh_frame_hdr contains a binary search table of pointers to FDEs. // Each entry of the search table consists of two values, // the starting PC from where FDEs covers, and the FDE's address. // It is sorted by PC. template void EhFrameHeader::writeTo(uint8_t *Buf) { const endianness E = ELFT::TargetEndianness; // Sort the FDE list by their PC and uniqueify. Usually there is only // one FDE for a PC (i.e. function), but if ICF merges two functions // into one, there can be more than one FDEs pointing to the address. auto Less = [](const FdeData &A, const FdeData &B) { return A.Pc < B.Pc; }; std::stable_sort(Fdes.begin(), Fdes.end(), Less); auto Eq = [](const FdeData &A, const FdeData &B) { return A.Pc == B.Pc; }; Fdes.erase(std::unique(Fdes.begin(), Fdes.end(), Eq), Fdes.end()); Buf[0] = 1; Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; Buf[2] = DW_EH_PE_udata4; Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; write32(Buf + 4, Out::EhFrame->Addr - this->getVA() - 4); write32(Buf + 8, Fdes.size()); Buf += 12; uintX_t VA = this->getVA(); for (FdeData &Fde : Fdes) { write32(Buf, Fde.Pc - VA); write32(Buf + 4, Fde.FdeVA - VA); Buf += 8; } } template size_t EhFrameHeader::getSize() const { // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs. return 12 + Out::EhFrame->NumFdes * 8; } template void EhFrameHeader::addFde(uint32_t Pc, uint32_t FdeVA) { Fdes.push_back({Pc, FdeVA}); } template bool EhFrameHeader::empty() const { return Out::EhFrame->empty(); } template VersionDefinitionSection::VersionDefinitionSection() : SyntheticSection(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t), ".gnu.version_d") {} static StringRef getFileDefName() { if (!Config->SoName.empty()) return Config->SoName; return Config->OutputFile; } template void VersionDefinitionSection::finalize() { FileDefNameOff = In::DynStrTab->addString(getFileDefName()); for (VersionDefinition &V : Config->VersionDefinitions) V.NameOff = In::DynStrTab->addString(V.Name); this->OutSec->Link = this->Link = In::DynStrTab->OutSec->SectionIndex; // sh_info should be set to the number of definitions. This fact is missed in // documentation, but confirmed by binutils community: // https://sourceware.org/ml/binutils/2014-11/msg00355.html this->OutSec->Info = this->Info = getVerDefNum(); } template void VersionDefinitionSection::writeOne(uint8_t *Buf, uint32_t Index, StringRef Name, size_t NameOff) { auto *Verdef = reinterpret_cast(Buf); Verdef->vd_version = 1; Verdef->vd_cnt = 1; Verdef->vd_aux = sizeof(Elf_Verdef); Verdef->vd_next = sizeof(Elf_Verdef) + sizeof(Elf_Verdaux); Verdef->vd_flags = (Index == 1 ? VER_FLG_BASE : 0); Verdef->vd_ndx = Index; Verdef->vd_hash = hashSysV(Name); auto *Verdaux = reinterpret_cast(Buf + sizeof(Elf_Verdef)); Verdaux->vda_name = NameOff; Verdaux->vda_next = 0; } template void VersionDefinitionSection::writeTo(uint8_t *Buf) { writeOne(Buf, 1, getFileDefName(), FileDefNameOff); for (VersionDefinition &V : Config->VersionDefinitions) { Buf += sizeof(Elf_Verdef) + sizeof(Elf_Verdaux); writeOne(Buf, V.Id, V.Name, V.NameOff); } // Need to terminate the last version definition. Elf_Verdef *Verdef = reinterpret_cast(Buf); Verdef->vd_next = 0; } template size_t VersionDefinitionSection::getSize() const { return (sizeof(Elf_Verdef) + sizeof(Elf_Verdaux)) * getVerDefNum(); } template VersionTableSection::VersionTableSection() : SyntheticSection(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t), ".gnu.version") {} template void VersionTableSection::finalize() { this->OutSec->Entsize = this->Entsize = sizeof(Elf_Versym); // At the moment of june 2016 GNU docs does not mention that sh_link field // should be set, but Sun docs do. Also readelf relies on this field. this->OutSec->Link = this->Link = In::DynSymTab->OutSec->SectionIndex; } template size_t VersionTableSection::getSize() const { return sizeof(Elf_Versym) * (In::DynSymTab->getSymbols().size() + 1); } template void VersionTableSection::writeTo(uint8_t *Buf) { auto *OutVersym = reinterpret_cast(Buf) + 1; for (const SymbolTableEntry &S : In::DynSymTab->getSymbols()) { OutVersym->vs_index = S.Symbol->symbol()->VersionId; ++OutVersym; } } template bool VersionTableSection::empty() const { return !In::VerDef && In::VerNeed->empty(); } template VersionNeedSection::VersionNeedSection() : SyntheticSection(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t), ".gnu.version_r") { // Identifiers in verneed section start at 2 because 0 and 1 are reserved // for VER_NDX_LOCAL and VER_NDX_GLOBAL. // First identifiers are reserved by verdef section if it exist. NextIndex = getVerDefNum() + 1; } template void VersionNeedSection::addSymbol(SharedSymbol *SS) { if (!SS->Verdef) { SS->symbol()->VersionId = VER_NDX_GLOBAL; return; } SharedFile *F = SS->file(); // If we don't already know that we need an Elf_Verneed for this DSO, prepare // to create one by adding it to our needed list and creating a dynstr entry // for the soname. if (F->VerdefMap.empty()) Needed.push_back({F, In::DynStrTab->addString(F->getSoName())}); typename SharedFile::NeededVer &NV = F->VerdefMap[SS->Verdef]; // If we don't already know that we need an Elf_Vernaux for this Elf_Verdef, // prepare to create one by allocating a version identifier and creating a // dynstr entry for the version name. if (NV.Index == 0) { NV.StrTab = In::DynStrTab->addString( SS->file()->getStringTable().data() + SS->Verdef->getAux()->vda_name); NV.Index = NextIndex++; } SS->symbol()->VersionId = NV.Index; } template void VersionNeedSection::writeTo(uint8_t *Buf) { // The Elf_Verneeds need to appear first, followed by the Elf_Vernauxs. auto *Verneed = reinterpret_cast(Buf); auto *Vernaux = reinterpret_cast(Verneed + Needed.size()); for (std::pair *, size_t> &P : Needed) { // Create an Elf_Verneed for this DSO. Verneed->vn_version = 1; Verneed->vn_cnt = P.first->VerdefMap.size(); Verneed->vn_file = P.second; Verneed->vn_aux = reinterpret_cast(Vernaux) - reinterpret_cast(Verneed); Verneed->vn_next = sizeof(Elf_Verneed); ++Verneed; // Create the Elf_Vernauxs for this Elf_Verneed. The loop iterates over // VerdefMap, which will only contain references to needed version // definitions. Each Elf_Vernaux is based on the information contained in // the Elf_Verdef in the source DSO. This loop iterates over a std::map of // pointers, but is deterministic because the pointers refer to Elf_Verdef // data structures within a single input file. for (auto &NV : P.first->VerdefMap) { Vernaux->vna_hash = NV.first->vd_hash; Vernaux->vna_flags = 0; Vernaux->vna_other = NV.second.Index; Vernaux->vna_name = NV.second.StrTab; Vernaux->vna_next = sizeof(Elf_Vernaux); ++Vernaux; } Vernaux[-1].vna_next = 0; } Verneed[-1].vn_next = 0; } template void VersionNeedSection::finalize() { this->OutSec->Link = this->Link = In::DynStrTab->OutSec->SectionIndex; this->OutSec->Info = this->Info = Needed.size(); } template size_t VersionNeedSection::getSize() const { unsigned Size = Needed.size() * sizeof(Elf_Verneed); for (const std::pair *, size_t> &P : Needed) Size += P.first->VerdefMap.size() * sizeof(Elf_Vernaux); return Size; } template bool VersionNeedSection::empty() const { return getNeedNum() == 0; } template MipsRldMapSection::MipsRldMapSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, sizeof(typename ELFT::uint), ".rld_map") {} template void MipsRldMapSection::writeTo(uint8_t *Buf) { // Apply filler from linker script. uint64_t Filler = Script::X->getFiller(this->Name); Filler = (Filler << 32) | Filler; memcpy(Buf, &Filler, getSize()); } template ARMExidxSentinelSection::ARMExidxSentinelSection() : SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX, sizeof(typename ELFT::uint), ".ARM.exidx") {} // Write a terminating sentinel entry to the end of the .ARM.exidx table. // This section will have been sorted last in the .ARM.exidx table. // This table entry will have the form: // | PREL31 upper bound of code that has exception tables | EXIDX_CANTUNWIND | template void ARMExidxSentinelSection::writeTo(uint8_t *Buf) { // Get the InputSection before us, we are by definition last auto RI = cast>(this->OutSec)->Sections.rbegin(); InputSection *LE = *(++RI); InputSection *LC = cast>(LE->getLinkOrderDep()); uint64_t S = LC->OutSec->Addr + LC->getOffset(LC->getSize()); uint64_t P = this->getVA(); Target->relocateOne(Buf, R_ARM_PREL31, S - P); write32le(Buf + 4, 0x1); } template InputSection *elf::createCommonSection(); template InputSection *elf::createCommonSection(); template InputSection *elf::createCommonSection(); template InputSection *elf::createCommonSection(); template InputSection *elf::createInterpSection(); template InputSection *elf::createInterpSection(); template InputSection *elf::createInterpSection(); template InputSection *elf::createInterpSection(); template MergeInputSection *elf::createCommentSection(); template MergeInputSection *elf::createCommentSection(); template MergeInputSection *elf::createCommentSection(); template MergeInputSection *elf::createCommentSection(); template class elf::MipsAbiFlagsSection; template class elf::MipsAbiFlagsSection; template class elf::MipsAbiFlagsSection; template class elf::MipsAbiFlagsSection; template class elf::MipsOptionsSection; template class elf::MipsOptionsSection; template class elf::MipsOptionsSection; template class elf::MipsOptionsSection; template class elf::MipsReginfoSection; template class elf::MipsReginfoSection; template class elf::MipsReginfoSection; template class elf::MipsReginfoSection; template class elf::BuildIdSection; template class elf::BuildIdSection; template class elf::BuildIdSection; template class elf::BuildIdSection; template class elf::GotSection; template class elf::GotSection; template class elf::GotSection; template class elf::GotSection; template class elf::MipsGotSection; template class elf::MipsGotSection; template class elf::MipsGotSection; template class elf::MipsGotSection; template class elf::GotPltSection; template class elf::GotPltSection; template class elf::GotPltSection; template class elf::GotPltSection; template class elf::IgotPltSection; template class elf::IgotPltSection; template class elf::IgotPltSection; template class elf::IgotPltSection; template class elf::StringTableSection; template class elf::StringTableSection; template class elf::StringTableSection; template class elf::StringTableSection; template class elf::DynamicSection; template class elf::DynamicSection; template class elf::DynamicSection; template class elf::DynamicSection; template class elf::RelocationSection; template class elf::RelocationSection; template class elf::RelocationSection; template class elf::RelocationSection; template class elf::SymbolTableSection; template class elf::SymbolTableSection; template class elf::SymbolTableSection; template class elf::SymbolTableSection; template class elf::GnuHashTableSection; template class elf::GnuHashTableSection; template class elf::GnuHashTableSection; template class elf::GnuHashTableSection; template class elf::HashTableSection; template class elf::HashTableSection; template class elf::HashTableSection; template class elf::HashTableSection; template class elf::PltSection; template class elf::PltSection; template class elf::PltSection; template class elf::PltSection; template class elf::IpltSection; template class elf::IpltSection; template class elf::IpltSection; template class elf::IpltSection; template class elf::GdbIndexSection; template class elf::GdbIndexSection; template class elf::GdbIndexSection; template class elf::GdbIndexSection; template class elf::EhFrameHeader; template class elf::EhFrameHeader; template class elf::EhFrameHeader; template class elf::EhFrameHeader; template class elf::VersionTableSection; template class elf::VersionTableSection; template class elf::VersionTableSection; template class elf::VersionTableSection; template class elf::VersionNeedSection; template class elf::VersionNeedSection; template class elf::VersionNeedSection; template class elf::VersionNeedSection; template class elf::VersionDefinitionSection; template class elf::VersionDefinitionSection; template class elf::VersionDefinitionSection; template class elf::VersionDefinitionSection; template class elf::MipsRldMapSection; template class elf::MipsRldMapSection; template class elf::MipsRldMapSection; template class elf::MipsRldMapSection; template class elf::ARMExidxSentinelSection; template class elf::ARMExidxSentinelSection; template class elf::ARMExidxSentinelSection; template class elf::ARMExidxSentinelSection; Index: vendor/lld/dist/ELF/SyntheticSections.h =================================================================== --- vendor/lld/dist/ELF/SyntheticSections.h (revision 313062) +++ vendor/lld/dist/ELF/SyntheticSections.h (revision 313063) @@ -1,747 +1,750 @@ //===- SyntheticSection.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_SYNTHETIC_SECTION_H #define LLD_ELF_SYNTHETIC_SECTION_H #include "GdbIndex.h" #include "InputSection.h" #include "llvm/ADT/MapVector.h" #include "llvm/MC/StringTableBuilder.h" namespace lld { namespace elf { template class SyntheticSection : public InputSection { typedef typename ELFT::uint uintX_t; public: SyntheticSection(uintX_t Flags, uint32_t Type, uintX_t Addralign, StringRef Name) : InputSection(Flags, Type, Addralign, ArrayRef(), Name, InputSectionData::Synthetic) { this->Live = true; } virtual ~SyntheticSection() = default; virtual void writeTo(uint8_t *Buf) = 0; virtual size_t getSize() const = 0; virtual void finalize() {} virtual bool empty() const { return false; } uintX_t getVA() const { return this->OutSec ? this->OutSec->Addr + this->OutSecOff : 0; } static bool classof(const InputSectionData *D) { return D->kind() == InputSectionData::Synthetic; } }; template class GotSection final : public SyntheticSection { typedef typename ELFT::uint uintX_t; public: GotSection(); void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } void finalize() override; bool empty() const override; void addEntry(SymbolBody &Sym); bool addDynTlsEntry(SymbolBody &Sym); bool addTlsIndex(); uintX_t getGlobalDynAddr(const SymbolBody &B) const; uintX_t getGlobalDynOffset(const SymbolBody &B) const; uintX_t getTlsIndexVA() { return this->getVA() + TlsIndexOff; } uint32_t getTlsIndexOff() const { return TlsIndexOff; } // Flag to force GOT to be in output if we have relocations // that relies on its address. bool HasGotOffRel = false; private: size_t NumEntries = 0; uint32_t TlsIndexOff = -1; uintX_t Size = 0; }; // .note.gnu.build-id section. template class BuildIdSection : public SyntheticSection { // First 16 bytes are a header. static const unsigned HeaderSize = 16; public: BuildIdSection(); void writeTo(uint8_t *Buf) override; size_t getSize() const override { return HeaderSize + HashSize; } void writeBuildId(llvm::ArrayRef Buf); private: void computeHash(llvm::ArrayRef Buf, std::function)> Hash); size_t HashSize; uint8_t *HashBuf; }; template class MipsGotSection final : public SyntheticSection { typedef typename ELFT::uint uintX_t; public: MipsGotSection(); void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } void finalize() override; bool empty() const override; void addEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr); bool addDynTlsEntry(SymbolBody &Sym); bool addTlsIndex(); uintX_t getPageEntryOffset(const SymbolBody &B, uintX_t Addend) const; uintX_t getBodyEntryOffset(const SymbolBody &B, uintX_t Addend) const; uintX_t getGlobalDynOffset(const SymbolBody &B) const; // Returns the symbol which corresponds to the first entry of the global part // of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic // table properties. // Returns nullptr if the global part is empty. const SymbolBody *getFirstGlobalEntry() const; // Returns the number of entries in the local part of GOT including // the number of reserved entries. unsigned getLocalEntriesNum() const; // Returns offset of TLS part of the MIPS GOT table. This part goes // after 'local' and 'global' entries. uintX_t getTlsOffset() const; uint32_t getTlsIndexOff() const { return TlsIndexOff; } uintX_t getGp() const; private: // MIPS GOT consists of three parts: local, global and tls. Each part // contains different types of entries. Here is a layout of GOT: // - Header entries | // - Page entries | Local part // - Local entries (16-bit access) | // - Local entries (32-bit access) | // - Normal global entries || Global part // - Reloc-only global entries || // - TLS entries ||| TLS part // // Header: // Two entries hold predefined value 0x0 and 0x80000000. // Page entries: // These entries created by R_MIPS_GOT_PAGE relocation and R_MIPS_GOT16 // relocation against local symbols. They are initialized by higher 16-bit // of the corresponding symbol's value. So each 64kb of address space // requires a single GOT entry. // Local entries (16-bit access): // These entries created by GOT relocations against global non-preemptible // symbols so dynamic linker is not necessary to resolve the symbol's // values. "16-bit access" means that corresponding relocations address // GOT using 16-bit index. Each unique Symbol-Addend pair has its own // GOT entry. // Local entries (32-bit access): // These entries are the same as above but created by relocations which // address GOT using 32-bit index (R_MIPS_GOT_HI16/LO16 etc). // Normal global entries: // These entries created by GOT relocations against preemptible global // symbols. They need to be initialized by dynamic linker and they ordered // exactly as the corresponding entries in the dynamic symbols table. // Reloc-only global entries: // These entries created for symbols that are referenced by dynamic // relocations R_MIPS_REL32. These entries are not accessed with gp-relative // addressing, but MIPS ABI requires that these entries be present in GOT. // TLS entries: // Entries created by TLS relocations. // Number of "Header" entries. static const unsigned HeaderEntriesNum = 2; // Number of allocated "Page" entries. uint32_t PageEntriesNum = 0; // Map output sections referenced by MIPS GOT relocations // to the first index of "Page" entries allocated for this section. llvm::SmallMapVector PageIndexMap; typedef std::pair GotEntry; typedef std::vector GotEntries; // Map from Symbol-Addend pair to the GOT index. llvm::DenseMap EntryIndexMap; // Local entries (16-bit access). GotEntries LocalEntries; // Local entries (32-bit access). GotEntries LocalEntries32; // Normal and reloc-only global entries. GotEntries GlobalEntries; // TLS entries. std::vector TlsEntries; uint32_t TlsIndexOff = -1; uintX_t Size = 0; }; template class GotPltSection final : public SyntheticSection { typedef typename ELFT::uint uintX_t; public: GotPltSection(); void addEntry(SymbolBody &Sym); size_t getSize() const override; void writeTo(uint8_t *Buf) override; bool empty() const override { return Entries.empty(); } private: std::vector Entries; }; // The IgotPltSection is a Got associated with the IpltSection for GNU Ifunc // Symbols that will be relocated by Target->IRelativeRel. // On most Targets the IgotPltSection will immediately follow the GotPltSection // on ARM the IgotPltSection will immediately follow the GotSection. template class IgotPltSection final : public SyntheticSection { typedef typename ELFT::uint uintX_t; public: IgotPltSection(); void addEntry(SymbolBody &Sym); size_t getSize() const override; void writeTo(uint8_t *Buf) override; bool empty() const override { return Entries.empty(); } private: std::vector Entries; }; template class StringTableSection final : public SyntheticSection { public: typedef typename ELFT::uint uintX_t; StringTableSection(StringRef Name, bool Dynamic); unsigned addString(StringRef S, bool HashIt = true); void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } bool isDynamic() const { return Dynamic; } private: const bool Dynamic; // ELF string tables start with a NUL byte, so 1. uintX_t Size = 1; llvm::DenseMap StringMap; std::vector Strings; }; template class DynamicReloc { typedef typename ELFT::uint uintX_t; public: DynamicReloc(uint32_t Type, const InputSectionBase *InputSec, uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym, uintX_t Addend) : Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec), UseSymVA(UseSymVA), Addend(Addend) {} DynamicReloc(uint32_t Type, const OutputSectionBase *OutputSec, uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym, uintX_t Addend) : Type(Type), Sym(Sym), OutputSec(OutputSec), OffsetInSec(OffsetInSec), UseSymVA(UseSymVA), Addend(Addend) {} uintX_t getOffset() const; uintX_t getAddend() const; uint32_t getSymIndex() const; const OutputSectionBase *getOutputSec() const { return OutputSec; } const InputSectionBase *getInputSec() const { return InputSec; } uint32_t Type; private: SymbolBody *Sym; const InputSectionBase *InputSec = nullptr; const OutputSectionBase *OutputSec = nullptr; uintX_t OffsetInSec; bool UseSymVA; uintX_t Addend; }; template class DynamicSection final : public SyntheticSection { typedef typename ELFT::Dyn Elf_Dyn; typedef typename ELFT::Rel Elf_Rel; typedef typename ELFT::Rela Elf_Rela; typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::uint uintX_t; // The .dynamic section contains information for the dynamic linker. // The section consists of fixed size entries, which consist of // type and value fields. Value are one of plain integers, symbol // addresses, or section addresses. This struct represents the entry. struct Entry { int32_t Tag; union { OutputSectionBase *OutSec; InputSection *InSec; uint64_t Val; const SymbolBody *Sym; }; enum KindT { SecAddr, SecSize, SymAddr, PlainInt, InSecAddr } Kind; Entry(int32_t Tag, OutputSectionBase *OutSec, KindT Kind = SecAddr) : Tag(Tag), OutSec(OutSec), Kind(Kind) {} Entry(int32_t Tag, InputSection *Sec) : Tag(Tag), InSec(Sec), Kind(InSecAddr) {} Entry(int32_t Tag, uint64_t Val) : Tag(Tag), Val(Val), Kind(PlainInt) {} Entry(int32_t Tag, const SymbolBody *Sym) : Tag(Tag), Sym(Sym), Kind(SymAddr) {} }; // finalize() fills this vector with the section contents. finalize() // cannot directly create final section contents because when the // function is called, symbol or section addresses are not fixed yet. std::vector Entries; public: DynamicSection(); void finalize() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } private: void addEntries(); void add(Entry E) { Entries.push_back(E); } uintX_t Size = 0; }; template class RelocationSection final : public SyntheticSection { typedef typename ELFT::Rel Elf_Rel; typedef typename ELFT::Rela Elf_Rela; typedef typename ELFT::uint uintX_t; public: RelocationSection(StringRef Name, bool Sort); void addReloc(const DynamicReloc &Reloc); unsigned getRelocOffset(); void finalize() override; void writeTo(uint8_t *Buf) override; bool empty() const override { return Relocs.empty(); } size_t getSize() const override { return Relocs.size() * this->Entsize; } size_t getRelativeRelocCount() const { return NumRelativeRelocs; } private: bool Sort; size_t NumRelativeRelocs = 0; std::vector> Relocs; }; struct SymbolTableEntry { SymbolBody *Symbol; size_t StrTabOffset; }; template class SymbolTableSection final : public SyntheticSection { public: typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::SymRange Elf_Sym_Range; typedef typename ELFT::uint uintX_t; SymbolTableSection(StringTableSection &StrTabSec); void finalize() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override { return getNumSymbols() * sizeof(Elf_Sym); } - void addSymbol(SymbolBody *Body); + void addGlobal(SymbolBody *Body); + void addLocal(SymbolBody *Body); StringTableSection &getStrTabSec() const { return StrTabSec; } - unsigned getNumSymbols() const { return NumLocals + Symbols.size() + 1; } + unsigned getNumSymbols() const { return Symbols.size() + 1; } + size_t getSymbolIndex(SymbolBody *Body); ArrayRef getSymbols() const { return Symbols; } static const OutputSectionBase *getOutputSection(SymbolBody *Sym); - unsigned NumLocals = 0; - StringTableSection &StrTabSec; - private: void writeLocalSymbols(uint8_t *&Buf); void writeGlobalSymbols(uint8_t *Buf); // A vector of symbols and their string table offsets. std::vector Symbols; + + StringTableSection &StrTabSec; + + unsigned NumLocals = 0; }; // Outputs GNU Hash section. For detailed explanation see: // https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections template class GnuHashTableSection final : public SyntheticSection { typedef typename ELFT::Off Elf_Off; typedef typename ELFT::Word Elf_Word; typedef typename ELFT::uint uintX_t; public: GnuHashTableSection(); void finalize() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override { return this->Size; } // Adds symbols to the hash table. // Sorts the input to satisfy GNU hash section requirements. void addSymbols(std::vector &Symbols); private: static unsigned calcNBuckets(unsigned NumHashed); static unsigned calcMaskWords(unsigned NumHashed); void writeHeader(uint8_t *&Buf); void writeBloomFilter(uint8_t *&Buf); void writeHashTable(uint8_t *Buf); struct SymbolData { SymbolBody *Body; size_t STName; uint32_t Hash; }; std::vector Symbols; unsigned MaskWords; unsigned NBuckets; unsigned Shift2; uintX_t Size = 0; }; template class HashTableSection final : public SyntheticSection { typedef typename ELFT::Word Elf_Word; public: HashTableSection(); void finalize() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override { return this->Size; } private: size_t Size = 0; }; template class PltSection final : public SyntheticSection { public: PltSection(); void writeTo(uint8_t *Buf) override; size_t getSize() const override; void addEntry(SymbolBody &Sym); bool empty() const override { return Entries.empty(); } private: std::vector> Entries; }; // The IpltSection is a variant of Plt for recording entries for GNU Ifunc // symbols that will be subject to a Target->IRelativeRel // The IpltSection immediately follows the Plt section in the Output Section template class IpltSection final : public SyntheticSection { public: IpltSection(); void writeTo(uint8_t *Buf) override; size_t getSize() const override; void addEntry(SymbolBody &Sym); bool empty() const override { return Entries.empty(); } private: std::vector> Entries; }; template class GdbIndexSection final : public SyntheticSection { typedef typename ELFT::uint uintX_t; const unsigned OffsetTypeSize = 4; const unsigned CuListOffset = 6 * OffsetTypeSize; const unsigned CompilationUnitSize = 16; const unsigned AddressEntrySize = 16 + OffsetTypeSize; const unsigned SymTabEntrySize = 2 * OffsetTypeSize; public: GdbIndexSection(); void finalize() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override; bool empty() const override; // Pairs of [CU Offset, CU length]. std::vector> CompilationUnits; llvm::StringTableBuilder StringPool; GdbHashTab SymbolTable; // The CU vector portion of the constant pool. std::vector>> CuVectors; std::vector> AddressArea; private: void parseDebugSections(); void readDwarf(InputSection *I); uint32_t CuTypesOffset; uint32_t SymTabOffset; uint32_t ConstantPoolOffset; uint32_t StringPoolOffset; size_t CuVectorsSize = 0; std::vector CuVectorsOffset; bool Finalized = false; }; // --eh-frame-hdr option tells linker to construct a header for all the // .eh_frame sections. This header is placed to a section named .eh_frame_hdr // and also to a PT_GNU_EH_FRAME segment. // At runtime the unwinder then can find all the PT_GNU_EH_FRAME segments by // calling dl_iterate_phdr. // This section contains a lookup table for quick binary search of FDEs. // Detailed info about internals can be found in Ian Lance Taylor's blog: // http://www.airs.com/blog/archives/460 (".eh_frame") // http://www.airs.com/blog/archives/462 (".eh_frame_hdr") template class EhFrameHeader final : public SyntheticSection { typedef typename ELFT::uint uintX_t; public: EhFrameHeader(); void writeTo(uint8_t *Buf) override; size_t getSize() const override; void addFde(uint32_t Pc, uint32_t FdeVA); bool empty() const override; private: struct FdeData { uint32_t Pc; uint32_t FdeVA; }; std::vector Fdes; }; // For more information about .gnu.version and .gnu.version_r see: // https://www.akkadia.org/drepper/symbol-versioning // The .gnu.version_d section which has a section type of SHT_GNU_verdef shall // contain symbol version definitions. The number of entries in this section // shall be contained in the DT_VERDEFNUM entry of the .dynamic section. // The section shall contain an array of Elf_Verdef structures, optionally // followed by an array of Elf_Verdaux structures. template class VersionDefinitionSection final : public SyntheticSection { typedef typename ELFT::Verdef Elf_Verdef; typedef typename ELFT::Verdaux Elf_Verdaux; public: VersionDefinitionSection(); void finalize() override; size_t getSize() const override; void writeTo(uint8_t *Buf) override; private: void writeOne(uint8_t *Buf, uint32_t Index, StringRef Name, size_t NameOff); unsigned FileDefNameOff; }; // The .gnu.version section specifies the required version of each symbol in the // dynamic symbol table. It contains one Elf_Versym for each dynamic symbol // table entry. An Elf_Versym is just a 16-bit integer that refers to a version // identifier defined in the either .gnu.version_r or .gnu.version_d section. // The values 0 and 1 are reserved. All other values are used for versions in // the own object or in any of the dependencies. template class VersionTableSection final : public SyntheticSection { typedef typename ELFT::Versym Elf_Versym; public: VersionTableSection(); void finalize() override; size_t getSize() const override; void writeTo(uint8_t *Buf) override; bool empty() const override; }; // The .gnu.version_r section defines the version identifiers used by // .gnu.version. It contains a linked list of Elf_Verneed data structures. Each // Elf_Verneed specifies the version requirements for a single DSO, and contains // a reference to a linked list of Elf_Vernaux data structures which define the // mapping from version identifiers to version names. template class VersionNeedSection final : public SyntheticSection { typedef typename ELFT::Verneed Elf_Verneed; typedef typename ELFT::Vernaux Elf_Vernaux; // A vector of shared files that need Elf_Verneed data structures and the // string table offsets of their sonames. std::vector *, size_t>> Needed; // The next available version identifier. unsigned NextIndex; public: VersionNeedSection(); void addSymbol(SharedSymbol *SS); void finalize() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override; size_t getNeedNum() const { return Needed.size(); } bool empty() const override; }; // .MIPS.abiflags section. template class MipsAbiFlagsSection final : public SyntheticSection { typedef llvm::object::Elf_Mips_ABIFlags Elf_Mips_ABIFlags; public: static MipsAbiFlagsSection *create(); MipsAbiFlagsSection(Elf_Mips_ABIFlags Flags); size_t getSize() const override { return sizeof(Elf_Mips_ABIFlags); } void writeTo(uint8_t *Buf) override; private: Elf_Mips_ABIFlags Flags; }; // .MIPS.options section. template class MipsOptionsSection final : public SyntheticSection { typedef llvm::object::Elf_Mips_Options Elf_Mips_Options; typedef llvm::object::Elf_Mips_RegInfo Elf_Mips_RegInfo; public: static MipsOptionsSection *create(); MipsOptionsSection(Elf_Mips_RegInfo Reginfo); void writeTo(uint8_t *Buf) override; size_t getSize() const override { return sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo); } private: Elf_Mips_RegInfo Reginfo; }; // MIPS .reginfo section. template class MipsReginfoSection final : public SyntheticSection { typedef llvm::object::Elf_Mips_RegInfo Elf_Mips_RegInfo; public: static MipsReginfoSection *create(); MipsReginfoSection(Elf_Mips_RegInfo Reginfo); size_t getSize() const override { return sizeof(Elf_Mips_RegInfo); } void writeTo(uint8_t *Buf) override; private: Elf_Mips_RegInfo Reginfo; }; // This is a MIPS specific section to hold a space within the data segment // of executable file which is pointed to by the DT_MIPS_RLD_MAP entry. // See "Dynamic section" in Chapter 5 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf template class MipsRldMapSection : public SyntheticSection { public: MipsRldMapSection(); size_t getSize() const override { return sizeof(typename ELFT::uint); } void writeTo(uint8_t *Buf) override; }; template class ARMExidxSentinelSection : public SyntheticSection { public: ARMExidxSentinelSection(); size_t getSize() const override { return 8; } void writeTo(uint8_t *Buf) override; }; template InputSection *createCommonSection(); template InputSection *createInterpSection(); template MergeInputSection *createCommentSection(); // Linker generated sections which can be used as inputs. template struct In { static InputSection *ARMAttributes; static BuildIdSection *BuildId; static InputSection *Common; static DynamicSection *Dynamic; static StringTableSection *DynStrTab; static SymbolTableSection *DynSymTab; static EhFrameHeader *EhFrameHdr; static GnuHashTableSection *GnuHashTab; static GdbIndexSection *GdbIndex; static GotSection *Got; static MipsGotSection *MipsGot; static GotPltSection *GotPlt; static IgotPltSection *IgotPlt; static HashTableSection *HashTab; static InputSection *Interp; static MipsRldMapSection *MipsRldMap; static PltSection *Plt; static IpltSection *Iplt; static RelocationSection *RelaDyn; static RelocationSection *RelaPlt; static RelocationSection *RelaIplt; static StringTableSection *ShStrTab; static StringTableSection *StrTab; static SymbolTableSection *SymTab; static VersionDefinitionSection *VerDef; static VersionTableSection *VerSym; static VersionNeedSection *VerNeed; }; template InputSection *In::ARMAttributes; template BuildIdSection *In::BuildId; template InputSection *In::Common; template DynamicSection *In::Dynamic; template StringTableSection *In::DynStrTab; template SymbolTableSection *In::DynSymTab; template EhFrameHeader *In::EhFrameHdr; template GdbIndexSection *In::GdbIndex; template GnuHashTableSection *In::GnuHashTab; template GotSection *In::Got; template MipsGotSection *In::MipsGot; template GotPltSection *In::GotPlt; template IgotPltSection *In::IgotPlt; template HashTableSection *In::HashTab; template InputSection *In::Interp; template MipsRldMapSection *In::MipsRldMap; template PltSection *In::Plt; template IpltSection *In::Iplt; template RelocationSection *In::RelaDyn; template RelocationSection *In::RelaPlt; template RelocationSection *In::RelaIplt; template StringTableSection *In::ShStrTab; template StringTableSection *In::StrTab; template SymbolTableSection *In::SymTab; template VersionDefinitionSection *In::VerDef; template VersionTableSection *In::VerSym; template VersionNeedSection *In::VerNeed; } // namespace elf } // namespace lld #endif Index: vendor/lld/dist/ELF/Writer.cpp =================================================================== --- vendor/lld/dist/ELF/Writer.cpp (revision 313062) +++ vendor/lld/dist/ELF/Writer.cpp (revision 313063) @@ -1,1742 +1,1738 @@ //===- 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 "LinkerScript.h" #include "Memory.h" #include "OutputSections.h" #include "Relocations.h" #include "Strings.h" #include "SymbolTable.h" #include "SyntheticSections.h" #include "Target.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" #include #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::uint uintX_t; typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Ehdr Elf_Ehdr; typedef typename ELFT::Phdr Elf_Phdr; typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::SymRange Elf_Sym_Range; typedef typename ELFT::Rela Elf_Rela; void run(); private: void createSyntheticSections(); void copyLocalSymbols(); void addReservedSymbols(); void addInputSec(InputSectionBase *S); void createSections(); void forEachRelSec(std::function &)> Fn); void sortSections(); void finalizeSections(); void addPredefinedSections(); std::vector createPhdrs(); void removeEmptyPTLoad(); void addPtArmExid(std::vector &Phdrs); void assignAddresses(); void assignFileOffsets(); void assignFileOffsetsBinary(); void setPhdrs(); void fixHeaders(); void fixSectionAlignments(); void fixAbsoluteSymbols(); void openFile(); void writeHeader(); void writeSections(); void writeSectionsBinary(); void writeBuildId(); std::unique_ptr Buffer; std::vector OutputSections; OutputSectionFactory Factory; void addRelIpltSymbols(); void addStartEndSymbols(); void addStartStopSymbols(OutputSectionBase *Sec); uintX_t getEntryAddr(); OutputSectionBase *findSection(StringRef Name); std::vector Phdrs; uintX_t FileSize; uintX_t SectionHeaderOff; bool AllocateHeader = true; }; } // anonymous namespace StringRef elf::getOutputSectionName(StringRef Name) { if (Config->Relocatable) return Name; for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".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(Twine(".") + Name.substr(2)); return Name; } template void elf::reportDiscarded(InputSectionBase *IS) { if (!Config->PrintGcSections) return; errs() << "removing unused section from '" << IS->Name << "' in file '" << IS->getFile()->getName() << "'\n"; } template static bool needsInterpSection() { return !Symtab::X->getSharedFiles().empty() && !Config->DynamicLinker.empty() && !Script::X->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; uintX_t Size = P.Last->Addr + P.Last->Size - P.First->Addr; return Size == 0; }); Phdrs.erase(I, Phdrs.end()); } // 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(); // We need to create some reserved symbols such as _end. Create them. if (!Config->Relocatable) addReservedSymbols(); // 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) forEachRelSec(createThunks); // Create output sections. Script::X->OutputSections = &OutputSections; if (ScriptConfig->HasSections) { // If linker script contains SECTIONS commands, let it create sections. Script::X->processCommands(Factory); // Linker scripts may have left some input sections unassigned. // Assign such sections using the default rule. Script::X->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::X->processCommands(Factory); } if (Config->Discard != DiscardPolicy::All) copyLocalSymbols(); // 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 (Config->Relocatable) { assignFileOffsets(); } else { if (ScriptConfig->HasSections) { Script::X->assignAddresses(Phdrs); } else { fixSectionAlignments(); assignAddresses(); } // 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(); fixAbsoluteSymbols(); } // 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; if (auto EC = Buffer->commit()) error(EC, "failed to write to the output file"); // 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)); // Create singleton output sections. Out::Bss = make>(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); Out::BssRelRo = make>(".bss.rel.ro", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); In::DynStrTab = make>(".dynstr", true); In::Dynamic = make>(); Out::EhFrame = make>(); In::RelaDyn = make>( Config->Rela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc); In::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(sizeof(uintX_t)); if (needsInterpSection()) { In::Interp = createInterpSection(); Symtab::X->Sections.push_back(In::Interp); } else { In::Interp = nullptr; } if (!Config->Relocatable) Symtab::X->Sections.push_back(createCommentSection()); if (Config->Strip != StripPolicy::All) { In::StrTab = make>(".strtab", false); In::SymTab = make>(*In::StrTab); } if (Config->BuildId != BuildIdKind::None) { In::BuildId = make>(); Symtab::X->Sections.push_back(In::BuildId); } InputSection *Common = createCommonSection(); if (!Common->Data.empty()) { In::Common = Common; Symtab::X->Sections.push_back(Common); } // Add MIPS-specific sections. bool HasDynSymTab = !Symtab::X->getSharedFiles().empty() || Config->Pic; if (Config->EMachine == EM_MIPS) { if (!Config->Shared && HasDynSymTab) { In::MipsRldMap = make>(); Symtab::X->Sections.push_back(In::MipsRldMap); } if (auto *Sec = MipsAbiFlagsSection::create()) Symtab::X->Sections.push_back(Sec); if (auto *Sec = MipsOptionsSection::create()) Symtab::X->Sections.push_back(Sec); if (auto *Sec = MipsReginfoSection::create()) Symtab::X->Sections.push_back(Sec); } if (HasDynSymTab) { In::DynSymTab = make>(*In::DynStrTab); Symtab::X->Sections.push_back(In::DynSymTab); In::VerSym = make>(); Symtab::X->Sections.push_back(In::VerSym); if (!Config->VersionDefinitions.empty()) { In::VerDef = make>(); Symtab::X->Sections.push_back(In::VerDef); } In::VerNeed = make>(); Symtab::X->Sections.push_back(In::VerNeed); if (Config->GnuHash) { In::GnuHashTab = make>(); Symtab::X->Sections.push_back(In::GnuHashTab); } if (Config->SysvHash) { In::HashTab = make>(); Symtab::X->Sections.push_back(In::HashTab); } Symtab::X->Sections.push_back(In::Dynamic); Symtab::X->Sections.push_back(In::DynStrTab); Symtab::X->Sections.push_back(In::RelaDyn); } // Add .got. MIPS' .got is so different from the other archs, // it has its own class. if (Config->EMachine == EM_MIPS) { In::MipsGot = make>(); Symtab::X->Sections.push_back(In::MipsGot); } else { In::Got = make>(); Symtab::X->Sections.push_back(In::Got); } In::GotPlt = make>(); Symtab::X->Sections.push_back(In::GotPlt); In::IgotPlt = make>(); Symtab::X->Sections.push_back(In::IgotPlt); if (Config->GdbIndex) { In::GdbIndex = make>(); Symtab::X->Sections.push_back(In::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->Rela ? ".rela.plt" : ".rel.plt", false /*Sort*/); Symtab::X->Sections.push_back(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*/); Symtab::X->Sections.push_back(In::RelaIplt); In::Plt = make>(); Symtab::X->Sections.push_back(In::Plt); In::Iplt = make>(); Symtab::X->Sections.push_back(In::Iplt); if (Config->EhFrameHdr) { In::EhFrameHdr = make>(); Symtab::X->Sections.push_back(In::EhFrameHdr); } } template static bool shouldKeepInSymtab(InputSectionBase *Sec, StringRef SymName, const SymbolBody &B) { if (B.isFile()) return false; // We keep sections in symtab for relocatable output. if (B.isSection()) return Config->Relocatable; // 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); } template static bool includeInSymtab(const SymbolBody &B) { if (!B.isLocal() && !B.symbol()->IsUsedInRegularObj) return false; // If --retain-symbols-file is given, we'll keep only symbols listed in that // file. if (Config->Discard == DiscardPolicy::RetainFile && !Config->RetainSymbolsFile.count(B.getName())) return false; if (auto *D = dyn_cast>(&B)) { // Always include absolute symbols. if (!D->Section) return true; // Exclude symbols pointing to garbage-collected sections. if (!D->Section->Live) return false; if (auto *S = dyn_cast>(D->Section)) 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 (!In::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; InputSectionBase *Sec = DR->Section; if (!shouldKeepInSymtab(Sec, B->getName(), *B)) continue; - ++In::SymTab->NumLocals; - if (Config->Relocatable) - B->DynsymIndex = In::SymTab->NumLocals; - F->KeptLocalSyms.push_back(std::make_pair( - DR, In::SymTab->StrTabSec.addString(B->getName()))); + In::SymTab->addLocal(B); } } } // 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). static int getPPC64SectionRank(StringRef SectionName) { return StringSwitch(SectionName) .Case(".tocbss", 0) .Case(".branch_lt", 2) .Case(".toc", 3) .Case(".toc1", 4) .Case(".opd", 5) .Default(1); } template bool elf::isRelroSection(const OutputSectionBase *Sec) { if (!Config->ZRelro) return false; uint64_t Flags = Sec->Flags; if (!(Flags & SHF_ALLOC) || !(Flags & SHF_WRITE)) return false; if (Flags & SHF_TLS) return true; uint32_t Type = Sec->Type; if (Type == SHT_INIT_ARRAY || Type == SHT_FINI_ARRAY || Type == SHT_PREINIT_ARRAY) return true; if (Sec == In::GotPlt->OutSec) return Config->ZNow; if (Sec == In::Dynamic->OutSec) return true; if (In::Got && Sec == In::Got->OutSec) return true; if (In::MipsGot && Sec == In::MipsGot->OutSec) return true; if (Sec == Out::BssRelRo) return true; StringRef S = Sec->getName(); return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" || S == ".eh_frame" || S == ".openbsd.randomdata"; } template static bool compareSectionsNonScript(const OutputSectionBase *A, const OutputSectionBase *B) { // Put .interp first because some loaders want to see that section // on the first page of the executable file when loaded into memory. bool AIsInterp = A->getName() == ".interp"; bool BIsInterp = B->getName() == ".interp"; if (AIsInterp != BIsInterp) return AIsInterp; // Allocatable sections go first to reduce the total PT_LOAD size and // so debug info doesn't change addresses in actual code. bool AIsAlloc = A->Flags & SHF_ALLOC; bool BIsAlloc = B->Flags & SHF_ALLOC; if (AIsAlloc != BIsAlloc) return AIsAlloc; // We don't have any special requirements for the relative order of two non // allocatable sections. if (!AIsAlloc) return false; // We want to put section specified by -T option first, so we // can start assigning VA starting from them later. auto AAddrSetI = Config->SectionStartMap.find(A->getName()); auto BAddrSetI = Config->SectionStartMap.find(B->getName()); bool AHasAddrSet = AAddrSetI != Config->SectionStartMap.end(); bool BHasAddrSet = BAddrSetI != Config->SectionStartMap.end(); if (AHasAddrSet != BHasAddrSet) return AHasAddrSet; if (AHasAddrSet) return AAddrSetI->second < BAddrSetI->second; // We want the read only sections first so that they go in the PT_LOAD // covering the program headers at the start of the file. bool AIsWritable = A->Flags & SHF_WRITE; bool BIsWritable = B->Flags & SHF_WRITE; if (AIsWritable != BIsWritable) return BIsWritable; if (!Config->SingleRoRx) { // For a corresponding reason, put non exec sections first (the program // header PT_LOAD is not executable). // We only do that if we are not using linker scripts, since with linker // scripts ro and rx sections are in the same PT_LOAD, so their relative // order is not important. The same applies for -no-rosegment. bool AIsExec = A->Flags & SHF_EXECINSTR; bool BIsExec = B->Flags & SHF_EXECINSTR; if (AIsExec != BIsExec) return BIsExec; } // If we got here we know that both A and B are in the same PT_LOAD. bool AIsTls = A->Flags & SHF_TLS; bool BIsTls = B->Flags & SHF_TLS; bool AIsNoBits = A->Type == SHT_NOBITS; bool BIsNoBits = B->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 AIsNonTlsNoBits = AIsNoBits && !AIsTls; bool BIsNonTlsNoBits = BIsNoBits && !BIsTls; if (AIsNonTlsNoBits != BIsNonTlsNoBits) return BIsNonTlsNoBits; // 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 AIsRelRo = isRelroSection(A); bool BIsRelRo = isRelroSection(B); if (AIsRelRo != BIsRelRo) return AIsNonTlsNoBits ? AIsRelRo : BIsRelRo; // 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 (AIsTls != BIsTls) return AIsTls; // Within the TLS initialization block, the non-nobits sections need to appear // first. if (AIsNoBits != BIsNoBits) return BIsNoBits; // Some architectures have additional ordering restrictions for sections // within the same PT_LOAD. if (Config->EMachine == EM_PPC64) return getPPC64SectionRank(A->getName()) < getPPC64SectionRank(B->getName()); return false; } // Output section ordering is determined by this function. template static bool compareSections(const OutputSectionBase *A, const OutputSectionBase *B) { // For now, put sections mentioned in a linker script first. int AIndex = Script::X->getSectionIndex(A->getName()); int BIndex = Script::X->getSectionIndex(B->getName()); bool AInScript = AIndex != INT_MAX; bool BInScript = BIndex != INT_MAX; if (AInScript != BInScript) return AInScript; // If both are in the script, use that order. if (AInScript) return AIndex < BIndex; return compareSectionsNonScript(A, B); } // Program header entry PhdrEntry::PhdrEntry(unsigned Type, unsigned Flags) { p_type = Type; p_flags = Flags; } void PhdrEntry::add(OutputSectionBase *Sec) { Last = Sec; if (!First) First = Sec; p_align = std::max(p_align, Sec->Addralign); if (p_type == PT_LOAD) Sec->FirstInPtLoad = First; } template static void addOptionalSynthetic(StringRef Name, OutputSectionBase *Sec, typename ELFT::uint Val, uint8_t StOther = STV_HIDDEN) { if (SymbolBody *S = Symtab::X->find(Name)) if (!S->isInCurrentDSO()) Symtab::X->addSynthetic(Name, Sec, Val, StOther); } template static Symbol *addRegular(StringRef Name, InputSectionBase *Sec, typename ELFT::uint Value) { // The linker generated symbols are added as STB_WEAK to allow user defined // ones to override them. return Symtab::X->addRegular(Name, STV_HIDDEN, STT_NOTYPE, Value, /*Size=*/0, STB_WEAK, Sec, /*File=*/nullptr); } template static Symbol *addOptionalRegular(StringRef Name, InputSectionBase *IS, typename ELFT::uint Value) { SymbolBody *S = Symtab::X->find(Name); if (!S) return nullptr; if (S->isInCurrentDSO()) return S->symbol(); return addRegular(Name, IS, Value); } // 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 (In::DynSymTab) return; StringRef S = Config->Rela ? "__rela_iplt_start" : "__rel_iplt_start"; addOptionalRegular(S, In::RelaIplt, 0); S = Config->Rela ? "__rela_iplt_end" : "__rel_iplt_end"; addOptionalRegular(S, In::RelaIplt, -1); } // 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. To simplify relocation // calculation we assign _gp value to it and calculate corresponding // relocations as relative to this value. 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. As usual special cases are ARM and // MIPS - the libc for these targets defines __tls_get_addr itself because // there are no TLS optimizations for these targets. if (!In::DynSymTab && (Config->EMachine != EM_MIPS && Config->EMachine != EM_ARM)) Symtab::X->addIgnored("__tls_get_addr"); // If linker script do layout we do not need to create any standart symbols. if (ScriptConfig->HasSections) return; ElfSym::EhdrStart = Symtab::X->addIgnored("__ehdr_start"); auto Define = [this](StringRef S, DefinedRegular *&Sym1, DefinedRegular *&Sym2) { Sym1 = Symtab::X->addIgnored(S, STV_DEFAULT); // The name without the underscore is not a reserved name, // so it is defined only when there is a reference against it. assert(S.startswith("_")); S = S.substr(1); if (SymbolBody *B = Symtab::X->find(S)) if (B->isUndefined()) Sym2 = Symtab::X->addAbsolute(S, STV_DEFAULT); }; Define("_end", ElfSym::End, ElfSym::End2); Define("_etext", ElfSym::Etext, ElfSym::Etext2); Define("_edata", ElfSym::Edata, ElfSym::Edata2); } // Sort input sections by section name suffixes for // __attribute__((init_priority(N))). template static void sortInitFini(OutputSectionBase *S) { if (S) reinterpret_cast *>(S)->sortInitFini(); } // Sort input sections by the special rule for .ctors and .dtors. template static void sortCtorsDtors(OutputSectionBase *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 *, int> 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 (OutputSectionBase *Base : OutputSections) if (auto *Sec = dyn_cast>(Base)) Sec->sort([&](InputSection *S) { return SectionOrder.lookup(S); }); } template void Writer::forEachRelSec( std::function &)> Fn) { for (InputSectionBase *IS : Symtab::X->Sections) { 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); } } template void Writer::addInputSec(InputSectionBase *IS) { if (!IS) return; if (!IS->Live) { reportDiscarded(IS); return; } OutputSectionBase *Sec; bool IsNew; StringRef OutsecName = getOutputSectionName(IS->Name); std::tie(Sec, IsNew) = Factory.create(IS, OutsecName); if (IsNew) OutputSections.push_back(Sec); Sec->addSection(IS); } template void Writer::createSections() { for (InputSectionBase *IS : Symtab::X->Sections) addInputSec(IS); sortBySymbolsOrder(OutputSections); sortInitFini(findSection(".init_array")); sortInitFini(findSection(".fini_array")); sortCtorsDtors(findSection(".ctors")); sortCtorsDtors(findSection(".dtors")); for (OutputSectionBase *Sec : OutputSections) Sec->assignOffsets(); } template static bool canSharePtLoad(const OutputSectionBase &S1, const OutputSectionBase &S2) { if (!(S1.Flags & SHF_ALLOC) || !(S2.Flags & SHF_ALLOC)) return false; bool S1IsWrite = S1.Flags & SHF_WRITE; bool S2IsWrite = S2.Flags & SHF_WRITE; if (S1IsWrite != S2IsWrite) return false; if (!S1IsWrite) return true; // RO and RX share a PT_LOAD with linker scripts. return (S1.Flags & SHF_EXECINSTR) == (S2.Flags & SHF_EXECINSTR); } 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 (!ScriptConfig->HasSections) { std::stable_sort(OutputSections.begin(), OutputSections.end(), compareSectionsNonScript); return; } Script::X->adjustSectionsBeforeSorting(); // 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 and // non-script sections independently. // * 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, [](OutputSectionBase *S) { return Script::X->getSectionIndex(S->getName()) == INT_MAX; }); while (NonScriptI != E) { auto BestPos = std::max_element( I, NonScriptI, [&](OutputSectionBase *&A, OutputSectionBase *&B) { bool ACanSharePtLoad = canSharePtLoad(**NonScriptI, *A); bool BCanSharePtLoad = canSharePtLoad(**NonScriptI, *B); if (ACanSharePtLoad != BCanSharePtLoad) return BCanSharePtLoad; bool ACmp = compareSectionsNonScript(*NonScriptI, A); bool BCmp = compareSectionsNonScript(*NonScriptI, B); if (ACmp != BCmp) return BCmp; // FIXME: missing test size_t PosA = &A - &OutputSections[0]; size_t PosB = &B - &OutputSections[0]; return ACmp ? PosA > PosB : PosA < PosB; }); // max_element only returns NonScriptI if the range is empty. If the range // is not empty we should consider moving the the element forward one // position. if (BestPos != NonScriptI && !compareSectionsNonScript(*NonScriptI, *BestPos)) ++BestPos; std::rotate(BestPos, NonScriptI, NonScriptI + 1); ++NonScriptI; } Script::X->adjustSectionsAfterSorting(); } template static void finalizeSynthetic(const std::vector *> &Sections) { for (SyntheticSection *SS : Sections) if (SS && SS->OutSec && !SS->empty()) { SS->finalize(); SS->OutSec->Size = 0; SS->OutSec->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 output. template static void removeUnusedSyntheticSections(std::vector &V) { // Input synthetic sections are placed after all regular ones. We iterate over // them all and exit at first non-synthetic. for (InputSectionBase *S : llvm::reverse(Symtab::X->Sections)) { SyntheticSection *SS = dyn_cast>(S); if (!SS) return; if (!SS->empty() || !SS->OutSec) continue; OutputSection *OutSec = cast>(SS->OutSec); OutSec->Sections.erase( std::find(OutSec->Sections.begin(), OutSec->Sections.end(), SS)); // If there is no other sections in output section, remove it from output. if (OutSec->Sections.empty()) V.erase(std::find(V.begin(), V.end(), OutSec)); } } // 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 (OutputSectionBase *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 (In::DynSymTab) addRegular("_DYNAMIC", In::Dynamic, 0); // Define __rel[a]_iplt_{start,end} symbols if needed. addRelIpltSymbols(); if (!Out::EhFrame->empty()) { OutputSections.push_back(Out::EhFrame); Out::EhFrame->finalize(); } // 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); // Now that we have defined all possible 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 (In::SymTab) - In::SymTab->addSymbol(Body); + In::SymTab->addGlobal(Body); if (In::DynSymTab && S->includeInDynsym()) { - In::DynSymTab->addSymbol(Body); + In::DynSymTab->addGlobal(Body); if (auto *SS = dyn_cast>(Body)) if (SS->file()->isNeeded()) In::VerNeed->addSymbol(SS); } } // Do not proceed if there was an undefined symbol. if (ErrorCount) return; // So far we have added sections from input object files. // This function adds linker-created Out::* sections. addPredefinedSections(); removeUnusedSyntheticSections(OutputSections); sortSections(); unsigned I = 1; for (OutputSectionBase *Sec : OutputSections) { Sec->SectionIndex = I++; Sec->ShName = In::ShStrTab->addString(Sec->getName()); } // 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::X->hasPhdrsCommands() ? Script::X->createPhdrs() : createPhdrs(); addPtArmExid(Phdrs); fixHeaders(); } // 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 (OutputSectionBase *Sec : OutputSections) Sec->finalize(); // Dynamic section must be the last one in this list and dynamic // symbol table section (DynSymTab) must be the first one. finalizeSynthetic( {In::DynSymTab, In::GnuHashTab, In::HashTab, In::SymTab, In::ShStrTab, In::StrTab, In::VerDef, In::DynStrTab, In::GdbIndex, In::Got, In::MipsGot, In::IgotPlt, In::GotPlt, In::RelaDyn, In::RelaIplt, In::RelaPlt, In::Plt, In::Iplt, In::Plt, In::EhFrameHdr, In::VerSym, In::VerNeed, In::Dynamic}); } template void Writer::addPredefinedSections() { if (Out::Bss->Size > 0) OutputSections.push_back(Out::Bss); if (Out::BssRelRo->Size > 0) OutputSections.push_back(Out::BssRelRo); auto OS = dyn_cast_or_null>(findSection(".ARM.exidx")); if (OS && !OS->Sections.empty() && !Config->Relocatable) OS->addSection(make>()); addInputSec(In::SymTab); addInputSec(In::ShStrTab); addInputSec(In::StrTab); } // 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, OutputSectionBase *OS) { // These symbols resolve to the image base if the section does not exist. // A special value -1 indicates end of the section. addOptionalSynthetic(Start, OS, 0); addOptionalSynthetic(End, OS, OS ? -1 : 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 (OutputSectionBase *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(OutputSectionBase *Sec) { StringRef S = Sec->getName(); if (!isValidCIdentifier(S)) return; addOptionalSynthetic(Saver.save("__start_" + S), Sec, 0, STV_DEFAULT); addOptionalSynthetic(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT); } template OutputSectionBase *Writer::findSection(StringRef Name) { for (OutputSectionBase *Sec : OutputSections) if (Sec->getName() == Name) return Sec; return nullptr; } template static bool needsPtLoad(OutputSectionBase *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. template static typename ELFT::uint computeFlags(typename ELFT::uint F) { if (Config->OMagic) return PF_R | PF_W | PF_X; if (Config->SingleRoRx && !(F & PF_W)) return F | PF_X; return F; } // 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. PhdrEntry &Hdr = *AddHdr(PT_PHDR, PF_R); Hdr.add(Out::ProgramHeaders); // PT_INTERP must be the second entry if exists. if (OutputSectionBase *Sec = findSection(".interp")) { PhdrEntry &Hdr = *AddHdr(PT_INTERP, Sec->getPhdrFlags()); Hdr.add(Sec); } // Add the first PT_LOAD segment for regular output sections. uintX_t Flags = computeFlags(PF_R); PhdrEntry *Load = AddHdr(PT_LOAD, Flags); PhdrEntry TlsHdr(PT_TLS, PF_R); PhdrEntry RelRo(PT_GNU_RELRO, PF_R); PhdrEntry Note(PT_NOTE, PF_R); for (OutputSectionBase *Sec : OutputSections) { if (!(Sec->Flags & SHF_ALLOC)) break; // If we meet TLS section then we create TLS header // and put all TLS sections inside for further use when // assign addresses. if (Sec->Flags & SHF_TLS) TlsHdr.add(Sec); 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. uintX_t NewFlags = computeFlags(Sec->getPhdrFlags()); if (Script::X->hasLMA(Sec->getName()) || Flags != NewFlags) { Load = AddHdr(PT_LOAD, NewFlags); Flags = NewFlags; } Load->add(Sec); if (isRelroSection(Sec)) RelRo.add(Sec); if (Sec->Type == SHT_NOTE) Note.add(Sec); } // Add the TLS segment unless it's empty. if (TlsHdr.First) Ret.push_back(std::move(TlsHdr)); // Add an entry for .dynamic. if (In::DynSymTab) { PhdrEntry &H = *AddHdr(PT_DYNAMIC, In::Dynamic->OutSec->getPhdrFlags()); H.add(In::Dynamic->OutSec); } // PT_GNU_RELRO includes all sections that should be marked as // read-only by dynamic linker after proccessing relocations. if (RelRo.First) Ret.push_back(std::move(RelRo)); // PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr. if (!Out::EhFrame->empty() && In::EhFrameHdr) { PhdrEntry &Hdr = *AddHdr(PT_GNU_EH_FRAME, In::EhFrameHdr->OutSec->getPhdrFlags()); Hdr.add(In::EhFrameHdr->OutSec); } // PT_OPENBSD_RANDOMIZE specifies the location and size of a part of the // memory image of the program that must be filled with random data before any // code in the object is executed. if (OutputSectionBase *Sec = findSection(".openbsd.randomdata")) { PhdrEntry &Hdr = *AddHdr(PT_OPENBSD_RANDOMIZE, Sec->getPhdrFlags()); Hdr.add(Sec); } // PT_GNU_STACK is a special section to tell the loader to make the // pages for the stack non-executable. if (!Config->ZExecstack) { PhdrEntry &Hdr = *AddHdr(PT_GNU_STACK, PF_R | PF_W); if (Config->ZStackSize != uint64_t(-1)) Hdr.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); if (Note.First) Ret.push_back(std::move(Note)); return Ret; } template void Writer::addPtArmExid(std::vector &Phdrs) { if (Config->EMachine != EM_ARM) return; auto I = std::find_if( OutputSections.begin(), OutputSections.end(), [](OutputSectionBase *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() { for (const PhdrEntry &P : Phdrs) if (P.p_type == PT_LOAD && P.First) P.First->PageAlign = true; for (const PhdrEntry &P : Phdrs) { if (P.p_type != PT_GNU_RELRO) continue; if (P.First) P.First->PageAlign = true; // 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); if (I == End || (I + 1) == End) continue; OutputSectionBase *Sec = *(I + 1); if (needsPtLoad(Sec)) Sec->PageAlign = true; } } template void elf::allocateHeaders(MutableArrayRef Phdrs, ArrayRef OutputSections) { auto FirstPTLoad = std::find_if(Phdrs.begin(), Phdrs.end(), [](const PhdrEntry &E) { return E.p_type == PT_LOAD; }); if (FirstPTLoad == Phdrs.end()) return; if (FirstPTLoad->First) for (OutputSectionBase *Sec : OutputSections) if (Sec->FirstInPtLoad == FirstPTLoad->First) Sec->FirstInPtLoad = Out::ElfHeader; FirstPTLoad->First = Out::ElfHeader; if (!FirstPTLoad->Last) FirstPTLoad->Last = Out::ProgramHeaders; } // We should set file offsets and VAs for elf header and program headers // sections. These are special, we do not include them into output sections // list, but have them to simplify the code. template void Writer::fixHeaders() { Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size(); // If the script has SECTIONS, assignAddresses will compute the values. if (ScriptConfig->HasSections) return; uintX_t HeaderSize = getHeaderSize(); // When -T
option is specified, lower the base to make room for those // sections. if (!Config->SectionStartMap.empty()) { uint64_t Min = -1; for (const auto &P : Config->SectionStartMap) Min = std::min(Min, P.second); if (HeaderSize < Min) Min -= HeaderSize; else AllocateHeader = false; if (Min < Config->ImageBase) Config->ImageBase = alignDown(Min, Config->MaxPageSize); } if (AllocateHeader) allocateHeaders(Phdrs, OutputSections); uintX_t BaseVA = Config->ImageBase; Out::ElfHeader->Addr = BaseVA; Out::ProgramHeaders->Addr = BaseVA + Out::ElfHeader->Size; } // Assign VAs (addresses at run-time) to output sections. template void Writer::assignAddresses() { uintX_t VA = Config->ImageBase; if (AllocateHeader) VA += getHeaderSize(); uintX_t ThreadBssOffset = 0; for (OutputSectionBase *Sec : OutputSections) { uintX_t Alignment = Sec->Addralign; if (Sec->PageAlign) Alignment = std::max(Alignment, Config->MaxPageSize); auto I = Config->SectionStartMap.find(Sec->getName()); if (I != Config->SectionStartMap.end()) VA = I->second; // We only assign VAs to allocated sections. if (needsPtLoad(Sec)) { VA = alignTo(VA, Alignment); Sec->Addr = VA; VA += Sec->Size; } else if (Sec->Flags & SHF_TLS && Sec->Type == SHT_NOBITS) { uintX_t TVA = VA + ThreadBssOffset; TVA = alignTo(TVA, Alignment); Sec->Addr = TVA; ThreadBssOffset = TVA - VA + Sec->Size; } } } // 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. template static uintX_t getFileAlignment(uintX_t Off, OutputSectionBase *Sec) { OutputSectionBase *First = Sec->FirstInPtLoad; // If the section is not in a PT_LOAD, we just have to align it. if (!First) return alignTo(Off, Sec->Addralign); // 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; } template void setOffset(OutputSectionBase *Sec, uintX_t &Off) { if (Sec->Type == SHT_NOBITS) { Sec->Offset = Off; return; } Off = getFileAlignment(Off, Sec); Sec->Offset = Off; Off += Sec->Size; } template void Writer::assignFileOffsetsBinary() { uintX_t Off = 0; for (OutputSectionBase *Sec : OutputSections) if (Sec->Flags & SHF_ALLOC) setOffset(Sec, Off); FileSize = alignTo(Off, sizeof(uintX_t)); } // Assign file offsets to output sections. template void Writer::assignFileOffsets() { uintX_t Off = 0; setOffset(Out::ElfHeader, Off); setOffset(Out::ProgramHeaders, Off); for (OutputSectionBase *Sec : OutputSections) setOffset(Sec, Off); SectionHeaderOff = alignTo(Off, sizeof(uintX_t)); FileSize = SectionHeaderOff + (OutputSections.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) { OutputSectionBase *First = P.First; OutputSectionBase *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, Config->MaxPageSize); + 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 typename ELFT::uint 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 (!Config->Entry.getAsInteger(0, Addr)) return Addr; // Case 4 if (OutputSectionBase *Sec = findSection(".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; } template static uint8_t getELFEncoding() { if (ELFT::TargetEndianness == llvm::support::little) return ELFDATA2LSB; return ELFDATA2MSB; } 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 absolute // symbol values that depend on section address and size. template void Writer::fixAbsoluteSymbols() { // __ehdr_start is the location of program headers. if (ElfSym::EhdrStart) ElfSym::EhdrStart->Value = Out::ProgramHeaders->Addr; auto Set = [](DefinedRegular *S1, DefinedRegular *S2, uintX_t V) { if (S1) S1->Value = V; if (S2) S2->Value = V; }; // _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. for (PhdrEntry &P : Phdrs) { if (P.p_type != PT_LOAD) continue; Set(ElfSym::End, ElfSym::End2, P.p_vaddr + P.p_memsz); uintX_t Val = P.p_vaddr + P.p_filesz; if (P.p_flags & PF_W) Set(ElfSym::Edata, ElfSym::Edata2, Val); else Set(ElfSym::Etext, ElfSym::Etext2, Val); } // Setup MIPS _gp_disp/__gnu_local_gp symbols which should // be equal to the _gp symbol's value. if (Config->EMachine == EM_MIPS) { if (!ElfSym::MipsGp->Value) { // Find GP-relative section with the lowest address // and use this address to calculate default _gp value. uintX_t Gp = -1; for (const OutputSectionBase * OS : OutputSections) if ((OS->Flags & SHF_MIPS_GPREL) && OS->Addr < Gp) Gp = OS->Addr; if (Gp != (uintX_t)-1) ElfSym::MipsGp->Value = Gp + 0x7ff0; } if (ElfSym::MipsGpDisp) ElfSym::MipsGpDisp->Value = ElfSym::MipsGp->Value; if (ElfSym::MipsLocalGp) ElfSym::MipsLocalGp->Value = ElfSym::MipsGp->Value; } } 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] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32; EHdr->e_ident[EI_DATA] = getELFEncoding(); 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 = OutputSections.size() + 1; EHdr->e_shstrndx = In::ShStrTab->OutSec->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 (OutputSectionBase *Sec : OutputSections) Sec->writeHeaderTo(++SHdrs); } // Removes a given file asynchronously. This is a performance hack, // so remove this when operating systems are improved. // // On Linux (and probably on other Unix-like systems), unlink(2) is a // noticeably slow system call. As of 2016, unlink takes 250 // milliseconds to remove a 1 GB file on ext4 filesystem on my machine. // // To create a new result file, we first remove existing file. So, if // you repeatedly link a 1 GB program in a regular compile-link-debug // cycle, every cycle wastes 250 milliseconds only to remove a file. // Since LLD can link a 1 GB binary in about 5 seconds, that waste // actually counts. // // This function spawns a background thread to call unlink. // The calling thread returns almost immediately. static void unlinkAsync(StringRef Path) { if (!Config->Threads || !sys::fs::exists(Config->OutputFile)) return; // First, rename Path to avoid race condition. We cannot remove // Path from a different thread because we are now going to create // Path as a new file. If we do that in a different thread, the new // thread can remove the new file. SmallString<128> TempPath; if (sys::fs::createUniqueFile(Path + "tmp%%%%%%%%", TempPath)) return; if (sys::fs::rename(Path, TempPath)) { sys::fs::remove(TempPath); return; } // Remove TempPath in background. std::thread([=] { ::remove(TempPath.str().str().c_str()); }).detach(); } // Open a result file. template void Writer::openFile() { unlinkAsync(Config->OutputFile); ErrorOr> BufferOrErr = FileOutputBuffer::create(Config->OutputFile, FileSize, FileOutputBuffer::F_executable); if (auto EC = BufferOrErr.getError()) error(EC, "failed to open " + Config->OutputFile); else Buffer = std::move(*BufferOrErr); } template void Writer::writeSectionsBinary() { uint8_t *Buf = Buffer->getBufferStart(); for (OutputSectionBase *Sec : OutputSections) if (Sec->Flags & SHF_ALLOC) Sec->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. Out::Opd = findSection(".opd"); if (Out::Opd) { Out::OpdBuf = Buf + Out::Opd->Offset; Out::Opd->writeTo(Buf + Out::Opd->Offset); } OutputSectionBase *EhFrameHdr = In::EhFrameHdr ? In::EhFrameHdr->OutSec : nullptr; for (OutputSectionBase *Sec : OutputSections) if (Sec != Out::Opd && Sec != EhFrameHdr) Sec->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 (!Out::EhFrame->empty() && EhFrameHdr) EhFrameHdr->writeTo(Buf + EhFrameHdr->Offset); } template void Writer::writeBuildId() { if (!In::BuildId || !In::BuildId->OutSec) return; // Compute a hash of all sections of the output file. uint8_t *Start = Buffer->getBufferStart(); uint8_t *End = Start + FileSize; In::BuildId->writeBuildId({Start, End}); } template void elf::writeResult(); template void elf::writeResult(); template void elf::writeResult(); template void elf::writeResult(); template void elf::allocateHeaders(MutableArrayRef, ArrayRef); template void elf::allocateHeaders(MutableArrayRef, ArrayRef); template void elf::allocateHeaders(MutableArrayRef, ArrayRef); template void elf::allocateHeaders(MutableArrayRef, ArrayRef); template bool elf::isRelroSection(const OutputSectionBase *); template bool elf::isRelroSection(const OutputSectionBase *); template bool elf::isRelroSection(const OutputSectionBase *); template bool elf::isRelroSection(const OutputSectionBase *); template void elf::reportDiscarded(InputSectionBase *); template void elf::reportDiscarded(InputSectionBase *); template void elf::reportDiscarded(InputSectionBase *); template void elf::reportDiscarded(InputSectionBase *); Index: vendor/lld/dist/test/ELF/Inputs/dtrace-r.o =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/x-object Property changes on: vendor/lld/dist/test/ELF/Inputs/dtrace-r.o ___________________________________________________________________ Added: epic ## -0,0 +1 ## +fail \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +application/x-object \ No newline at end of property Index: vendor/lld/dist/test/ELF/aarch64-relro.s =================================================================== --- vendor/lld/dist/test/ELF/aarch64-relro.s (nonexistent) +++ vendor/lld/dist/test/ELF/aarch64-relro.s (revision 313063) @@ -0,0 +1,14 @@ +# REQUIRES: aarch64 +# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t +# RUN: ld.lld %t -o %t2 +# RUN: llvm-readobj -program-headers %t2 | FileCheck %s + +# CHECK: Type: PT_GNU_RELRO +# CHECK-NEXT: Offset: +# CHECK-NEXT: VirtualAddress: +# CHECK-NEXT: PhysicalAddress: +# CHECK-NEXT: FileSize: +# CHECK-NEXT: MemSize: 4096 + +.section .data.rel.ro,"aw",%progbits +.byte 1 Property changes on: vendor/lld/dist/test/ELF/aarch64-relro.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/ELF/basic-mips.s =================================================================== --- vendor/lld/dist/test/ELF/basic-mips.s (revision 313062) +++ vendor/lld/dist/test/ELF/basic-mips.s (revision 313063) @@ -1,319 +1,319 @@ # RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t.o # RUN: ld.lld %t.o -o %t.exe # RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t.exe \ # RUN: | FileCheck %s # REQUIRES: mips # Exits with return code 1 on Linux. .globl __start __start: li $a0,1 li $v0,4001 syscall # CHECK: ElfHeader { # CHECK-NEXT: Ident { # CHECK-NEXT: Magic: (7F 45 4C 46) # CHECK-NEXT: Class: 32-bit (0x1) # CHECK-NEXT: DataEncoding: LittleEndian (0x1) # CHECK-NEXT: FileVersion: 1 # CHECK-NEXT: OS/ABI: SystemV (0x0) # CHECK-NEXT: ABIVersion: 0 # CHECK-NEXT: Unused: (00 00 00 00 00 00 00) # CHECK-NEXT: } # CHECK-NEXT: Type: Executable (0x2) # CHECK-NEXT: Machine: EM_MIPS (0x8) # CHECK-NEXT: Version: 1 # CHECK-NEXT: Entry: 0x20000 # CHECK-NEXT: ProgramHeaderOffset: 0x34 # CHECK-NEXT: SectionHeaderOffset: 0x200A0 # CHECK-NEXT: Flags [ # CHECK-NEXT: EF_MIPS_ABI_O32 # CHECK-NEXT: EF_MIPS_ARCH_32 # CHECK-NEXT: EF_MIPS_CPIC # CHECK-NEXT: ] # CHECK-NEXT: HeaderSize: 52 # CHECK-NEXT: ProgramHeaderEntrySize: 32 # CHECK-NEXT: ProgramHeaderCount: 6 # CHECK-NEXT: SectionHeaderEntrySize: 40 # CHECK-NEXT: SectionHeaderCount: 11 # CHECK-NEXT: StringTableSectionIndex: 9 # CHECK-NEXT: } # CHECK-NEXT: Sections [ # CHECK-NEXT: Section { # CHECK-NEXT: Index: 0 # CHECK-NEXT: Name: (0) # CHECK-NEXT: Type: SHT_NULL (0x0) # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 # CHECK-NEXT: Offset: 0x0 # CHECK-NEXT: Size: 0 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 0 # CHECK-NEXT: EntrySize: 0 # CHECK-NEXT: } # CHECK-NEXT: Section { # CHECK-NEXT: Index: 1 # CHECK-NEXT: Name: .MIPS.abiflags # CHECK-NEXT: Type: SHT_MIPS_ABIFLAGS (0x7000002A) # CHECK-NEXT: Flags [ (0x2) # CHECK-NEXT: SHF_ALLOC (0x2) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x100F8 # CHECK-NEXT: Offset: 0xF8 # CHECK-NEXT: Size: 24 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 8 # CHECK-NEXT: EntrySize: 24 # CHECK-NEXT: } # CHECK-NEXT: Section { # CHECK-NEXT: Index: 2 # CHECK-NEXT: Name: .reginfo # CHECK-NEXT: Type: SHT_MIPS_REGINFO (0x70000006) # CHECK-NEXT: Flags [ (0x2) # CHECK-NEXT: SHF_ALLOC (0x2) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x10110 # CHECK-NEXT: Offset: 0x110 # CHECK-NEXT: Size: 24 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 4 # CHECK-NEXT: EntrySize: 24 # CHECK-NEXT: } # CHECK-NEXT: Section { # CHECK-NEXT: Index: 3 # CHECK-NEXT: Name: .text # CHECK-NEXT: Type: SHT_PROGBITS (0x1) # CHECK-NEXT: Flags [ (0x6) # CHECK-NEXT: SHF_ALLOC (0x2) # CHECK-NEXT: SHF_EXECINSTR (0x4) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x20000 # CHECK-NEXT: Offset: 0x10000 # CHECK-NEXT: Size: 12 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 16 # CHECK-NEXT: EntrySize: 0 # CHECK-NEXT: } # CHECK-NEXT: Section { # CHECK-NEXT: Index: 4 # CHECK-NEXT: Name: .data # CHECK-NEXT: Type: SHT_PROGBITS (0x1) # CHECK-NEXT: Flags [ (0x3) # CHECK-NEXT: SHF_ALLOC (0x2) # CHECK-NEXT: SHF_WRITE (0x1) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x30000 # CHECK-NEXT: Offset: 0x20000 # CHECK-NEXT: Size: 0 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 16 # CHECK-NEXT: EntrySize: 0 # CHECK-NEXT: } # CHECK-NEXT: Section { # CHECK-NEXT: Index: 5 # CHECK-NEXT: Name: .got # CHECK-NEXT: Type: SHT_PROGBITS (0x1) # CHECK-NEXT: Flags [ (0x10000003) # CHECK-NEXT: SHF_ALLOC (0x2) # CHECK-NEXT: SHF_MIPS_GPREL (0x10000000) # CHECK-NEXT: SHF_WRITE (0x1) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x30000 # CHECK-NEXT: Offset: 0x20000 # CHECK-NEXT: Size: 8 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 4 # CHECK-NEXT: EntrySize: 0 # CHECK-NEXT: } # CHECK-NEXT: Section { # CHECK-NEXT: Index: 6 # CHECK-NEXT: Name: .bss # CHECK-NEXT: Type: SHT_NOBITS (0x8) # CHECK-NEXT: Flags [ (0x3) # CHECK-NEXT: SHF_ALLOC (0x2) # CHECK-NEXT: SHF_WRITE (0x1) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x40000 # CHECK-NEXT: Offset: 0x20008 # CHECK-NEXT: Size: 0 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 16 # CHECK-NEXT: EntrySize: 0 # CHECK-NEXT: } # CHECK-NEXT: Section { # CHECK-NEXT: Index: 7 # CHECK-NEXT: Name: .comment # CHECK-NEXT: Type: SHT_PROGBITS (0x1) # CHECK-NEXT: Flags [ (0x30) # CHECK-NEXT: SHF_MERGE (0x10) # CHECK-NEXT: SHF_STRINGS (0x20) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 # CHECK-NEXT: Offset: 0x20008 # CHECK-NEXT: Size: 8 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 1 # CHECK-NEXT: EntrySize: 1 # CHECK-NEXT: } # CHECK-NEXT: Section { # CHECK-NEXT: Index: 8 # CHECK-NEXT: Name: .symtab # CHECK-NEXT: Type: SHT_SYMTAB (0x2) # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 # CHECK-NEXT: Offset: 0x20010 # CHECK-NEXT: Size: 48 # CHECK-NEXT: Link: 10 -# CHECK-NEXT: Info: 1 +# CHECK-NEXT: Info: 2 # CHECK-NEXT: AddressAlignment: 4 # CHECK-NEXT: EntrySize: 16 # CHECK-NEXT: } # CHECK-NEXT: Section { # CHECK-NEXT: Index: 9 # CHECK-NEXT: Name: .shstrtab # CHECK-NEXT: Type: SHT_STRTAB (0x3) # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 # CHECK-NEXT: Offset: 0x20040 # CHECK-NEXT: Size: 82 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 1 # CHECK-NEXT: EntrySize: 0 # CHECK-NEXT: } # CHECK-NEXT: Section { # CHECK-NEXT: Index: 10 # CHECK-NEXT: Name: .strtab # CHECK-NEXT: Type: SHT_STRTAB (0x3) # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 # CHECK-NEXT: Offset: 0x20092 # CHECK-NEXT: Size: 13 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 1 # CHECK-NEXT: EntrySize: 0 # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: Symbols [ # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: (0) # CHECK-NEXT: Value: 0x0 # CHECK-NEXT: Size: 0 # CHECK-NEXT: Binding: Local (0x0) # CHECK-NEXT: Type: None (0x0) # CHECK-NEXT: Other: 0 # CHECK-NEXT: Section: Undefined (0x0) # CHECK-NEXT: } # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: _gp # CHECK-NEXT: Value: 0x37FF0 # CHECK-NEXT: Size: 0 # CHECK-NEXT: Binding: Local # CHECK-NEXT: Type: None (0x0) # CHECK-NEXT: Other [ (0x2) # CHECK-NEXT: STV_HIDDEN (0x2) # CHECK-NEXT: ] # CHECK-NEXT: Section: Absolute # CHECK-NEXT: } # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: __start # CHECK-NEXT: Value: 0x20000 # CHECK-NEXT: Size: 0 # CHECK-NEXT: Binding: Global (0x1) # CHECK-NEXT: Type: None (0x0) # CHECK-NEXT: Other: 0 # CHECK-NEXT: Section: .text # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: ProgramHeaders [ # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_PHDR (0x6) # CHECK-NEXT: Offset: 0x34 # CHECK-NEXT: VirtualAddress: 0x10034 # CHECK-NEXT: PhysicalAddress: 0x10034 # CHECK-NEXT: FileSize: 192 # CHECK-NEXT: MemSize: 192 # CHECK-NEXT: Flags [ (0x4) # CHECK-NEXT: PF_R (0x4) # CHECK-NEXT: ] # CHECK-NEXT: Alignment: 4 # CHECK-NEXT: } # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_LOAD (0x1) # CHECK-NEXT: Offset: 0x0 # CHECK-NEXT: VirtualAddress: 0x10000 # CHECK-NEXT: PhysicalAddress: 0x10000 # CHECK-NEXT: FileSize: 296 # CHECK-NEXT: MemSize: 296 # CHECK-NEXT: Flags [ (0x4) # CHECK-NEXT: PF_R (0x4) # CHECK-NEXT: ] # CHECK-NEXT: Alignment: 65536 # CHECK-NEXT: } # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_LOAD (0x1) # CHECK-NEXT: Offset: 0x10000 # CHECK-NEXT: VirtualAddress: 0x20000 # CHECK-NEXT: PhysicalAddress: 0x20000 # CHECK-NEXT: FileSize: 12 # CHECK-NEXT: MemSize: 12 # CHECK-NEXT: Flags [ (0x5) # CHECK-NEXT: PF_R (0x4) # CHECK-NEXT: PF_X (0x1) # CHECK-NEXT: ] # CHECK-NEXT: Alignment: 65536 # CHECK-NEXT: } # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_LOAD (0x1) # CHECK-NEXT: Offset: 0x20000 # CHECK-NEXT: VirtualAddress: 0x30000 # CHECK-NEXT: PhysicalAddress: 0x30000 # CHECK-NEXT: FileSize: 8 # CHECK-NEXT: MemSize: 65536 # CHECK-NEXT: Flags [ # CHECK-NEXT: PF_R # CHECK-NEXT: PF_W # CHECK-NEXT: ] # CHECK-NEXT: Alignment: 65536 # CHECK-NEXT: } # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_GNU_RELRO (0x6474E552) # CHECK-NEXT: Offset: 0x20000 # CHECK-NEXT: VirtualAddress: 0x30000 # CHECK-NEXT: PhysicalAddress: 0x30000 # CHECK-NEXT: FileSize: 8 # CHECK-NEXT: MemSize: 65536 # CHECK-NEXT: Flags [ (0x4) # CHECK-NEXT: PF_R (0x4) # CHECK-NEXT: ] # CHECK-NEXT: Alignment: 1 # CHECK-NEXT: } # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_GNU_STACK # CHECK-NEXT: Offset: 0x0 # CHECK-NEXT: VirtualAddress: 0x0 # CHECK-NEXT: PhysicalAddress: 0x0 # CHECK-NEXT: FileSize: 0 # CHECK-NEXT: MemSize: 0 # CHECK-NEXT: Flags [ # CHECK-NEXT: PF_R # CHECK-NEXT: PF_W # CHECK-NEXT: ] # CHECK-NEXT: Alignment: 0 # CHECK-NEXT: } # CHECK-NEXT:] Index: vendor/lld/dist/test/ELF/basic-ppc.s =================================================================== --- vendor/lld/dist/test/ELF/basic-ppc.s (revision 313062) +++ vendor/lld/dist/test/ELF/basic-ppc.s (revision 313063) @@ -1,317 +1,317 @@ # RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-freebsd %s -o %t # RUN: ld.lld -discard-all -shared %t -o %t2 # RUN: llvm-readobj -file-headers -sections -section-data -program-headers %t2 | FileCheck %s # REQUIRES: ppc # exits with return code 42 on FreeBSD .text li 0,1 li 3,1 sc // CHECK: Format: ELF32-ppc // CHECK-NEXT: Arch: powerpc // CHECK-NEXT: AddressSize: 32bit // CHECK-NEXT: LoadName: // CHECK-NEXT: ElfHeader { // CHECK-NEXT: Ident { // CHECK-NEXT: Magic: (7F 45 4C 46) // CHECK-NEXT: Class: 32-bit (0x1) // CHECK-NEXT: DataEncoding: BigEndian (0x2) // CHECK-NEXT: FileVersion: 1 // CHECK-NEXT: OS/ABI: FreeBSD (0x9) // CHECK-NEXT: ABIVersion: 0 // CHECK-NEXT: Unused: (00 00 00 00 00 00 00) // CHECK-NEXT: } // CHECK-NEXT: Type: SharedObject (0x3) // CHECK-NEXT: Machine: EM_PPC (0x14) // CHECK-NEXT: Version: 1 // CHECK-NEXT: Entry: 0x1000 // CHECK-NEXT: ProgramHeaderOffset: 0x34 // CHECK-NEXT: SectionHeaderOffset: 0x20AC // CHECK-NEXT: Flags [ (0x0) // CHECK-NEXT: ] // CHECK-NEXT: HeaderSize: 52 // CHECK-NEXT: ProgramHeaderEntrySize: 32 // CHECK-NEXT: ProgramHeaderCount: 7 // CHECK-NEXT: SectionHeaderEntrySize: 40 // CHECK-NEXT: SectionHeaderCount: 10 // CHECK-NEXT: StringTableSectionIndex: 8 // CHECK-NEXT: } // CHECK-NEXT: Sections [ // CHECK-NEXT: Section { // CHECK-NEXT: Index: 0 // CHECK-NEXT: Name: (0) // CHECK-NEXT: Type: SHT_NULL (0x0) // CHECK-NEXT: Flags [ (0x0) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 // CHECK-NEXT: Offset: 0x0 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 0 // CHECK-NEXT: EntrySize: 0 // CHECK-NEXT: SectionData ( // CHECK-NEXT: ) // CHECK-NEXT: } // CHECK-NEXT: Section { // CHECK-NEXT: Index: 1 // CHECK-NEXT: Name: .dynsym // CHECK-NEXT: Type: SHT_DYNSYM (0xB) // CHECK-NEXT: Flags [ (0x2) // CHECK-NEXT: SHF_ALLOC (0x2) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x114 // CHECK-NEXT: Offset: 0x114 // CHECK-NEXT: Size: 16 // CHECK-NEXT: Link: 3 // CHECK-NEXT: Info: 1 // CHECK-NEXT: AddressAlignment: 4 // CHECK-NEXT: EntrySize: 16 // CHECK-NEXT: SectionData ( // CHECK-NEXT: 0000: 00000000 00000000 00000000 00000000 |................| // CHECK-NEXT: ) // CHECK-NEXT: } // CHECK-NEXT: Section { // CHECK-NEXT: Index: 2 // CHECK-NEXT: Name: .hash // CHECK-NEXT: Type: SHT_HASH (0x5) // CHECK-NEXT: Flags [ (0x2) // CHECK-NEXT: SHF_ALLOC (0x2) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x124 // CHECK-NEXT: Offset: 0x124 // CHECK-NEXT: Size: 16 // CHECK-NEXT: Link: 1 // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 4 // CHECK-NEXT: EntrySize: 4 // CHECK-NEXT: SectionData ( // CHECK-NEXT: 0000: 00000001 00000001 00000000 00000000 |................| // CHECK-NEXT: ) // CHECK-NEXT: } // CHECK-NEXT: Section { // CHECK-NEXT: Index: 3 // CHECK-NEXT: Name: .dynstr // CHECK-NEXT: Type: SHT_STRTAB (0x3) // CHECK-NEXT: Flags [ (0x2) // CHECK-NEXT: SHF_ALLOC (0x2) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x134 // CHECK-NEXT: Offset: 0x134 // CHECK-NEXT: Size: 1 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 1 // CHECK-NEXT: EntrySize: 0 // CHECK-NEXT: SectionData ( // CHECK-NEXT: 0000: 00 |.| // CHECK-NEXT: ) // CHECK-NEXT: } // CHECK-NEXT: Section { // CHECK-NEXT: Index: 4 // CHECK-NEXT: Name: .text // CHECK-NEXT: Type: SHT_PROGBITS (0x1) // CHECK-NEXT: Flags [ (0x6) // CHECK-NEXT: SHF_ALLOC (0x2) // CHECK-NEXT: SHF_EXECINSTR (0x4) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x1000 // CHECK-NEXT: Offset: 0x1000 // CHECK-NEXT: Size: 12 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 4 // CHECK-NEXT: EntrySize: 0 // CHECK-NEXT: SectionData ( // CHECK-NEXT: 0000: 38000001 38600001 44000002 |8...8`..D...| // CHECK-NEXT: ) // CHECK-NEXT: } // CHECK-NEXT: Section { // CHECK-NEXT: Index: 5 // CHECK-NEXT: Name: .dynamic // CHECK-NEXT: Type: SHT_DYNAMIC (0x6) // CHECK-NEXT: Flags [ (0x3) // CHECK-NEXT: SHF_ALLOC (0x2) // CHECK-NEXT: SHF_WRITE (0x1) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x2000 // CHECK-NEXT: Offset: 0x2000 // CHECK-NEXT: Size: 48 // CHECK-NEXT: Link: 3 // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 4 // CHECK-NEXT: EntrySize: 8 // CHECK-NEXT: SectionData ( // CHECK-NEXT: 0000: 00000006 00000114 0000000B 00000010 |................| // CHECK-NEXT: 0010: 00000005 00000134 0000000A 00000001 |.......4........| // CHECK-NEXT: 0020: 00000004 00000124 00000000 00000000 |.......$........| // CHECK-NEXT: ) // CHECK-NEXT: } // CHECK-NEXT: Section { // CHECK-NEXT: Index: 6 // CHECK-NEXT: Name: .comment // CHECK-NEXT: Type: SHT_PROGBITS (0x1) // CHECK-NEXT: Flags [ (0x30) // CHECK-NEXT: SHF_MERGE (0x10) // CHECK-NEXT: SHF_STRINGS (0x20) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 // CHECK-NEXT: Offset: 0x2030 // CHECK-NEXT: Size: 8 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 1 // CHECK-NEXT: EntrySize: 1 // CHECK-NEXT: SectionData ( // CHECK-NEXT: 0000: 4C4C4420 312E3000 |LLD 1.0.| // CHECK-NEXT: ) // CHECK-NEXT: } // CHECK-NEXT: Section { // CHECK-NEXT: Index: 7 // CHECK-NEXT: Name: .symtab // CHECK-NEXT: Type: SHT_SYMTAB (0x2) // CHECK-NEXT: Flags [ (0x0) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 // CHECK-NEXT: Offset: 0x2038 // CHECK-NEXT: Size: 32 // CHECK-NEXT: Link: 9 -// CHECK-NEXT: Info: 1 +// CHECK-NEXT: Info: 2 // CHECK-NEXT: AddressAlignment: 4 // CHECK-NEXT: EntrySize: 16 // CHECK-NEXT: SectionData ( // CHECK-NEXT: 0000: 00000000 00000000 00000000 00000000 |................| // CHECK-NEXT: 0010: 00000001 00002000 00000000 00020005 |...... .........| // CHECK-NEXT: ) // CHECK-NEXT: } // CHECK-NEXT: Section { // CHECK-NEXT: Index: 8 // CHECK-NEXT: Name: .shstrtab // CHECK-NEXT: Type: SHT_STRTAB (0x3) // CHECK-NEXT: Flags [ (0x0) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 // CHECK-NEXT: Offset: 0x2058 // CHECK-NEXT: Size: 73 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 1 // CHECK-NEXT: EntrySize: 0 // CHECK-NEXT: SectionData ( // CHECK-NEXT: 0000: 002E6479 6E73796D 002E6861 7368002E |..dynsym..hash..| // CHECK-NEXT: 0010: 64796E73 7472002E 74657874 002E6479 |dynstr..text..dy| // CHECK-NEXT: 0020: 6E616D69 63002E63 6F6D6D65 6E74002E |namic..comment..| // CHECK-NEXT: 0030: 73796D74 6162002E 73687374 72746162 |symtab..shstrtab| // CHECK-NEXT: 0040: 002E7374 72746162 00 |..strtab.| // CHECK-NEXT: ) // CHECK-NEXT: } // CHECK-NEXT: Section { // CHECK-NEXT: Index: 9 // CHECK-NEXT: Name: .strtab // CHECK-NEXT: Type: SHT_STRTAB (0x3) // CHECK-NEXT: Flags [ (0x0) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 // CHECK-NEXT: Offset: 0x20A1 // CHECK-NEXT: Size: 1 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 1 // CHECK-NEXT: EntrySize: 0 // CHECK-NEXT: SectionData ( // CHECK-NEXT: 0000: 005F4459 4E414D49 4300 |._DYNAMIC.| // CHECK-NEXT: ) // CHECK-NEXT: } // CHECK-NEXT: ] // CHECK-NEXT: ProgramHeaders [ // CHECK-NEXT: ProgramHeader { // CHECK-NEXT: Type: PT_PHDR (0x6) // CHECK-NEXT: Offset: 0x34 // CHECK-NEXT: VirtualAddress: 0x34 // CHECK-NEXT: PhysicalAddress: 0x34 // CHECK-NEXT: FileSize: 224 // CHECK-NEXT: MemSize: 224 // CHECK-NEXT: Flags [ (0x4) // CHECK-NEXT: PF_R (0x4) // CHECK-NEXT: ] // CHECK-NEXT: Alignment: 4 // CHECK-NEXT: } // CHECK-NEXT: ProgramHeader { // CHECK-NEXT: Type: PT_LOAD (0x1) // CHECK-NEXT: Offset: 0x0 // CHECK-NEXT: VirtualAddress: 0x0 // CHECK-NEXT: PhysicalAddress: 0x0 // CHECK-NEXT: FileSize: 309 // CHECK-NEXT: MemSize: 309 // CHECK-NEXT: Flags [ (0x4) // CHECK-NEXT: PF_R (0x4) // CHECK-NEXT: ] // CHECK-NEXT: Alignment: 4096 // CHECK-NEXT: } // CHECK-NEXT: ProgramHeader { // CHECK-NEXT: Type: PT_LOAD (0x1) // CHECK-NEXT: Offset: 0x1000 // CHECK-NEXT: VirtualAddress: 0x1000 // CHECK-NEXT: PhysicalAddress: 0x1000 // CHECK-NEXT: FileSize: 12 // CHECK-NEXT: MemSize: 12 // CHECK-NEXT: Flags [ (0x5) // CHECK-NEXT: PF_R (0x4) // CHECK-NEXT: PF_X (0x1) // CHECK-NEXT: ] // CHECK-NEXT: Alignment: 4096 // CHECK-NEXT: } // CHECK-NEXT: ProgramHeader { // CHECK-NEXT: Type: PT_LOAD (0x1) // CHECK-NEXT: Offset: 0x2000 // CHECK-NEXT: VirtualAddress: 0x2000 // CHECK-NEXT: PhysicalAddress: 0x2000 // CHECK-NEXT: FileSize: 48 // CHECK-NEXT: MemSize: 48 // CHECK-NEXT: Flags [ (0x6) // CHECK-NEXT: PF_R (0x4) // CHECK-NEXT: PF_W (0x2) // CHECK-NEXT: ] // CHECK-NEXT: Alignment: 4096 // CHECK-NEXT: } // CHECK-NEXT: ProgramHeader { // CHECK-NEXT: Type: PT_DYNAMIC (0x2) // CHECK-NEXT: Offset: 0x2000 // CHECK-NEXT: VirtualAddress: 0x2000 // CHECK-NEXT: PhysicalAddress: 0x2000 // CHECK-NEXT: FileSize: 48 // CHECK-NEXT: MemSize: 48 // CHECK-NEXT: Flags [ (0x6) // CHECK-NEXT: PF_R (0x4) // CHECK-NEXT: PF_W (0x2) // CHECK-NEXT: ] // CHECK-NEXT: Alignment: 4 // CHECK-NEXT: } // CHECK-NEXT: ProgramHeader { // CHECK-NEXT: Type: PT_GNU_RELRO (0x6474E552) // CHECK-NEXT: Offset: 0x2000 // CHECK-NEXT: VirtualAddress: 0x2000 // CHECK-NEXT: PhysicalAddress: 0x2000 // CHECK-NEXT: FileSize: 48 // CHECK-NEXT: MemSize: 4096 // CHECK-NEXT: Flags [ (0x4) // CHECK-NEXT: PF_R (0x4) // CHECK-NEXT: ] // CHECK-NEXT: Alignment: 1 // CHECK-NEXT: } // CHECK-NEXT: ProgramHeader { // CHECK-NEXT: Type: PT_GNU_STACK (0x6474E551) // CHECK-NEXT: Offset: 0x0 // CHECK-NEXT: VirtualAddress: 0x0 // CHECK-NEXT: PhysicalAddress: 0x0 // CHECK-NEXT: FileSize: 0 // CHECK-NEXT: MemSize: 0 // CHECK-NEXT: Flags [ (0x6) // CHECK-NEXT: PF_R (0x4) // CHECK-NEXT: PF_W (0x2) // CHECK-NEXT: ] // CHECK-NEXT: Alignment: 0 // CHECK-NEXT: } // CHECK-NEXT: ] Index: vendor/lld/dist/test/ELF/dtrace-r.test =================================================================== --- vendor/lld/dist/test/ELF/dtrace-r.test (nonexistent) +++ vendor/lld/dist/test/ELF/dtrace-r.test (revision 313063) @@ -0,0 +1,8 @@ +RUN: ld.lld -r -o %t.o %p/Inputs/dtrace-r.o +RUN: llvm-readobj -r %t.o | FileCheck %s + +CHECK: Relocations [ +CHECK-NEXT: Section ({{.*}}) .rela.text { +CHECK-NEXT: 0x0 R_X86_64_NONE - 0x0 +CHECK-NEXT: } +CHECK-NEXT: ]