Index: vendor/lld/dist/ELF/InputSection.cpp =================================================================== --- vendor/lld/dist/ELF/InputSection.cpp (revision 319468) +++ vendor/lld/dist/ELF/InputSection.cpp (revision 319469) @@ -1,975 +1,997 @@ //===- 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 "llvm/Support/Path.h" #include "llvm/Support/Threading.h" #include using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support; using namespace llvm::support::endian; using namespace llvm::sys; using namespace lld; using namespace lld::elf; std::vector elf::InputSections; // Returns a string to construct an error message. std::string lld::toString(const InputSectionBase *Sec) { return (toString(Sec->File) + ":(" + 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)); } InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags, uint32_t Type, uint64_t Entsize, uint32_t Link, uint32_t Info, uint32_t Alignment, ArrayRef Data, StringRef Name, Kind SectionKind) : SectionBase(SectionKind, Name, Flags, Entsize, Alignment, Type, Info, Link), File(File), Data(Data), Repl(this) { Live = !Config->GcSections || !(Flags & SHF_ALLOC); Assigned = false; NumRelocations = 0; AreRelocsRela = false; // The ELF spec states that a value of 0 means the section has // no alignment constraits. uint32_t V = std::max(Alignment, 1); if (!isPowerOf2_64(V)) fatal(toString(File) + ": section sh_addralign is not a power of 2"); this->Alignment = V; } // GNU assembler 2.24 and LLVM 4.0.0's MC (the newest release as of // March 2017) fail to infer section types for sections starting with // ".init_array." or ".fini_array.". They set SHT_PROGBITS instead of // SHF_INIT_ARRAY. As a result, the following assembler directive // creates ".init_array.100" with SHT_PROGBITS, for example. // // .section .init_array.100, "aw" // // This function forces SHT_{INIT,FINI}_ARRAY so that we can handle // incorrect inputs as if they were correct from the beginning. static uint64_t getType(uint64_t Type, StringRef Name) { if (Type == SHT_PROGBITS && Name.startswith(".init_array.")) return SHT_INIT_ARRAY; if (Type == SHT_PROGBITS && Name.startswith(".fini_array.")) return SHT_FINI_ARRAY; return Type; } template InputSectionBase::InputSectionBase(elf::ObjectFile *File, const typename ELFT::Shdr *Hdr, StringRef Name, Kind SectionKind) : InputSectionBase(File, Hdr->sh_flags & ~SHF_INFO_LINK, getType(Hdr->sh_type, Name), Hdr->sh_entsize, Hdr->sh_link, Hdr->sh_info, Hdr->sh_addralign, getSectionContents(File, Hdr), Name, SectionKind) { // 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 (Hdr->sh_addralign > UINT32_MAX) fatal(toString(File) + ": section sh_addralign is too large"); } size_t InputSectionBase::getSize() const { if (auto *S = dyn_cast(this)) return S->getSize(); return Data.size(); } uint64_t InputSectionBase::getOffsetInFile() const { const uint8_t *FileStart = (const uint8_t *)File->MB.getBufferStart(); const uint8_t *SecStart = Data.begin(); return SecStart - FileStart; } uint64_t SectionBase::getOffset(uint64_t Offset) const { switch (kind()) { case Output: { auto *OS = cast(this); // For output sections we treat offset -1 as the end of the section. return Offset == uint64_t(-1) ? OS->Size : Offset; } case Regular: return cast(this)->OutSecOff + Offset; case Synthetic: { auto *IS = cast(this); // For synthetic sections we treat offset -1 as the end of the section. return IS->OutSecOff + (Offset == uint64_t(-1) ? IS->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: const MergeInputSection *MS = cast(this); - if (MS->MergeSec) - return MS->MergeSec->OutSecOff + MS->getOffset(Offset); + if (InputSection *IS = MS->getParent()) + return IS->OutSecOff + MS->getOffset(Offset); return MS->getOffset(Offset); } llvm_unreachable("invalid section kind"); } OutputSection *SectionBase::getOutputSection() { + InputSection *Sec; if (auto *IS = dyn_cast(this)) - return IS->OutSec; - if (auto *MS = dyn_cast(this)) - return MS->MergeSec ? MS->MergeSec->OutSec : nullptr; - if (auto *EH = dyn_cast(this)) - return EH->EHSec->OutSec; - return cast(this); + Sec = IS; + else if (auto *MS = dyn_cast(this)) + Sec = MS->getParent(); + else if (auto *EH = dyn_cast(this)) + Sec = EH->getParent(); + else + return cast(this); + return Sec ? Sec->getParent() : nullptr; } // Uncompress section contents. Note that this function is called // from parallel_for_each, so it must be thread-safe. void InputSectionBase::uncompress() { Decompressor Dec = check(Decompressor::create(Name, toStringRef(Data), Config->IsLE, Config->Is64)); size_t Size = Dec.getDecompressedSize(); char *OutputBuf; { static std::mutex Mu; std::lock_guard Lock(Mu); OutputBuf = BAlloc.Allocate(Size); } if (Error E = Dec.decompress({OutputBuf, Size})) fatal(toString(this) + ": decompress failed: " + llvm::toString(std::move(E))); this->Data = ArrayRef((uint8_t *)OutputBuf, Size); this->Flags &= ~(uint64_t)SHF_COMPRESSED; } uint64_t SectionBase::getOffset(const DefinedRegular &Sym) const { return getOffset(Sym.Value); } -InputSectionBase *InputSectionBase::getLinkOrderDep() const { - if ((Flags & SHF_LINK_ORDER) && Link != 0) - return File->getSections()[Link]; +InputSection *InputSectionBase::getLinkOrderDep() const { + if ((Flags & SHF_LINK_ORDER) && Link != 0) { + InputSectionBase *L = File->getSections()[Link]; + if (auto *IS = dyn_cast(L)) + return IS; + error( + "Merge and .eh_frame sections are not supported with SHF_LINK_ORDER " + + toString(L)); + } return nullptr; } // Returns a source location string. Used to construct an error message. template std::string InputSectionBase::getLocation(uint64_t Offset) { // We don't have file for synthetic sections. if (getFile() == nullptr) return (Config->OutputFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")") .str(); // First check if we can get desired values from debugging information. std::string LineInfo = getFile()->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 = getFile()->SourceFile; if (SrcFile.empty()) SrcFile = toString(File); // Find a function symbol that encloses a given location. for (SymbolBody *B : getFile()->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(); } // Returns a source location string. This function is intended to be // used for constructing an error message. The returned message looks // like this: // // foo.c:42 (/home/alice/possibly/very/long/path/foo.c:42) // // Returns an empty string if there's no way to get line info. template std::string InputSectionBase::getSrcMsg(uint64_t Offset) { // Synthetic sections don't have input files. elf::ObjectFile *File = getFile(); if (!File) return ""; Optional Info = File->getDILineInfo(this, Offset); // File->SourceFile contains STT_FILE symbol, and that is a last resort. if (!Info) return File->SourceFile; std::string Path = Info->FileName; std::string Filename = path::filename(Path); std::string Lineno = ":" + std::to_string(Info->Line); if (Filename == Path) return Filename + Lineno; return Filename + Lineno + " (" + Path + Lineno + ")"; } // Returns a filename string along with an optional section name. This // function is intended to be used for constructing an error // message. The returned message looks like this: // // path/to/foo.o:(function bar) // // or // // path/to/foo.o:(function bar) in archive path/to/bar.a template std::string InputSectionBase::getObjMsg(uint64_t Off) { // Synthetic sections don't have input files. elf::ObjectFile *File = getFile(); std::string Filename = File ? File->getName() : "(internal)"; std::string Archive; if (!File->ArchiveName.empty()) Archive = (" in archive " + File->ArchiveName).str(); // Find a symbol that encloses a given location. for (SymbolBody *B : getFile()->getSymbols()) if (auto *D = dyn_cast(B)) if (D->Section == this && D->Value <= Off && Off < D->Value + D->Size) return Filename + ":(" + toString(*D) + ")" + Archive; // If there's no symbol, print out the offset in the section. return (Filename + ":(" + Name + "+0x" + utohexstr(Off) + ")" + Archive) .str(); } InputSectionBase InputSectionBase::Discarded; InputSection::InputSection(uint64_t Flags, uint32_t Type, uint32_t Alignment, ArrayRef Data, StringRef Name, Kind K) : InputSectionBase(nullptr, Flags, Type, /*Entsize*/ 0, /*Link*/ 0, /*Info*/ 0, Alignment, Data, Name, K) {} template InputSection::InputSection(elf::ObjectFile *F, const typename ELFT::Shdr *Header, StringRef Name) : InputSectionBase(F, Header, Name, InputSectionBase::Regular) {} bool InputSection::classof(const SectionBase *S) { return S->kind() == SectionBase::Regular || S->kind() == SectionBase::Synthetic; } bool InputSectionBase::classof(const SectionBase *S) { return S->kind() != Output; } +OutputSection *InputSection::getParent() const { + return cast_or_null(Parent); +} + void InputSection::copyShtGroup(uint8_t *Buf) { assert(this->Type == SHT_GROUP); ArrayRef From = getDataAs(); uint32_t *To = reinterpret_cast(Buf); // First entry is a flag word, we leave it unchanged. *To++ = From[0]; // Here we adjust indices of sections that belong to group as it // might change during linking. ArrayRef Sections = this->File->getSections(); for (uint32_t Val : From.slice(1)) { uint32_t Index = read32(&Val, Config->Endianness); - write32(To++, Sections[Index]->OutSec->SectionIndex, Config->Endianness); + write32(To++, Sections[Index]->getOutputSection()->SectionIndex, + Config->Endianness); } } InputSectionBase *InputSection::getRelocatedSection() { assert(this->Type == SHT_RELA || this->Type == SHT_REL); ArrayRef Sections = this->File->getSections(); return Sections[this->Info]; } // This is used for -r and --emit-relocs. 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 void InputSection::copyRelocations(uint8_t *Buf, ArrayRef Rels) { InputSectionBase *RelocatedSection = getRelocatedSection(); // Loop is slow and have complexity O(N*M), where N - amount of // relocations and M - amount of symbols in symbol table. // That happens because getSymbolIndex(...) call below performs // simple linear search. for (const RelTy &Rel : Rels) { uint32_t Type = Rel.getType(Config->IsMips64EL); SymbolBody &Body = this->getFile()->getRelocTargetSym(Rel); auto *P = reinterpret_cast(Buf); Buf += sizeof(RelTy); if (Config->IsRela) P->r_addend = getAddend(Rel); // Output section VA is zero for -r, so r_offset is an offset within the // section, but for --emit-relocs it is an virtual address. - P->r_offset = RelocatedSection->OutSec->Addr + + P->r_offset = RelocatedSection->getOutputSection()->Addr + RelocatedSection->getOffset(Rel.r_offset); P->setSymbolAndType(InX::SymTab->getSymbolIndex(&Body), Type, Config->IsMips64EL); if (Body.Type == STT_SECTION) { // We combine multiple section symbols into only one per // section. This means we have to update the addend. That is // trivial for Elf_Rela, but for Elf_Rel we have to write to the // section data. We do that by adding to the Relocation vector. // .eh_frame is horribly special and can reference discarded sections. To // avoid having to parse and recreate .eh_frame, we just replace any // relocation in it pointing to discarded sections with R_*_NONE, which // hopefully creates a frame that is ignored at runtime. SectionBase *Section = cast(Body).Section; if (Section == &InputSection::Discarded) { P->setSymbolAndType(0, 0, false); continue; } if (Config->IsRela) { P->r_addend += Body.getVA() - Section->getOutputSection()->Addr; } else if (Config->Relocatable) { const uint8_t *BufLoc = RelocatedSection->Data.begin() + Rel.r_offset; RelocatedSection->Relocations.push_back( {R_ABS, Type, Rel.r_offset, Target->getImplicitAddend(BufLoc, Type), &Body}); } } } } 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; } } // ARM SBREL relocations are of the form S + A - B where B is the static base // The ARM ABI defines base to be "addressing origin of the output segment // defining the symbol S". We defined the "addressing origin"/static base to be // the base of the PT_LOAD segment containing the Body. // The procedure call standard only defines a Read Write Position Independent // RWPI variant so in practice we should expect the static base to be the base // of the RW segment. static uint64_t getARMStaticBase(const SymbolBody &Body) { OutputSection *OS = Body.getOutputSection(); if (!OS || !OS->FirstInPtLoad) fatal("SBREL relocation to " + Body.getName() + " without static base\n"); return OS->FirstInPtLoad->Addr; } static uint64_t getRelocTargetVA(uint32_t Type, int64_t A, uint64_t P, const SymbolBody &Body, RelExpr Expr) { switch (Expr) { case R_ABS: case R_RELAX_GOT_PC_NOPIC: return Body.getVA(A); case R_ARM_SBREL: return Body.getVA(A) - getARMStaticBase(Body); case R_GOT: case R_RELAX_TLS_GD_TO_IE_ABS: return Body.getGotVA() + A; case R_GOTONLY_PC: return InX::Got->getVA() + A - P; case R_GOTONLY_PC_FROM_END: return InX::Got->getVA() + A - P + InX::Got->getSize(); case R_GOTREL: return Body.getVA(A) - InX::Got->getVA(); case R_GOTREL_FROM_END: return Body.getVA(A) - InX::Got->getVA() - InX::Got->getSize(); case R_GOT_FROM_END: case R_RELAX_TLS_GD_TO_IE_END: return Body.getGotOffset() + A - InX::Got->getSize(); case R_GOT_OFF: return Body.getGotOffset() + A; case R_GOT_PAGE_PC: case R_RELAX_TLS_GD_TO_IE_PAGE_PC: return getAArch64Page(Body.getGotVA() + A) - getAArch64Page(P); case R_GOT_PC: case R_RELAX_TLS_GD_TO_IE: return Body.getGotVA() + A - P; case R_HINT: case R_NONE: case R_TLSDESC_CALL: llvm_unreachable("cannot relocate hint relocs"); case R_MIPS_GOTREL: return Body.getVA(A) - InX::MipsGot->getGp(); case R_MIPS_GOT_GP: return InX::MipsGot->getGp() + A; case R_MIPS_GOT_GP_PC: { // R_MIPS_LO16 expression has R_MIPS_GOT_GP_PC type iif the target // is _gp_disp symbol. In that case we should use the following // formula for calculation "AHL + GP - P + 4". For details see p. 4-19 at // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf uint64_t V = InX::MipsGot->getGp() + A - P; if (Type == R_MIPS_LO16) V += 4; return V; } 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 InX::MipsGot->getVA() + InX::MipsGot->getPageEntryOffset(Body, A) - InX::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 InX::MipsGot->getVA() + InX::MipsGot->getBodyEntryOffset(Body, A) - InX::MipsGot->getGp(); case R_MIPS_TLSGD: return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() + InX::MipsGot->getGlobalDynOffset(Body) - InX::MipsGot->getGp(); case R_MIPS_TLSLD: return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() + InX::MipsGot->getTlsIndexOff() - InX::MipsGot->getGp(); case R_PAGE_PC: case R_PLT_PAGE_PC: if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) return getAArch64Page(A); return getAArch64Page(Body.getVA(A)) - getAArch64Page(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); } return Body.getVA(A) - P; case R_PLT: return Body.getPltVA() + A; case R_PLT_PC: case R_PPC_PLT_OPD: return Body.getPltVA() + A - P; 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_PPC_TOC: return getPPC64TocBase() + A; case R_RELAX_GOT_PC: return Body.getVA(A) - P; case R_RELAX_TLS_GD_TO_LE: case R_RELAX_TLS_IE_TO_LE: case R_RELAX_TLS_LD_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_SIZE: return A; // Body.getSize was already folded into the addend. case R_TLSDESC: return InX::Got->getGlobalDynAddr(Body) + A; case R_TLSDESC_PAGE: return getAArch64Page(InX::Got->getGlobalDynAddr(Body) + A) - getAArch64Page(P); case R_TLSGD: return InX::Got->getGlobalDynOffset(Body) + A - InX::Got->getSize(); case R_TLSGD_PC: return InX::Got->getGlobalDynAddr(Body) + A - P; case R_TLSLD: return InX::Got->getTlsIndexOff() + A - InX::Got->getSize(); case R_TLSLD_PC: return InX::Got->getTlsIndexVA() + A - 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 void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef Rels) { for (const RelTy &Rel : Rels) { uint32_t Type = Rel.getType(Config->IsMips64EL); uint64_t Offset = getOffset(Rel.r_offset); uint8_t *BufLoc = Buf + Offset; int64_t Addend = getAddend(Rel); if (!RelTy::IsRela) Addend += Target->getImplicitAddend(BufLoc, Type); SymbolBody &Sym = this->getFile()->getRelocTargetSym(Rel); RelExpr Expr = Target->getRelExpr(Type, Sym, BufLoc); if (Expr == R_NONE) continue; if (Expr != R_ABS) { error(this->getLocation(Offset) + ": has non-ABS reloc"); return; } - uint64_t AddrLoc = this->OutSec->Addr + Offset; + uint64_t AddrLoc = getParent()->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 elf::ObjectFile *InputSectionBase::getFile() const { return cast_or_null>(File); } template void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) { if (Flags & SHF_ALLOC) relocateAlloc(Buf, BufEnd); else relocateNonAlloc(Buf, BufEnd); } template void InputSectionBase::relocateNonAlloc(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 = cast(this); assert(!(IS->Flags & SHF_ALLOC)); if (IS->AreRelocsRela) IS->relocateNonAlloc(Buf, IS->template relas()); else IS->relocateNonAlloc(Buf, IS->template rels()); } void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) { assert(Flags & SHF_ALLOC); const unsigned Bits = Config->Wordsize * 8; for (const Relocation &Rel : Relocations) { uint64_t Offset = getOffset(Rel.Offset); uint8_t *BufLoc = Buf + Offset; uint32_t Type = Rel.Type; uint64_t AddrLoc = getOutputSection()->Addr + Offset; RelExpr Expr = Rel.Expr; uint64_t TargetVA = SignExtend64( getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), Bits); 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 or --emit-relocs 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; } // If -r is given, linker should keep SHT_GROUP sections. We should fixup // them, see copyShtGroup(). if (this->Type == SHT_GROUP) { copyShtGroup(Buf + OutSecOff); return; } // Copy section contents from source object file to output file // and then apply relocations. memcpy(Buf + OutSecOff, Data.data(), Data.size()); uint8_t *BufEnd = Buf + OutSecOff + Data.size(); this->relocate(Buf, BufEnd); } 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 typename ELFT::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; } +SyntheticSection *EhInputSection::getParent() const { + return cast_or_null(Parent); +} + bool EhInputSection::classof(const SectionBase *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 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; +} + +SyntheticSection *MergeInputSection::getParent() const { + return cast_or_null(Parent); } // Split SHF_STRINGS section. Such section is a sequence of // null-terminated strings. 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. 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 typename ELFT::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). void MergeInputSection::splitIntoPieces() { ArrayRef Data = this->Data; uint64_t EntSize = this->Entsize; if (this->Flags & SHF_STRINGS) splitStrings(Data, EntSize); else splitNonStrings(Data, EntSize); if (Config->GcSections && (this->Flags & SHF_ALLOC)) for (uint64_t Off : LiveOffsets) this->getSectionPiece(Off)->Live = true; } bool MergeInputSection::classof(const SectionBase *S) { return S->kind() == InputSectionBase::Merge; } // Do binary search to get a section piece at a given input offset. SectionPiece *MergeInputSection::getSectionPiece(uint64_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; } const SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) const { uint64_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 uint64_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. uint64_t MergeInputSection::getOffset(uint64_t Offset) const { // Initialize OffsetMap lazily. llvm::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; uint64_t Addend = Offset - Piece.InputOff; return Piece.OutputOff + Addend; } template InputSection::InputSection(elf::ObjectFile *, const ELF32LE::Shdr *, StringRef); template InputSection::InputSection(elf::ObjectFile *, const ELF32BE::Shdr *, StringRef); template InputSection::InputSection(elf::ObjectFile *, const ELF64LE::Shdr *, StringRef); template InputSection::InputSection(elf::ObjectFile *, const ELF64BE::Shdr *, StringRef); template std::string InputSectionBase::getLocation(uint64_t); template std::string InputSectionBase::getLocation(uint64_t); template std::string InputSectionBase::getLocation(uint64_t); template std::string InputSectionBase::getLocation(uint64_t); template std::string InputSectionBase::getSrcMsg(uint64_t); template std::string InputSectionBase::getSrcMsg(uint64_t); template std::string InputSectionBase::getSrcMsg(uint64_t); template std::string InputSectionBase::getSrcMsg(uint64_t); template std::string InputSectionBase::getObjMsg(uint64_t); template std::string InputSectionBase::getObjMsg(uint64_t); template std::string InputSectionBase::getObjMsg(uint64_t); template std::string InputSectionBase::getObjMsg(uint64_t); template void InputSection::writeTo(uint8_t *); template void InputSection::writeTo(uint8_t *); template void InputSection::writeTo(uint8_t *); template void InputSection::writeTo(uint8_t *); template elf::ObjectFile *InputSectionBase::getFile() const; template elf::ObjectFile *InputSectionBase::getFile() const; template elf::ObjectFile *InputSectionBase::getFile() const; template elf::ObjectFile *InputSectionBase::getFile() const; template MergeInputSection::MergeInputSection(elf::ObjectFile *, const ELF32LE::Shdr *, StringRef); template MergeInputSection::MergeInputSection(elf::ObjectFile *, const ELF32BE::Shdr *, StringRef); template MergeInputSection::MergeInputSection(elf::ObjectFile *, const ELF64LE::Shdr *, StringRef); template MergeInputSection::MergeInputSection(elf::ObjectFile *, const ELF64BE::Shdr *, StringRef); template EhInputSection::EhInputSection(elf::ObjectFile *, const ELF32LE::Shdr *, StringRef); template EhInputSection::EhInputSection(elf::ObjectFile *, const ELF32BE::Shdr *, StringRef); template EhInputSection::EhInputSection(elf::ObjectFile *, const ELF64LE::Shdr *, StringRef); template EhInputSection::EhInputSection(elf::ObjectFile *, const ELF64BE::Shdr *, StringRef); template void EhInputSection::split(); template void EhInputSection::split(); template void EhInputSection::split(); template void EhInputSection::split(); Index: vendor/lld/dist/ELF/InputSection.h =================================================================== --- vendor/lld/dist/ELF/InputSection.h (revision 319468) +++ vendor/lld/dist/ELF/InputSection.h (revision 319469) @@ -1,334 +1,339 @@ //===- InputSection.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_SECTION_H #define LLD_ELF_INPUT_SECTION_H #include "Config.h" #include "Relocations.h" #include "Thunks.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Threading.h" #include namespace lld { namespace elf { class DefinedCommon; class SymbolBody; struct SectionPiece; class DefinedRegular; class SyntheticSection; template class EhFrameSection; class MergeSyntheticSection; template class ObjectFile; class OutputSection; // This is the base class of all sections that lld handles. Some are sections in // input files, some are sections in the produced output file and some exist // just as a convenience for implementing special ways of combining some // sections. class SectionBase { public: enum Kind { Regular, EHFrame, Merge, Synthetic, Output }; Kind kind() const { return (Kind)SectionKind; } StringRef Name; unsigned SectionKind : 3; // The next two bit fields are only used by InputSectionBase, but we // put them here so the struct packs better. // The garbage collector sets sections' Live bits. // If GC is disabled, all sections are considered live by default. unsigned Live : 1; // for garbage collection unsigned Assigned : 1; // for linker script uint32_t Alignment; // These corresponds to the fields in Elf_Shdr. uint64_t Flags; uint64_t Entsize; uint32_t Type; uint32_t Link; uint32_t Info; OutputSection *getOutputSection(); const OutputSection *getOutputSection() const { return const_cast(this)->getOutputSection(); } // Translate an offset in the input section to an offset in the output // section. uint64_t getOffset(uint64_t Offset) const; uint64_t getOffset(const DefinedRegular &Sym) const; protected: SectionBase(Kind SectionKind, StringRef Name, uint64_t Flags, uint64_t Entsize, uint64_t Alignment, uint32_t Type, uint32_t Info, uint32_t Link) : Name(Name), SectionKind(SectionKind), Alignment(Alignment), Flags(Flags), Entsize(Entsize), Type(Type), Link(Link), Info(Info) { Live = false; Assigned = false; } }; // This corresponds to a section of an input file. class InputSectionBase : public SectionBase { public: static bool classof(const SectionBase *S); // The file this section is from. InputFile *File; ArrayRef Data; uint64_t getOffsetInFile() const; static InputSectionBase Discarded; InputSectionBase() : SectionBase(Regular, "", /*Flags*/ 0, /*Entsize*/ 0, /*Alignment*/ 0, /*Type*/ 0, /*Info*/ 0, /*Link*/ 0), Repl(this) { Live = false; Assigned = false; NumRelocations = 0; AreRelocsRela = false; } template InputSectionBase(ObjectFile *File, const typename ELFT::Shdr *Header, StringRef Name, Kind SectionKind); InputSectionBase(InputFile *File, uint64_t Flags, uint32_t Type, uint64_t Entsize, uint32_t Link, uint32_t Info, uint32_t Alignment, ArrayRef Data, StringRef Name, Kind SectionKind); - OutputSection *OutSec = nullptr; + // Input sections are part of an output section. Special sections + // like .eh_frame and merge sections are first combined into a + // synthetic section that is then added to an output section. In all + // cases this points one level up. + SectionBase *Parent = nullptr; + // Relocations that refer to this section. const void *FirstRelocation = nullptr; unsigned NumRelocations : 31; unsigned AreRelocsRela : 1; template ArrayRef rels() const { assert(!AreRelocsRela); return llvm::makeArrayRef( static_cast(FirstRelocation), NumRelocations); } template ArrayRef relas() const { assert(AreRelocsRela); return llvm::makeArrayRef( static_cast(FirstRelocation), NumRelocations); } // This pointer points to the "real" instance of this instance. // Usually Repl == this. However, if ICF merges two sections, // Repl pointer of one section points to another section. So, // if you need to get a pointer to this instance, do not use // this but instead this->Repl. InputSectionBase *Repl; // InputSections that are dependent on us (reverse dependency for GC) llvm::TinyPtrVector DependentSections; // Returns the size of this section (even if this is a common or BSS.) size_t getSize() const; template ObjectFile *getFile() const; template llvm::object::ELFFile getObj() const { return getFile()->getObj(); } - InputSectionBase *getLinkOrderDep() const; + InputSection *getLinkOrderDep() const; void uncompress(); // Returns a source location string. Used to construct an error message. template std::string getLocation(uint64_t Offset); template std::string getSrcMsg(uint64_t Offset); template std::string getObjMsg(uint64_t Offset); template void relocate(uint8_t *Buf, uint8_t *BufEnd); void relocateAlloc(uint8_t *Buf, uint8_t *BufEnd); template void relocateNonAlloc(uint8_t *Buf, uint8_t *BufEnd); std::vector Relocations; template llvm::ArrayRef getDataAs() const { size_t S = Data.size(); assert(S % sizeof(T) == 0); return llvm::makeArrayRef((const T *)Data.data(), S / sizeof(T)); } }; // SectionPiece represents a piece of splittable section contents. // We allocate a lot of these and binary search on them. This means that they // have to be as compact as possible, which is why we don't store the size (can // be found by looking at the next one) and put the hash in a side table. struct SectionPiece { SectionPiece(size_t Off, bool Live = false) : InputOff(Off), OutputOff(-1), Live(Live || !Config->GcSections) {} size_t InputOff; ssize_t OutputOff : 8 * sizeof(ssize_t) - 1; size_t Live : 1; }; static_assert(sizeof(SectionPiece) == 2 * sizeof(size_t), "SectionPiece is too big"); // This corresponds to a SHF_MERGE section of an input file. class MergeInputSection : public InputSectionBase { public: template MergeInputSection(ObjectFile *F, const typename ELFT::Shdr *Header, StringRef Name); static bool classof(const SectionBase *S); void splitIntoPieces(); // Mark the piece at a given offset live. Used by GC. void markLiveAt(uint64_t Offset) { assert(this->Flags & llvm::ELF::SHF_ALLOC); LiveOffsets.insert(Offset); } // Translate an offset in the input section to an offset // in the output section. uint64_t getOffset(uint64_t Offset) const; // Splittable sections are handled as a sequence of data // rather than a single large blob of data. std::vector Pieces; // Returns I'th piece's data. This function is very hot when // string merging is enabled, so we want to inline. LLVM_ATTRIBUTE_ALWAYS_INLINE llvm::CachedHashStringRef getData(size_t I) const { size_t Begin = Pieces[I].InputOff; size_t End; if (Pieces.size() - 1 == I) End = this->Data.size(); else End = Pieces[I + 1].InputOff; StringRef S = {(const char *)(this->Data.data() + Begin), End - Begin}; return {S, Hashes[I]}; } // Returns the SectionPiece at a given input section offset. SectionPiece *getSectionPiece(uint64_t Offset); const SectionPiece *getSectionPiece(uint64_t Offset) const; - // MergeInputSections are aggregated to a synthetic input sections, - // and then added to an OutputSection. This pointer points to a - // synthetic MergeSyntheticSection which this section belongs to. - MergeSyntheticSection *MergeSec = nullptr; + SyntheticSection *getParent() const; private: void splitStrings(ArrayRef A, size_t Size); void splitNonStrings(ArrayRef A, size_t Size); std::vector Hashes; mutable llvm::DenseMap OffsetMap; mutable llvm::once_flag InitOffsetMap; llvm::DenseSet LiveOffsets; }; struct EhSectionPiece : public SectionPiece { EhSectionPiece(size_t Off, InputSectionBase *ID, uint32_t Size, unsigned FirstRelocation) : SectionPiece(Off, false), ID(ID), Size(Size), FirstRelocation(FirstRelocation) {} InputSectionBase *ID; uint32_t Size; uint32_t size() const { return Size; } ArrayRef data() { return {ID->Data.data() + this->InputOff, Size}; } unsigned FirstRelocation; }; // This corresponds to a .eh_frame section of an input file. class EhInputSection : public InputSectionBase { public: template EhInputSection(ObjectFile *F, const typename ELFT::Shdr *Header, StringRef Name); static bool classof(const SectionBase *S); template void split(); template void split(ArrayRef Rels); // Splittable sections are handled as a sequence of data // rather than a single large blob of data. std::vector Pieces; - SyntheticSection *EHSec = nullptr; + + SyntheticSection *getParent() const; }; // This is a section that is added directly to an output section // instead of needing special combination via a synthetic section. This // includes all input sections with the exceptions of SHF_MERGE and // .eh_frame. It also includes the synthetic sections themselves. class InputSection : public InputSectionBase { public: InputSection(uint64_t Flags, uint32_t Type, uint32_t Alignment, ArrayRef Data, StringRef Name, Kind K = Regular); template InputSection(ObjectFile *F, const typename ELFT::Shdr *Header, StringRef Name); // Write this section to a mmap'ed file, assuming Buf is pointing to // beginning of the output section. template void writeTo(uint8_t *Buf); + + OutputSection *getParent() const; // The offset from beginning of the output sections this section was assigned // to. The writer sets a value. uint64_t OutSecOff = 0; static bool classof(const SectionBase *S); InputSectionBase *getRelocatedSection(); template void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef Rels); // Used by ICF. uint32_t Class[2] = {0, 0}; // Called by ICF to merge two input sections. void replace(InputSection *Other); private: template void copyRelocations(uint8_t *Buf, llvm::ArrayRef Rels); void copyShtGroup(uint8_t *Buf); }; // The list of all input sections. extern std::vector InputSections; } // namespace elf std::string toString(const elf::InputSectionBase *); } // namespace lld #endif Index: vendor/lld/dist/ELF/LinkerScript.cpp =================================================================== --- vendor/lld/dist/ELF/LinkerScript.cpp (revision 319468) +++ vendor/lld/dist/ELF/LinkerScript.cpp (revision 319469) @@ -1,1163 +1,1208 @@ //===- LinkerScript.cpp ---------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains the parser/evaluator of the linker script. // //===----------------------------------------------------------------------===// #include "LinkerScript.h" #include "Config.h" #include "InputSection.h" #include "Memory.h" #include "OutputSections.h" #include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Threads.h" #include "Writer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include #include #include #include #include #include #include #include using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; LinkerScript *elf::Script; uint64_t ExprValue::getValue() const { if (Sec) { - if (Sec->getOutputSection()) - return alignTo(Sec->getOffset(Val) + Sec->getOutputSection()->Addr, - Alignment); + if (OutputSection *OS = Sec->getOutputSection()) + return alignTo(Sec->getOffset(Val) + OS->Addr, Alignment); error("unable to evaluate expression: input section " + Sec->Name + " has no output section assigned"); } return alignTo(Val, Alignment); } uint64_t ExprValue::getSecAddr() const { if (Sec) return Sec->getOffset(0) + Sec->getOutputSection()->Addr; return 0; } template static SymbolBody *addRegular(SymbolAssignment *Cmd) { Symbol *Sym; uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; std::tie(Sym, std::ignore) = Symtab::X->insert( Cmd->Name, /*Type*/ 0, Visibility, /*CanOmitFromDynSym*/ false, /*File*/ nullptr); Sym->Binding = STB_GLOBAL; ExprValue Value = Cmd->Expression(); SectionBase *Sec = Value.isAbsolute() ? nullptr : Value.Sec; // We want to set symbol values early if we can. This allows us to use symbols // as variables in linker scripts. Doing so allows us to write expressions // like this: `alignment = 16; . = ALIGN(., alignment)` uint64_t SymValue = Value.isAbsolute() ? Value.getValue() : 0; replaceBody(Sym, Cmd->Name, /*IsLocal=*/false, Visibility, STT_NOTYPE, SymValue, 0, Sec, nullptr); return Sym->body(); } -OutputSection *LinkerScript::getOutputSection(const Twine &Loc, - StringRef Name) { - for (OutputSection *Sec : *OutputSections) - if (Sec->Name == Name) - return Sec; - - static OutputSection Dummy("", 0, 0); - if (ErrorOnMissingSection) - error(Loc + ": undefined section " + Name); - return &Dummy; +OutputSectionCommand * +LinkerScript::createOutputSectionCommand(StringRef Name, StringRef Location) { + OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name]; + OutputSectionCommand *Cmd; + if (CmdRef && CmdRef->Location.empty()) { + // There was a forward reference. + Cmd = CmdRef; + } else { + Cmd = make(Name); + if (!CmdRef) + CmdRef = Cmd; + } + Cmd->Location = Location; + return Cmd; } -// This function is essentially the same as getOutputSection(Name)->Size, -// but it won't print out an error message if a given section is not found. -// -// Linker script does not create an output section if its content is empty. -// We want to allow SIZEOF(.foo) where .foo is a section which happened to -// be empty. That is why this function is different from getOutputSection(). -uint64_t LinkerScript::getOutputSectionSize(StringRef Name) { - for (OutputSection *Sec : *OutputSections) - if (Sec->Name == Name) - return Sec->Size; - return 0; +OutputSectionCommand * +LinkerScript::getOrCreateOutputSectionCommand(StringRef Name) { + OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name]; + if (!CmdRef) + CmdRef = make(Name); + return CmdRef; } void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) { uint64_t Val = E().getValue(); if (Val < Dot) { if (InSec) error(Loc + ": unable to move location counter backward for: " + CurOutSec->Name); else error(Loc + ": unable to move location counter backward"); } Dot = Val; // Update to location counter means update to section size. if (InSec) CurOutSec->Size = Dot - CurOutSec->Addr; } // Sets value of a symbol. Two kinds of symbols are processed: synthetic // symbols, whose value is an offset from beginning of section and regular // symbols whose value is absolute. void LinkerScript::assignSymbol(SymbolAssignment *Cmd, bool InSec) { if (Cmd->Name == ".") { setDot(Cmd->Expression, Cmd->Location, InSec); return; } if (!Cmd->Sym) return; auto *Sym = cast(Cmd->Sym); ExprValue V = Cmd->Expression(); if (V.isAbsolute()) { Sym->Value = V.getValue(); } else { Sym->Section = V.Sec; if (Sym->Section->Flags & SHF_ALLOC) Sym->Value = alignTo(V.Val, V.Alignment); else Sym->Value = V.getValue(); } } static SymbolBody *findSymbol(StringRef S) { switch (Config->EKind) { case ELF32LEKind: return Symtab::X->find(S); case ELF32BEKind: return Symtab::X->find(S); case ELF64LEKind: return Symtab::X->find(S); case ELF64BEKind: return Symtab::X->find(S); default: llvm_unreachable("unknown Config->EKind"); } } static SymbolBody *addRegularSymbol(SymbolAssignment *Cmd) { switch (Config->EKind) { case ELF32LEKind: return addRegular(Cmd); case ELF32BEKind: return addRegular(Cmd); case ELF64LEKind: return addRegular(Cmd); case ELF64BEKind: return addRegular(Cmd); default: llvm_unreachable("unknown Config->EKind"); } } void LinkerScript::addSymbol(SymbolAssignment *Cmd) { if (Cmd->Name == ".") return; // If a symbol was in PROVIDE(), we need to define it only when // it is a referenced undefined symbol. SymbolBody *B = findSymbol(Cmd->Name); if (Cmd->Provide && (!B || B->isDefined())) return; Cmd->Sym = addRegularSymbol(Cmd); } bool SymbolAssignment::classof(const BaseCommand *C) { return C->Kind == AssignmentKind; } bool OutputSectionCommand::classof(const BaseCommand *C) { return C->Kind == OutputSectionKind; } // Fill [Buf, Buf + Size) with Filler. // This is used for linker script "=fillexp" command. static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) { size_t I = 0; for (; I + 4 < Size; I += 4) memcpy(Buf + I, &Filler, 4); memcpy(Buf + I, &Filler, Size - I); } bool InputSectionDescription::classof(const BaseCommand *C) { return C->Kind == InputSectionKind; } bool AssertCommand::classof(const BaseCommand *C) { return C->Kind == AssertKind; } bool BytesDataCommand::classof(const BaseCommand *C) { return C->Kind == BytesDataKind; } static StringRef basename(InputSectionBase *S) { if (S->File) return sys::path::filename(S->File->getName()); return ""; } bool LinkerScript::shouldKeep(InputSectionBase *S) { for (InputSectionDescription *ID : Opt.KeptSections) if (ID->FilePat.match(basename(S))) for (SectionPattern &P : ID->SectionPatterns) if (P.SectionPat.match(S->Name)) return true; return false; } // A helper function for the SORT() command. static std::function getComparator(SortSectionPolicy K) { switch (K) { case SortSectionPolicy::Alignment: return [](InputSectionBase *A, InputSectionBase *B) { // ">" is not a mistake. Sections with larger alignments are placed // before sections with smaller alignments in order to reduce the // amount of padding necessary. This is compatible with GNU. return A->Alignment > B->Alignment; }; case SortSectionPolicy::Name: return [](InputSectionBase *A, InputSectionBase *B) { return A->Name < B->Name; }; case SortSectionPolicy::Priority: return [](InputSectionBase *A, InputSectionBase *B) { return getPriority(A->Name) < getPriority(B->Name); }; default: llvm_unreachable("unknown sort policy"); } } // A helper function for the SORT() command. static bool matchConstraints(ArrayRef Sections, ConstraintKind Kind) { if (Kind == ConstraintKind::NoConstraint) return true; bool IsRW = llvm::any_of(Sections, [](InputSectionBase *Sec) { return static_cast(Sec)->Flags & SHF_WRITE; }); return (IsRW && Kind == ConstraintKind::ReadWrite) || (!IsRW && Kind == ConstraintKind::ReadOnly); } static void sortSections(InputSection **Begin, InputSection **End, SortSectionPolicy K) { if (K != SortSectionPolicy::Default && K != SortSectionPolicy::None) std::stable_sort(Begin, End, getComparator(K)); } // Compute and remember which sections the InputSectionDescription matches. std::vector LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { std::vector Ret; // Collects all sections that satisfy constraints of Cmd. for (const SectionPattern &Pat : Cmd->SectionPatterns) { size_t SizeBefore = Ret.size(); for (InputSectionBase *Sec : InputSections) { - if (!isa(Sec)) + if (Sec->Assigned) continue; - if (Sec->Assigned) + if (!Sec->Live) { + reportDiscarded(Sec); continue; + } // For -emit-relocs we have to ignore entries like // .rela.dyn : { *(.rela.data) } // which are common because they are in the default bfd script. if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) continue; StringRef Filename = basename(Sec); if (!Cmd->FilePat.match(Filename) || Pat.ExcludedFilePat.match(Filename) || !Pat.SectionPat.match(Sec->Name)) continue; Ret.push_back(cast(Sec)); Sec->Assigned = true; } // Sort sections as instructed by SORT-family commands and --sort-section // option. Because SORT-family commands can be nested at most two depth // (e.g. SORT_BY_NAME(SORT_BY_ALIGNMENT(.text.*))) and because the command // line option is respected even if a SORT command is given, the exact // behavior we have here is a bit complicated. Here are the rules. // // 1. If two SORT commands are given, --sort-section is ignored. // 2. If one SORT command is given, and if it is not SORT_NONE, // --sort-section is handled as an inner SORT command. // 3. If one SORT command is given, and if it is SORT_NONE, don't sort. // 4. If no SORT command is given, sort according to --sort-section. InputSection **Begin = Ret.data() + SizeBefore; InputSection **End = Ret.data() + Ret.size(); if (Pat.SortOuter != SortSectionPolicy::None) { if (Pat.SortInner == SortSectionPolicy::Default) sortSections(Begin, End, Config->SortSection); else sortSections(Begin, End, Pat.SortInner); sortSections(Begin, End, Pat.SortOuter); } } return Ret; } void LinkerScript::discard(ArrayRef V) { for (InputSectionBase *S : V) { S->Live = false; if (S == InX::ShStrTab) error("discarding .shstrtab section is not allowed"); discard(S->DependentSections); } } std::vector LinkerScript::createInputSectionList(OutputSectionCommand &OutCmd) { std::vector Ret; for (BaseCommand *Base : OutCmd.Commands) { auto *Cmd = dyn_cast(Base); if (!Cmd) continue; Cmd->Sections = computeInputSections(Cmd); Ret.insert(Ret.end(), Cmd->Sections.begin(), Cmd->Sections.end()); } return Ret; } void LinkerScript::processCommands(OutputSectionFactory &Factory) { // A symbol can be assigned before any section is mentioned in the linker // script. In an DSO, the symbol values are addresses, so the only important // section values are: // * SHN_UNDEF // * SHN_ABS // * Any value meaning a regular section. // To handle that, create a dummy aether section that fills the void before // the linker scripts switches to another section. It has an index of one // which will map to whatever the first actual section is. Aether = make("", 0, SHF_ALLOC); Aether->SectionIndex = 1; CurOutSec = Aether; Dot = 0; for (size_t I = 0; I < Opt.Commands.size(); ++I) { // Handle symbol assignments outside of any output section. if (auto *Cmd = dyn_cast(Opt.Commands[I])) { addSymbol(Cmd); continue; } if (auto *Cmd = dyn_cast(Opt.Commands[I])) { std::vector V = createInputSectionList(*Cmd); // The output section name `/DISCARD/' is special. // Any input section assigned to it is discarded. if (Cmd->Name == "/DISCARD/") { discard(V); continue; } // This is for ONLY_IF_RO and ONLY_IF_RW. An output section directive // ".foo : ONLY_IF_R[OW] { ... }" is handled only if all member input // sections satisfy a given constraint. If not, a directive is handled // as if it wasn't present from the beginning. // // Because we'll iterate over Commands many more times, the easiest // way to "make it as if it wasn't present" is to just remove it. if (!matchConstraints(V, Cmd->Constraint)) { for (InputSectionBase *S : V) S->Assigned = false; Opt.Commands.erase(Opt.Commands.begin() + I); --I; continue; } // A directive may contain symbol definitions like this: // ".foo : { ...; bar = .; }". Handle them. for (BaseCommand *Base : Cmd->Commands) if (auto *OutCmd = dyn_cast(Base)) addSymbol(OutCmd); // Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign // is given, input sections are aligned to that value, whether the // given value is larger or smaller than the original section alignment. if (Cmd->SubalignExpr) { uint32_t Subalign = Cmd->SubalignExpr().getValue(); for (InputSectionBase *S : V) S->Alignment = Subalign; } // Add input sections to an output section. for (InputSectionBase *S : V) Factory.addInputSec(S, Cmd->Name, Cmd->Sec); if (OutputSection *Sec = Cmd->Sec) { assert(Sec->SectionIndex == INT_MAX); Sec->SectionIndex = I; SecToCommand[Sec] = Cmd; } } } CurOutSec = nullptr; } void LinkerScript::fabricateDefaultCommands() { std::vector Commands; // Define start address uint64_t StartAddr = Config->ImageBase + elf::getHeaderSize(); // The Sections with -T
have been sorted in order of ascending // address. We must lower StartAddr if the lowest -T
as // calls to setDot() must be monotonically increasing. for (auto& KV : Config->SectionStartMap) StartAddr = std::min(StartAddr, KV.second); Commands.push_back( make(".", [=] { return StartAddr; }, "")); // For each OutputSection that needs a VA fabricate an OutputSectionCommand // with an InputSectionDescription describing the InputSections for (OutputSection *Sec : *OutputSections) { - auto *OSCmd = make(Sec->Name); + auto *OSCmd = createOutputSectionCommand(Sec->Name, ""); OSCmd->Sec = Sec; SecToCommand[Sec] = OSCmd; // Prefer user supplied address over additional alignment constraint auto I = Config->SectionStartMap.find(Sec->Name); if (I != Config->SectionStartMap.end()) Commands.push_back( make(".", [=] { return I->second; }, "")); else if (Sec->PageAlign) OSCmd->AddrExpr = [=] { return alignTo(Script->getDot(), Config->MaxPageSize); }; Commands.push_back(OSCmd); if (Sec->Sections.size()) { auto *ISD = make(""); OSCmd->Commands.push_back(ISD); for (InputSection *ISec : Sec->Sections) { ISD->Sections.push_back(ISec); ISec->Assigned = true; } } } // SECTIONS commands run before other non SECTIONS commands Commands.insert(Commands.end(), Opt.Commands.begin(), Opt.Commands.end()); Opt.Commands = std::move(Commands); } // Add sections that didn't match any sections command. void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) { for (InputSectionBase *S : InputSections) { - if (!S->Live || S->OutSec) + if (!S->Live || S->Parent) continue; StringRef Name = getOutputSectionName(S->Name); auto I = std::find_if( Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) { if (auto *Cmd = dyn_cast(Base)) return Cmd->Name == Name; return false; }); if (I == Opt.Commands.end()) { Factory.addInputSec(S, Name); } else { auto *Cmd = cast(*I); Factory.addInputSec(S, Name, Cmd->Sec); if (OutputSection *Sec = Cmd->Sec) { SecToCommand[Sec] = Cmd; unsigned Index = std::distance(Opt.Commands.begin(), I); assert(Sec->SectionIndex == INT_MAX || Sec->SectionIndex == Index); Sec->SectionIndex = Index; } auto *ISD = make(""); ISD->Sections.push_back(cast(S)); Cmd->Commands.push_back(ISD); } } } uint64_t LinkerScript::advance(uint64_t Size, unsigned Align) { bool IsTbss = (CurOutSec->Flags & SHF_TLS) && CurOutSec->Type == SHT_NOBITS; uint64_t Start = IsTbss ? Dot + ThreadBssOffset : Dot; Start = alignTo(Start, Align); uint64_t End = Start + Size; if (IsTbss) ThreadBssOffset = End - Dot; else Dot = End; return End; } void LinkerScript::output(InputSection *S) { uint64_t Pos = advance(S->getSize(), S->Alignment); S->OutSecOff = Pos - S->getSize() - CurOutSec->Addr; // Update output section size after adding each section. This is so that // SIZEOF works correctly in the case below: // .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) } CurOutSec->Size = Pos - CurOutSec->Addr; // If there is a memory region associated with this input section, then // place the section in that region and update the region index. if (CurMemRegion) { CurMemRegion->Offset += CurOutSec->Size; uint64_t CurSize = CurMemRegion->Offset - CurMemRegion->Origin; if (CurSize > CurMemRegion->Length) { uint64_t OverflowAmt = CurSize - CurMemRegion->Length; error("section '" + CurOutSec->Name + "' will not fit in region '" + CurMemRegion->Name + "': overflowed by " + Twine(OverflowAmt) + " bytes"); } } } void LinkerScript::switchTo(OutputSection *Sec) { if (CurOutSec == Sec) return; CurOutSec = Sec; CurOutSec->Addr = advance(0, CurOutSec->Alignment); // If neither AT nor AT> is specified for an allocatable section, the linker // will set the LMA such that the difference between VMA and LMA for the // section is the same as the preceding output section in the same region // https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html if (LMAOffset) CurOutSec->LMAOffset = LMAOffset(); } void LinkerScript::process(BaseCommand &Base) { // This handles the assignments to symbol or to the dot. if (auto *Cmd = dyn_cast(&Base)) { assignSymbol(Cmd, true); return; } // Handle BYTE(), SHORT(), LONG(), or QUAD(). if (auto *Cmd = dyn_cast(&Base)) { Cmd->Offset = Dot - CurOutSec->Addr; Dot += Cmd->Size; CurOutSec->Size = Dot - CurOutSec->Addr; return; } // Handle ASSERT(). if (auto *Cmd = dyn_cast(&Base)) { Cmd->Expression(); return; } // Handle a single input section description command. // It calculates and assigns the offsets for each section and also // updates the output section size. auto &Cmd = cast(Base); - for (InputSectionBase *Sec : Cmd.Sections) { + for (InputSection *Sec : Cmd.Sections) { // We tentatively added all synthetic sections at the beginning and removed // empty ones afterwards (because there is no way to know whether they were // going be empty or not other than actually running linker scripts.) // We need to ignore remains of empty sections. if (auto *S = dyn_cast(Sec)) if (S->empty()) continue; if (!Sec->Live) continue; - assert(CurOutSec == Sec->OutSec); - output(cast(Sec)); + assert(CurOutSec == Sec->getParent()); + output(Sec); } } // This function searches for a memory region to place the given output // section in. If found, a pointer to the appropriate memory region is // returned. Otherwise, a nullptr is returned. MemoryRegion *LinkerScript::findMemoryRegion(OutputSectionCommand *Cmd) { // If a memory region name was specified in the output section command, // then try to find that region first. if (!Cmd->MemoryRegionName.empty()) { auto It = Opt.MemoryRegions.find(Cmd->MemoryRegionName); if (It != Opt.MemoryRegions.end()) return &It->second; error("memory region '" + Cmd->MemoryRegionName + "' not declared"); return nullptr; } // If at least one memory region is defined, all sections must // belong to some memory region. Otherwise, we don't need to do // anything for memory regions. if (Opt.MemoryRegions.empty()) return nullptr; OutputSection *Sec = Cmd->Sec; // See if a region can be found by matching section flags. for (auto &Pair : Opt.MemoryRegions) { MemoryRegion &M = Pair.second; if ((M.Flags & Sec->Flags) && (M.NegFlags & Sec->Flags) == 0) return &M; } // Otherwise, no suitable region was found. if (Sec->Flags & SHF_ALLOC) error("no memory region specified for section '" + Sec->Name + "'"); return nullptr; } // This function assigns offsets to input sections and an output section // for a single sections command (e.g. ".text { *(.text); }"). void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) { OutputSection *Sec = Cmd->Sec; if (!Sec) return; if (Cmd->AddrExpr && (Sec->Flags & SHF_ALLOC)) setDot(Cmd->AddrExpr, Cmd->Location, false); if (Cmd->LMAExpr) { uint64_t D = Dot; LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; }; } CurMemRegion = Cmd->MemRegion; if (CurMemRegion) Dot = CurMemRegion->Offset; switchTo(Sec); // We do not support custom layout for compressed debug sectons. // At this point we already know their size and have compressed content. if (CurOutSec->Flags & SHF_COMPRESSED) return; for (BaseCommand *C : Cmd->Commands) process(*C); } void LinkerScript::removeEmptyCommands() { // It is common practice to use very generic linker scripts. So for any // given run some of the output sections in the script will be empty. // We could create corresponding empty output sections, but that would // clutter the output. // We instead remove trivially empty sections. The bfd linker seems even // more aggressive at removing them. auto Pos = std::remove_if( Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) { if (auto *Cmd = dyn_cast(Base)) return std::find(OutputSections->begin(), OutputSections->end(), Cmd->Sec) == OutputSections->end(); return false; }); Opt.Commands.erase(Pos, Opt.Commands.end()); } static bool isAllSectionDescription(const OutputSectionCommand &Cmd) { for (BaseCommand *Base : Cmd.Commands) if (!isa(*Base)) return false; return true; } void LinkerScript::adjustSectionsBeforeSorting() { // If the output section contains only symbol assignments, create a // corresponding output section. The bfd linker seems to only create them if // '.' is assigned to, but creating these section should not have any bad // consequeces and gives us a section to put the symbol in. uint64_t Flags = SHF_ALLOC; for (int I = 0, E = Opt.Commands.size(); I != E; ++I) { auto *Cmd = dyn_cast(Opt.Commands[I]); if (!Cmd) continue; if (OutputSection *Sec = Cmd->Sec) { Flags = Sec->Flags; continue; } if (isAllSectionDescription(*Cmd)) continue; auto *OutSec = make(Cmd->Name, SHT_PROGBITS, Flags); OutSec->SectionIndex = I; OutputSections->push_back(OutSec); Cmd->Sec = OutSec; SecToCommand[OutSec] = Cmd; } } void LinkerScript::adjustSectionsAfterSorting() { placeOrphanSections(); // Try and find an appropriate memory region to assign offsets in. for (BaseCommand *Base : Opt.Commands) { if (auto *Cmd = dyn_cast(Base)) { Cmd->MemRegion = findMemoryRegion(Cmd); // Handle align (e.g. ".foo : ALIGN(16) { ... }"). if (Cmd->AlignExpr) Cmd->Sec->updateAlignment(Cmd->AlignExpr().getValue()); } } // If output section command doesn't specify any segments, // and we haven't previously assigned any section to segment, // then we simply assign section to the very first load segment. // Below is an example of such linker script: // PHDRS { seg PT_LOAD; } // SECTIONS { .aaa : { *(.aaa) } } std::vector DefPhdrs; auto FirstPtLoad = std::find_if(Opt.PhdrsCommands.begin(), Opt.PhdrsCommands.end(), [](const PhdrsCommand &Cmd) { return Cmd.Type == PT_LOAD; }); if (FirstPtLoad != Opt.PhdrsCommands.end()) DefPhdrs.push_back(FirstPtLoad->Name); // Walk the commands and propagate the program headers to commands that don't // explicitly specify them. for (BaseCommand *Base : Opt.Commands) { auto *Cmd = dyn_cast(Base); if (!Cmd) continue; if (Cmd->Phdrs.empty()) Cmd->Phdrs = DefPhdrs; else DefPhdrs = Cmd->Phdrs; } removeEmptyCommands(); } // When placing orphan sections, we want to place them after symbol assignments // so that an orphan after // begin_foo = .; // foo : { *(foo) } // end_foo = .; // doesn't break the intended meaning of the begin/end symbols. // We don't want to go over sections since Writer::sortSections is the // one in charge of deciding the order of the sections. // We don't want to go over alignments, since doing so in // rx_sec : { *(rx_sec) } // . = ALIGN(0x1000); // /* The RW PT_LOAD starts here*/ // rw_sec : { *(rw_sec) } // would mean that the RW PT_LOAD would become unaligned. static bool shouldSkip(BaseCommand *Cmd) { if (isa(Cmd)) return false; if (auto *Assign = dyn_cast(Cmd)) return Assign->Name != "."; return true; } // Orphan sections are sections present in the input files which are // not explicitly placed into the output file by the linker script. // // When the control reaches this function, Opt.Commands contains // output section commands for non-orphan sections only. This function // adds new elements for orphan sections so that all sections are // explicitly handled by Opt.Commands. // // Writer::sortSections has already sorted output sections. // What we need to do is to scan OutputSections vector and // Opt.Commands in parallel to find orphan sections. If there is an // output section that doesn't have a corresponding entry in // Opt.Commands, we will insert a new entry to Opt.Commands. // // There is some ambiguity as to where exactly a new entry should be // inserted, because Opt.Commands contains not only output section // commands but also other types of commands such as symbol assignment // expressions. There's no correct answer here due to the lack of the // formal specification of the linker script. We use heuristics to // determine whether a new output command should be added before or // after another commands. For the details, look at shouldSkip // function. void LinkerScript::placeOrphanSections() { // The OutputSections are already in the correct order. // This loops creates or moves commands as needed so that they are in the // correct order. int CmdIndex = 0; // As a horrible special case, skip the first . assignment if it is before any // section. We do this because it is common to set a load address by starting // the script with ". = 0xabcd" and the expectation is that every section is // after that. auto FirstSectionOrDotAssignment = std::find_if(Opt.Commands.begin(), Opt.Commands.end(), [](BaseCommand *Cmd) { return !shouldSkip(Cmd); }); if (FirstSectionOrDotAssignment != Opt.Commands.end()) { CmdIndex = FirstSectionOrDotAssignment - Opt.Commands.begin(); if (isa(**FirstSectionOrDotAssignment)) ++CmdIndex; } for (OutputSection *Sec : *OutputSections) { StringRef Name = Sec->Name; // Find the last spot where we can insert a command and still get the // correct result. auto CmdIter = Opt.Commands.begin() + CmdIndex; auto E = Opt.Commands.end(); while (CmdIter != E && shouldSkip(*CmdIter)) { ++CmdIter; ++CmdIndex; } // If there is no command corresponding to this output section, // create one and put a InputSectionDescription in it so that both // representations agree on which input sections to use. OutputSectionCommand *Cmd = getCmd(Sec); if (!Cmd) { - Cmd = make(Name); + Cmd = createOutputSectionCommand(Name, ""); Opt.Commands.insert(CmdIter, Cmd); ++CmdIndex; Cmd->Sec = Sec; SecToCommand[Sec] = Cmd; auto *ISD = make(""); for (InputSection *IS : Sec->Sections) ISD->Sections.push_back(IS); Cmd->Commands.push_back(ISD); continue; } // Continue from where we found it. while (*CmdIter != Cmd) { ++CmdIter; ++CmdIndex; } ++CmdIndex; } } void LinkerScript::processNonSectionCommands() { for (BaseCommand *Base : Opt.Commands) { if (auto *Cmd = dyn_cast(Base)) assignSymbol(Cmd, false); else if (auto *Cmd = dyn_cast(Base)) Cmd->Expression(); } } // Do a last effort at synchronizing the linker script "AST" and the section // list. This is needed to account for last minute changes, like adding a // .ARM.exidx terminator and sorting SHF_LINK_ORDER sections. // // FIXME: We should instead create the "AST" earlier and the above changes would // be done directly in the "AST". // // This can only handle new sections being added and sections being reordered. void LinkerScript::synchronize() { for (BaseCommand *Base : Opt.Commands) { auto *Cmd = dyn_cast(Base); if (!Cmd) continue; ArrayRef Sections = Cmd->Sec->Sections; std::vector ScriptSections; DenseSet ScriptSectionsSet; for (BaseCommand *Base : Cmd->Commands) { auto *ISD = dyn_cast(Base); if (!ISD) continue; for (InputSection *&IS : ISD->Sections) { if (IS->Live) { ScriptSections.push_back(&IS); ScriptSectionsSet.insert(IS); } } } std::vector Missing; for (InputSection *IS : Sections) if (!ScriptSectionsSet.count(IS)) Missing.push_back(IS); if (!Missing.empty()) { auto ISD = make(""); ISD->Sections = Missing; Cmd->Commands.push_back(ISD); for (InputSection *&IS : ISD->Sections) if (IS->Live) ScriptSections.push_back(&IS); } assert(ScriptSections.size() == Sections.size()); for (int I = 0, N = Sections.size(); I < N; ++I) *ScriptSections[I] = Sections[I]; } } -static bool allocateHeaders(std::vector &Phdrs, - ArrayRef OutputSections, - uint64_t Min) { +static bool +allocateHeaders(std::vector &Phdrs, + ArrayRef OutputSectionCommands, + uint64_t Min) { auto FirstPTLoad = std::find_if(Phdrs.begin(), Phdrs.end(), [](const PhdrEntry &E) { return E.p_type == PT_LOAD; }); if (FirstPTLoad == Phdrs.end()) return false; uint64_t HeaderSize = getHeaderSize(); if (HeaderSize <= Min || Script->hasPhdrsCommands()) { Min = alignDown(Min - HeaderSize, Config->MaxPageSize); Out::ElfHeader->Addr = Min; Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size; return true; } assert(FirstPTLoad->First == Out::ElfHeader); OutputSection *ActualFirst = nullptr; - for (OutputSection *Sec : OutputSections) { + for (OutputSectionCommand *Cmd : OutputSectionCommands) { + OutputSection *Sec = Cmd->Sec; if (Sec->FirstInPtLoad == Out::ElfHeader) { ActualFirst = Sec; break; } } if (ActualFirst) { - for (OutputSection *Sec : OutputSections) + for (OutputSectionCommand *Cmd : OutputSectionCommands) { + OutputSection *Sec = Cmd->Sec; if (Sec->FirstInPtLoad == Out::ElfHeader) Sec->FirstInPtLoad = ActualFirst; + } FirstPTLoad->First = ActualFirst; } else { Phdrs.erase(FirstPTLoad); } auto PhdrI = std::find_if(Phdrs.begin(), Phdrs.end(), [](const PhdrEntry &E) { return E.p_type == PT_PHDR; }); if (PhdrI != Phdrs.end()) Phdrs.erase(PhdrI); return false; } -void LinkerScript::assignAddresses(std::vector &Phdrs) { +void LinkerScript::assignAddresses( + std::vector &Phdrs, + ArrayRef OutputSectionCommands) { // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = 0; ErrorOnMissingSection = true; switchTo(Aether); for (BaseCommand *Base : Opt.Commands) { if (auto *Cmd = dyn_cast(Base)) { assignSymbol(Cmd, false); continue; } if (auto *Cmd = dyn_cast(Base)) { Cmd->Expression(); continue; } auto *Cmd = cast(Base); assignOffsets(Cmd); } uint64_t MinVA = std::numeric_limits::max(); - for (OutputSection *Sec : *OutputSections) { + for (OutputSectionCommand *Cmd : OutputSectionCommands) { + OutputSection *Sec = Cmd->Sec; if (Sec->Flags & SHF_ALLOC) MinVA = std::min(MinVA, Sec->Addr); else Sec->Addr = 0; } - allocateHeaders(Phdrs, *OutputSections, MinVA); + allocateHeaders(Phdrs, OutputSectionCommands, MinVA); } // Creates program headers as instructed by PHDRS linker script command. std::vector LinkerScript::createPhdrs() { std::vector Ret; // Process PHDRS and FILEHDR keywords because they are not // real output sections and cannot be added in the following loop. for (const PhdrsCommand &Cmd : Opt.PhdrsCommands) { Ret.emplace_back(Cmd.Type, Cmd.Flags == UINT_MAX ? PF_R : Cmd.Flags); PhdrEntry &Phdr = Ret.back(); if (Cmd.HasFilehdr) Phdr.add(Out::ElfHeader); if (Cmd.HasPhdrs) Phdr.add(Out::ProgramHeaders); if (Cmd.LMAExpr) { Phdr.p_paddr = Cmd.LMAExpr().getValue(); Phdr.HasLMA = true; } } // Add output sections to program headers. for (OutputSection *Sec : *OutputSections) { if (!(Sec->Flags & SHF_ALLOC)) break; // Assign headers specified by linker script for (size_t Id : getPhdrIndices(Sec)) { Ret[Id].add(Sec); if (Opt.PhdrsCommands[Id].Flags == UINT_MAX) Ret[Id].p_flags |= Sec->getPhdrFlags(); } } return Ret; } bool LinkerScript::ignoreInterpSection() { // Ignore .interp section in case we have PHDRS specification // and PT_INTERP isn't listed. if (Opt.PhdrsCommands.empty()) return false; for (PhdrsCommand &Cmd : Opt.PhdrsCommands) if (Cmd.Type == PT_INTERP) return false; return true; } OutputSectionCommand *LinkerScript::getCmd(OutputSection *Sec) const { auto I = SecToCommand.find(Sec); if (I == SecToCommand.end()) return nullptr; return I->second; } uint32_t OutputSectionCommand::getFiller() { if (Filler) return *Filler; if (Sec->Flags & SHF_EXECINSTR) return Target->TrapInstr; return 0; } static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) { if (Size == 1) *Buf = Data; else if (Size == 2) write16(Buf, Data, Config->Endianness); else if (Size == 4) write32(Buf, Data, Config->Endianness); else if (Size == 8) write64(Buf, Data, Config->Endianness); else llvm_unreachable("unsupported Size argument"); } +// Compress section contents if this section contains debug info. +template void OutputSectionCommand::maybeCompress() { + typedef typename ELFT::Chdr Elf_Chdr; + + // Compress only DWARF debug sections. + if (!Config->CompressDebugSections || (Sec->Flags & SHF_ALLOC) || + !Name.startswith(".debug_")) + return; + + // Create a section header. + Sec->ZDebugHeader.resize(sizeof(Elf_Chdr)); + auto *Hdr = reinterpret_cast(Sec->ZDebugHeader.data()); + Hdr->ch_type = ELFCOMPRESS_ZLIB; + Hdr->ch_size = Sec->Size; + Hdr->ch_addralign = Sec->Alignment; + + // Write section contents to a temporary buffer and compress it. + std::vector Buf(Sec->Size); + writeTo(Buf.data()); + if (Error E = zlib::compress(toStringRef(Buf), Sec->CompressedData)) + fatal("compress failed: " + llvm::toString(std::move(E))); + + // Update section headers. + Sec->Size = sizeof(Elf_Chdr) + Sec->CompressedData.size(); + Sec->Flags |= SHF_COMPRESSED; +} + template void OutputSectionCommand::writeTo(uint8_t *Buf) { Sec->Loc = Buf; // We may have already rendered compressed content when using // -compress-debug-sections option. Write it together with header. if (!Sec->CompressedData.empty()) { memcpy(Buf, Sec->ZDebugHeader.data(), Sec->ZDebugHeader.size()); memcpy(Buf + Sec->ZDebugHeader.size(), Sec->CompressedData.data(), Sec->CompressedData.size()); return; } if (Sec->Type == SHT_NOBITS) return; // Write leading padding. - ArrayRef Sections = Sec->Sections; + std::vector Sections; + for (BaseCommand *Cmd : Commands) + if (auto *ISD = dyn_cast(Cmd)) + for (InputSection *IS : ISD->Sections) + if (IS->Live) + Sections.push_back(IS); uint32_t Filler = getFiller(); if (Filler) fill(Buf, Sections.empty() ? Sec->Size : Sections[0]->OutSecOff, Filler); parallelForEachN(0, Sections.size(), [=](size_t I) { InputSection *IS = Sections[I]; IS->writeTo(Buf); // Fill gaps between sections. if (Filler) { uint8_t *Start = Buf + IS->OutSecOff + IS->getSize(); uint8_t *End; if (I + 1 == Sections.size()) End = Buf + Sec->Size; else End = Buf + Sections[I + 1]->OutSecOff; fill(Start, End - Start, Filler); } }); // Linker scripts may have BYTE()-family commands with which you // can write arbitrary bytes to the output. Process them if any. for (BaseCommand *Base : Commands) if (auto *Data = dyn_cast(Base)) writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size); } bool LinkerScript::hasLMA(OutputSection *Sec) { if (OutputSectionCommand *Cmd = getCmd(Sec)) if (Cmd->LMAExpr) return true; return false; } ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) { if (S == ".") return {CurOutSec, Dot - CurOutSec->Addr}; if (SymbolBody *B = findSymbol(S)) { if (auto *D = dyn_cast(B)) return {D->Section, D->Value}; if (auto *C = dyn_cast(B)) return {InX::Common, C->Offset}; } error(Loc + ": symbol not found: " + S); return 0; } bool LinkerScript::isDefined(StringRef S) { return findSymbol(S) != nullptr; } // Returns indices of ELF headers containing specific section. Each index is a // zero based number of ELF header listed within PHDRS {} script block. std::vector LinkerScript::getPhdrIndices(OutputSection *Sec) { if (OutputSectionCommand *Cmd = getCmd(Sec)) { std::vector Ret; for (StringRef PhdrName : Cmd->Phdrs) Ret.push_back(getPhdrIndex(Cmd->Location, PhdrName)); return Ret; } return {}; } size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) { size_t I = 0; for (PhdrsCommand &Cmd : Opt.PhdrsCommands) { if (Cmd.Name == PhdrName) return I; ++I; } error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS"); return 0; } template void OutputSectionCommand::writeTo(uint8_t *Buf); template void OutputSectionCommand::writeTo(uint8_t *Buf); template void OutputSectionCommand::writeTo(uint8_t *Buf); template void OutputSectionCommand::writeTo(uint8_t *Buf); + +template void OutputSectionCommand::maybeCompress(); +template void OutputSectionCommand::maybeCompress(); +template void OutputSectionCommand::maybeCompress(); +template void OutputSectionCommand::maybeCompress(); Index: vendor/lld/dist/ELF/LinkerScript.h =================================================================== --- vendor/lld/dist/ELF/LinkerScript.h (revision 319468) +++ vendor/lld/dist/ELF/LinkerScript.h (revision 319469) @@ -1,294 +1,300 @@ //===- LinkerScript.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_LINKER_SCRIPT_H #define LLD_ELF_LINKER_SCRIPT_H #include "Config.h" #include "Strings.h" #include "Writer.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/MemoryBuffer.h" #include #include #include #include #include namespace lld { namespace elf { class DefinedCommon; class SymbolBody; class InputSectionBase; class InputSection; class OutputSection; class OutputSectionFactory; class InputSectionBase; class SectionBase; struct ExprValue { SectionBase *Sec; uint64_t Val; bool ForceAbsolute; uint64_t Alignment = 1; ExprValue(SectionBase *Sec, bool ForceAbsolute, uint64_t Val, uint64_t Alignment) : Sec(Sec), Val(Val), ForceAbsolute(ForceAbsolute), Alignment(Alignment) { } ExprValue(SectionBase *Sec, bool ForceAbsolute, uint64_t Val) : Sec(Sec), Val(Val), ForceAbsolute(ForceAbsolute) {} ExprValue(SectionBase *Sec, uint64_t Val) : ExprValue(Sec, false, Val) {} ExprValue(uint64_t Val) : ExprValue(nullptr, Val) {} bool isAbsolute() const { return ForceAbsolute || Sec == nullptr; } uint64_t getValue() const; uint64_t getSecAddr() const; }; // This represents an expression in the linker script. // ScriptParser::readExpr reads an expression and returns an Expr. // Later, we evaluate the expression by calling the function. typedef std::function Expr; // This enum is used to implement linker script SECTIONS command. // https://sourceware.org/binutils/docs/ld/SECTIONS.html#SECTIONS enum SectionsCommandKind { AssignmentKind, // . = expr or = expr OutputSectionKind, InputSectionKind, AssertKind, // ASSERT(expr) BytesDataKind // BYTE(expr), SHORT(expr), LONG(expr) or QUAD(expr) }; struct BaseCommand { BaseCommand(int K) : Kind(K) {} int Kind; }; // This represents ". = " or " = ". struct SymbolAssignment : BaseCommand { SymbolAssignment(StringRef Name, Expr E, std::string Loc) : BaseCommand(AssignmentKind), Name(Name), Expression(E), Location(Loc) {} static bool classof(const BaseCommand *C); // The LHS of an expression. Name is either a symbol name or ".". StringRef Name; SymbolBody *Sym = nullptr; // The RHS of an expression. Expr Expression; // Command attributes for PROVIDE, HIDDEN and PROVIDE_HIDDEN. bool Provide = false; bool Hidden = false; // Holds file name and line number for error reporting. std::string Location; }; // Linker scripts allow additional constraints to be put on ouput sections. // If an output section is marked as ONLY_IF_RO, the section is created // only if its input sections are read-only. Likewise, an output section // with ONLY_IF_RW is created if all input sections are RW. enum class ConstraintKind { NoConstraint, ReadOnly, ReadWrite }; // This struct is used to represent the location and size of regions of // target memory. Instances of the struct are created by parsing the // MEMORY command. struct MemoryRegion { std::string Name; uint64_t Origin; uint64_t Length; uint64_t Offset; uint32_t Flags; uint32_t NegFlags; }; struct OutputSectionCommand : BaseCommand { OutputSectionCommand(StringRef Name) : BaseCommand(OutputSectionKind), Name(Name) {} static bool classof(const BaseCommand *C); OutputSection *Sec = nullptr; MemoryRegion *MemRegion = nullptr; StringRef Name; Expr AddrExpr; Expr AlignExpr; Expr LMAExpr; Expr SubalignExpr; std::vector Commands; std::vector Phdrs; llvm::Optional Filler; ConstraintKind Constraint = ConstraintKind::NoConstraint; std::string Location; std::string MemoryRegionName; template void writeTo(uint8_t *Buf); + template void maybeCompress(); uint32_t getFiller(); }; // This struct represents one section match pattern in SECTIONS() command. // It can optionally have negative match pattern for EXCLUDED_FILE command. // Also it may be surrounded with SORT() command, so contains sorting rules. struct SectionPattern { SectionPattern(StringMatcher &&Pat1, StringMatcher &&Pat2) : ExcludedFilePat(Pat1), SectionPat(Pat2) {} StringMatcher ExcludedFilePat; StringMatcher SectionPat; SortSectionPolicy SortOuter; SortSectionPolicy SortInner; }; struct InputSectionDescription : BaseCommand { InputSectionDescription(StringRef FilePattern) : BaseCommand(InputSectionKind), FilePat(FilePattern) {} static bool classof(const BaseCommand *C); StringMatcher FilePat; // Input sections that matches at least one of SectionPatterns // will be associated with this InputSectionDescription. std::vector SectionPatterns; std::vector Sections; }; // Represents an ASSERT(). struct AssertCommand : BaseCommand { AssertCommand(Expr E) : BaseCommand(AssertKind), Expression(E) {} static bool classof(const BaseCommand *C); Expr Expression; }; // Represents BYTE(), SHORT(), LONG(), or QUAD(). struct BytesDataCommand : BaseCommand { BytesDataCommand(Expr E, unsigned Size) : BaseCommand(BytesDataKind), Expression(E), Size(Size) {} static bool classof(const BaseCommand *C); Expr Expression; unsigned Offset; unsigned Size; }; struct PhdrsCommand { StringRef Name; unsigned Type; bool HasFilehdr; bool HasPhdrs; unsigned Flags; Expr LMAExpr; }; // ScriptConfiguration holds linker script parse results. struct ScriptConfiguration { // Used to assign addresses to sections. std::vector Commands; // Used to assign sections to headers. std::vector PhdrsCommands; bool HasSections = false; // List of section patterns specified with KEEP commands. They will // be kept even if they are unused and --gc-sections is specified. std::vector KeptSections; // A map from memory region name to a memory region descriptor. llvm::DenseMap MemoryRegions; // A list of symbols referenced by the script. std::vector ReferencedSymbols; }; class LinkerScript final { llvm::DenseMap SecToCommand; + llvm::DenseMap NameToOutputSectionCommand; + void assignSymbol(SymbolAssignment *Cmd, bool InSec); void setDot(Expr E, const Twine &Loc, bool InSec); std::vector computeInputSections(const InputSectionDescription *); std::vector createInputSectionList(OutputSectionCommand &Cmd); std::vector getPhdrIndices(OutputSection *Sec); size_t getPhdrIndex(const Twine &Loc, StringRef PhdrName); MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd); void switchTo(OutputSection *Sec); uint64_t advance(uint64_t Size, unsigned Align); void output(InputSection *Sec); void process(BaseCommand &Base); OutputSection *Aether; - bool ErrorOnMissingSection = false; uint64_t Dot; uint64_t ThreadBssOffset = 0; std::function LMAOffset; OutputSection *CurOutSec = nullptr; MemoryRegion *CurMemRegion = nullptr; public: + bool ErrorOnMissingSection = false; + OutputSectionCommand *createOutputSectionCommand(StringRef Name, + StringRef Location); + OutputSectionCommand *getOrCreateOutputSectionCommand(StringRef Name); + OutputSectionCommand *getCmd(OutputSection *Sec) const; bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); } uint64_t getDot() { return Dot; } - OutputSection *getOutputSection(const Twine &Loc, StringRef S); - uint64_t getOutputSectionSize(StringRef S); void discard(ArrayRef V); ExprValue getSymbolValue(const Twine &Loc, StringRef S); bool isDefined(StringRef S); std::vector *OutputSections; void fabricateDefaultCommands(); void addOrphanSections(OutputSectionFactory &Factory); void removeEmptyCommands(); void adjustSectionsBeforeSorting(); void adjustSectionsAfterSorting(); std::vector createPhdrs(); bool ignoreInterpSection(); bool hasLMA(OutputSection *Sec); bool shouldKeep(InputSectionBase *S); void assignOffsets(OutputSectionCommand *Cmd); void placeOrphanSections(); void processNonSectionCommands(); void synchronize(); - void assignAddresses(std::vector &Phdrs); + void assignAddresses(std::vector &Phdrs, + ArrayRef OutputSectionCommands); void addSymbol(SymbolAssignment *Cmd); void processCommands(OutputSectionFactory &Factory); // Parsed linker script configurations are set to this struct. ScriptConfiguration Opt; }; extern LinkerScript *Script; } // end namespace elf } // end namespace lld #endif // LLD_ELF_LINKER_SCRIPT_H Index: vendor/lld/dist/ELF/MarkLive.cpp =================================================================== --- vendor/lld/dist/ELF/MarkLive.cpp (revision 319468) +++ vendor/lld/dist/ELF/MarkLive.cpp (revision 319469) @@ -1,265 +1,266 @@ //===- MarkLive.cpp -------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements --gc-sections, which is a feature to remove unused // sections from output. Unused sections are sections that are not reachable // from known GC-root symbols or sections. Naturally the feature is // implemented as a mark-sweep garbage collector. // // Here's how it works. Each InputSectionBase has a "Live" bit. The bit is off // by default. Starting with GC-root symbols or sections, markLive function // defined in this file visits all reachable sections to set their Live // bits. Writer will then ignore sections whose Live bits are off, so that // such sections are not included into output. // //===----------------------------------------------------------------------===// #include "InputSection.h" #include "LinkerScript.h" #include "Memory.h" #include "OutputSections.h" #include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "Target.h" #include "Writer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Object/ELF.h" #include #include using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; namespace { // A resolved relocation. The Sec and Offset fields are set if the relocation // was resolved to an offset within a section. struct ResolvedReloc { InputSectionBase *Sec; uint64_t Offset; }; } // end anonymous namespace template static typename ELFT::uint getAddend(InputSectionBase &Sec, const typename ELFT::Rel &Rel) { return Target->getImplicitAddend(Sec.Data.begin() + Rel.r_offset, Rel.getType(Config->IsMips64EL)); } template static typename ELFT::uint getAddend(InputSectionBase &Sec, const typename ELFT::Rela &Rel) { return Rel.r_addend; } // There are normally few input sections whose names are valid C // identifiers, so we just store a std::vector instead of a multimap. static DenseMap> CNamedSections; template static void resolveReloc(InputSectionBase &Sec, RelT &Rel, std::function Fn) { SymbolBody &B = Sec.getFile()->getRelocTargetSym(Rel); if (auto *D = dyn_cast(&B)) { if (!D->Section) return; typename ELFT::uint Offset = D->Value; if (D->isSection()) Offset += getAddend(Sec, Rel); Fn({cast(D->Section)->Repl, Offset}); } else if (auto *U = dyn_cast(&B)) { for (InputSectionBase *Sec : CNamedSections.lookup(U->getName())) Fn({Sec, 0}); } } // Calls Fn for each section that Sec refers to via relocations. template static void forEachSuccessor(InputSection &Sec, std::function Fn) { if (Sec.AreRelocsRela) { for (const typename ELFT::Rela &Rel : Sec.template relas()) resolveReloc(Sec, Rel, Fn); } else { for (const typename ELFT::Rel &Rel : Sec.template rels()) resolveReloc(Sec, Rel, Fn); } for (InputSectionBase *IS : Sec.DependentSections) Fn({IS, 0}); } // The .eh_frame section is an unfortunate special case. // The section is divided in CIEs and FDEs and the relocations it can have are // * CIEs can refer to a personality function. // * FDEs can refer to a LSDA // * FDEs refer to the function they contain information about // The last kind of relocation cannot keep the referred section alive, or they // would keep everything alive in a common object file. In fact, each FDE is // alive if the section it refers to is alive. // To keep things simple, in here we just ignore the last relocation kind. The // other two keep the referred section alive. // // A possible improvement would be to fully process .eh_frame in the middle of // the gc pass. With that we would be able to also gc some sections holding // LSDAs and personality functions if we found that they were unused. template static void scanEhFrameSection(EhInputSection &EH, ArrayRef Rels, std::function Enqueue) { const endianness E = ELFT::TargetEndianness; for (unsigned I = 0, N = EH.Pieces.size(); I < N; ++I) { EhSectionPiece &Piece = EH.Pieces[I]; unsigned FirstRelI = Piece.FirstRelocation; if (FirstRelI == (unsigned)-1) continue; if (read32(Piece.data().data() + 4) == 0) { // This is a CIE, we only need to worry about the first relocation. It is // known to point to the personality function. resolveReloc(EH, Rels[FirstRelI], Enqueue); continue; } // This is a FDE. The relocations point to the described function or to // a LSDA. We only need to keep the LSDA alive, so ignore anything that // points to executable sections. typename ELFT::uint PieceEnd = Piece.InputOff + Piece.size(); for (unsigned I2 = FirstRelI, N2 = Rels.size(); I2 < N2; ++I2) { const RelTy &Rel = Rels[I2]; if (Rel.r_offset >= PieceEnd) break; resolveReloc(EH, Rels[I2], [&](ResolvedReloc R) { if (!R.Sec || R.Sec == &InputSection::Discarded) return; if (R.Sec->Flags & SHF_EXECINSTR) return; Enqueue({R.Sec, 0}); }); } } } template static void scanEhFrameSection(EhInputSection &EH, std::function Enqueue) { if (!EH.NumRelocations) return; // Unfortunately we need to split .eh_frame early since some relocations in // .eh_frame keep other section alive and some don't. EH.split(); if (EH.AreRelocsRela) scanEhFrameSection(EH, EH.template relas(), Enqueue); else scanEhFrameSection(EH, EH.template rels(), Enqueue); } // We do not garbage-collect two types of sections: // 1) Sections used by the loader (.init, .fini, .ctors, .dtors or .jcr) // 2) Non-allocatable sections which typically contain debugging information template static bool isReserved(InputSectionBase *Sec) { switch (Sec->Type) { case SHT_FINI_ARRAY: case SHT_INIT_ARRAY: case SHT_NOTE: case SHT_PREINIT_ARRAY: return true; default: if (!(Sec->Flags & SHF_ALLOC)) return true; StringRef S = Sec->Name; return S.startswith(".ctors") || S.startswith(".dtors") || S.startswith(".init") || S.startswith(".fini") || S.startswith(".jcr"); } } // This is the main function of the garbage collector. // Starting from GC-root sections, this function visits all reachable // sections to set their "Live" bits. template void elf::markLive() { SmallVector Q; CNamedSections.clear(); auto Enqueue = [&](ResolvedReloc R) { // Skip over discarded sections. This in theory shouldn't happen, because // the ELF spec doesn't allow a relocation to point to a deduplicated // COMDAT section directly. Unfortunately this happens in practice (e.g. // .eh_frame) so we need to add a check. if (R.Sec == &InputSection::Discarded) return; // We don't gc non alloc sections. if (!(R.Sec->Flags & SHF_ALLOC)) return; // Usually, a whole section is marked as live or dead, but in mergeable // (splittable) sections, each piece of data has independent liveness bit. // So we explicitly tell it which offset is in use. if (auto *MS = dyn_cast(R.Sec)) MS->markLiveAt(R.Offset); if (R.Sec->Live) return; R.Sec->Live = true; // Add input section to the queue. if (InputSection *S = dyn_cast(R.Sec)) Q.push_back(S); }; auto MarkSymbol = [&](const SymbolBody *Sym) { if (auto *D = dyn_cast_or_null(Sym)) - Enqueue({cast(D->Section), D->Value}); + if (auto *IS = cast_or_null(D->Section)) + Enqueue({IS, D->Value}); }; // Add GC root symbols. MarkSymbol(Symtab::X->find(Config->Entry)); MarkSymbol(Symtab::X->find(Config->Init)); MarkSymbol(Symtab::X->find(Config->Fini)); for (StringRef S : Config->Undefined) MarkSymbol(Symtab::X->find(S)); // Preserve externally-visible symbols if the symbols defined by this // file can interrupt other ELF file's symbols at runtime. for (const Symbol *S : Symtab::X->getSymbols()) if (S->includeInDynsym()) MarkSymbol(S->body()); // Preserve special sections and those which are specified in linker // script KEEP command. for (InputSectionBase *Sec : InputSections) { // .eh_frame is always marked as live now, but also it can reference to // sections that contain personality. We preserve all non-text sections // referred by .eh_frame here. if (auto *EH = dyn_cast_or_null(Sec)) scanEhFrameSection(*EH, Enqueue); if (Sec->Flags & SHF_LINK_ORDER) continue; if (isReserved(Sec) || Script->shouldKeep(Sec)) Enqueue({Sec, 0}); else if (isValidCIdentifier(Sec->Name)) { CNamedSections[Saver.save("__start_" + Sec->Name)].push_back(Sec); CNamedSections[Saver.save("__end_" + Sec->Name)].push_back(Sec); } } // Mark all reachable sections. while (!Q.empty()) forEachSuccessor(*Q.pop_back_val(), Enqueue); } template void elf::markLive(); template void elf::markLive(); template void elf::markLive(); template void elf::markLive(); Index: vendor/lld/dist/ELF/OutputSections.cpp =================================================================== --- vendor/lld/dist/ELF/OutputSections.cpp (revision 319468) +++ vendor/lld/dist/ELF/OutputSections.cpp (revision 319469) @@ -1,444 +1,411 @@ //===- OutputSections.cpp -------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "OutputSections.h" #include "Config.h" #include "LinkerScript.h" #include "Memory.h" #include "Strings.h" #include "SymbolTable.h" #include "SyntheticSections.h" #include "Target.h" #include "Threads.h" -#include "llvm/Support/Compression.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/SHA1.h" using namespace llvm; using namespace llvm::dwarf; using namespace llvm::object; using namespace llvm::support::endian; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; uint8_t Out::First; OutputSection *Out::Opd; uint8_t *Out::OpdBuf; PhdrEntry *Out::TlsPhdr; OutputSection *Out::DebugInfo; OutputSection *Out::ElfHeader; OutputSection *Out::ProgramHeaders; OutputSection *Out::PreinitArray; OutputSection *Out::InitArray; OutputSection *Out::FiniArray; uint32_t OutputSection::getPhdrFlags() const { uint32_t Ret = PF_R; if (Flags & SHF_WRITE) Ret |= PF_W; if (Flags & SHF_EXECINSTR) Ret |= PF_X; return Ret; } template void OutputSection::writeHeaderTo(typename ELFT::Shdr *Shdr) { Shdr->sh_entsize = Entsize; Shdr->sh_addralign = Alignment; Shdr->sh_type = Type; Shdr->sh_offset = Offset; Shdr->sh_flags = Flags; Shdr->sh_info = Info; Shdr->sh_link = Link; Shdr->sh_addr = Addr; Shdr->sh_size = Size; Shdr->sh_name = ShName; } OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags) : SectionBase(Output, Name, Flags, /*Entsize*/ 0, /*Alignment*/ 1, Type, /*Info*/ 0, /*Link*/ 0), SectionIndex(INT_MAX) {} static bool compareByFilePosition(InputSection *A, InputSection *B) { // Synthetic doesn't have link order dependecy, stable_sort will keep it last if (A->kind() == InputSectionBase::Synthetic || B->kind() == InputSectionBase::Synthetic) return false; - auto *LA = cast(A->getLinkOrderDep()); - auto *LB = cast(B->getLinkOrderDep()); - OutputSection *AOut = LA->OutSec; - OutputSection *BOut = LB->OutSec; + InputSection *LA = A->getLinkOrderDep(); + InputSection *LB = B->getLinkOrderDep(); + OutputSection *AOut = LA->getParent(); + OutputSection *BOut = LB->getParent(); if (AOut != BOut) return AOut->SectionIndex < BOut->SectionIndex; return LA->OutSecOff < LB->OutSecOff; } -// Compress section contents if this section contains debug info. -template void OutputSection::maybeCompress() { - typedef typename ELFT::Chdr Elf_Chdr; - - // Compress only DWARF debug sections. - if (!Config->CompressDebugSections || (Flags & SHF_ALLOC) || - !Name.startswith(".debug_")) - return; - - // Create a section header. - ZDebugHeader.resize(sizeof(Elf_Chdr)); - auto *Hdr = reinterpret_cast(ZDebugHeader.data()); - Hdr->ch_type = ELFCOMPRESS_ZLIB; - Hdr->ch_size = Size; - Hdr->ch_addralign = Alignment; - - // Write section contents to a temporary buffer and compress it. - std::vector Buf(Size); - Script->getCmd(this)->writeTo(Buf.data()); - if (Error E = zlib::compress(toStringRef(Buf), CompressedData)) - fatal("compress failed: " + llvm::toString(std::move(E))); - - // Update section headers. - Size = sizeof(Elf_Chdr) + CompressedData.size(); - Flags |= SHF_COMPRESSED; -} - template static void finalizeShtGroup(OutputSection *Sec) { // sh_link field for SHT_GROUP sections should contain the section index of // the symbol table. - Sec->Link = InX::SymTab->OutSec->SectionIndex; + Sec->Link = InX::SymTab->getParent()->SectionIndex; // sh_info then contain index of an entry in symbol table section which // provides signature of the section group. elf::ObjectFile *Obj = Sec->Sections[0]->getFile(); assert(Config->Relocatable && Sec->Sections.size() == 1); ArrayRef Symbols = Obj->getSymbols(); Sec->Info = InX::SymTab->getSymbolIndex(Symbols[Sec->Sections[0]->Info - 1]); } template void OutputSection::finalize() { if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) { std::sort(Sections.begin(), Sections.end(), compareByFilePosition); assignOffsets(); // We must preserve the link order dependency of sections with the // SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We // need to translate the InputSection sh_link to the OutputSection sh_link, // all InputSections in the OutputSection have the same dependency. if (auto *D = this->Sections.front()->getLinkOrderDep()) - this->Link = D->OutSec->SectionIndex; + this->Link = D->getParent()->SectionIndex; } uint32_t Type = this->Type; if (Type == SHT_GROUP) { finalizeShtGroup(this); return; } if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL)) return; InputSection *First = Sections[0]; if (isa(First)) return; - this->Link = InX::SymTab->OutSec->SectionIndex; + this->Link = InX::SymTab->getParent()->SectionIndex; // sh_info for SHT_REL[A] sections should contain the section header index of // the section to which the relocation applies. InputSectionBase *S = First->getRelocatedSection(); - this->Info = S->OutSec->SectionIndex; + Info = S->getOutputSection()->SectionIndex; } static uint64_t updateOffset(uint64_t Off, InputSection *S) { Off = alignTo(Off, S->Alignment); S->OutSecOff = Off; return Off + S->getSize(); } void OutputSection::addSection(InputSection *S) { assert(S->Live); Sections.push_back(S); - S->OutSec = this; + S->Parent = this; this->updateAlignment(S->Alignment); // The actual offsets will be computed by assignAddresses. For now, use // crude approximation so that it is at least easy for other code to know the // section order. It is also used to calculate the output section size early // for compressed debug sections. this->Size = updateOffset(Size, S); // If this section contains a table of fixed-size entries, sh_entsize // holds the element size. Consequently, if this contains two or more // input sections, all of them must have the same sh_entsize. However, // you can put different types of input sections into one output // sectin by using linker scripts. I don't know what to do here. // Probably we sholuld handle that as an error. But for now we just // pick the largest sh_entsize. this->Entsize = std::max(this->Entsize, S->Entsize); } // This function is called after we sort input sections // and scan relocations to setup sections' offsets. void OutputSection::assignOffsets() { uint64_t Off = 0; for (InputSection *S : Sections) Off = updateOffset(Off, S); this->Size = Off; } void OutputSection::sort(std::function Order) { typedef std::pair Pair; auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; }; std::vector V; for (InputSection *S : Sections) V.push_back({Order(S), S}); std::stable_sort(V.begin(), V.end(), Comp); Sections.clear(); for (Pair &P : V) Sections.push_back(P.second); } // Sorts input sections by section name suffixes, so that .foo.N comes // before .foo.M if N < M. Used to sort .{init,fini}_array.N sections. // We want to keep the original order if the priorities are the same // because the compiler keeps the original initialization order in a // translation unit and we need to respect that. // For more detail, read the section of the GCC's manual about init_priority. void OutputSection::sortInitFini() { // Sort sections by priority. sort([](InputSectionBase *S) { return getPriority(S->Name); }); } // Returns true if S matches /Filename.?\.o$/. static bool isCrtBeginEnd(StringRef S, StringRef Filename) { if (!S.endswith(".o")) return false; S = S.drop_back(2); if (S.endswith(Filename)) return true; return !S.empty() && S.drop_back().endswith(Filename); } static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); } static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); } // .ctors and .dtors are sorted by this priority from highest to lowest. // // 1. The section was contained in crtbegin (crtbegin contains // some sentinel value in its .ctors and .dtors so that the runtime // can find the beginning of the sections.) // // 2. The section has an optional priority value in the form of ".ctors.N" // or ".dtors.N" where N is a number. Unlike .{init,fini}_array, // they are compared as string rather than number. // // 3. The section is just ".ctors" or ".dtors". // // 4. The section was contained in crtend, which contains an end marker. // // In an ideal world, we don't need this function because .init_array and // .ctors are duplicate features (and .init_array is newer.) However, there // are too many real-world use cases of .ctors, so we had no choice to // support that with this rather ad-hoc semantics. static bool compCtors(const InputSection *A, const InputSection *B) { bool BeginA = isCrtbegin(A->File->getName()); bool BeginB = isCrtbegin(B->File->getName()); if (BeginA != BeginB) return BeginA; bool EndA = isCrtend(A->File->getName()); bool EndB = isCrtend(B->File->getName()); if (EndA != EndB) return EndB; StringRef X = A->Name; StringRef Y = B->Name; assert(X.startswith(".ctors") || X.startswith(".dtors")); assert(Y.startswith(".ctors") || Y.startswith(".dtors")); X = X.substr(6); Y = Y.substr(6); if (X.empty() && Y.empty()) return false; return X < Y; } // Sorts input sections by the special rules for .ctors and .dtors. // Unfortunately, the rules are different from the one for .{init,fini}_array. // Read the comment above. void OutputSection::sortCtorsDtors() { std::stable_sort(Sections.begin(), Sections.end(), compCtors); } static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) { // The ELF spec just says // ---------------------------------------------------------------- // In the first phase, input sections that match in name, type and // attribute flags should be concatenated into single sections. // ---------------------------------------------------------------- // // However, it is clear that at least some flags have to be ignored for // section merging. At the very least SHF_GROUP and SHF_COMPRESSED have to be // ignored. We should not have two output .text sections just because one was // in a group and another was not for example. // // It also seems that that wording was a late addition and didn't get the // necessary scrutiny. // // Merging sections with different flags is expected by some users. One // reason is that if one file has // // int *const bar __attribute__((section(".foo"))) = (int *)0; // // gcc with -fPIC will produce a read only .foo section. But if another // file has // // int zed; // int *const bar __attribute__((section(".foo"))) = (int *)&zed; // // gcc with -fPIC will produce a read write section. // // Last but not least, when using linker script the merge rules are forced by // the script. Unfortunately, linker scripts are name based. This means that // expressions like *(.foo*) can refer to multiple input sections with // different flags. We cannot put them in different output sections or we // would produce wrong results for // // start = .; *(.foo.*) end = .; *(.bar) // // and a mapping of .foo1 and .bar1 to one section and .foo2 and .bar2 to // another. The problem is that there is no way to layout those output // sections such that the .foo sections are the only thing between the start // and end symbols. // // Given the above issues, we instead merge sections by name and error on // incompatible types and flags. uint32_t Alignment = 0; uint64_t Flags = 0; if (Config->Relocatable && (C->Flags & SHF_MERGE)) { Alignment = std::max(C->Alignment, C->Entsize); Flags = C->Flags & (SHF_MERGE | SHF_STRINGS); } return SectionKey{OutsecName, Flags, Alignment}; } OutputSectionFactory::OutputSectionFactory( std::vector &OutputSections) : OutputSections(OutputSections) {} static uint64_t getIncompatibleFlags(uint64_t Flags) { return Flags & (SHF_ALLOC | SHF_TLS); } // We allow sections of types listed below to merged into a // single progbits section. This is typically done by linker // scripts. Merging nobits and progbits will force disk space // to be allocated for nobits sections. Other ones don't require // any special treatment on top of progbits, so there doesn't // seem to be a harm in merging them. static bool canMergeToProgbits(unsigned Type) { return Type == SHT_NOBITS || Type == SHT_PROGBITS || Type == SHT_INIT_ARRAY || Type == SHT_PREINIT_ARRAY || Type == SHT_FINI_ARRAY || Type == SHT_NOTE; } -static void reportDiscarded(InputSectionBase *IS) { +void elf::reportDiscarded(InputSectionBase *IS) { if (!Config->PrintGcSections) return; message("removing unused section from '" + IS->Name + "' in file '" + IS->File->getName()); } void OutputSectionFactory::addInputSec(InputSectionBase *IS, StringRef OutsecName) { SectionKey Key = createKey(IS, OutsecName); OutputSection *&Sec = Map[Key]; return addInputSec(IS, OutsecName, Sec); } void OutputSectionFactory::addInputSec(InputSectionBase *IS, StringRef OutsecName, OutputSection *&Sec) { if (!IS->Live) { reportDiscarded(IS); return; } uint64_t Flags = IS->Flags; if (!Config->Relocatable) Flags &= ~(uint64_t)SHF_GROUP; if (Sec) { if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags)) error("incompatible section flags for " + Sec->Name + "\n>>> " + toString(IS) + ": 0x" + utohexstr(IS->Flags) + "\n>>> output section " + Sec->Name + ": 0x" + utohexstr(Sec->Flags)); if (Sec->Type != IS->Type) { if (canMergeToProgbits(Sec->Type) && canMergeToProgbits(IS->Type)) Sec->Type = SHT_PROGBITS; else error("section type mismatch for " + IS->Name + "\n>>> " + toString(IS) + ": " + getELFSectionTypeName(Config->EMachine, IS->Type) + "\n>>> output section " + Sec->Name + ": " + getELFSectionTypeName(Config->EMachine, Sec->Type)); } Sec->Flags |= Flags; } else { Sec = make(OutsecName, IS->Type, Flags); OutputSections.push_back(Sec); } Sec->addSection(cast(IS)); } OutputSectionFactory::~OutputSectionFactory() {} SectionKey DenseMapInfo::getEmptyKey() { return SectionKey{DenseMapInfo::getEmptyKey(), 0, 0}; } SectionKey DenseMapInfo::getTombstoneKey() { return SectionKey{DenseMapInfo::getTombstoneKey(), 0, 0}; } unsigned DenseMapInfo::getHashValue(const SectionKey &Val) { return hash_combine(Val.Name, Val.Flags, Val.Alignment); } bool DenseMapInfo::isEqual(const SectionKey &LHS, const SectionKey &RHS) { return DenseMapInfo::isEqual(LHS.Name, RHS.Name) && LHS.Flags == RHS.Flags && LHS.Alignment == RHS.Alignment; } uint64_t elf::getHeaderSize() { if (Config->OFormatBinary) return 0; return Out::ElfHeader->Size + Out::ProgramHeaders->Size; } template void OutputSection::writeHeaderTo(ELF32LE::Shdr *Shdr); template void OutputSection::writeHeaderTo(ELF32BE::Shdr *Shdr); template void OutputSection::writeHeaderTo(ELF64LE::Shdr *Shdr); template void OutputSection::writeHeaderTo(ELF64BE::Shdr *Shdr); template void OutputSection::finalize(); template void OutputSection::finalize(); template void OutputSection::finalize(); template void OutputSection::finalize(); - -template void OutputSection::maybeCompress(); -template void OutputSection::maybeCompress(); -template void OutputSection::maybeCompress(); -template void OutputSection::maybeCompress(); Index: vendor/lld/dist/ELF/OutputSections.h =================================================================== --- vendor/lld/dist/ELF/OutputSections.h (revision 319468) +++ vendor/lld/dist/ELF/OutputSections.h (revision 319469) @@ -1,157 +1,157 @@ //===- OutputSections.h -----------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_ELF_OUTPUT_SECTIONS_H #define LLD_ELF_OUTPUT_SECTIONS_H #include "Config.h" #include "InputSection.h" #include "Relocations.h" #include "lld/Core/LLVM.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELF.h" namespace lld { namespace elf { struct PhdrEntry; class SymbolBody; struct EhSectionPiece; class EhInputSection; class InputSection; class InputSectionBase; class MergeInputSection; class OutputSection; template class ObjectFile; template class SharedFile; class SharedSymbol; class DefinedRegular; // This represents a section in an output file. // It is composed of multiple InputSections. // The writer creates multiple OutputSections and assign them unique, // non-overlapping file offsets and VAs. class OutputSection final : public SectionBase { public: OutputSection(StringRef Name, uint32_t Type, uint64_t Flags); static bool classof(const SectionBase *S) { return S->kind() == SectionBase::Output; } uint64_t getLMA() const { return Addr + LMAOffset; } template void writeHeaderTo(typename ELFT::Shdr *SHdr); unsigned SectionIndex; unsigned SortRank; uint32_t getPhdrFlags() const; void updateAlignment(uint32_t Val) { if (Val > Alignment) Alignment = Val; } // If true, this section will be page aligned on disk. // Typically the first section of each PT_LOAD segment has this flag. bool PageAlign = false; // Pointer to the first section in PT_LOAD segment, which this section // also resides in. This field is used to correctly compute file offset // of a section. When two sections share the same load segment, difference // between their file offsets should be equal to difference between their // virtual addresses. To compute some section offset we use the following // formula: Off = Off_first + VA - VA_first. OutputSection *FirstInPtLoad = nullptr; // The following fields correspond to Elf_Shdr members. uint64_t Size = 0; uint64_t Offset = 0; uint64_t LMAOffset = 0; uint64_t Addr = 0; uint32_t ShName = 0; void addSection(InputSection *S); void sort(std::function Order); void sortInitFini(); void sortCtorsDtors(); template void finalize(); - template void maybeCompress(); void assignOffsets(); std::vector Sections; // Used for implementation of --compress-debug-sections option. std::vector ZDebugHeader; llvm::SmallVector CompressedData; // Location in the output buffer. uint8_t *Loc = nullptr; }; // All output sections that are handled by the linker specially are // globally accessible. Writer initializes them, so don't use them // until Writer is initialized. struct Out { static uint8_t First; static OutputSection *Opd; static uint8_t *OpdBuf; static PhdrEntry *TlsPhdr; static OutputSection *DebugInfo; static OutputSection *ElfHeader; static OutputSection *ProgramHeaders; static OutputSection *PreinitArray; static OutputSection *InitArray; static OutputSection *FiniArray; }; struct SectionKey { StringRef Name; uint64_t Flags; uint32_t Alignment; }; } } namespace llvm { template <> struct DenseMapInfo { static lld::elf::SectionKey getEmptyKey(); static lld::elf::SectionKey getTombstoneKey(); static unsigned getHashValue(const lld::elf::SectionKey &Val); static bool isEqual(const lld::elf::SectionKey &LHS, const lld::elf::SectionKey &RHS); }; } namespace lld { namespace elf { // This class knows how to create an output section for a given // input section. Output section type is determined by various // factors, including input section's sh_flags, sh_type and // linker scripts. class OutputSectionFactory { public: OutputSectionFactory(std::vector &OutputSections); ~OutputSectionFactory(); void addInputSec(InputSectionBase *IS, StringRef OutsecName); void addInputSec(InputSectionBase *IS, StringRef OutsecName, OutputSection *&Sec); private: llvm::SmallDenseMap Map; std::vector &OutputSections; }; uint64_t getHeaderSize(); +void reportDiscarded(InputSectionBase *IS); } // namespace elf } // namespace lld #endif Index: vendor/lld/dist/ELF/Relocations.cpp =================================================================== --- vendor/lld/dist/ELF/Relocations.cpp (revision 319468) +++ vendor/lld/dist/ELF/Relocations.cpp (revision 319469) @@ -1,1085 +1,1085 @@ //===- Relocations.cpp ----------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains platform-independent functions to process relocations. // I'll describe the overview of this file here. // // Simple relocations are easy to handle for the linker. For example, // for R_X86_64_PC64 relocs, the linker just has to fix up locations // with the relative offsets to the target symbols. It would just be // reading records from relocation sections and applying them to output. // // But not all relocations are that easy to handle. For example, for // R_386_GOTOFF relocs, the linker has to create new GOT entries for // symbols if they don't exist, and fix up locations with GOT entry // offsets from the beginning of GOT section. So there is more than // fixing addresses in relocation processing. // // ELF defines a large number of complex relocations. // // The functions in this file analyze relocations and do whatever needs // to be done. It includes, but not limited to, the following. // // - create GOT/PLT entries // - create new relocations in .dynsym to let the dynamic linker resolve // them at runtime (since ELF supports dynamic linking, not all // relocations can be resolved at link-time) // - create COPY relocs and reserve space in .bss // - replace expensive relocs (in terms of runtime cost) with cheap ones // - error out infeasible combinations such as PIC and non-relative relocs // // Note that the functions in this file don't actually apply relocations // because it doesn't know about the output file nor the output file buffer. // It instead stores Relocation objects to InputSection's Relocations // vector to let it apply later in InputSection::writeTo. // //===----------------------------------------------------------------------===// #include "Relocations.h" #include "Config.h" #include "Memory.h" #include "OutputSections.h" #include "Strings.h" #include "SymbolTable.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" #include "llvm/Support/Endian.h" #include "llvm/Support/raw_ostream.h" #include using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; // Construct a message in the following format. // // >>> defined in /home/alice/src/foo.o // >>> referenced by bar.c:12 (/home/alice/src/bar.c:12) // >>> /home/alice/src/bar.o:(.text+0x1) template static std::string getLocation(InputSectionBase &S, const SymbolBody &Sym, uint64_t Off) { std::string Msg = "\n>>> defined in " + toString(Sym.File) + "\n>>> referenced by "; std::string Src = S.getSrcMsg(Off); if (!Src.empty()) Msg += Src + "\n>>> "; return Msg + S.getObjMsg(Off); } static bool isPreemptible(const SymbolBody &Body, uint32_t Type) { // In case of MIPS GP-relative relocations always resolve to a definition // in a regular input file, ignoring the one-definition rule. So we, // for example, should not attempt to create a dynamic relocation even // if the target symbol is preemptible. There are two two MIPS GP-relative // relocations R_MIPS_GPREL16 and R_MIPS_GPREL32. But only R_MIPS_GPREL16 // can be against a preemptible symbol. // To get MIPS relocation type we apply 0xff mask. In case of O32 ABI all // relocation types occupy eight bit. In case of N64 ABI we extract first // relocation from 3-in-1 packet because only the first relocation can // be against a real symbol. if (Config->EMachine == EM_MIPS && (Type & 0xff) == R_MIPS_GPREL16) return false; return Body.isPreemptible(); } // This function is similar to the `handleTlsRelocation`. MIPS does not // support any relaxations for TLS relocations so by factoring out MIPS // handling in to the separate function we can simplify the code and do not // pollute other `handleTlsRelocation` by MIPS `ifs` statements. // Mips has a custom MipsGotSection that handles the writing of GOT entries // without dynamic relocations. template static unsigned handleMipsTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C, uint64_t Offset, int64_t Addend, RelExpr Expr) { if (Expr == R_MIPS_TLSLD) { if (InX::MipsGot->addTlsIndex() && Config->Pic) In::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::MipsGot, InX::MipsGot->getTlsIndexOff(), false, nullptr, 0}); C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } if (Expr == R_MIPS_TLSGD) { if (InX::MipsGot->addDynTlsEntry(Body) && Body.isPreemptible()) { uint64_t Off = InX::MipsGot->getGlobalDynOffset(Body); In::RelaDyn->addReloc( {Target->TlsModuleIndexRel, InX::MipsGot, Off, false, &Body, 0}); if (Body.isPreemptible()) In::RelaDyn->addReloc({Target->TlsOffsetRel, InX::MipsGot, Off + Config->Wordsize, false, &Body, 0}); } C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } return 0; } // This function is similar to the `handleMipsTlsRelocation`. ARM also does not // support any relaxations for TLS relocations. ARM is logically similar to Mips // in how it handles TLS, but Mips uses its own custom GOT which handles some // of the cases that ARM uses GOT relocations for. // // We look for TLS global dynamic and local dynamic relocations, these may // require the generation of a pair of GOT entries that have associated // dynamic relocations. When the results of the dynamic relocations can be // resolved at static link time we do so. This is necessary for static linking // as there will be no dynamic loader to resolve them at load-time. // // The pair of GOT entries created are of the form // GOT[e0] Module Index (Used to find pointer to TLS block at run-time) // GOT[e1] Offset of symbol in TLS block template static unsigned handleARMTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C, uint64_t Offset, int64_t Addend, RelExpr Expr) { // The Dynamic TLS Module Index Relocation for a symbol defined in an // executable is always 1. If the target Symbol is not preemtible then // we know the offset into the TLS block at static link time. bool NeedDynId = Body.isPreemptible() || Config->Shared; bool NeedDynOff = Body.isPreemptible(); auto AddTlsReloc = [&](uint64_t Off, uint32_t Type, SymbolBody *Dest, bool Dyn) { if (Dyn) In::RelaDyn->addReloc({Type, InX::Got, Off, false, Dest, 0}); else InX::Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest}); }; // Local Dynamic is for access to module local TLS variables, while still // being suitable for being dynamically loaded via dlopen. // GOT[e0] is the module index, with a special value of 0 for the current // module. GOT[e1] is unused. There only needs to be one module index entry. if (Expr == R_TLSLD_PC && InX::Got->addTlsIndex()) { AddTlsReloc(InX::Got->getTlsIndexOff(), Target->TlsModuleIndexRel, NeedDynId ? nullptr : &Body, NeedDynId); C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } // Global Dynamic is the most general purpose access model. When we know // the module index and offset of symbol in TLS block we can fill these in // using static GOT relocations. if (Expr == R_TLSGD_PC) { if (InX::Got->addDynTlsEntry(Body)) { uint64_t Off = InX::Got->getGlobalDynOffset(Body); AddTlsReloc(Off, Target->TlsModuleIndexRel, &Body, NeedDynId); AddTlsReloc(Off + Config->Wordsize, Target->TlsOffsetRel, &Body, NeedDynOff); } C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } return 0; } // Returns the number of relocations processed. template static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C, typename ELFT::uint Offset, int64_t Addend, RelExpr Expr) { if (!(C.Flags & SHF_ALLOC)) return 0; if (!Body.isTls()) return 0; if (Config->EMachine == EM_ARM) return handleARMTlsRelocation(Type, Body, C, Offset, Addend, Expr); if (Config->EMachine == EM_MIPS) return handleMipsTlsRelocation(Type, Body, C, Offset, Addend, Expr); bool IsPreemptible = isPreemptible(Body, Type); if (isRelExprOneOf(Expr) && Config->Shared) { if (InX::Got->addDynTlsEntry(Body)) { uint64_t Off = InX::Got->getGlobalDynOffset(Body); In::RelaDyn->addReloc( {Target->TlsDescRel, InX::Got, Off, !IsPreemptible, &Body, 0}); } if (Expr != R_TLSDESC_CALL) C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } if (isRelExprOneOf(Expr)) { // Local-Dynamic relocs can be relaxed to Local-Exec. if (!Config->Shared) { C.Relocations.push_back( {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body}); return 2; } if (InX::Got->addTlsIndex()) In::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::Got, InX::Got->getTlsIndexOff(), false, nullptr, 0}); C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } // Local-Dynamic relocs can be relaxed to Local-Exec. if (isRelExprOneOf(Expr) && !Config->Shared) { C.Relocations.push_back( {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body}); return 1; } if (isRelExprOneOf(Expr)) { if (Config->Shared) { if (InX::Got->addDynTlsEntry(Body)) { uint64_t Off = InX::Got->getGlobalDynOffset(Body); In::RelaDyn->addReloc( {Target->TlsModuleIndexRel, InX::Got, Off, false, &Body, 0}); // If the symbol is preemptible we need the dynamic linker to write // the offset too. uint64_t OffsetOff = Off + Config->Wordsize; if (IsPreemptible) In::RelaDyn->addReloc( {Target->TlsOffsetRel, InX::Got, OffsetOff, false, &Body, 0}); else InX::Got->Relocations.push_back( {R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Body}); } C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } // Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec // depending on the symbol being locally defined or not. if (IsPreemptible) { C.Relocations.push_back( {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type, Offset, Addend, &Body}); if (!Body.isInGot()) { InX::Got->addEntry(Body); In::RelaDyn->addReloc({Target->TlsGotRel, InX::Got, Body.getGotOffset(), false, &Body, 0}); } } else { C.Relocations.push_back( {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type, Offset, Addend, &Body}); } return Target->TlsGdRelaxSkip; } // Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally // defined. if (isRelExprOneOf(Expr) && !Config->Shared && !IsPreemptible) { C.Relocations.push_back( {R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Body}); return 1; } if (Expr == R_TLSDESC_CALL) return 1; return 0; } static uint32_t getMipsPairType(uint32_t Type, const SymbolBody &Sym) { switch (Type) { case R_MIPS_HI16: return R_MIPS_LO16; case R_MIPS_GOT16: return Sym.isLocal() ? R_MIPS_LO16 : R_MIPS_NONE; case R_MIPS_PCHI16: return R_MIPS_PCLO16; case R_MICROMIPS_HI16: return R_MICROMIPS_LO16; default: return R_MIPS_NONE; } } // True if non-preemptable symbol always has the same value regardless of where // the DSO is loaded. static bool isAbsolute(const SymbolBody &Body) { if (Body.isUndefined()) return !Body.isLocal() && Body.symbol()->isWeak(); if (const auto *DR = dyn_cast(&Body)) return DR->Section == nullptr; // Absolute symbol. return false; } static bool isAbsoluteValue(const SymbolBody &Body) { return isAbsolute(Body) || Body.isTls(); } // Returns true if Expr refers a PLT entry. static bool needsPlt(RelExpr Expr) { return isRelExprOneOf(Expr); } // Returns true if Expr refers a GOT entry. Note that this function // returns false for TLS variables even though they need GOT, because // TLS variables uses GOT differently than the regular variables. static bool needsGot(RelExpr Expr) { return isRelExprOneOf(Expr); } // True if this expression is of the form Sym - X, where X is a position in the // file (PC, or GOT for example). static bool isRelExpr(RelExpr Expr) { return isRelExprOneOf(Expr); } // Returns true if a given relocation can be computed at link-time. // // For instance, we know the offset from a relocation to its target at // link-time if the relocation is PC-relative and refers a // non-interposable function in the same executable. This function // will return true for such relocation. // // If this function returns false, that means we need to emit a // dynamic relocation so that the relocation will be fixed at load-time. template static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type, const SymbolBody &Body, InputSectionBase &S, uint64_t RelOff) { // These expressions always compute a constant if (isRelExprOneOf(E)) + R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, + R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_PC, R_TLSGD, + R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E)) return true; // These never do, except if the entire file is position dependent or if // only the low bits are used. if (E == R_GOT || E == R_PLT || E == R_TLSDESC) return Target->usesOnlyLowPageBits(Type) || !Config->Pic; if (isPreemptible(Body, Type)) return false; if (!Config->Pic) return true; // For the target and the relocation, we want to know if they are // absolute or relative. bool AbsVal = isAbsoluteValue(Body); bool RelE = isRelExpr(E); if (AbsVal && !RelE) return true; if (!AbsVal && RelE) return true; if (!AbsVal && !RelE) return Target->usesOnlyLowPageBits(Type); // Relative relocation to an absolute value. This is normally unrepresentable, // but if the relocation refers to a weak undefined symbol, we allow it to // resolve to the image base. This is a little strange, but it allows us to // link function calls to such symbols. Normally such a call will be guarded // with a comparison, which will load a zero from the GOT. // Another special case is MIPS _gp_disp symbol which represents offset // between start of a function and '_gp' value and defined as absolute just // to simplify the code. assert(AbsVal && RelE); if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) return true; error("relocation " + toString(Type) + " cannot refer to absolute symbol: " + toString(Body) + getLocation(S, Body, RelOff)); return true; } static RelExpr toPlt(RelExpr Expr) { if (Expr == R_PPC_OPD) return R_PPC_PLT_OPD; if (Expr == R_PC) return R_PLT_PC; if (Expr == R_PAGE_PC) return R_PLT_PAGE_PC; if (Expr == R_ABS) return R_PLT; return Expr; } static RelExpr fromPlt(RelExpr Expr) { // We decided not to use a plt. Optimize a reference to the plt to a // reference to the symbol itself. if (Expr == R_PLT_PC) return R_PC; if (Expr == R_PPC_PLT_OPD) return R_PPC_OPD; if (Expr == R_PLT) return R_ABS; return Expr; } // Returns true if a given shared symbol is in a read-only segment in a DSO. template static bool isReadOnly(SharedSymbol *SS) { typedef typename ELFT::Phdr Elf_Phdr; uint64_t Value = SS->getValue(); // Determine if the symbol is read-only by scanning the DSO's program headers. auto *File = cast>(SS->File); for (const Elf_Phdr &Phdr : check(File->getObj().program_headers())) if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) && !(Phdr.p_flags & ELF::PF_W) && Value >= Phdr.p_vaddr && Value < Phdr.p_vaddr + Phdr.p_memsz) return true; return false; } // Returns symbols at the same offset as a given symbol, including SS itself. // // If two or more symbols are at the same offset, and at least one of // them are copied by a copy relocation, all of them need to be copied. // Otherwise, they would refer different places at runtime. template static std::vector getSymbolsAt(SharedSymbol *SS) { typedef typename ELFT::Sym Elf_Sym; auto *File = cast>(SS->File); uint64_t Shndx = SS->getShndx(); uint64_t Value = SS->getValue(); std::vector Ret; for (const Elf_Sym &S : File->getGlobalSymbols()) { if (S.st_shndx != Shndx || S.st_value != Value) continue; StringRef Name = check(S.getName(File->getStringTable())); SymbolBody *Sym = Symtab::X->find(Name); if (auto *Alias = dyn_cast_or_null(Sym)) Ret.push_back(Alias); } return Ret; } // Reserve space in .bss or .bss.rel.ro for copy relocation. // // The copy relocation is pretty much a hack. If you use a copy relocation // in your program, not only the symbol name but the symbol's size, RW/RO // bit and alignment become part of the ABI. In addition to that, if the // symbol has aliases, the aliases become part of the ABI. That's subtle, // but if you violate that implicit ABI, that can cause very counter- // intuitive consequences. // // So, what is the copy relocation? It's for linking non-position // independent code to DSOs. In an ideal world, all references to data // exported by DSOs should go indirectly through GOT. But if object files // are compiled as non-PIC, all data references are direct. There is no // way for the linker to transform the code to use GOT, as machine // instructions are already set in stone in object files. This is where // the copy relocation takes a role. // // A copy relocation instructs the dynamic linker to copy data from a DSO // to a specified address (which is usually in .bss) at load-time. If the // static linker (that's us) finds a direct data reference to a DSO // symbol, it creates a copy relocation, so that the symbol can be // resolved as if it were in .bss rather than in a DSO. // // As you can see in this function, we create a copy relocation for the // dynamic linker, and the relocation contains not only symbol name but // various other informtion about the symbol. So, such attributes become a // part of the ABI. // // Note for application developers: I can give you a piece of advice if // you are writing a shared library. You probably should export only // functions from your library. You shouldn't export variables. // // As an example what can happen when you export variables without knowing // the semantics of copy relocations, assume that you have an exported // variable of type T. It is an ABI-breaking change to add new members at // end of T even though doing that doesn't change the layout of the // existing members. That's because the space for the new members are not // reserved in .bss unless you recompile the main program. That means they // are likely to overlap with other data that happens to be laid out next // to the variable in .bss. This kind of issue is sometimes very hard to // debug. What's a solution? Instead of exporting a varaible V from a DSO, // define an accessor getV(). template static void addCopyRelSymbol(SharedSymbol *SS) { // Copy relocation against zero-sized symbol doesn't make sense. uint64_t SymSize = SS->template getSize(); if (SymSize == 0) fatal("cannot create a copy relocation for symbol " + toString(*SS)); // See if this symbol is in a read-only segment. If so, preserve the symbol's // memory protection by reserving space in the .bss.rel.ro section. bool IsReadOnly = isReadOnly(SS); BssSection *Sec = IsReadOnly ? InX::BssRelRo : InX::Bss; uint64_t Off = Sec->reserveSpace(SymSize, SS->getAlignment()); // Look through the DSO's dynamic symbol table for aliases and create a // dynamic symbol for each one. This causes the copy relocation to correctly // interpose any aliases. for (SharedSymbol *Sym : getSymbolsAt(SS)) { Sym->NeedsCopy = true; Sym->CopyRelSec = Sec; Sym->CopyRelSecOff = Off; Sym->symbol()->IsUsedInRegularObj = true; } In::RelaDyn->addReloc({Target->CopyRel, Sec, Off, false, SS, 0}); } template static RelExpr adjustExpr(SymbolBody &Body, RelExpr Expr, uint32_t Type, const uint8_t *Data, InputSectionBase &S, typename ELFT::uint RelOff) { if (Body.isGnuIFunc()) { Expr = toPlt(Expr); } else if (!isPreemptible(Body, Type)) { if (needsPlt(Expr)) Expr = fromPlt(Expr); if (Expr == R_GOT_PC && !isAbsoluteValue(Body)) Expr = Target->adjustRelaxExpr(Type, Data, Expr); } bool IsWrite = !Config->ZText || (S.Flags & SHF_WRITE); if (IsWrite || isStaticLinkTimeConstant(Expr, Type, Body, S, RelOff)) return Expr; // This relocation would require the dynamic linker to write a value to read // only memory. We can hack around it if we are producing an executable and // the refered symbol can be preemepted to refer to the executable. if (Config->Shared || (Config->Pic && !isRelExpr(Expr))) { error("can't create dynamic relocation " + toString(Type) + " against " + (Body.getName().empty() ? "local symbol in readonly segment" : "symbol: " + toString(Body)) + getLocation(S, Body, RelOff)); return Expr; } if (Body.getVisibility() != STV_DEFAULT) { error("cannot preempt symbol: " + toString(Body) + getLocation(S, Body, RelOff)); return Expr; } if (Body.isObject()) { // Produce a copy relocation. auto *B = cast(&Body); if (!B->NeedsCopy) { if (Config->ZNocopyreloc) error("unresolvable relocation " + toString(Type) + " against symbol '" + toString(*B) + "'; recompile with -fPIC or remove '-z nocopyreloc'" + getLocation(S, Body, RelOff)); addCopyRelSymbol(B); } return Expr; } if (Body.isFunc()) { // This handles a non PIC program call to function in a shared library. In // an ideal world, we could just report an error saying the relocation can // overflow at runtime. In the real world with glibc, crt1.o has a // R_X86_64_PC32 pointing to libc.so. // // The general idea on how to handle such cases is to create a PLT entry and // use that as the function value. // // For the static linking part, we just return a plt expr and everything // else will use the the PLT entry as the address. // // The remaining problem is making sure pointer equality still works. We // need the help of the dynamic linker for that. We let it know that we have // a direct reference to a so symbol by creating an undefined symbol with a // non zero st_value. Seeing that, the dynamic linker resolves the symbol to // the value of the symbol we created. This is true even for got entries, so // pointer equality is maintained. To avoid an infinite loop, the only entry // that points to the real function is a dedicated got entry used by the // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT, // R_386_JMP_SLOT, etc). Body.NeedsPltAddr = true; return toPlt(Expr); } error("symbol '" + toString(Body) + "' defined in " + toString(Body.File) + " has no type"); return Expr; } // Returns an addend of a given relocation. If it is RELA, an addend // is in a relocation itself. If it is REL, we need to read it from an // input section. template static int64_t computeAddend(const RelTy &Rel, const uint8_t *Buf) { uint32_t Type = Rel.getType(Config->IsMips64EL); int64_t A = RelTy::IsRela ? getAddend(Rel) : Target->getImplicitAddend(Buf + Rel.r_offset, Type); if (Config->EMachine == EM_PPC64 && Config->Pic && Type == R_PPC64_TOC) A += getPPC64TocBase(); return A; } // MIPS has an odd notion of "paired" relocations to calculate addends. // For example, if a relocation is of R_MIPS_HI16, there must be a // R_MIPS_LO16 relocation after that, and an addend is calculated using // the two relocations. template static int64_t computeMipsAddend(const RelTy &Rel, InputSectionBase &Sec, RelExpr Expr, SymbolBody &Body, const RelTy *End) { if (Expr == R_MIPS_GOTREL && Body.isLocal()) return Sec.getFile()->MipsGp0; // The ABI says that the paired relocation is used only for REL. // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf if (RelTy::IsRela) return 0; uint32_t Type = Rel.getType(Config->IsMips64EL); uint32_t PairTy = getMipsPairType(Type, Body); if (PairTy == R_MIPS_NONE) return 0; const uint8_t *Buf = Sec.Data.data(); uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL); // To make things worse, paired relocations might not be contiguous in // the relocation table, so we need to do linear search. *sigh* for (const RelTy *RI = &Rel; RI != End; ++RI) { if (RI->getType(Config->IsMips64EL) != PairTy) continue; if (RI->getSymbol(Config->IsMips64EL) != SymIndex) continue; endianness E = Config->Endianness; int32_t Hi = (read32(Buf + Rel.r_offset, E) & 0xffff) << 16; int32_t Lo = SignExtend32<16>(read32(Buf + RI->r_offset, E)); return Hi + Lo; } warn("can't find matching " + toString(PairTy) + " relocation for " + toString(Type)); return 0; } template static void reportUndefined(SymbolBody &Sym, InputSectionBase &S, uint64_t Offset) { if (Config->UnresolvedSymbols == UnresolvedPolicy::IgnoreAll) return; bool CanBeExternal = Sym.symbol()->computeBinding() != STB_LOCAL && Sym.getVisibility() == STV_DEFAULT; if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal) return; std::string Msg = "undefined symbol: " + toString(Sym) + "\n>>> referenced by "; std::string Src = S.getSrcMsg(Offset); if (!Src.empty()) Msg += Src + "\n>>> "; Msg += S.getObjMsg(Offset); if (Config->UnresolvedSymbols == UnresolvedPolicy::WarnAll || (Config->UnresolvedSymbols == UnresolvedPolicy::Warn && CanBeExternal)) { warn(Msg); } else { error(Msg); } } template static std::pair mergeMipsN32RelTypes(uint32_t Type, uint32_t Offset, RelTy *I, RelTy *E) { // MIPS N32 ABI treats series of successive relocations with the same offset // as a single relocation. The similar approach used by N64 ABI, but this ABI // packs all relocations into the single relocation record. Here we emulate // this for the N32 ABI. Iterate over relocation with the same offset and put // theirs types into the single bit-set. uint32_t Processed = 0; for (; I != E && Offset == I->r_offset; ++I) { ++Processed; Type |= I->getType(Config->IsMips64EL) << (8 * Processed); } return std::make_pair(Type, Processed); } // .eh_frame sections are mergeable input sections, so their input // offsets are not linearly mapped to output section. For each input // offset, we need to find a section piece containing the offset and // add the piece's base address to the input offset to compute the // output offset. That isn't cheap. // // This class is to speed up the offset computation. When we process // relocations, we access offsets in the monotonically increasing // order. So we can optimize for that access pattern. // // For sections other than .eh_frame, this class doesn't do anything. namespace { class OffsetGetter { public: explicit OffsetGetter(InputSectionBase &Sec) { if (auto *Eh = dyn_cast(&Sec)) { P = Eh->Pieces; Size = Eh->Pieces.size(); } } // Translates offsets in input sections to offsets in output sections. // Given offset must increase monotonically. We assume that P is // sorted by InputOff. uint64_t get(uint64_t Off) { if (P.empty()) return Off; while (I != Size && P[I].InputOff + P[I].size() <= Off) ++I; if (I == Size) return Off; // P must be contiguous, so there must be no holes in between. assert(P[I].InputOff <= Off && "Relocation not in any piece"); // Offset -1 means that the piece is dead (i.e. garbage collected). if (P[I].OutputOff == -1) return -1; return P[I].OutputOff + Off - P[I].InputOff; } private: ArrayRef P; size_t I = 0; size_t Size; }; } // namespace template static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt, RelocationSection *Rel, uint32_t Type, SymbolBody &Sym, bool UseSymVA) { Plt->addEntry(Sym); GotPlt->addEntry(Sym); Rel->addReloc({Type, GotPlt, Sym.getGotPltOffset(), UseSymVA, &Sym, 0}); } template static void addGotEntry(SymbolBody &Sym, bool Preemptible) { InX::Got->addEntry(Sym); uint64_t Off = Sym.getGotOffset(); uint32_t DynType; RelExpr Expr = R_ABS; if (Sym.isTls()) { DynType = Target->TlsGotRel; Expr = R_TLS; } else if (!Preemptible && Config->Pic && !isAbsolute(Sym)) { DynType = Target->RelativeRel; } else { DynType = Target->GotRel; } bool Constant = !Preemptible && !(Config->Pic && !isAbsolute(Sym)); if (!Constant) In::RelaDyn->addReloc( {DynType, InX::Got, Off, !Preemptible, &Sym, 0}); if (Constant || (!Config->IsRela && !Preemptible)) InX::Got->Relocations.push_back({Expr, DynType, Off, 0, &Sym}); } // The reason we have to do this early scan is as follows // * To mmap the output file, we need to know the size // * For that, we need to know how many dynamic relocs we will have. // It might be possible to avoid this by outputting the file with write: // * Write the allocated output sections, computing addresses. // * Apply relocations, recording which ones require a dynamic reloc. // * Write the dynamic relocations. // * Write the rest of the file. // This would have some drawbacks. For example, we would only know if .rela.dyn // is needed after applying relocations. If it is, it will go after rw and rx // sections. Given that it is ro, we will need an extra PT_LOAD. This // complicates things for the dynamic linker and means we would have to reserve // space for the extra PT_LOAD even if we end up not using it. template static void scanRelocs(InputSectionBase &Sec, ArrayRef Rels) { OffsetGetter GetOffset(Sec); for (auto I = Rels.begin(), End = Rels.end(); I != End; ++I) { const RelTy &Rel = *I; SymbolBody &Body = Sec.getFile()->getRelocTargetSym(Rel); uint32_t Type = Rel.getType(Config->IsMips64EL); if (Config->MipsN32Abi) { uint32_t Processed; std::tie(Type, Processed) = mergeMipsN32RelTypes(Type, Rel.r_offset, I + 1, End); I += Processed; } // Compute the offset of this section in the output section. uint64_t Offset = GetOffset.get(Rel.r_offset); if (Offset == uint64_t(-1)) continue; // Report undefined symbols. The fact that we report undefined // symbols here means that we report undefined symbols only when // they have relocations pointing to them. We don't care about // undefined symbols that are in dead-stripped sections. if (!Body.isLocal() && Body.isUndefined() && !Body.symbol()->isWeak()) reportUndefined(Body, Sec, Rel.r_offset); RelExpr Expr = Target->getRelExpr(Type, Body, Sec.Data.begin() + Rel.r_offset); // Ignore "hint" relocations because they are only markers for relaxation. if (isRelExprOneOf(Expr)) continue; bool Preemptible = isPreemptible(Body, Type); Expr = adjustExpr(Body, Expr, Type, Sec.Data.data() + Rel.r_offset, Sec, Rel.r_offset); if (ErrorCount) continue; // This relocation does not require got entry, but it is relative to got and // needs it to be created. Here we request for that. if (isRelExprOneOf(Expr)) InX::Got->HasGotOffRel = true; // Read an addend. int64_t Addend = computeAddend(Rel, Sec.Data.data()); if (Config->EMachine == EM_MIPS) Addend += computeMipsAddend(Rel, Sec, Expr, Body, End); // Process some TLS relocations, including relaxing TLS relocations. // Note that this function does not handle all TLS relocations. if (unsigned Processed = handleTlsRelocation(Type, Body, Sec, Offset, Addend, Expr)) { I += (Processed - 1); continue; } // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol. if (needsPlt(Expr) && !Body.isInPlt()) { if (Body.isGnuIFunc() && !Preemptible) addPltEntry(InX::Iplt, InX::IgotPlt, In::RelaIplt, Target->IRelativeRel, Body, true); else addPltEntry(InX::Plt, InX::GotPlt, In::RelaPlt, Target->PltRel, Body, !Preemptible); } // Create a GOT slot if a relocation needs GOT. if (needsGot(Expr)) { if (Config->EMachine == EM_MIPS) { // MIPS ABI has special rules to process GOT entries and doesn't // require relocation entries for them. A special case is TLS // relocations. In that case dynamic loader applies dynamic // relocations to initialize TLS GOT entries. // 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 InX::MipsGot->addEntry(Body, Addend, Expr); if (Body.isTls() && Body.isPreemptible()) In::RelaDyn->addReloc({Target->TlsGotRel, InX::MipsGot, Body.getGotOffset(), false, &Body, 0}); } else if (!Body.isInGot()) { addGotEntry(Body, Preemptible); } } if (!needsPlt(Expr) && !needsGot(Expr) && isPreemptible(Body, Type)) { // We don't know anything about the finaly symbol. Just ask the dynamic // linker to handle the relocation for us. if (!Target->isPicRel(Type)) error("relocation " + toString(Type) + " cannot be used against shared object; recompile with -fPIC" + getLocation(Sec, Body, Offset)); In::RelaDyn->addReloc( {Target->getDynRel(Type), &Sec, Offset, false, &Body, Addend}); // MIPS ABI turns using of GOT and dynamic relocations inside out. // While regular ABI uses dynamic relocations to fill up GOT entries // MIPS ABI requires dynamic linker to fills up GOT entries using // specially sorted dynamic symbol table. This affects even dynamic // relocations against symbols which do not require GOT entries // creation explicitly, i.e. do not have any GOT-relocations. So if // a preemptible symbol has a dynamic relocation we anyway have // to create a GOT entry for it. // If a non-preemptible symbol has a dynamic relocation against it, // dynamic linker takes it st_value, adds offset and writes down // result of the dynamic relocation. In case of preemptible symbol // dynamic linker performs symbol resolution, writes the symbol value // to the GOT entry and reads the GOT entry when it needs to perform // a dynamic relocation. // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19 if (Config->EMachine == EM_MIPS) InX::MipsGot->addEntry(Body, Addend, Expr); continue; } // If the relocation points to something in the file, we can process it. bool IsConstant = isStaticLinkTimeConstant(Expr, Type, Body, Sec, Rel.r_offset); // The size is not going to change, so we fold it in here. if (Expr == R_SIZE) Addend += Body.getSize(); // If the output being produced is position independent, the final value // is still not known. In that case we still need some help from the // dynamic linker. We can however do better than just copying the incoming // relocation. We can process some of it and and just ask the dynamic // linker to add the load address. if (!IsConstant) In::RelaDyn->addReloc( {Target->RelativeRel, &Sec, Offset, true, &Body, Addend}); // If the produced value is a constant, we just remember to write it // when outputting this section. We also have to do it if the format // uses Elf_Rel, since in that case the written value is the addend. if (IsConstant || !RelTy::IsRela) Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); } } template void elf::scanRelocations(InputSectionBase &S) { if (S.AreRelocsRela) scanRelocs(S, S.relas()); else scanRelocs(S, S.rels()); } // Insert the Thunks for OutputSection OS into their designated place // in the Sections vector, and recalculate the InputSection output section // offsets. // This may invalidate any output section offsets stored outside of InputSection void ThunkCreator::mergeThunks(OutputSection *OS, std::vector &Thunks) { // Order Thunks in ascending OutSecOff auto ThunkCmp = [](const ThunkSection *A, const ThunkSection *B) { return A->OutSecOff < B->OutSecOff; }; std::stable_sort(Thunks.begin(), Thunks.end(), ThunkCmp); // Merge sorted vectors of Thunks and InputSections by OutSecOff std::vector Tmp; Tmp.reserve(OS->Sections.size() + Thunks.size()); auto MergeCmp = [](const InputSection *A, const InputSection *B) { // std::merge requires a strict weak ordering. if (A->OutSecOff < B->OutSecOff) return true; if (A->OutSecOff == B->OutSecOff) // Check if Thunk is immediately before any specific Target InputSection // for example Mips LA25 Thunks. if (auto *TA = dyn_cast(A)) if (TA && TA->getTargetInputSection() == B) return true; return false; }; std::merge(OS->Sections.begin(), OS->Sections.end(), Thunks.begin(), Thunks.end(), std::back_inserter(Tmp), MergeCmp); OS->Sections = std::move(Tmp); OS->assignOffsets(); } ThunkSection *ThunkCreator::getOSThunkSec(ThunkSection *&TS, OutputSection *OS) { if (TS == nullptr) { uint32_t Off = 0; for (auto *IS : OS->Sections) { Off = IS->OutSecOff + IS->getSize(); if ((IS->Flags & SHF_EXECINSTR) == 0) break; } TS = make(OS, Off); ThunkSections[OS].push_back(TS); } return TS; } ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS, OutputSection *OS) { ThunkSection *TS = ThunkedSections.lookup(IS); if (TS) return TS; - auto *TOS = cast(IS->OutSec); + auto *TOS = IS->getParent(); TS = make(TOS, IS->OutSecOff); ThunkSections[TOS].push_back(TS); ThunkedSections[IS] = TS; return TS; } std::pair ThunkCreator::getThunk(SymbolBody &Body, uint32_t Type) { auto res = ThunkedSymbols.insert({&Body, nullptr}); if (res.second) res.first->second = addThunk(Type, Body); return std::make_pair(res.first->second, res.second); } // Process all relocations from the InputSections that have been assigned // to OutputSections and redirect through Thunks if needed. // // createThunks must be called after scanRelocs has created the Relocations for // each InputSection. It must be called before the static symbol table is // finalized. If any Thunks are added to an OutputSection the output section // offsets of the InputSections will change. // // FIXME: All Thunks are assumed to be in range of the relocation. Range // extension Thunks are not yet supported. bool ThunkCreator::createThunks(ArrayRef OutputSections) { // Create all the Thunks and insert them into synthetic ThunkSections. The // ThunkSections are later inserted back into the OutputSection. // We separate the creation of ThunkSections from the insertion of the // ThunkSections back into the OutputSection as ThunkSections are not always // inserted into the same OutputSection as the caller. for (OutputSection *OS : OutputSections) { ThunkSection *OSTS = nullptr; for (InputSection *IS : OS->Sections) { for (Relocation &Rel : IS->Relocations) { SymbolBody &Body = *Rel.Sym; if (!Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Body)) continue; Thunk *T; bool IsNew; std::tie(T, IsNew) = getThunk(Body, Rel.Type); if (IsNew) { // Find or create a ThunkSection for the new Thunk ThunkSection *TS; if (auto *TIS = T->getTargetInputSection()) TS = getISThunkSec(TIS, OS); else TS = getOSThunkSec(OSTS, OS); TS->addThunk(T); } // Redirect relocation to Thunk, we never go via the PLT to a Thunk Rel.Sym = T->ThunkSym; Rel.Expr = fromPlt(Rel.Expr); } } } // Merge all created synthetic ThunkSections back into OutputSection for (auto &KV : ThunkSections) mergeThunks(KV.first, KV.second); return !ThunkSections.empty(); } template void elf::scanRelocations(InputSectionBase &); template void elf::scanRelocations(InputSectionBase &); template void elf::scanRelocations(InputSectionBase &); template void elf::scanRelocations(InputSectionBase &); Index: vendor/lld/dist/ELF/ScriptParser.cpp =================================================================== --- vendor/lld/dist/ELF/ScriptParser.cpp (revision 319468) +++ vendor/lld/dist/ELF/ScriptParser.cpp (revision 319469) @@ -1,1193 +1,1209 @@ //===- ScriptParser.cpp ---------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains a recursive-descendent parser for linker scripts. // Parsed results are stored to Config and Script global objects. // //===----------------------------------------------------------------------===// #include "ScriptParser.h" #include "Config.h" #include "Driver.h" #include "InputSection.h" #include "LinkerScript.h" #include "Memory.h" #include "OutputSections.h" #include "ScriptLexer.h" #include "Symbols.h" #include "Target.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ELF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include #include #include using namespace llvm; using namespace llvm::ELF; using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; static bool isUnderSysroot(StringRef Path); namespace { class ScriptParser final : ScriptLexer { public: ScriptParser(MemoryBufferRef MB) : ScriptLexer(MB), IsUnderSysroot(isUnderSysroot(MB.getBufferIdentifier())) {} void readLinkerScript(); void readVersionScript(); void readDynamicList(); private: void addFile(StringRef Path); + OutputSection *checkSection(OutputSectionCommand *Cmd, StringRef Loccation); void readAsNeeded(); void readEntry(); void readExtern(); void readGroup(); void readInclude(); void readMemory(); void readOutput(); void readOutputArch(); void readOutputFormat(); void readPhdrs(); void readSearchDir(); void readSections(); void readVersion(); void readVersionScriptCommand(); SymbolAssignment *readAssignment(StringRef Name); BytesDataCommand *readBytesDataCommand(StringRef Tok); uint32_t readFill(); uint32_t parseFill(StringRef Tok); OutputSectionCommand *readOutputSectionDescription(StringRef OutSec); std::vector readOutputSectionPhdrs(); InputSectionDescription *readInputSectionDescription(StringRef Tok); StringMatcher readFilePatterns(); std::vector readInputSectionsList(); InputSectionDescription *readInputSectionRules(StringRef FilePattern); unsigned readPhdrType(); SortSectionPolicy readSortKind(); SymbolAssignment *readProvideHidden(bool Provide, bool Hidden); SymbolAssignment *readProvideOrAssignment(StringRef Tok); void readSort(); AssertCommand *readAssert(); Expr readAssertExpr(); uint64_t readMemoryAssignment(StringRef, StringRef, StringRef); std::pair readMemoryAttributes(); Expr readExpr(); Expr readExpr1(Expr Lhs, int MinPrec); StringRef readParenLiteral(); Expr readPrimary(); Expr readTernary(Expr Cond); Expr readParenExpr(); // For parsing version script. std::vector readVersionExtern(); void readAnonymousDeclaration(); void readVersionDeclaration(StringRef VerStr); std::pair, std::vector> readSymbols(); bool IsUnderSysroot; }; } // namespace static bool isUnderSysroot(StringRef Path) { if (Config->Sysroot == "") return false; for (; !Path.empty(); Path = sys::path::parent_path(Path)) if (sys::fs::equivalent(Config->Sysroot, Path)) return true; return false; } // Some operations only support one non absolute value. Move the // absolute one to the right hand side for convenience. static void moveAbsRight(ExprValue &A, ExprValue &B) { if (A.isAbsolute()) std::swap(A, B); if (!B.isAbsolute()) error("At least one side of the expression must be absolute"); } static ExprValue add(ExprValue A, ExprValue B) { moveAbsRight(A, B); return {A.Sec, A.ForceAbsolute, A.Val + B.getValue()}; } static ExprValue sub(ExprValue A, ExprValue B) { return {A.Sec, A.Val - B.getValue()}; } static ExprValue mul(ExprValue A, ExprValue B) { return A.getValue() * B.getValue(); } static ExprValue div(ExprValue A, ExprValue B) { if (uint64_t BV = B.getValue()) return A.getValue() / BV; error("division by zero"); return 0; } static ExprValue bitAnd(ExprValue A, ExprValue B) { moveAbsRight(A, B); return {A.Sec, A.ForceAbsolute, (A.getValue() & B.getValue()) - A.getSecAddr()}; } static ExprValue bitOr(ExprValue A, ExprValue B) { moveAbsRight(A, B); return {A.Sec, A.ForceAbsolute, (A.getValue() | B.getValue()) - A.getSecAddr()}; } void ScriptParser::readDynamicList() { expect("{"); readAnonymousDeclaration(); if (!atEOF()) setError("EOF expected, but got " + next()); } void ScriptParser::readVersionScript() { readVersionScriptCommand(); if (!atEOF()) setError("EOF expected, but got " + next()); } void ScriptParser::readVersionScriptCommand() { if (consume("{")) { readAnonymousDeclaration(); return; } while (!atEOF() && !Error && peek() != "}") { StringRef VerStr = next(); if (VerStr == "{") { setError("anonymous version definition is used in " "combination with other version definitions"); return; } expect("{"); readVersionDeclaration(VerStr); } } void ScriptParser::readVersion() { expect("{"); readVersionScriptCommand(); expect("}"); } void ScriptParser::readLinkerScript() { while (!atEOF()) { StringRef Tok = next(); if (Tok == ";") continue; if (Tok == "ASSERT") { Script->Opt.Commands.push_back(readAssert()); } else if (Tok == "ENTRY") { readEntry(); } else if (Tok == "EXTERN") { readExtern(); } else if (Tok == "GROUP" || Tok == "INPUT") { readGroup(); } else if (Tok == "INCLUDE") { readInclude(); } else if (Tok == "MEMORY") { readMemory(); } else if (Tok == "OUTPUT") { readOutput(); } else if (Tok == "OUTPUT_ARCH") { readOutputArch(); } else if (Tok == "OUTPUT_FORMAT") { readOutputFormat(); } else if (Tok == "PHDRS") { readPhdrs(); } else if (Tok == "SEARCH_DIR") { readSearchDir(); } else if (Tok == "SECTIONS") { readSections(); } else if (Tok == "VERSION") { readVersion(); } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok)) { Script->Opt.Commands.push_back(Cmd); } else { setError("unknown directive: " + Tok); } } } void ScriptParser::addFile(StringRef S) { if (IsUnderSysroot && S.startswith("/")) { SmallString<128> PathData; StringRef Path = (Config->Sysroot + S).toStringRef(PathData); if (sys::fs::exists(Path)) { Driver->addFile(Saver.save(Path), /*WithLOption=*/false); return; } } if (sys::path::is_absolute(S)) { Driver->addFile(S, /*WithLOption=*/false); } else if (S.startswith("=")) { if (Config->Sysroot.empty()) Driver->addFile(S.substr(1), /*WithLOption=*/false); else Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)), /*WithLOption=*/false); } else if (S.startswith("-l")) { Driver->addLibrary(S.substr(2)); } else if (sys::fs::exists(S)) { Driver->addFile(S, /*WithLOption=*/false); } else { if (Optional Path = findFromSearchPaths(S)) Driver->addFile(Saver.save(*Path), /*WithLOption=*/true); else setError("unable to find " + S); } } void ScriptParser::readAsNeeded() { expect("("); bool Orig = Config->AsNeeded; Config->AsNeeded = true; while (!Error && !consume(")")) addFile(unquote(next())); Config->AsNeeded = Orig; } void ScriptParser::readEntry() { // -e takes predecence over ENTRY(). expect("("); StringRef Tok = next(); if (Config->Entry.empty()) Config->Entry = Tok; expect(")"); } void ScriptParser::readExtern() { expect("("); while (!Error && !consume(")")) Config->Undefined.push_back(next()); } void ScriptParser::readGroup() { expect("("); while (!Error && !consume(")")) { if (consume("AS_NEEDED")) readAsNeeded(); else addFile(unquote(next())); } } void ScriptParser::readInclude() { StringRef Tok = unquote(next()); // https://sourceware.org/binutils/docs/ld/File-Commands.html: // The file will be searched for in the current directory, and in any // directory specified with the -L option. if (sys::fs::exists(Tok)) { if (Optional MB = readFile(Tok)) tokenize(*MB); return; } if (Optional Path = findFromSearchPaths(Tok)) { if (Optional MB = readFile(*Path)) tokenize(*MB); return; } setError("cannot open " + Tok); } void ScriptParser::readOutput() { // -o takes predecence over OUTPUT(). expect("("); StringRef Tok = next(); if (Config->OutputFile.empty()) Config->OutputFile = unquote(Tok); expect(")"); } void ScriptParser::readOutputArch() { // OUTPUT_ARCH is ignored for now. expect("("); while (!Error && !consume(")")) skip(); } void ScriptParser::readOutputFormat() { // Error checking only for now. expect("("); skip(); if (consume(")")) return; expect(","); skip(); expect(","); skip(); expect(")"); } void ScriptParser::readPhdrs() { expect("{"); while (!Error && !consume("}")) { Script->Opt.PhdrsCommands.push_back( {next(), PT_NULL, false, false, UINT_MAX, nullptr}); PhdrsCommand &PhdrCmd = Script->Opt.PhdrsCommands.back(); PhdrCmd.Type = readPhdrType(); while (!Error && !consume(";")) { if (consume("FILEHDR")) PhdrCmd.HasFilehdr = true; else if (consume("PHDRS")) PhdrCmd.HasPhdrs = true; else if (consume("AT")) PhdrCmd.LMAExpr = readParenExpr(); else if (consume("FLAGS")) PhdrCmd.Flags = readParenExpr()().getValue(); else setError("unexpected header attribute: " + next()); } } } void ScriptParser::readSearchDir() { expect("("); StringRef Tok = next(); if (!Config->Nostdlib) Config->SearchPaths.push_back(unquote(Tok)); expect(")"); } void ScriptParser::readSections() { Script->Opt.HasSections = true; // -no-rosegment is used to avoid placing read only non-executable sections in // their own segment. We do the same if SECTIONS command is present in linker // script. See comment for computeFlags(). Config->SingleRoRx = true; expect("{"); while (!Error && !consume("}")) { StringRef Tok = next(); BaseCommand *Cmd = readProvideOrAssignment(Tok); if (!Cmd) { if (Tok == "ASSERT") Cmd = readAssert(); else Cmd = readOutputSectionDescription(Tok); } Script->Opt.Commands.push_back(Cmd); } } static int precedence(StringRef Op) { return StringSwitch(Op) .Cases("*", "/", 5) .Cases("+", "-", 4) .Cases("<<", ">>", 3) .Cases("<", "<=", ">", ">=", "==", "!=", 2) .Cases("&", "|", 1) .Default(-1); } StringMatcher ScriptParser::readFilePatterns() { std::vector V; while (!Error && !consume(")")) V.push_back(next()); return StringMatcher(V); } SortSectionPolicy ScriptParser::readSortKind() { if (consume("SORT") || consume("SORT_BY_NAME")) return SortSectionPolicy::Name; if (consume("SORT_BY_ALIGNMENT")) return SortSectionPolicy::Alignment; if (consume("SORT_BY_INIT_PRIORITY")) return SortSectionPolicy::Priority; if (consume("SORT_NONE")) return SortSectionPolicy::None; return SortSectionPolicy::Default; } // Reads SECTIONS command contents in the following form: // // ::= * // ::= ? // ::= "EXCLUDE_FILE" "(" + ")" // // For example, // // *(.foo EXCLUDE_FILE (a.o) .bar EXCLUDE_FILE (b.o) .baz) // // is parsed as ".foo", ".bar" with "a.o", and ".baz" with "b.o". // The semantics of that is section .foo in any file, section .bar in // any file but a.o, and section .baz in any file but b.o. std::vector ScriptParser::readInputSectionsList() { std::vector Ret; while (!Error && peek() != ")") { StringMatcher ExcludeFilePat; if (consume("EXCLUDE_FILE")) { expect("("); ExcludeFilePat = readFilePatterns(); } std::vector V; while (!Error && peek() != ")" && peek() != "EXCLUDE_FILE") V.push_back(next()); if (!V.empty()) Ret.push_back({std::move(ExcludeFilePat), StringMatcher(V)}); else setError("section pattern is expected"); } return Ret; } // Reads contents of "SECTIONS" directive. That directive contains a // list of glob patterns for input sections. The grammar is as follows. // // ::= // | "(" ")" // | "(" "(" ")" ")" // // ::= "SORT" | "SORT_BY_NAME" | "SORT_BY_ALIGNMENT" // | "SORT_BY_INIT_PRIORITY" | "SORT_NONE" // // is parsed by readInputSectionsList(). InputSectionDescription * ScriptParser::readInputSectionRules(StringRef FilePattern) { auto *Cmd = make(FilePattern); expect("("); while (!Error && !consume(")")) { SortSectionPolicy Outer = readSortKind(); SortSectionPolicy Inner = SortSectionPolicy::Default; std::vector V; if (Outer != SortSectionPolicy::Default) { expect("("); Inner = readSortKind(); if (Inner != SortSectionPolicy::Default) { expect("("); V = readInputSectionsList(); expect(")"); } else { V = readInputSectionsList(); } expect(")"); } else { V = readInputSectionsList(); } for (SectionPattern &Pat : V) { Pat.SortInner = Inner; Pat.SortOuter = Outer; } std::move(V.begin(), V.end(), std::back_inserter(Cmd->SectionPatterns)); } return Cmd; } InputSectionDescription * ScriptParser::readInputSectionDescription(StringRef Tok) { // Input section wildcard can be surrounded by KEEP. // https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#Input-Section-Keep if (Tok == "KEEP") { expect("("); StringRef FilePattern = next(); InputSectionDescription *Cmd = readInputSectionRules(FilePattern); expect(")"); Script->Opt.KeptSections.push_back(Cmd); return Cmd; } return readInputSectionRules(Tok); } void ScriptParser::readSort() { expect("("); expect("CONSTRUCTORS"); expect(")"); } AssertCommand *ScriptParser::readAssert() { return make(readAssertExpr()); } Expr ScriptParser::readAssertExpr() { expect("("); Expr E = readExpr(); expect(","); StringRef Msg = unquote(next()); expect(")"); return [=] { if (!E().getValue()) error(Msg); return Script->getDot(); }; } // Reads a FILL(expr) command. We handle the FILL command as an // alias for =fillexp section attribute, which is different from // what GNU linkers do. // https://sourceware.org/binutils/docs/ld/Output-Section-Data.html uint32_t ScriptParser::readFill() { expect("("); uint32_t V = parseFill(next()); expect(")"); return V; } OutputSectionCommand * ScriptParser::readOutputSectionDescription(StringRef OutSec) { - OutputSectionCommand *Cmd = make(OutSec); - Cmd->Location = getCurrentLocation(); + OutputSectionCommand *Cmd = + Script->createOutputSectionCommand(OutSec, getCurrentLocation()); // Read an address expression. // https://sourceware.org/binutils/docs/ld/Output-Section-Address.html if (peek() != ":") Cmd->AddrExpr = readExpr(); expect(":"); if (consume("AT")) Cmd->LMAExpr = readParenExpr(); if (consume("ALIGN")) Cmd->AlignExpr = readParenExpr(); if (consume("SUBALIGN")) Cmd->SubalignExpr = readParenExpr(); // Parse constraints. if (consume("ONLY_IF_RO")) Cmd->Constraint = ConstraintKind::ReadOnly; if (consume("ONLY_IF_RW")) Cmd->Constraint = ConstraintKind::ReadWrite; expect("{"); while (!Error && !consume("}")) { StringRef Tok = next(); if (Tok == ";") { // Empty commands are allowed. Do nothing here. } else if (SymbolAssignment *Assign = readProvideOrAssignment(Tok)) { Cmd->Commands.push_back(Assign); } else if (BytesDataCommand *Data = readBytesDataCommand(Tok)) { Cmd->Commands.push_back(Data); } else if (Tok == "ASSERT") { Cmd->Commands.push_back(readAssert()); expect(";"); } else if (Tok == "CONSTRUCTORS") { // CONSTRUCTORS is a keyword to make the linker recognize C++ ctors/dtors // by name. This is for very old file formats such as ECOFF/XCOFF. // For ELF, we should ignore. } else if (Tok == "FILL") { Cmd->Filler = readFill(); } else if (Tok == "SORT") { readSort(); } else if (peek() == "(") { Cmd->Commands.push_back(readInputSectionDescription(Tok)); } else { setError("unknown command " + Tok); } } if (consume(">")) Cmd->MemoryRegionName = next(); Cmd->Phdrs = readOutputSectionPhdrs(); if (consume("=")) Cmd->Filler = parseFill(next()); else if (peek().startswith("=")) Cmd->Filler = parseFill(next().drop_front()); // Consume optional comma following output section command. consume(","); return Cmd; } // Parses a given string as a octal/decimal/hexadecimal number and // returns it as a big-endian number. Used for `=`. // https://sourceware.org/binutils/docs/ld/Output-Section-Fill.html // // When reading a hexstring, ld.bfd handles it as a blob of arbitrary // size, while ld.gold always handles it as a 32-bit big-endian number. // We are compatible with ld.gold because it's easier to implement. uint32_t ScriptParser::parseFill(StringRef Tok) { uint32_t V = 0; if (!to_integer(Tok, V)) setError("invalid filler expression: " + Tok); uint32_t Buf; write32be(&Buf, V); return Buf; } SymbolAssignment *ScriptParser::readProvideHidden(bool Provide, bool Hidden) { expect("("); SymbolAssignment *Cmd = readAssignment(next()); Cmd->Provide = Provide; Cmd->Hidden = Hidden; expect(")"); expect(";"); return Cmd; } SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) { SymbolAssignment *Cmd = nullptr; if (peek() == "=" || peek() == "+=") { Cmd = readAssignment(Tok); expect(";"); } else if (Tok == "PROVIDE") { Cmd = readProvideHidden(true, false); } else if (Tok == "HIDDEN") { Cmd = readProvideHidden(false, true); } else if (Tok == "PROVIDE_HIDDEN") { Cmd = readProvideHidden(true, true); } return Cmd; } SymbolAssignment *ScriptParser::readAssignment(StringRef Name) { StringRef Op = next(); assert(Op == "=" || Op == "+="); Expr E = readExpr(); if (Op == "+=") { std::string Loc = getCurrentLocation(); E = [=] { return add(Script->getSymbolValue(Loc, Name), E()); }; } return make(Name, E, getCurrentLocation()); } // This is an operator-precedence parser to parse a linker // script expression. Expr ScriptParser::readExpr() { // Our lexer is context-aware. Set the in-expression bit so that // they apply different tokenization rules. bool Orig = InExpr; InExpr = true; Expr E = readExpr1(readPrimary(), 0); InExpr = Orig; return E; } static Expr combine(StringRef Op, Expr L, Expr R) { if (Op == "+") return [=] { return add(L(), R()); }; if (Op == "-") return [=] { return sub(L(), R()); }; if (Op == "*") return [=] { return mul(L(), R()); }; if (Op == "/") return [=] { return div(L(), R()); }; if (Op == "<<") return [=] { return L().getValue() << R().getValue(); }; if (Op == ">>") return [=] { return L().getValue() >> R().getValue(); }; if (Op == "<") return [=] { return L().getValue() < R().getValue(); }; if (Op == ">") return [=] { return L().getValue() > R().getValue(); }; if (Op == ">=") return [=] { return L().getValue() >= R().getValue(); }; if (Op == "<=") return [=] { return L().getValue() <= R().getValue(); }; if (Op == "==") return [=] { return L().getValue() == R().getValue(); }; if (Op == "!=") return [=] { return L().getValue() != R().getValue(); }; if (Op == "&") return [=] { return bitAnd(L(), R()); }; if (Op == "|") return [=] { return bitOr(L(), R()); }; llvm_unreachable("invalid operator"); } // This is a part of the operator-precedence parser. This function // assumes that the remaining token stream starts with an operator. Expr ScriptParser::readExpr1(Expr Lhs, int MinPrec) { while (!atEOF() && !Error) { // Read an operator and an expression. if (consume("?")) return readTernary(Lhs); StringRef Op1 = peek(); if (precedence(Op1) < MinPrec) break; skip(); Expr Rhs = readPrimary(); // Evaluate the remaining part of the expression first if the // next operator has greater precedence than the previous one. // For example, if we have read "+" and "3", and if the next // operator is "*", then we'll evaluate 3 * ... part first. while (!atEOF()) { StringRef Op2 = peek(); if (precedence(Op2) <= precedence(Op1)) break; Rhs = readExpr1(Rhs, precedence(Op2)); } Lhs = combine(Op1, Lhs, Rhs); } return Lhs; } uint64_t static getConstant(StringRef S) { if (S == "COMMONPAGESIZE") return Target->PageSize; if (S == "MAXPAGESIZE") return Config->MaxPageSize; error("unknown constant: " + S); return 0; } // Parses Tok as an integer. It recognizes hexadecimal (prefixed with // "0x" or suffixed with "H") and decimal numbers. Decimal numbers may // have "K" (Ki) or "M" (Mi) suffixes. static Optional parseInt(StringRef Tok) { // Negative number if (Tok.startswith("-")) { if (Optional Val = parseInt(Tok.substr(1))) return -*Val; return None; } // Hexadecimal uint64_t Val; if (Tok.startswith_lower("0x") && to_integer(Tok.substr(2), Val, 16)) return Val; if (Tok.endswith_lower("H") && to_integer(Tok.drop_back(), Val, 16)) return Val; // Decimal if (Tok.endswith_lower("K")) { if (!to_integer(Tok.drop_back(), Val, 10)) return None; return Val * 1024; } if (Tok.endswith_lower("M")) { if (!to_integer(Tok.drop_back(), Val, 10)) return None; return Val * 1024 * 1024; } if (!to_integer(Tok, Val, 10)) return None; return Val; } BytesDataCommand *ScriptParser::readBytesDataCommand(StringRef Tok) { int Size = StringSwitch(Tok) .Case("BYTE", 1) .Case("SHORT", 2) .Case("LONG", 4) .Case("QUAD", 8) .Default(-1); if (Size == -1) return nullptr; return make(readParenExpr(), Size); } StringRef ScriptParser::readParenLiteral() { expect("("); StringRef Tok = next(); expect(")"); return Tok; } +OutputSection *ScriptParser::checkSection(OutputSectionCommand *Cmd, + StringRef Location) { + if (Cmd->Location.empty() && Script->ErrorOnMissingSection) + error(Location + ": undefined section " + Cmd->Name); + if (Cmd->Sec) + return Cmd->Sec; + static OutputSection Dummy("", 0, 0); + return &Dummy; +} + Expr ScriptParser::readPrimary() { if (peek() == "(") return readParenExpr(); if (consume("~")) { Expr E = readPrimary(); return [=] { return ~E().getValue(); }; } if (consume("-")) { Expr E = readPrimary(); return [=] { return -E().getValue(); }; } StringRef Tok = next(); std::string Location = getCurrentLocation(); // Built-in functions are parsed here. // https://sourceware.org/binutils/docs/ld/Builtin-Functions.html. if (Tok == "ABSOLUTE") { Expr Inner = readParenExpr(); return [=] { ExprValue I = Inner(); I.ForceAbsolute = true; return I; }; } if (Tok == "ADDR") { StringRef Name = readParenLiteral(); - return [=]() -> ExprValue { - return {Script->getOutputSection(Location, Name), 0}; - }; + OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name); + return [=]() -> ExprValue { return {checkSection(Cmd, Location), 0}; }; } if (Tok == "ALIGN") { expect("("); Expr E = readExpr(); if (consume(")")) return [=] { return alignTo(Script->getDot(), E().getValue()); }; expect(","); Expr E2 = readExpr(); expect(")"); return [=] { ExprValue V = E(); V.Alignment = E2().getValue(); return V; }; } if (Tok == "ALIGNOF") { StringRef Name = readParenLiteral(); - return [=] { return Script->getOutputSection(Location, Name)->Alignment; }; + OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name); + return [=] { return checkSection(Cmd, Location)->Alignment; }; } if (Tok == "ASSERT") return readAssertExpr(); if (Tok == "CONSTANT") { StringRef Name = readParenLiteral(); return [=] { return getConstant(Name); }; } if (Tok == "DATA_SEGMENT_ALIGN") { expect("("); Expr E = readExpr(); expect(","); readExpr(); expect(")"); return [=] { return alignTo(Script->getDot(), E().getValue()); }; } if (Tok == "DATA_SEGMENT_END") { expect("("); expect("."); expect(")"); return [] { return Script->getDot(); }; } if (Tok == "DATA_SEGMENT_RELRO_END") { // GNU linkers implements more complicated logic to handle // DATA_SEGMENT_RELRO_END. We instead ignore the arguments and // just align to the next page boundary for simplicity. expect("("); readExpr(); expect(","); readExpr(); expect(")"); return [] { return alignTo(Script->getDot(), Target->PageSize); }; } if (Tok == "DEFINED") { StringRef Name = readParenLiteral(); return [=] { return Script->isDefined(Name) ? 1 : 0; }; } if (Tok == "LENGTH") { StringRef Name = readParenLiteral(); if (Script->Opt.MemoryRegions.count(Name) == 0) setError("memory region not defined: " + Name); return [=] { return Script->Opt.MemoryRegions[Name].Length; }; } if (Tok == "LOADADDR") { StringRef Name = readParenLiteral(); - return [=] { return Script->getOutputSection(Location, Name)->getLMA(); }; + OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name); + return [=] { return checkSection(Cmd, Location)->getLMA(); }; } if (Tok == "ORIGIN") { StringRef Name = readParenLiteral(); if (Script->Opt.MemoryRegions.count(Name) == 0) setError("memory region not defined: " + Name); return [=] { return Script->Opt.MemoryRegions[Name].Origin; }; } if (Tok == "SEGMENT_START") { expect("("); skip(); expect(","); Expr E = readExpr(); expect(")"); return [=] { return E(); }; } if (Tok == "SIZEOF") { StringRef Name = readParenLiteral(); - return [=] { return Script->getOutputSectionSize(Name); }; + OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name); + // Linker script does not create an output section if its content is empty. + // We want to allow SIZEOF(.foo) where .foo is a section which happened to + // be empty. + return [=] { return Cmd->Sec ? Cmd->Sec->Size : 0; }; } if (Tok == "SIZEOF_HEADERS") return [=] { return elf::getHeaderSize(); }; // Tok is the dot. if (Tok == ".") return [=] { return Script->getSymbolValue(Location, Tok); }; // Tok is a literal number. if (Optional Val = parseInt(Tok)) return [=] { return *Val; }; // Tok is a symbol name. if (!isValidCIdentifier(Tok)) setError("malformed number: " + Tok); Script->Opt.ReferencedSymbols.push_back(Tok); return [=] { return Script->getSymbolValue(Location, Tok); }; } Expr ScriptParser::readTernary(Expr Cond) { Expr L = readExpr(); expect(":"); Expr R = readExpr(); return [=] { return Cond().getValue() ? L() : R(); }; } Expr ScriptParser::readParenExpr() { expect("("); Expr E = readExpr(); expect(")"); return E; } std::vector ScriptParser::readOutputSectionPhdrs() { std::vector Phdrs; while (!Error && peek().startswith(":")) { StringRef Tok = next(); Phdrs.push_back((Tok.size() == 1) ? next() : Tok.substr(1)); } return Phdrs; } // Read a program header type name. The next token must be a // name of a program header type or a constant (e.g. "0x3"). unsigned ScriptParser::readPhdrType() { StringRef Tok = next(); if (Optional Val = parseInt(Tok)) return *Val; unsigned Ret = StringSwitch(Tok) .Case("PT_NULL", PT_NULL) .Case("PT_LOAD", PT_LOAD) .Case("PT_DYNAMIC", PT_DYNAMIC) .Case("PT_INTERP", PT_INTERP) .Case("PT_NOTE", PT_NOTE) .Case("PT_SHLIB", PT_SHLIB) .Case("PT_PHDR", PT_PHDR) .Case("PT_TLS", PT_TLS) .Case("PT_GNU_EH_FRAME", PT_GNU_EH_FRAME) .Case("PT_GNU_STACK", PT_GNU_STACK) .Case("PT_GNU_RELRO", PT_GNU_RELRO) .Case("PT_OPENBSD_RANDOMIZE", PT_OPENBSD_RANDOMIZE) .Case("PT_OPENBSD_WXNEEDED", PT_OPENBSD_WXNEEDED) .Case("PT_OPENBSD_BOOTDATA", PT_OPENBSD_BOOTDATA) .Default(-1); if (Ret == (unsigned)-1) { setError("invalid program header type: " + Tok); return PT_NULL; } return Ret; } // Reads an anonymous version declaration. void ScriptParser::readAnonymousDeclaration() { std::vector Locals; std::vector Globals; std::tie(Locals, Globals) = readSymbols(); for (SymbolVersion V : Locals) { if (V.Name == "*") Config->DefaultSymbolVersion = VER_NDX_LOCAL; else Config->VersionScriptLocals.push_back(V); } for (SymbolVersion V : Globals) Config->VersionScriptGlobals.push_back(V); expect(";"); } // Reads a non-anonymous version definition, // e.g. "VerStr { global: foo; bar; local: *; };". void ScriptParser::readVersionDeclaration(StringRef VerStr) { // Read a symbol list. std::vector Locals; std::vector Globals; std::tie(Locals, Globals) = readSymbols(); for (SymbolVersion V : Locals) { if (V.Name == "*") Config->DefaultSymbolVersion = VER_NDX_LOCAL; else Config->VersionScriptLocals.push_back(V); } // Create a new version definition and add that to the global symbols. VersionDefinition Ver; Ver.Name = VerStr; Ver.Globals = Globals; // User-defined version number starts from 2 because 0 and 1 are // reserved for VER_NDX_LOCAL and VER_NDX_GLOBAL, respectively. Ver.Id = Config->VersionDefinitions.size() + 2; Config->VersionDefinitions.push_back(Ver); // Each version may have a parent version. For example, "Ver2" // defined as "Ver2 { global: foo; local: *; } Ver1;" has "Ver1" // as a parent. This version hierarchy is, probably against your // instinct, purely for hint; the runtime doesn't care about it // at all. In LLD, we simply ignore it. if (peek() != ";") skip(); expect(";"); } // Reads a list of symbols, e.g. "{ global: foo; bar; local: *; };". std::pair, std::vector> ScriptParser::readSymbols() { std::vector Locals; std::vector Globals; std::vector *V = &Globals; while (!Error) { if (consume("}")) break; if (consumeLabel("local")) { V = &Locals; continue; } if (consumeLabel("global")) { V = &Globals; continue; } if (consume("extern")) { std::vector Ext = readVersionExtern(); V->insert(V->end(), Ext.begin(), Ext.end()); } else { StringRef Tok = next(); V->push_back({unquote(Tok), false, hasWildcard(Tok)}); } expect(";"); } return {Locals, Globals}; } // Reads an "extern C++" directive, e.g., // "extern "C++" { ns::*; "f(int, double)"; };" std::vector ScriptParser::readVersionExtern() { StringRef Tok = next(); bool IsCXX = Tok == "\"C++\""; if (!IsCXX && Tok != "\"C\"") setError("Unknown language"); expect("{"); std::vector Ret; while (!Error && peek() != "}") { StringRef Tok = next(); bool HasWildcard = !Tok.startswith("\"") && hasWildcard(Tok); Ret.push_back({unquote(Tok), IsCXX, HasWildcard}); expect(";"); } expect("}"); return Ret; } uint64_t ScriptParser::readMemoryAssignment(StringRef S1, StringRef S2, StringRef S3) { if (!consume(S1) && !consume(S2) && !consume(S3)) { setError("expected one of: " + S1 + ", " + S2 + ", or " + S3); return 0; } expect("="); return readExpr()().getValue(); } // Parse the MEMORY command as specified in: // https://sourceware.org/binutils/docs/ld/MEMORY.html // // MEMORY { name [(attr)] : ORIGIN = origin, LENGTH = len ... } void ScriptParser::readMemory() { expect("{"); while (!Error && !consume("}")) { StringRef Name = next(); uint32_t Flags = 0; uint32_t NegFlags = 0; if (consume("(")) { std::tie(Flags, NegFlags) = readMemoryAttributes(); expect(")"); } expect(":"); uint64_t Origin = readMemoryAssignment("ORIGIN", "org", "o"); expect(","); uint64_t Length = readMemoryAssignment("LENGTH", "len", "l"); // Add the memory region to the region map (if it doesn't already exist). auto It = Script->Opt.MemoryRegions.find(Name); if (It != Script->Opt.MemoryRegions.end()) setError("region '" + Name + "' already defined"); else Script->Opt.MemoryRegions[Name] = {Name, Origin, Length, Origin, Flags, NegFlags}; } } // This function parses the attributes used to match against section // flags when placing output sections in a memory region. These flags // are only used when an explicit memory region name is not used. std::pair ScriptParser::readMemoryAttributes() { uint32_t Flags = 0; uint32_t NegFlags = 0; bool Invert = false; for (char C : next().lower()) { uint32_t Flag = 0; if (C == '!') Invert = !Invert; else if (C == 'w') Flag = SHF_WRITE; else if (C == 'x') Flag = SHF_EXECINSTR; else if (C == 'a') Flag = SHF_ALLOC; else if (C != 'r') setError("invalid memory region attribute"); if (Invert) NegFlags |= Flag; else Flags |= Flag; } return {Flags, NegFlags}; } void elf::readLinkerScript(MemoryBufferRef MB) { ScriptParser(MB).readLinkerScript(); } void elf::readVersionScript(MemoryBufferRef MB) { ScriptParser(MB).readVersionScript(); } void elf::readDynamicList(MemoryBufferRef MB) { ScriptParser(MB).readDynamicList(); } Index: vendor/lld/dist/ELF/Symbols.cpp =================================================================== --- vendor/lld/dist/ELF/Symbols.cpp (revision 319468) +++ vendor/lld/dist/ELF/Symbols.cpp (revision 319469) @@ -1,386 +1,386 @@ //===- Symbols.cpp --------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Symbols.h" #include "Error.h" #include "InputFiles.h" #include "InputSection.h" #include "OutputSections.h" #include "Strings.h" #include "SyntheticSections.h" #include "Target.h" #include "Writer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Path.h" #include using namespace llvm; using namespace llvm::object; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; DefinedRegular *ElfSym::Bss; DefinedRegular *ElfSym::Etext1; DefinedRegular *ElfSym::Etext2; DefinedRegular *ElfSym::Edata1; DefinedRegular *ElfSym::Edata2; DefinedRegular *ElfSym::End1; DefinedRegular *ElfSym::End2; DefinedRegular *ElfSym::MipsGp; DefinedRegular *ElfSym::MipsGpDisp; DefinedRegular *ElfSym::MipsLocalGp; static uint64_t getSymVA(const SymbolBody &Body, int64_t &Addend) { switch (Body.kind()) { case SymbolBody::DefinedRegularKind: { auto &D = cast(Body); SectionBase *IS = D.Section; if (auto *ISB = dyn_cast_or_null(IS)) IS = ISB->Repl; // According to the ELF spec reference to a local symbol from outside // the group are not allowed. Unfortunately .eh_frame breaks that rule // and must be treated specially. For now we just replace the symbol with // 0. if (IS == &InputSection::Discarded) return 0; // This is an absolute symbol. if (!IS) return D.Value; uint64_t Offset = D.Value; // An object in an SHF_MERGE section might be referenced via a // section symbol (as a hack for reducing the number of local // symbols). // Depending on the addend, the reference via a section symbol // refers to a different object in the merge section. // Since the objects in the merge section are not necessarily // contiguous in the output, the addend can thus affect the final // VA in a non-linear way. // To make this work, we incorporate the addend into the section // offset (and zero out the addend for later processing) so that // we find the right object in the section. if (D.isSection()) { Offset += Addend; Addend = 0; } const OutputSection *OutSec = IS->getOutputSection(); // In the typical case, this is actually very simple and boils // down to adding together 3 numbers: // 1. The address of the output section. // 2. The offset of the input section within the output section. // 3. The offset within the input section (this addition happens // inside InputSection::getOffset). // // If you understand the data structures involved with this next // line (and how they get built), then you have a pretty good // understanding of the linker. uint64_t VA = (OutSec ? OutSec->Addr : 0) + IS->getOffset(Offset); if (D.isTls() && !Config->Relocatable) { if (!Out::TlsPhdr) fatal(toString(D.File) + " has a STT_TLS symbol but doesn't have a PT_TLS section"); return VA - Out::TlsPhdr->p_vaddr; } return VA; } case SymbolBody::DefinedCommonKind: if (!Config->DefineCommon) return 0; - return InX::Common->OutSec->Addr + InX::Common->OutSecOff + + return InX::Common->getParent()->Addr + InX::Common->OutSecOff + cast(Body).Offset; case SymbolBody::SharedKind: { auto &SS = cast(Body); if (SS.NeedsCopy) - return SS.CopyRelSec->OutSec->Addr + SS.CopyRelSec->OutSecOff + + return SS.CopyRelSec->getParent()->Addr + SS.CopyRelSec->OutSecOff + SS.CopyRelSecOff; if (SS.NeedsPltAddr) return Body.getPltVA(); return 0; } case SymbolBody::UndefinedKind: return 0; case SymbolBody::LazyArchiveKind: case SymbolBody::LazyObjectKind: assert(Body.symbol()->IsUsedInRegularObj && "lazy symbol reached writer"); return 0; } llvm_unreachable("invalid symbol kind"); } SymbolBody::SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type) : SymbolKind(K), NeedsCopy(false), NeedsPltAddr(false), IsLocal(IsLocal), IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false), IsInIgot(false), Type(Type), StOther(StOther), Name(Name) {} // Returns true if a symbol can be replaced at load-time by a symbol // with the same name defined in other ELF executable or DSO. bool SymbolBody::isPreemptible() const { if (isLocal()) return false; // Shared symbols resolve to the definition in the DSO. The exceptions are // symbols with copy relocations (which resolve to .bss) or preempt plt // entries (which resolve to that plt entry). if (isShared()) return !NeedsCopy && !NeedsPltAddr; // That's all that can be preempted in a non-DSO. if (!Config->Shared) return false; // Only symbols that appear in dynsym can be preempted. if (!symbol()->includeInDynsym()) return false; // Only default visibility symbols can be preempted. if (symbol()->Visibility != STV_DEFAULT) return false; // -Bsymbolic means that definitions are not preempted. if (Config->Bsymbolic || (Config->BsymbolicFunctions && isFunc())) return !isDefined(); return true; } uint64_t SymbolBody::getVA(int64_t Addend) const { uint64_t OutVA = getSymVA(*this, Addend); return OutVA + Addend; } uint64_t SymbolBody::getGotVA() const { return InX::Got->getVA() + getGotOffset(); } uint64_t SymbolBody::getGotOffset() const { return GotIndex * Target->GotEntrySize; } uint64_t SymbolBody::getGotPltVA() const { if (this->IsInIgot) return InX::IgotPlt->getVA() + getGotPltOffset(); return InX::GotPlt->getVA() + getGotPltOffset(); } uint64_t SymbolBody::getGotPltOffset() const { return GotPltIndex * Target->GotPltEntrySize; } uint64_t SymbolBody::getPltVA() const { if (this->IsInIplt) return InX::Iplt->getVA() + PltIndex * Target->PltEntrySize; return InX::Plt->getVA() + Target->PltHeaderSize + PltIndex * Target->PltEntrySize; } template typename ELFT::uint SymbolBody::getSize() const { if (const auto *C = dyn_cast(this)) return C->Size; if (const auto *DR = dyn_cast(this)) return DR->Size; if (const auto *S = dyn_cast(this)) return S->getSize(); return 0; } OutputSection *SymbolBody::getOutputSection() const { if (auto *S = dyn_cast(this)) { if (S->Section) return S->Section->getOutputSection(); return nullptr; } if (auto *S = dyn_cast(this)) { if (S->NeedsCopy) - return S->CopyRelSec->OutSec; + return S->CopyRelSec->getParent(); return nullptr; } if (isa(this)) { if (Config->DefineCommon) - return InX::Common->OutSec; + return InX::Common->getParent(); return nullptr; } return nullptr; } // If a symbol name contains '@', the characters after that is // a symbol version name. This function parses that. void SymbolBody::parseSymbolVersion() { StringRef S = getName(); size_t Pos = S.find('@'); if (Pos == 0 || Pos == StringRef::npos) return; StringRef Verstr = S.substr(Pos + 1); if (Verstr.empty()) return; // Truncate the symbol name so that it doesn't include the version string. Name = {S.data(), Pos}; // If this is not in this DSO, it is not a definition. if (!isInCurrentDSO()) return; // '@@' in a symbol name means the default version. // It is usually the most recent one. bool IsDefault = (Verstr[0] == '@'); if (IsDefault) Verstr = Verstr.substr(1); for (VersionDefinition &Ver : Config->VersionDefinitions) { if (Ver.Name != Verstr) continue; if (IsDefault) symbol()->VersionId = Ver.Id; else symbol()->VersionId = Ver.Id | VERSYM_HIDDEN; return; } // It is an error if the specified version is not defined. error(toString(File) + ": symbol " + S + " has undefined version " + Verstr); } Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type) : SymbolBody(K, Name, IsLocal, StOther, Type) {} template bool DefinedRegular::isMipsPIC() const { if (!Section || !isFunc()) return false; return (this->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC || (cast(Section) ->template getFile() ->getObj() .getHeader() ->e_flags & EF_MIPS_PIC); } Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type, InputFile *File) : SymbolBody(SymbolBody::UndefinedKind, Name, IsLocal, StOther, Type) { this->File = File; } DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint32_t Alignment, uint8_t StOther, uint8_t Type, InputFile *File) : Defined(SymbolBody::DefinedCommonKind, Name, /*IsLocal=*/false, StOther, Type), Alignment(Alignment), Size(Size) { this->File = File; } // If a shared symbol is referred via a copy relocation, its alignment // becomes part of the ABI. This function returns a symbol alignment. // Because symbols don't have alignment attributes, we need to infer that. template uint32_t SharedSymbol::getAlignment() const { auto *File = cast>(this->File); uint32_t SecAlign = File->getSection(getSym())->sh_addralign; uint64_t SymValue = getSym().st_value; uint32_t SymAlign = uint32_t(1) << countTrailingZeros(SymValue); return std::min(SecAlign, SymAlign); } InputFile *Lazy::fetch() { if (auto *S = dyn_cast(this)) return S->fetch(); return cast(this)->fetch(); } LazyArchive::LazyArchive(ArchiveFile &File, const llvm::object::Archive::Symbol S, uint8_t Type) : Lazy(LazyArchiveKind, S.getName(), Type), Sym(S) { this->File = &File; } LazyObject::LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type) : Lazy(LazyObjectKind, Name, Type) { this->File = &File; } InputFile *LazyArchive::fetch() { std::pair MBInfo = file()->getMember(&Sym); // getMember returns an empty buffer if the member was already // read from the library. if (MBInfo.first.getBuffer().empty()) return nullptr; return createObjectFile(MBInfo.first, file()->getName(), MBInfo.second); } InputFile *LazyObject::fetch() { return file()->fetch(); } uint8_t Symbol::computeBinding() const { if (Config->Relocatable) return Binding; if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) return STB_LOCAL; if (VersionId == VER_NDX_LOCAL && body()->isInCurrentDSO()) return STB_LOCAL; if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE) return STB_GLOBAL; return Binding; } bool Symbol::includeInDynsym() const { if (computeBinding() == STB_LOCAL) return false; return ExportDynamic || body()->isShared() || (body()->isUndefined() && Config->Shared); } // Print out a log message for --trace-symbol. void elf::printTraceSymbol(Symbol *Sym) { SymbolBody *B = Sym->body(); std::string S; if (B->isUndefined()) S = ": reference to "; else if (B->isCommon()) S = ": common definition of "; else S = ": definition of "; message(toString(B->File) + S + B->getName()); } // Returns a symbol for an error message. std::string lld::toString(const SymbolBody &B) { if (Config->Demangle) if (Optional S = demangle(B.getName())) return *S; return B.getName(); } template uint32_t SymbolBody::template getSize() const; template uint32_t SymbolBody::template getSize() const; template uint64_t SymbolBody::template getSize() const; template uint64_t SymbolBody::template getSize() const; template bool DefinedRegular::template isMipsPIC() const; template bool DefinedRegular::template isMipsPIC() const; template bool DefinedRegular::template isMipsPIC() const; template bool DefinedRegular::template isMipsPIC() const; template uint32_t SharedSymbol::template getAlignment() const; template uint32_t SharedSymbol::template getAlignment() const; template uint32_t SharedSymbol::template getAlignment() const; template uint32_t SharedSymbol::template getAlignment() const; Index: vendor/lld/dist/ELF/SyntheticSections.cpp =================================================================== --- vendor/lld/dist/ELF/SyntheticSections.cpp (revision 319468) +++ vendor/lld/dist/ELF/SyntheticSections.cpp (revision 319469) @@ -1,2320 +1,2327 @@ //===- 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/DebugInfo/DWARF/DWARFDebugPubTable.h" #include "llvm/Object/ELFObjectFile.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; uint64_t SyntheticSection::getVA() const { - if (this->OutSec) - return this->OutSec->Addr + this->OutSecOff; + if (OutputSection *Sec = getParent()) + return Sec->Addr + OutSecOff; return 0; } 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() { if (!Config->DefineCommon) return nullptr; // Sort the common symbols by alignment as an heuristic to pack them better. std::vector Syms = getCommonSymbols(); if (Syms.empty()) return nullptr; std::stable_sort(Syms.begin(), Syms.end(), [](const DefinedCommon *A, const DefinedCommon *B) { return A->Alignment > B->Alignment; }); BssSection *Sec = make("COMMON"); for (DefinedCommon *Sym : Syms) Sym->Offset = Sec->reserveSpace(Sym->Size, Sym->Alignment); return Sec; } // 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 "readelf --string-dump .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((ObjectFile *)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) { this->Entsize = sizeof(Elf_Mips_ABIFlags); } 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 : InputSections) { if (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) { this->Entsize = sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_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 = InX::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 : InputSections) { if (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) { this->Entsize = sizeof(Elf_Mips_RegInfo); } template void MipsReginfoSection::writeTo(uint8_t *Buf) { if (!Config->Relocatable) Reginfo.ri_gp_value = InX::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 : InputSections) { if (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; } InputSection *elf::createInterpSection() { // StringSaver guarantees that the returned string ends with '\0'. StringRef S = Saver.save(Config->DynamicLinker); ArrayRef Contents = {(const uint8_t *)S.data(), S.size() + 1}; auto *Sec = make(SHF_ALLOC, SHT_PROGBITS, 1, Contents, ".interp"); Sec->Live = true; return Sec; } SymbolBody *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, uint64_t Size, InputSectionBase *Section) { auto *S = make(Name, /*IsLocal*/ true, STV_DEFAULT, Type, Value, Size, Section, nullptr); if (InX::SymTab) InX::SymTab->addSymbol(S); return S; } 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"); } } BuildIdSection::BuildIdSection() : SyntheticSection(SHF_ALLOC, SHT_NOTE, 1, ".note.gnu.build-id"), HashSize(getHashSize()) {} void BuildIdSection::writeTo(uint8_t *Buf) { endianness E = Config->Endianness; write32(Buf, 4, E); // Name size write32(Buf + 4, HashSize, E); // Content size write32(Buf + 8, NT_GNU_BUILD_ID, E); // 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. 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. parallelForEachN(0, Chunks.size(), [&](size_t I) { HashFn(Hashes.data() + I * HashSize, Chunks[I]); }); // Write to the final output buffer. HashFn(HashBuf, Hashes); } BssSection::BssSection(StringRef Name) : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, 0, Name) {} size_t BssSection::reserveSpace(uint64_t Size, uint32_t Alignment) { - if (OutSec) - OutSec->updateAlignment(Alignment); + if (OutputSection *Sec = getParent()) + Sec->updateAlignment(Alignment); this->Size = alignTo(this->Size, Alignment) + Size; this->Alignment = std::max(this->Alignment, Alignment); return this->Size - Size; } 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 EhFrameSection::EhFrameSection() : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame") {} // Search for an existing CIE record or create a new one. // CIE records from input object files are uniquified by their contents // and where their relocations point to. template template CieRecord *EhFrameSection::addCie(EhSectionPiece &Piece, ArrayRef Rels) { auto *Sec = cast(Piece.ID); const endianness E = ELFT::TargetEndianness; if (read32(Piece.data().data() + 4) != 0) fatal(toString(Sec) + ": CIE expected at beginning of .eh_frame"); SymbolBody *Personality = nullptr; unsigned FirstRelI = Piece.FirstRelocation; if (FirstRelI != (unsigned)-1) Personality = &Sec->template getFile()->getRelocTargetSym(Rels[FirstRelI]); // Search for an existing CIE by CIE contents/relocation target pair. CieRecord *Cie = &CieMap[{Piece.data(), Personality}]; // If not found, create a new one. if (Cie->Piece == nullptr) { Cie->Piece = &Piece; Cies.push_back(Cie); } return Cie; } // There is one FDE per function. Returns true if a given FDE // points to a live function. template template bool EhFrameSection::isFdeLive(EhSectionPiece &Piece, ArrayRef Rels) { auto *Sec = cast(Piece.ID); unsigned FirstRelI = Piece.FirstRelocation; if (FirstRelI == (unsigned)-1) return false; const RelTy &Rel = Rels[FirstRelI]; SymbolBody &B = Sec->template getFile()->getRelocTargetSym(Rel); auto *D = dyn_cast(&B); if (!D || !D->Section) return false; auto *Target = cast(cast(D->Section)->Repl); return Target && Target->Live; } // .eh_frame is a sequence of CIE or FDE records. In general, there // is one CIE record per input object file which is followed by // a list of FDEs. This function searches an existing CIE or create a new // one and associates FDEs to the CIE. template template void EhFrameSection::addSectionAux(EhInputSection *Sec, ArrayRef Rels) { const endianness E = ELFT::TargetEndianness; DenseMap OffsetToCie; for (EhSectionPiece &Piece : Sec->Pieces) { // The empty record is the end marker. if (Piece.size() == 4) return; size_t Offset = Piece.InputOff; uint32_t ID = read32(Piece.data().data() + 4); if (ID == 0) { OffsetToCie[Offset] = addCie(Piece, Rels); continue; } uint32_t CieOffset = Offset + 4 - ID; CieRecord *Cie = OffsetToCie[CieOffset]; if (!Cie) fatal(toString(Sec) + ": invalid CIE reference"); if (!isFdeLive(Piece, Rels)) continue; Cie->FdePieces.push_back(&Piece); NumFdes++; } } template void EhFrameSection::addSection(InputSectionBase *C) { auto *Sec = cast(C); - Sec->EHSec = this; + Sec->Parent = this; updateAlignment(Sec->Alignment); Sections.push_back(Sec); for (auto *DS : Sec->DependentSections) DependentSections.push_back(DS); // .eh_frame is a sequence of CIE or FDE records. This function // splits it into pieces so that we can call // SplitInputSection::getSectionPiece on the section. Sec->split(); if (Sec->Pieces.empty()) return; if (Sec->NumRelocations) { if (Sec->AreRelocsRela) addSectionAux(Sec, Sec->template relas()); else addSectionAux(Sec, Sec->template rels()); return; } addSectionAux(Sec, makeArrayRef(nullptr, nullptr)); } template static void writeCieFde(uint8_t *Buf, ArrayRef D) { memcpy(Buf, D.data(), D.size()); // Fix the size field. -4 since size does not include the size field itself. const endianness E = ELFT::TargetEndianness; write32(Buf, alignTo(D.size(), sizeof(typename ELFT::uint)) - 4); } template void EhFrameSection::finalizeContents() { if (this->Size) return; // Already finalized. size_t Off = 0; for (CieRecord *Cie : Cies) { Cie->Piece->OutputOff = Off; Off += alignTo(Cie->Piece->size(), Config->Wordsize); for (EhSectionPiece *Fde : Cie->FdePieces) { Fde->OutputOff = Off; Off += alignTo(Fde->size(), Config->Wordsize); } } // The LSB standard does not allow a .eh_frame section with zero // Call Frame Information records. Therefore add a CIE record length // 0 as a terminator if this .eh_frame section is empty. if (Off == 0) Off = 4; this->Size = Off; } template static uint64_t readFdeAddr(uint8_t *Buf, int Size) { const endianness E = ELFT::TargetEndianness; switch (Size) { case DW_EH_PE_udata2: return read16(Buf); case DW_EH_PE_udata4: return read32(Buf); case DW_EH_PE_udata8: return read64(Buf); case DW_EH_PE_absptr: if (ELFT::Is64Bits) return read64(Buf); return read32(Buf); } fatal("unknown FDE size encoding"); } // Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to. // We need it to create .eh_frame_hdr section. template uint64_t EhFrameSection::getFdePc(uint8_t *Buf, size_t FdeOff, uint8_t Enc) { // The starting address to which this FDE applies is // stored at FDE + 8 byte. size_t Off = FdeOff + 8; uint64_t Addr = readFdeAddr(Buf + Off, Enc & 0x7); if ((Enc & 0x70) == DW_EH_PE_absptr) return Addr; if ((Enc & 0x70) == DW_EH_PE_pcrel) - return Addr + this->OutSec->Addr + Off; + return Addr + getParent()->Addr + Off; fatal("unknown FDE size relative encoding"); } template void EhFrameSection::writeTo(uint8_t *Buf) { const endianness E = ELFT::TargetEndianness; for (CieRecord *Cie : Cies) { size_t CieOffset = Cie->Piece->OutputOff; writeCieFde(Buf + CieOffset, Cie->Piece->data()); for (EhSectionPiece *Fde : Cie->FdePieces) { size_t Off = Fde->OutputOff; writeCieFde(Buf + Off, Fde->data()); // FDE's second word should have the offset to an associated CIE. // Write it. write32(Buf + Off + 4, Off + 4 - CieOffset); } } for (EhInputSection *S : Sections) S->relocateAlloc(Buf, nullptr); // Construct .eh_frame_hdr. .eh_frame_hdr is a binary search table // to get a FDE from an address to which FDE is applied. So here // we obtain two addresses and pass them to EhFrameHdr object. if (In::EhFrameHdr) { for (CieRecord *Cie : Cies) { uint8_t Enc = getFdeEncoding(Cie->Piece); for (SectionPiece *Fde : Cie->FdePieces) { uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc); - uint64_t FdeVA = this->OutSec->Addr + Fde->OutputOff; + uint64_t FdeVA = getParent()->Addr + Fde->OutputOff; In::EhFrameHdr->addFde(Pc, FdeVA); } } } } GotSection::GotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Target->GotEntrySize, ".got") {} void GotSection::addEntry(SymbolBody &Sym) { Sym.GotIndex = NumEntries; ++NumEntries; } 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. bool GotSection::addTlsIndex() { if (TlsIndexOff != uint32_t(-1)) return false; TlsIndexOff = NumEntries * Config->Wordsize; NumEntries += 2; return true; } uint64_t GotSection::getGlobalDynAddr(const SymbolBody &B) const { return this->getVA() + B.GlobalDynIndex * Config->Wordsize; } uint64_t GotSection::getGlobalDynOffset(const SymbolBody &B) const { return B.GlobalDynIndex * Config->Wordsize; } void GotSection::finalizeContents() { Size = NumEntries * Config->Wordsize; } 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; } void GotSection::writeTo(uint8_t *Buf) { relocateAlloc(Buf, Buf + Size); } MipsGotSection::MipsGotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16, ".got") {} void MipsGotSection::addEntry(SymbolBody &Sym, int64_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. - auto *DefSym = cast(&Sym); - PageIndexMap.insert({DefSym->Section->getOutputSection(), 0}); + PageIndexMap.insert({Sym.getOutputSection(), 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, uint64_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); } } 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. bool MipsGotSection::addTlsIndex() { if (TlsIndexOff != uint32_t(-1)) return false; TlsIndexOff = TlsEntries.size() * Config->Wordsize; 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; } uint64_t MipsGotSection::getPageEntryOffset(const SymbolBody &B, int64_t Addend) const { - const OutputSection *OutSec = - cast(&B)->Section->getOutputSection(); + const OutputSection *OutSec = B.getOutputSection(); uint64_t SecAddr = getMipsPageAddr(OutSec->Addr); uint64_t SymAddr = getMipsPageAddr(B.getVA(Addend)); uint64_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff; assert(Index < PageEntriesNum); return (HeaderEntriesNum + Index) * Config->Wordsize; } uint64_t MipsGotSection::getBodyEntryOffset(const SymbolBody &B, int64_t Addend) const { // Calculate offset of the GOT entries block: TLS, global, local. uint64_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 * Config->Wordsize; } uint64_t MipsGotSection::getTlsOffset() const { return (getLocalEntriesNum() + GlobalEntries.size()) * Config->Wordsize; } uint64_t MipsGotSection::getGlobalDynOffset(const SymbolBody &B) const { return B.GlobalDynIndex * Config->Wordsize; } const SymbolBody *MipsGotSection::getFirstGlobalEntry() const { return GlobalEntries.empty() ? nullptr : GlobalEntries.front().first; } unsigned MipsGotSection::getLocalEntriesNum() const { return HeaderEntriesNum + PageEntriesNum + LocalEntries.size() + LocalEntries32.size(); } void MipsGotSection::finalizeContents() { updateAllocSize(); } void MipsGotSection::updateAllocSize() { 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()) * Config->Wordsize; } 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; } uint64_t MipsGotSection::getGp() const { return ElfSym::MipsGp->getVA(0); } static uint64_t readUint(uint8_t *Buf) { if (Config->Is64) return read64(Buf, Config->Endianness); return read32(Buf, Config->Endianness); } static void writeUint(uint8_t *Buf, uint64_t Val) { if (Config->Is64) write64(Buf, Val, Config->Endianness); else write32(Buf, Val, Config->Endianness); } 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. writeUint(Buf + Config->Wordsize, (uint64_t)1 << (Config->Wordsize * 8 - 1)); Buf += HeaderEntriesNum * Config->Wordsize; // Write 'page address' entries to the local part of the GOT. for (std::pair &L : PageIndexMap) { size_t PageCount = getMipsPageCount(L.first->Size); uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr); for (size_t PI = 0; PI < PageCount; ++PI) { uint8_t *Entry = Buf + (L.second + PI) * Config->Wordsize; writeUint(Entry, FirstPageAddr + PI * 0x10000); } } Buf += PageEntriesNum * Config->Wordsize; auto AddEntry = [&](const GotEntry &SA) { uint8_t *Entry = Buf; Buf += Config->Wordsize; const SymbolBody *Body = SA.first; uint64_t VA = Body->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; uint64_t VA = B->getVA(); if (B->GotIndex != -1U) { uint8_t *Entry = Buf + B->GotIndex * Config->Wordsize; writeUint(Entry, VA - 0x7000); } if (B->GlobalDynIndex != -1U) { uint8_t *Entry = Buf + B->GlobalDynIndex * Config->Wordsize; writeUint(Entry, 1); Entry += Config->Wordsize; writeUint(Entry, VA - 0x8000); } } } GotPltSection::GotPltSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Target->GotPltEntrySize, ".got.plt") {} void GotPltSection::addEntry(SymbolBody &Sym) { Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size(); Entries.push_back(&Sym); } size_t GotPltSection::getSize() const { return (Target->GotPltHeaderEntriesNum + Entries.size()) * Target->GotPltEntrySize; } void GotPltSection::writeTo(uint8_t *Buf) { Target->writeGotPltHeader(Buf); Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize; for (const SymbolBody *B : Entries) { Target->writeGotPlt(Buf, *B); Buf += Config->Wordsize; } } // On ARM the IgotPltSection is part of the GotSection, on other Targets it is // part of the .got.plt IgotPltSection::IgotPltSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Target->GotPltEntrySize, Config->EMachine == EM_ARM ? ".got" : ".got.plt") {} void IgotPltSection::addEntry(SymbolBody &Sym) { Sym.IsInIgot = true; Sym.GotPltIndex = Entries.size(); Entries.push_back(&Sym); } size_t IgotPltSection::getSize() const { return Entries.size() * Target->GotPltEntrySize; } void IgotPltSection::writeTo(uint8_t *Buf) { for (const SymbolBody *B : Entries) { Target->writeIgotPlt(Buf, *B); Buf += Config->Wordsize; } } StringTableSection::StringTableSection(StringRef Name, bool Dynamic) : SyntheticSection(Dynamic ? (uint64_t)SHF_ALLOC : 0, SHT_STRTAB, 1, Name), Dynamic(Dynamic) { // ELF string tables start with a NUL byte. addString(""); } // 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. 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; } void StringTableSection::writeTo(uint8_t *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, Config->Wordsize, ".dynamic") { this->Entsize = ELFT::Is64Bits ? 16 : 8; // .dynamic section is not writable on MIPS and on Fuchsia OS // which passes -z rodynamic. // 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 || Config->ZRodynamic) 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, InX::DynStrTab->addString(S)}); if (!Config->Rpath.empty()) add({Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH, InX::DynStrTab->addString(Config->Rpath)}); for (SharedFile *F : Symtab::X->getSharedFiles()) if (F->isNeeded()) add({DT_NEEDED, InX::DynStrTab->addString(F->SoName)}); if (!Config->SoName.empty()) add({DT_SONAME, InX::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->ZNodlopen) DtFlags1 |= DF_1_NOOPEN; 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}); // DT_DEBUG is a pointer to debug informaion used by debuggers at runtime. We // need it for each process, so we don't write it for DSOs. The loader writes // the pointer into this entry. // // DT_DEBUG is the only .dynamic entry that needs to be written to. Some // systems (currently only Fuchsia OS) provide other means to give the // debugger this information. Such systems may choose make .dynamic read-only. // If the target is such a system (used -z rodynamic) don't write DT_DEBUG. if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic) add({DT_DEBUG, (uint64_t)0}); } // Add remaining entries to complete .dynamic contents. template void DynamicSection::finalizeContents() { if (this->Size) return; // Already finalized. - this->Link = InX::DynStrTab->OutSec->SectionIndex; - if (In::RelaDyn->OutSec->Size > 0) { + this->Link = InX::DynStrTab->getParent()->SectionIndex; + if (In::RelaDyn->getParent()->Size > 0) { bool IsRela = Config->IsRela; add({IsRela ? DT_RELA : DT_REL, In::RelaDyn}); - add({IsRela ? DT_RELASZ : DT_RELSZ, In::RelaDyn->OutSec->Size}); + add({IsRela ? DT_RELASZ : DT_RELSZ, In::RelaDyn->getParent()->Size}); add({IsRela ? DT_RELAENT : DT_RELENT, uint64_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) { + if (In::RelaPlt->getParent()->Size > 0) { add({DT_JMPREL, In::RelaPlt}); - add({DT_PLTRELSZ, In::RelaPlt->OutSec->Size}); + add({DT_PLTRELSZ, In::RelaPlt->getParent()->Size}); add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT, InX::GotPlt}); add({DT_PLTREL, uint64_t(Config->IsRela ? DT_RELA : DT_REL)}); } add({DT_SYMTAB, InX::DynSymTab}); add({DT_SYMENT, sizeof(Elf_Sym)}); add({DT_STRTAB, InX::DynStrTab}); add({DT_STRSZ, InX::DynStrTab->getSize()}); if (!Config->ZText) add({DT_TEXTREL, (uint64_t)0}); if (InX::GnuHashTab) add({DT_GNU_HASH, InX::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, InX::DynSymTab->getNumSymbols()}); add({DT_MIPS_LOCAL_GOTNO, InX::MipsGot->getLocalEntriesNum()}); if (const SymbolBody *B = InX::MipsGot->getFirstGlobalEntry()) add({DT_MIPS_GOTSYM, B->DynsymIndex}); else add({DT_MIPS_GOTSYM, InX::DynSymTab->getNumSymbols()}); add({DT_PLTGOT, InX::MipsGot}); if (InX::MipsRldMap) add({DT_MIPS_RLD_MAP, InX::MipsRldMap}); } - this->OutSec->Link = this->Link; + getParent()->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; + P->d_un.d_ptr = E.InSec->getParent()->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->getVA(); break; case Entry::PlainInt: P->d_un.d_val = E.Val; break; } ++P; } } uint64_t DynamicReloc::getOffset() const { - return InputSec->OutSec->Addr + InputSec->getOffset(OffsetInSec); + return InputSec->getOutputSection()->Addr + InputSec->getOffset(OffsetInSec); } int64_t DynamicReloc::getAddend() const { if (UseSymVA) return Sym->getVA(Addend); return Addend; } uint32_t DynamicReloc::getSymIndex() const { if (Sym && !UseSymVA) return Sym->DynsymIndex; return 0; } template RelocationSection::RelocationSection(StringRef Name, bool Sort) : SyntheticSection(SHF_ALLOC, Config->IsRela ? SHT_RELA : SHT_REL, Config->Wordsize, Name), Sort(Sort) { this->Entsize = Config->IsRela ? 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->IsMips64EL) == Target->RelativeRel; bool BIsRel = B.getType(Config->IsMips64EL) == Target->RelativeRel; if (AIsRel != BIsRel) return AIsRel; return A.getSymbol(Config->IsMips64EL) < B.getSymbol(Config->IsMips64EL); } template void RelocationSection::writeTo(uint8_t *Buf) { uint8_t *BufBegin = Buf; for (const DynamicReloc &Rel : Relocs) { auto *P = reinterpret_cast(Buf); Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); if (Config->IsRela) P->r_addend = Rel.getAddend(); P->r_offset = Rel.getOffset(); if (Config->EMachine == EM_MIPS && Rel.getInputSec() == InX::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 += InX::MipsGot->getTlsOffset(); P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL); } if (Sort) { if (Config->IsRela) 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::finalizeContents() { - this->Link = InX::DynSymTab ? InX::DynSymTab->OutSec->SectionIndex - : InX::SymTab->OutSec->SectionIndex; + this->Link = InX::DynSymTab ? InX::DynSymTab->getParent()->SectionIndex + : InX::SymTab->getParent()->SectionIndex; // Set required output section properties. - this->OutSec->Link = this->Link; + getParent()->Link = this->Link; } SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec) : SyntheticSection(StrTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0, StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB, Config->Wordsize, StrTabSec.isDynamic() ? ".dynsym" : ".symtab"), StrTabSec(StrTabSec) {} // 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 SymbolTableEntry &L, const SymbolTableEntry &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.Symbol->IsInGlobalMipsGot; bool RIsInLocalGot = !R.Symbol->IsInGlobalMipsGot; if (LIsInLocalGot || RIsInLocalGot) return !RIsInLocalGot; return L.Symbol->GotIndex < R.Symbol->GotIndex; } // Finalize a symbol table. The ELF spec requires that all local // symbols precede global symbols, so we sort symbol entries in this // function. (For .dynsym, we don't do that because symbols for // dynamic linking are inherently all globals.) void SymbolTableBaseSection::finalizeContents() { - this->OutSec->Link = StrTabSec.OutSec->SectionIndex; + getParent()->Link = StrTabSec.getParent()->SectionIndex; // If it is a .dynsym, there should be no local symbols, but we need // to do a few things for the dynamic linker. if (this->Type == SHT_DYNSYM) { // Section's Info field has the index of the first non-local symbol. // Because the first symbol entry is a null entry, 1 is the first. - this->OutSec->Info = 1; + getParent()->Info = 1; if (InX::GnuHashTab) { // NB: It also sorts Symbols to meet the GNU hash table requirements. InX::GnuHashTab->addSymbols(Symbols); } else if (Config->EMachine == EM_MIPS) { std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols); } size_t I = 0; for (const SymbolTableEntry &S : Symbols) S.Symbol->DynsymIndex = ++I; return; } } void SymbolTableBaseSection::postThunkContents() { if (this->Type == SHT_DYNSYM) return; // move all local symbols before global symbols. auto It = std::stable_partition( Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) { return S.Symbol->isLocal() || S.Symbol->symbol()->computeBinding() == STB_LOCAL; }); size_t NumLocals = It - Symbols.begin(); - this->OutSec->Info = NumLocals + 1; + getParent()->Info = NumLocals + 1; } void SymbolTableBaseSection::addSymbol(SymbolBody *B) { // Adding a local symbol to a .dynsym is a bug. assert(this->Type != SHT_DYNSYM || !B->isLocal()); bool HashIt = B->isLocal(); Symbols.push_back({B, StrTabSec.addString(B->getName(), HashIt)}); } size_t SymbolTableBaseSection::getSymbolIndex(SymbolBody *Body) { auto I = llvm::find_if(Symbols, [&](const SymbolTableEntry &E) { if (E.Symbol == Body) return true; // This is used for -r, so we have to handle multiple section // symbols being combined. if (Body->Type == STT_SECTION && E.Symbol->Type == STT_SECTION) - return cast(Body)->Section->getOutputSection() == - cast(E.Symbol)->Section->getOutputSection(); + return Body->getOutputSection() == E.Symbol->getOutputSection(); return false; }); if (I == Symbols.end()) return 0; return I - Symbols.begin() + 1; } template SymbolTableSection::SymbolTableSection(StringTableSection &StrTabSec) : SymbolTableBaseSection(StrTabSec) { this->Entsize = sizeof(Elf_Sym); } // Write the internal symbol table contents to the output symbol table. template void SymbolTableSection::writeTo(uint8_t *Buf) { // The first entry is a null entry as per the ELF spec. Buf += sizeof(Elf_Sym); auto *ESym = reinterpret_cast(Buf); for (SymbolTableEntry &Ent : Symbols) { SymbolBody *Body = Ent.Symbol; // Set st_info and st_other. if (Body->isLocal()) { ESym->setBindingAndType(STB_LOCAL, Body->Type); } else { ESym->setBindingAndType(Body->symbol()->computeBinding(), Body->Type); ESym->setVisibility(Body->symbol()->Visibility); } ESym->st_name = Ent.StrTabOffset; ESym->st_size = Body->getSize(); // Set a section index. if (const OutputSection *OutSec = Body->getOutputSection()) ESym->st_shndx = OutSec->SectionIndex; else if (isa(Body)) ESym->st_shndx = SHN_ABS; else if (isa(Body)) ESym->st_shndx = SHN_COMMON; // st_value is usually an address of a symbol, but that has a // special meaining for uninstantiated common symbols (this can // occur if -r is given). if (!Config->DefineCommon && isa(Body)) ESym->st_value = cast(Body)->Alignment; else ESym->st_value = Body->getVA(); ++ESym; } // 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 (Config->EMachine == EM_MIPS) { auto *ESym = reinterpret_cast(Buf); for (SymbolTableEntry &Ent : Symbols) { SymbolBody *Body = Ent.Symbol; if (Body->isInPlt() && Body->NeedsPltAddr) ESym->st_other |= STO_MIPS_PLT; if (Config->Relocatable) if (auto *D = dyn_cast(Body)) if (D->isMipsPIC()) ESym->st_other |= STO_MIPS_PIC; ++ESym; } } } // .hash and .gnu.hash sections contain on-disk hash tables that map // symbol names to their dynamic symbol table indices. Their purpose // is to help the dynamic linker resolve symbols quickly. If ELF files // don't have them, the dynamic linker has to do linear search on all // dynamic symbols, which makes programs slower. Therefore, a .hash // section is added to a DSO by default. A .gnu.hash is added if you // give the -hash-style=gnu or -hash-style=both option. // // The Unix semantics of resolving dynamic symbols is somewhat expensive. // Each ELF file has a list of DSOs that the ELF file depends on and a // list of dynamic symbols that need to be resolved from any of the // DSOs. That means resolving all dynamic symbols takes O(m)*O(n) // where m is the number of DSOs and n is the number of dynamic // symbols. For modern large programs, both m and n are large. So // making each step faster by using hash tables substiantially // improves time to load programs. // // (Note that this is not the only way to design the shared library. // For instance, the Windows DLL takes a different approach. On // Windows, each dynamic symbol has a name of DLL from which the symbol // has to be resolved. That makes the cost of symbol resolution O(n). // This disables some hacky techniques you can use on Unix such as // LD_PRELOAD, but this is arguably better semantics than the Unix ones.) // // Due to historical reasons, we have two different hash tables, .hash // and .gnu.hash. They are for the same purpose, and .gnu.hash is a new // and better version of .hash. .hash is just an on-disk hash table, but // .gnu.hash has a bloom filter in addition to a hash table to skip // DSOs very quickly. If you are sure that your dynamic linker knows // about .gnu.hash, you want to specify -hash-style=gnu. Otherwise, a // safe bet is to specify -hash-style=both for backward compatibilty. GnuHashTableSection::GnuHashTableSection() : SyntheticSection(SHF_ALLOC, SHT_GNU_HASH, Config->Wordsize, ".gnu.hash") { } void GnuHashTableSection::finalizeContents() { - this->OutSec->Link = InX::DynSymTab->OutSec->SectionIndex; + getParent()->Link = InX::DynSymTab->getParent()->SectionIndex; // Computes bloom filter size in word size. We want to allocate 8 // bits for each symbol. It must be a power of two. if (Symbols.empty()) MaskWords = 1; else MaskWords = NextPowerOf2((Symbols.size() - 1) / Config->Wordsize); Size = 16; // Header Size += Config->Wordsize * MaskWords; // Bloom filter Size += NBuckets * 4; // Hash buckets Size += Symbols.size() * 4; // Hash values } void GnuHashTableSection::writeTo(uint8_t *Buf) { // Write a header. write32(Buf, NBuckets, Config->Endianness); write32(Buf + 4, InX::DynSymTab->getNumSymbols() - Symbols.size(), Config->Endianness); write32(Buf + 8, MaskWords, Config->Endianness); write32(Buf + 12, getShift2(), Config->Endianness); Buf += 16; // Write a bloom filter and a hash table. writeBloomFilter(Buf); Buf += Config->Wordsize * MaskWords; writeHashTable(Buf); } // This function writes a 2-bit bloom filter. This bloom filter alone // usually filters out 80% or more of all symbol lookups [1]. // The dynamic linker uses the hash table only when a symbol is not // filtered out by a bloom filter. // // [1] Ulrich Drepper (2011), "How To Write Shared Libraries" (Ver. 4.1.2), // p.9, https://www.akkadia.org/drepper/dsohowto.pdf void GnuHashTableSection::writeBloomFilter(uint8_t *Buf) { const unsigned C = Config->Wordsize * 8; for (const Entry &Sym : Symbols) { size_t I = (Sym.Hash / C) & (MaskWords - 1); uint64_t Val = readUint(Buf + I * Config->Wordsize); Val |= uint64_t(1) << (Sym.Hash % C); Val |= uint64_t(1) << ((Sym.Hash >> getShift2()) % C); writeUint(Buf + I * Config->Wordsize, Val); } } void GnuHashTableSection::writeHashTable(uint8_t *Buf) { // Group symbols by hash value. std::vector> Syms(NBuckets); for (const Entry &Ent : Symbols) Syms[Ent.Hash % NBuckets].push_back(Ent); // Write hash buckets. Hash buckets contain indices in the following // hash value table. uint32_t *Buckets = reinterpret_cast(Buf); for (size_t I = 0; I < NBuckets; ++I) if (!Syms[I].empty()) write32(Buckets + I, Syms[I][0].Body->DynsymIndex, Config->Endianness); // Write a hash value table. It represents a sequence of chains that // share the same hash modulo value. The last element of each chain // is terminated by LSB 1. uint32_t *Values = Buckets + NBuckets; size_t I = 0; for (std::vector &Vec : Syms) { if (Vec.empty()) continue; for (const Entry &Ent : makeArrayRef(Vec).drop_back()) write32(Values + I++, Ent.Hash & ~1, Config->Endianness); write32(Values + I++, Vec.back().Hash | 1, Config->Endianness); } } static uint32_t hashGnu(StringRef Name) { uint32_t H = 5381; for (uint8_t C : Name) H = (H << 5) + H + C; return H; } // Returns a number of hash buckets to accomodate given number of elements. // We want to choose a moderate number that is not too small (which // causes too many hash collisions) and not too large (which wastes // disk space.) // // We return a prime number because it (is believed to) achieve good // hash distribution. static size_t getBucketSize(size_t NumSymbols) { // List of largest prime numbers that are not greater than 2^n + 1. for (size_t N : {131071, 65521, 32749, 16381, 8191, 4093, 2039, 1021, 509, 251, 127, 61, 31, 13, 7, 3, 1}) if (N <= NumSymbols) return N; return 0; } // 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. void GnuHashTableSection::addSymbols(std::vector &V) { // We cannot use 'auto' for Mid because GCC 6.1 cannot deduce // its type 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 (SymbolTableEntry &Ent : llvm::make_range(Mid, V.end())) { SymbolBody *B = Ent.Symbol; Symbols.push_back({B, Ent.StrTabOffset, hashGnu(B->getName())}); } NBuckets = getBucketSize(Symbols.size()); std::stable_sort(Symbols.begin(), Symbols.end(), [&](const Entry &L, const Entry &R) { return L.Hash % NBuckets < R.Hash % NBuckets; }); V.erase(Mid, V.end()); for (const Entry &Ent : Symbols) V.push_back({Ent.Body, Ent.StrTabOffset}); } template HashTableSection::HashTableSection() : SyntheticSection(SHF_ALLOC, SHT_HASH, 4, ".hash") { this->Entsize = 4; } template void HashTableSection::finalizeContents() { - this->OutSec->Link = InX::DynSymTab->OutSec->SectionIndex; + getParent()->Link = InX::DynSymTab->getParent()->SectionIndex; unsigned NumEntries = 2; // nbucket and nchain. NumEntries += InX::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 += InX::DynSymTab->getNumSymbols(); this->Size = NumEntries * 4; } template void HashTableSection::writeTo(uint8_t *Buf) { // A 32-bit integer type in the target endianness. typedef typename ELFT::Word Elf_Word; unsigned NumSymbols = InX::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 : InX::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; } } PltSection::PltSection(size_t S) : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt"), HeaderSize(S) {} void PltSection::writeTo(uint8_t *Buf) { // At beginning of PLT but not the IPLT, we have code to call the dynamic // linker to resolve dynsyms at runtime. Write such code. if (HeaderSize != 0) Target->writePltHeader(Buf); size_t Off = HeaderSize; // The IPlt is immediately after the Plt, account for this in RelOff unsigned PltOff = getPltRelocOff(); for (auto &I : Entries) { const SymbolBody *B = I.first; unsigned RelOff = I.second + PltOff; 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(); RelocationSection *PltRelocSection = In::RelaPlt; if (HeaderSize == 0) { PltRelocSection = In::RelaIplt; Sym.IsInIplt = true; } unsigned RelOff = PltRelocSection->getRelocOffset(); Entries.push_back(std::make_pair(&Sym, RelOff)); } size_t PltSection::getSize() const { return HeaderSize + Entries.size() * Target->PltEntrySize; } // Some architectures such as additional symbols in the PLT section. For // example ARM uses mapping symbols to aid disassembly void PltSection::addSymbols() { // The PLT may have symbols defined for the Header, the IPLT has no header if (HeaderSize != 0) Target->addPltHeaderSymbols(this); size_t Off = HeaderSize; for (size_t I = 0; I < Entries.size(); ++I) { Target->addPltSymbols(this, Off); Off += Target->PltEntrySize; } } unsigned PltSection::getPltRelocOff() const { return (HeaderSize == 0) ? InX::Plt->getSize() : 0; } GdbIndexSection::GdbIndexSection() : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"), StringPool(llvm::StringTableBuilder::ELF) {} // 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; } static std::vector> readCuList(DWARFContext &Dwarf, InputSection *Sec) { std::vector> Ret; for (std::unique_ptr &CU : Dwarf.compile_units()) Ret.push_back({Sec->OutSecOff + CU->getOffset(), CU->getLength() + 4}); return Ret; } static InputSection *findSection(ArrayRef Arr, uint64_t Offset) { for (InputSectionBase *S : Arr) if (auto *IS = dyn_cast_or_null(S)) if (IS != &InputSection::Discarded && IS->Live && Offset >= IS->getOffsetInFile() && Offset < IS->getOffsetInFile() + IS->getSize()) return IS; return nullptr; } static std::vector readAddressArea(DWARFContext &Dwarf, InputSection *Sec, size_t CurrentCU) { std::vector Ret; for (std::unique_ptr &CU : Dwarf.compile_units()) { DWARFAddressRangesVector Ranges; CU->collectAddressRanges(Ranges); ArrayRef Sections = Sec->File->getSections(); for (DWARFAddressRange &R : Ranges) if (InputSection *S = findSection(Sections, R.LowPC)) Ret.push_back({S, R.LowPC - S->getOffsetInFile(), R.HighPC - S->getOffsetInFile(), CurrentCU}); ++CurrentCU; } return Ret; } static std::vector> readPubNamesAndTypes(DWARFContext &Dwarf, bool IsLE) { StringRef Data[] = {Dwarf.getGnuPubNamesSection(), Dwarf.getGnuPubTypesSection()}; std::vector> Ret; for (StringRef D : Data) { DWARFDebugPubTable PubTable(D, IsLE, true); for (const DWARFDebugPubTable::Set &Set : PubTable.getData()) for (const DWARFDebugPubTable::Entry &Ent : Set.Entries) Ret.push_back({Ent.Name, Ent.Descriptor.toBits()}); } return Ret; } class ObjInfoTy : public llvm::LoadedObjectInfo { uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override { auto &S = static_cast(Sec); if (S.getFlags() & ELF::SHF_ALLOC) return S.getOffset(); return 0; } std::unique_ptr clone() const override { return {}; } }; void GdbIndexSection::readDwarf(InputSection *Sec) { Expected> Obj = object::ObjectFile::createObjectFile(Sec->File->MB); if (!Obj) { error(toString(Sec->File) + ": error creating DWARF context"); return; } ObjInfoTy ObjInfo; DWARFContextInMemory Dwarf(*Obj.get(), &ObjInfo); size_t CuId = CompilationUnits.size(); for (std::pair &P : readCuList(Dwarf, Sec)) CompilationUnits.push_back(P); for (AddressEntry &Ent : readAddressArea(Dwarf, Sec, CuId)) AddressArea.push_back(Ent); std::vector> NamesAndTypes = readPubNamesAndTypes(Dwarf, Config->IsLE); 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.resize(CuVectors.size() + 1); } CuVectors[Sym->CuVectorIndex].insert((Pair.second << 24) | (uint32_t)CuId); } } void GdbIndexSection::finalizeContents() { if (Finalized) return; Finalized = true; for (InputSectionBase *S : InputSections) if (InputSection *IS = dyn_cast(S)) - if (IS->OutSec && IS->Name == ".debug_info") + if (IS->getParent() && IS->Name == ".debug_info") readDwarf(IS); SymbolTable.finalizeContents(); // 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::set &CuVec : CuVectors) { CuVectorsOffset.push_back(CuVectorsSize); CuVectorsSize += OffsetTypeSize * (CuVec.size() + 1); } StringPoolOffset = ConstantPoolOffset + CuVectorsSize; StringPool.finalizeInOrder(); } size_t GdbIndexSection::getSize() const { const_cast(this)->finalizeContents(); return StringPoolOffset + StringPool.getSize(); } 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) { - uint64_t BaseAddr = E.Section->OutSec->Addr + E.Section->getOffset(0); + uint64_t BaseAddr = E.Section->getParent()->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::set &CuVec : CuVectors) { write32le(Buf, CuVec.size()); Buf += 4; for (uint32_t Val : CuVec) { write32le(Buf, Val); Buf += 4; } } StringPool.write(Buf); } 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, In::EhFrame->OutSec->Addr - this->getVA() - 4); + write32(Buf + 4, In::EhFrame->getParent()->Addr - this->getVA() - 4); write32(Buf + 8, Fdes.size()); Buf += 12; uint64_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 + In::EhFrame->NumFdes * 8; } template void EhFrameHeader::addFde(uint32_t Pc, uint32_t FdeVA) { Fdes.push_back({Pc, FdeVA}); } template bool EhFrameHeader::empty() const { return In::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::finalizeContents() { FileDefNameOff = InX::DynStrTab->addString(getFileDefName()); for (VersionDefinition &V : Config->VersionDefinitions) V.NameOff = InX::DynStrTab->addString(V.Name); - this->OutSec->Link = InX::DynStrTab->OutSec->SectionIndex; + getParent()->Link = InX::DynStrTab->getParent()->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 = getVerDefNum(); + getParent()->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") { this->Entsize = sizeof(Elf_Versym); } template void VersionTableSection::finalizeContents() { // 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 = InX::DynSymTab->OutSec->SectionIndex; + getParent()->Link = InX::DynSymTab->getParent()->SectionIndex; } template size_t VersionTableSection::getSize() const { return sizeof(Elf_Versym) * (InX::DynSymTab->getSymbols().size() + 1); } template void VersionTableSection::writeTo(uint8_t *Buf) { auto *OutVersym = reinterpret_cast(Buf) + 1; for (const SymbolTableEntry &S : InX::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) { auto *Ver = reinterpret_cast(SS->Verdef); if (!Ver) { SS->symbol()->VersionId = VER_NDX_GLOBAL; return; } auto *File = cast>(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 (File->VerdefMap.empty()) Needed.push_back({File, InX::DynStrTab->addString(File->SoName)}); typename SharedFile::NeededVer &NV = File->VerdefMap[Ver]; // 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 = InX::DynStrTab->addString(File->getStringTable().data() + Ver->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::finalizeContents() { - this->OutSec->Link = InX::DynStrTab->OutSec->SectionIndex; - this->OutSec->Info = Needed.size(); + getParent()->Link = InX::DynStrTab->getParent()->SectionIndex; + getParent()->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; } MergeSyntheticSection::MergeSyntheticSection(StringRef Name, uint32_t Type, uint64_t Flags, uint32_t Alignment) : SyntheticSection(Flags, Type, Alignment, Name), Builder(StringTableBuilder::RAW, Alignment) {} void MergeSyntheticSection::addSection(MergeInputSection *MS) { assert(!Finalized); - MS->MergeSec = this; + MS->Parent = this; Sections.push_back(MS); } void MergeSyntheticSection::writeTo(uint8_t *Buf) { Builder.write(Buf); } bool MergeSyntheticSection::shouldTailMerge() const { return (this->Flags & SHF_STRINGS) && Config->Optimize >= 2; } void MergeSyntheticSection::finalizeTailMerge() { // Add all string pieces to the string table builder to create section // contents. for (MergeInputSection *Sec : Sections) for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) if (Sec->Pieces[I].Live) Builder.add(Sec->getData(I)); // Fix the string table content. After this, the contents will never change. Builder.finalize(); // finalize() fixed tail-optimized strings, so we can now get // offsets of strings. Get an offset for each string and save it // to a corresponding StringPiece for easy access. for (MergeInputSection *Sec : Sections) for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) if (Sec->Pieces[I].Live) Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I)); } void MergeSyntheticSection::finalizeNoTailMerge() { // Add all string pieces to the string table builder to create section // contents. Because we are not tail-optimizing, offsets of strings are // fixed when they are added to the builder (string table builder contains // a hash table from strings to offsets). for (MergeInputSection *Sec : Sections) for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) if (Sec->Pieces[I].Live) Sec->Pieces[I].OutputOff = Builder.add(Sec->getData(I)); Builder.finalizeInOrder(); } void MergeSyntheticSection::finalizeContents() { if (Finalized) return; Finalized = true; if (shouldTailMerge()) finalizeTailMerge(); else finalizeNoTailMerge(); } size_t MergeSyntheticSection::getSize() const { // We should finalize string builder to know the size. const_cast(this)->finalizeContents(); return Builder.getSize(); } MipsRldMapSection::MipsRldMapSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize, ".rld_map") {} ARMExidxSentinelSection::ARMExidxSentinelSection() : SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX, Config->Wordsize, ".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 | +// The sentinel must have the PREL31 value of an address higher than any +// address described by any other table entry. void ARMExidxSentinelSection::writeTo(uint8_t *Buf) { - // Get the InputSection before us, we are by definition last - auto RI = 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(); + // The Sections are sorted in order of ascending PREL31 address with the + // sentinel last. We need to find the InputSection that precedes the + // sentinel. By construction the Sentinel is in the last + // InputSectionDescription as the InputSection that precedes it. + OutputSectionCommand *C = Script->getCmd(getParent()); + auto ISD = std::find_if(C->Commands.rbegin(), C->Commands.rend(), + [](const BaseCommand *Base) { + return isa(Base); + }); + auto L = cast(*ISD); + InputSection *Highest = L->Sections[L->Sections.size() - 2]; + InputSection *LS = Highest->getLinkOrderDep(); + uint64_t S = LS->getParent()->Addr + LS->getOffset(LS->getSize()); + uint64_t P = getVA(); Target->relocateOne(Buf, R_ARM_PREL31, S - P); write32le(Buf + 4, 0x1); } ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off) : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, Config->Wordsize, ".text.thunk") { - this->OutSec = OS; + this->Parent = OS; this->OutSecOff = Off; } void ThunkSection::addThunk(Thunk *T) { uint64_t Off = alignTo(Size, T->alignment); T->Offset = Off; Thunks.push_back(T); T->addSymbols(*this); Size = Off + T->size(); } void ThunkSection::writeTo(uint8_t *Buf) { for (const Thunk *T : Thunks) T->writeTo(Buf + T->Offset, *this); } InputSection *ThunkSection::getTargetInputSection() const { const Thunk *T = Thunks.front(); return T->getTargetInputSection(); } InputSection *InX::ARMAttributes; BssSection *InX::Bss; BssSection *InX::BssRelRo; BuildIdSection *InX::BuildId; InputSection *InX::Common; SyntheticSection *InX::Dynamic; StringTableSection *InX::DynStrTab; SymbolTableBaseSection *InX::DynSymTab; InputSection *InX::Interp; GdbIndexSection *InX::GdbIndex; GotSection *InX::Got; GotPltSection *InX::GotPlt; GnuHashTableSection *InX::GnuHashTab; IgotPltSection *InX::IgotPlt; MipsGotSection *InX::MipsGot; MipsRldMapSection *InX::MipsRldMap; PltSection *InX::Plt; PltSection *InX::Iplt; StringTableSection *InX::ShStrTab; StringTableSection *InX::StrTab; SymbolTableBaseSection *InX::SymTab; template void PltSection::addEntry(SymbolBody &Sym); template void PltSection::addEntry(SymbolBody &Sym); template void PltSection::addEntry(SymbolBody &Sym); template void PltSection::addEntry(SymbolBody &Sym); template InputSection *elf::createCommonSection(); template InputSection *elf::createCommonSection(); template InputSection *elf::createCommonSection(); template InputSection *elf::createCommonSection(); 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::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::HashTableSection; template class elf::HashTableSection; template class elf::HashTableSection; template class elf::HashTableSection; 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::EhFrameSection; template class elf::EhFrameSection; template class elf::EhFrameSection; template class elf::EhFrameSection; Index: vendor/lld/dist/ELF/SyntheticSections.h =================================================================== --- vendor/lld/dist/ELF/SyntheticSections.h (revision 319468) +++ vendor/lld/dist/ELF/SyntheticSections.h (revision 319469) @@ -1,801 +1,801 @@ //===- SyntheticSection.h ---------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Synthetic sections represent chunks of linker-created data. If you // need to create a chunk of data that to be included in some section // in the result, you probably want to create that as a synthetic section. // // Synthetic sections are designed as input sections as opposed to // output sections because we want to allow them to be manipulated // using linker scripts just like other input sections from regular // files. // //===----------------------------------------------------------------------===// #ifndef LLD_ELF_SYNTHETIC_SECTION_H #define LLD_ELF_SYNTHETIC_SECTION_H #include "EhFrame.h" #include "GdbIndex.h" #include "InputSection.h" #include "llvm/ADT/MapVector.h" #include "llvm/MC/StringTableBuilder.h" #include namespace lld { namespace elf { class SyntheticSection : public InputSection { public: SyntheticSection(uint64_t Flags, uint32_t Type, uint32_t Alignment, StringRef Name) : InputSection(Flags, Type, Alignment, {}, Name, InputSectionBase::Synthetic) { this->Live = true; } virtual ~SyntheticSection() = default; virtual void writeTo(uint8_t *Buf) = 0; virtual size_t getSize() const = 0; virtual void finalizeContents() {} // If the section has the SHF_ALLOC flag and the size may be changed if // thunks are added, update the section size. virtual void updateAllocSize() {} // If any additional finalization of contents are needed post thunk creation. virtual void postThunkContents() {} virtual bool empty() const { return false; } uint64_t getVA() const; - static bool classof(const InputSectionBase *D) { + static bool classof(const SectionBase *D) { return D->kind() == InputSectionBase::Synthetic; } }; struct CieRecord { EhSectionPiece *Piece = nullptr; std::vector FdePieces; }; // Section for .eh_frame. template class EhFrameSection final : public SyntheticSection { typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Rel Elf_Rel; typedef typename ELFT::Rela Elf_Rela; void updateAlignment(uint64_t Val) { if (Val > this->Alignment) this->Alignment = Val; } public: EhFrameSection(); void writeTo(uint8_t *Buf) override; void finalizeContents() override; bool empty() const override { return Sections.empty(); } size_t getSize() const override { return Size; } void addSection(InputSectionBase *S); size_t NumFdes = 0; std::vector Sections; private: uint64_t Size = 0; template void addSectionAux(EhInputSection *S, llvm::ArrayRef Rels); template CieRecord *addCie(EhSectionPiece &Piece, ArrayRef Rels); template bool isFdeLive(EhSectionPiece &Piece, ArrayRef Rels); uint64_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc); std::vector Cies; // CIE records are uniquified by their contents and personality functions. llvm::DenseMap, SymbolBody *>, CieRecord> CieMap; }; class GotSection : public SyntheticSection { public: GotSection(); size_t getSize() const override { return Size; } void finalizeContents() override; bool empty() const override; void writeTo(uint8_t *Buf) override; void addEntry(SymbolBody &Sym); bool addDynTlsEntry(SymbolBody &Sym); bool addTlsIndex(); uint64_t getGlobalDynAddr(const SymbolBody &B) const; uint64_t getGlobalDynOffset(const SymbolBody &B) const; uint64_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; protected: size_t NumEntries = 0; uint32_t TlsIndexOff = -1; uint64_t Size = 0; }; // .note.gnu.build-id section. 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; }; // BssSection is used to reserve space for copy relocations and common symbols. // We create three instances of this class for .bss, .bss.rel.ro and "COMMON", // that are used for writable symbols, read-only symbols and common symbols, // respectively. class BssSection final : public SyntheticSection { public: BssSection(StringRef Name); void writeTo(uint8_t *) override {} bool empty() const override { return getSize() == 0; } size_t reserveSpace(uint64_t Size, uint32_t Alignment); size_t getSize() const override { return Size; } private: uint64_t Size = 0; }; class MipsGotSection final : public SyntheticSection { public: MipsGotSection(); void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } void updateAllocSize() override; void finalizeContents() override; bool empty() const override; void addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr); bool addDynTlsEntry(SymbolBody &Sym); bool addTlsIndex(); uint64_t getPageEntryOffset(const SymbolBody &B, int64_t Addend) const; uint64_t getBodyEntryOffset(const SymbolBody &B, int64_t Addend) const; uint64_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. uint64_t getTlsOffset() const; uint32_t getTlsIndexOff() const { return TlsIndexOff; } uint64_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; uint64_t Size = 0; }; class GotPltSection final : public SyntheticSection { 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 PltSection 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. class IgotPltSection final : public SyntheticSection { 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; }; class StringTableSection final : public SyntheticSection { public: 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; uint64_t Size = 0; llvm::DenseMap StringMap; std::vector Strings; }; class DynamicReloc { public: DynamicReloc(uint32_t Type, const InputSectionBase *InputSec, uint64_t OffsetInSec, bool UseSymVA, SymbolBody *Sym, int64_t Addend) : Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec), UseSymVA(UseSymVA), Addend(Addend) {} uint64_t getOffset() const; int64_t getAddend() const; uint32_t getSymIndex() const; const InputSectionBase *getInputSec() const { return InputSec; } uint32_t Type; private: SymbolBody *Sym; const InputSectionBase *InputSec = nullptr; uint64_t OffsetInSec; bool UseSymVA; int64_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; // 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 { OutputSection *OutSec; InputSection *InSec; uint64_t Val; const SymbolBody *Sym; }; enum KindT { SecAddr, SecSize, SymAddr, PlainInt, InSecAddr } Kind; Entry(int32_t Tag, OutputSection *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) {} }; // finalizeContents() fills this vector with the section contents. std::vector Entries; public: DynamicSection(); void finalizeContents() 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); } uint64_t Size = 0; }; template class RelocationSection final : public SyntheticSection { typedef typename ELFT::Rel Elf_Rel; typedef typename ELFT::Rela Elf_Rela; public: RelocationSection(StringRef Name, bool Sort); void addReloc(const DynamicReloc &Reloc); unsigned getRelocOffset(); void finalizeContents() 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; }; class SymbolTableBaseSection : public SyntheticSection { public: SymbolTableBaseSection(StringTableSection &StrTabSec); void finalizeContents() override; void postThunkContents() override; size_t getSize() const override { return getNumSymbols() * Entsize; } void addSymbol(SymbolBody *Body); unsigned getNumSymbols() const { return Symbols.size() + 1; } size_t getSymbolIndex(SymbolBody *Body); ArrayRef getSymbols() const { return Symbols; } protected: // A vector of symbols and their string table offsets. std::vector Symbols; StringTableSection &StrTabSec; }; template class SymbolTableSection final : public SymbolTableBaseSection { typedef typename ELFT::Sym Elf_Sym; public: SymbolTableSection(StringTableSection &StrTabSec); void writeTo(uint8_t *Buf) override; }; // Outputs GNU Hash section. For detailed explanation see: // https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections class GnuHashTableSection final : public SyntheticSection { public: GnuHashTableSection(); void finalizeContents() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } // Adds symbols to the hash table. // Sorts the input to satisfy GNU hash section requirements. void addSymbols(std::vector &Symbols); private: size_t getShift2() const { return Config->Is64 ? 6 : 5; } void writeBloomFilter(uint8_t *Buf); void writeHashTable(uint8_t *Buf); struct Entry { SymbolBody *Body; size_t StrTabOffset; uint32_t Hash; }; std::vector Symbols; size_t MaskWords; size_t NBuckets = 0; size_t Size = 0; }; template class HashTableSection final : public SyntheticSection { public: HashTableSection(); void finalizeContents() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } private: size_t Size = 0; }; // The PltSection is used for both the Plt and Iplt. The former always has a // header as its first entry that is used at run-time to resolve lazy binding. // The latter is used for GNU Ifunc symbols, that will be subject to a // Target->IRelativeRel. class PltSection : public SyntheticSection { public: PltSection(size_t HeaderSize); void writeTo(uint8_t *Buf) override; size_t getSize() const override; bool empty() const override { return Entries.empty(); } void addSymbols(); template void addEntry(SymbolBody &Sym); private: void writeHeader(uint8_t *Buf){}; void addHeaderSymbols(){}; unsigned getPltRelocOff() const; std::vector> Entries; // Iplt always has HeaderSize of 0, the Plt HeaderSize is always non-zero size_t HeaderSize; }; class GdbIndexSection final : public SyntheticSection { 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 finalizeContents() 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 readDwarf(InputSection *Sec); 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 { 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 finalizeContents() 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 finalizeContents() 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 finalizeContents() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override; size_t getNeedNum() const { return Needed.size(); } bool empty() const override; }; // MergeSyntheticSection is a class that allows us to put mergeable sections // with different attributes in a single output sections. To do that // we put them into MergeSyntheticSection synthetic input sections which are // attached to regular output sections. class MergeSyntheticSection final : public SyntheticSection { public: MergeSyntheticSection(StringRef Name, uint32_t Type, uint64_t Flags, uint32_t Alignment); void addSection(MergeInputSection *MS); void writeTo(uint8_t *Buf) override; void finalizeContents() override; bool shouldTailMerge() const; size_t getSize() const override; private: void finalizeTailMerge(); void finalizeNoTailMerge(); bool Finalized = false; llvm::StringTableBuilder Builder; std::vector Sections; }; // .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 class MipsRldMapSection : public SyntheticSection { public: MipsRldMapSection(); size_t getSize() const override { return Config->Wordsize; } void writeTo(uint8_t *Buf) override {} }; class ARMExidxSentinelSection : public SyntheticSection { public: ARMExidxSentinelSection(); size_t getSize() const override { return 8; } void writeTo(uint8_t *Buf) override; }; // A container for one or more linker generated thunks. Instances of these // thunks including ARM interworking and Mips LA25 PI to non-PI thunks. class ThunkSection : public SyntheticSection { public: // ThunkSection in OS, with desired OutSecOff of Off ThunkSection(OutputSection *OS, uint64_t Off); // Add a newly created Thunk to this container: // Thunk is given offset from start of this InputSection // Thunk defines a symbol in this InputSection that can be used as target // of a relocation void addThunk(Thunk *T); size_t getSize() const override { return Size; } void writeTo(uint8_t *Buf) override; InputSection *getTargetInputSection() const; private: std::vector Thunks; size_t Size = 0; }; template InputSection *createCommonSection(); InputSection *createInterpSection(); template MergeInputSection *createCommentSection(); SymbolBody *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, uint64_t Size, InputSectionBase *Section); // Linker generated sections which can be used as inputs. struct InX { static InputSection *ARMAttributes; static BssSection *Bss; static BssSection *BssRelRo; static BuildIdSection *BuildId; static InputSection *Common; static SyntheticSection *Dynamic; static StringTableSection *DynStrTab; static SymbolTableBaseSection *DynSymTab; static GnuHashTableSection *GnuHashTab; static InputSection *Interp; static GdbIndexSection *GdbIndex; static GotSection *Got; static GotPltSection *GotPlt; static IgotPltSection *IgotPlt; static MipsGotSection *MipsGot; static MipsRldMapSection *MipsRldMap; static PltSection *Plt; static PltSection *Iplt; static StringTableSection *ShStrTab; static StringTableSection *StrTab; static SymbolTableBaseSection *SymTab; }; template struct In : public InX { static EhFrameHeader *EhFrameHdr; static EhFrameSection *EhFrame; static HashTableSection *HashTab; static RelocationSection *RelaDyn; static RelocationSection *RelaPlt; static RelocationSection *RelaIplt; static VersionDefinitionSection *VerDef; static VersionTableSection *VerSym; static VersionNeedSection *VerNeed; }; template EhFrameHeader *In::EhFrameHdr; template EhFrameSection *In::EhFrame; template HashTableSection *In::HashTab; template RelocationSection *In::RelaDyn; template RelocationSection *In::RelaPlt; template RelocationSection *In::RelaIplt; template VersionDefinitionSection *In::VerDef; template VersionTableSection *In::VerSym; template VersionNeedSection *In::VerNeed; } // namespace elf } // namespace lld #endif Index: vendor/lld/dist/ELF/Target.cpp =================================================================== --- vendor/lld/dist/ELF/Target.cpp (revision 319468) +++ vendor/lld/dist/ELF/Target.cpp (revision 319469) @@ -1,2410 +1,2410 @@ //===- Target.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Machine-specific things, such as applying relocations, creation of // GOT or PLT entries, etc., are handled in this file. // // Refer the ELF spec for the single letter variables, S, A or P, used // in this file. // // Some functions defined in this file has "relaxTls" as part of their names. // They do peephole optimization for TLS variables by rewriting instructions. // They are not part of the ABI but optional optimization, so you can skip // them if you are not interested in how TLS variables are optimized. // See the following paper for the details. // // Ulrich Drepper, ELF Handling For Thread-Local Storage // http://www.akkadia.org/drepper/tls.pdf // //===----------------------------------------------------------------------===// #include "Target.h" #include "Error.h" #include "InputFiles.h" #include "Memory.h" #include "OutputSections.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Thunks.h" #include "Writer.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Object/ELF.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" using namespace llvm; using namespace llvm::object; using namespace llvm::support::endian; using namespace llvm::ELF; std::string lld::toString(uint32_t Type) { StringRef S = getELFRelocationTypeName(elf::Config->EMachine, Type); if (S == "Unknown") return ("Unknown (" + Twine(Type) + ")").str(); return S; } namespace lld { namespace elf { TargetInfo *Target; static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); } static void or32be(uint8_t *P, int32_t V) { write32be(P, read32be(P) | V); } template static std::string getErrorLoc(const uint8_t *Loc) { for (InputSectionBase *D : InputSections) { auto *IS = dyn_cast_or_null(D); - if (!IS || !IS->OutSec) + if (!IS || !IS->getParent()) continue; - uint8_t *ISLoc = cast(IS->OutSec)->Loc + IS->OutSecOff; + uint8_t *ISLoc = IS->getParent()->Loc + IS->OutSecOff; if (ISLoc <= Loc && Loc < ISLoc + IS->getSize()) return IS->template getLocation(Loc - ISLoc) + ": "; } return ""; } static std::string getErrorLocation(const uint8_t *Loc) { switch (Config->EKind) { case ELF32LEKind: return getErrorLoc(Loc); case ELF32BEKind: return getErrorLoc(Loc); case ELF64LEKind: return getErrorLoc(Loc); case ELF64BEKind: return getErrorLoc(Loc); default: llvm_unreachable("unknown ELF type"); } } template static void checkInt(uint8_t *Loc, int64_t V, uint32_t Type) { if (!isInt(V)) error(getErrorLocation(Loc) + "relocation " + toString(Type) + " out of range"); } template static void checkUInt(uint8_t *Loc, uint64_t V, uint32_t Type) { if (!isUInt(V)) error(getErrorLocation(Loc) + "relocation " + toString(Type) + " out of range"); } template static void checkIntUInt(uint8_t *Loc, uint64_t V, uint32_t Type) { if (!isInt(V) && !isUInt(V)) error(getErrorLocation(Loc) + "relocation " + toString(Type) + " out of range"); } template static void checkAlignment(uint8_t *Loc, uint64_t V, uint32_t Type) { if ((V & (N - 1)) != 0) error(getErrorLocation(Loc) + "improper alignment for relocation " + toString(Type)); } namespace { class X86TargetInfo final : public TargetInfo { public: X86TargetInfo(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; void writeGotPltHeader(uint8_t *Buf) const override; uint32_t getDynRel(uint32_t Type) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const override; void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; }; template class X86_64TargetInfo final : public TargetInfo { public: X86_64TargetInfo(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; bool isPicRel(uint32_t Type) const override; void writeGotPltHeader(uint8_t *Buf) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const override; void relaxGot(uint8_t *Loc, uint64_t Val) const override; void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; private: void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, uint8_t ModRm) const; }; class PPCTargetInfo final : public TargetInfo { public: PPCTargetInfo(); void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; }; class PPC64TargetInfo final : public TargetInfo { public: PPC64TargetInfo(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; }; class AArch64TargetInfo final : public TargetInfo { public: AArch64TargetInfo(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; bool isPicRel(uint32_t Type) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; bool usesOnlyLowPageBits(uint32_t Type) const override; void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const override; void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; }; class AMDGPUTargetInfo final : public TargetInfo { public: AMDGPUTargetInfo(); void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; }; class ARMTargetInfo final : public TargetInfo { public: ARMTargetInfo(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; bool isPicRel(uint32_t Type) const override; uint32_t getDynRel(uint32_t Type) const override; int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; void addPltSymbols(InputSectionBase *IS, uint64_t Off) const override; void addPltHeaderSymbols(InputSectionBase *ISD) const override; bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; }; template class MipsTargetInfo final : public TargetInfo { public: MipsTargetInfo(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; bool isPicRel(uint32_t Type) const override; uint32_t getDynRel(uint32_t Type) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; bool usesOnlyLowPageBits(uint32_t Type) const override; }; } // anonymous namespace TargetInfo *createTarget() { switch (Config->EMachine) { case EM_386: case EM_IAMCU: return make(); case EM_AARCH64: return make(); case EM_AMDGPU: return make(); case EM_ARM: return make(); case EM_MIPS: switch (Config->EKind) { case ELF32LEKind: return make>(); case ELF32BEKind: return make>(); case ELF64LEKind: return make>(); case ELF64BEKind: return make>(); default: fatal("unsupported MIPS target"); } case EM_PPC: return make(); case EM_PPC64: return make(); case EM_X86_64: if (Config->EKind == ELF32LEKind) return make>(); return make>(); } fatal("unknown target machine"); } TargetInfo::~TargetInfo() {} int64_t TargetInfo::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { return 0; } bool TargetInfo::usesOnlyLowPageBits(uint32_t Type) const { return false; } bool TargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, const SymbolBody &S) const { return false; } void TargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const { writeGotPlt(Buf, S); } RelExpr TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const { return Expr; } void TargetInfo::relaxGot(uint8_t *Loc, uint64_t Val) const { llvm_unreachable("Should not have claimed to be relaxable"); } void TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { llvm_unreachable("Should not have claimed to be relaxable"); } void TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { llvm_unreachable("Should not have claimed to be relaxable"); } void TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { llvm_unreachable("Should not have claimed to be relaxable"); } void TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { llvm_unreachable("Should not have claimed to be relaxable"); } X86TargetInfo::X86TargetInfo() { CopyRel = R_386_COPY; GotRel = R_386_GLOB_DAT; PltRel = R_386_JUMP_SLOT; IRelativeRel = R_386_IRELATIVE; RelativeRel = R_386_RELATIVE; TlsGotRel = R_386_TLS_TPOFF; TlsModuleIndexRel = R_386_TLS_DTPMOD32; TlsOffsetRel = R_386_TLS_DTPOFF32; GotEntrySize = 4; GotPltEntrySize = 4; PltEntrySize = 16; PltHeaderSize = 16; TlsGdRelaxSkip = 2; // 0xCC is the "int3" (call debug exception handler) instruction. TrapInstr = 0xcccccccc; } RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { case R_386_8: case R_386_16: case R_386_32: case R_386_TLS_LDO_32: return R_ABS; case R_386_TLS_GD: return R_TLSGD; case R_386_TLS_LDM: return R_TLSLD; case R_386_PLT32: return R_PLT_PC; case R_386_PC8: case R_386_PC16: case R_386_PC32: return R_PC; case R_386_GOTPC: return R_GOTONLY_PC_FROM_END; case R_386_TLS_IE: return R_GOT; case R_386_GOT32: case R_386_GOT32X: // These relocations can be calculated in two different ways. // Usual calculation is G + A - GOT what means an offset in GOT table // (R_GOT_FROM_END). When instruction pointed by relocation has no base // register, then relocations can be used when PIC code is disabled. In that // case calculation is G + A, it resolves to an address of entry in GOT // (R_GOT) and not an offset. // // To check that instruction has no base register we scan ModR/M byte. // See "Table 2-2. 32-Bit Addressing Forms with the ModR/M Byte" // (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/ // 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf) if ((Loc[-1] & 0xc7) != 0x5) return R_GOT_FROM_END; if (Config->Pic) error(toString(S.File) + ": relocation " + toString(Type) + " against '" + S.getName() + "' without base register can not be used when PIC enabled"); return R_GOT; case R_386_TLS_GOTIE: return R_GOT_FROM_END; case R_386_GOTOFF: return R_GOTREL_FROM_END; case R_386_TLS_LE: return R_TLS; case R_386_TLS_LE_32: return R_NEG_TLS; case R_386_NONE: return R_NONE; default: error(toString(S.File) + ": unknown relocation type: " + toString(Type)); return R_HINT; } } RelExpr X86TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const { switch (Expr) { default: return Expr; case R_RELAX_TLS_GD_TO_IE: return R_RELAX_TLS_GD_TO_IE_END; case R_RELAX_TLS_GD_TO_LE: return R_RELAX_TLS_GD_TO_LE_NEG; } } void X86TargetInfo::writeGotPltHeader(uint8_t *Buf) const { write32le(Buf, InX::Dynamic->getVA()); } void X86TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const { // Entries in .got.plt initially points back to the corresponding // PLT entries with a fixed offset to skip the first instruction. write32le(Buf, S.getPltVA() + 6); } void X86TargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const { // An x86 entry is the address of the ifunc resolver function. write32le(Buf, S.getVA()); } uint32_t X86TargetInfo::getDynRel(uint32_t Type) const { if (Type == R_386_TLS_LE) return R_386_TLS_TPOFF; if (Type == R_386_TLS_LE_32) return R_386_TLS_TPOFF32; return Type; } void X86TargetInfo::writePltHeader(uint8_t *Buf) const { if (Config->Pic) { const uint8_t V[] = { 0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl GOTPLT+4(%ebx) 0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *GOTPLT+8(%ebx) 0x90, 0x90, 0x90, 0x90 // nop }; memcpy(Buf, V, sizeof(V)); uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); uint32_t GotPlt = InX::GotPlt->getVA() - Ebx; write32le(Buf + 2, GotPlt + 4); write32le(Buf + 8, GotPlt + 8); return; } const uint8_t PltData[] = { 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushl (GOTPLT+4) 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *(GOTPLT+8) 0x90, 0x90, 0x90, 0x90 // nop }; memcpy(Buf, PltData, sizeof(PltData)); uint32_t GotPlt = InX::GotPlt->getVA(); write32le(Buf + 2, GotPlt + 4); write32le(Buf + 8, GotPlt + 8); } void X86TargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Inst[] = { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, // jmp *foo_in_GOT|*foo@GOT(%ebx) 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $reloc_offset 0xe9, 0x00, 0x00, 0x00, 0x00 // jmp .PLT0@PC }; memcpy(Buf, Inst, sizeof(Inst)); if (Config->Pic) { // jmp *foo@GOT(%ebx) uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); Buf[1] = 0xa3; write32le(Buf + 2, GotPltEntryAddr - Ebx); } else { // jmp *foo_in_GOT Buf[1] = 0x25; write32le(Buf + 2, GotPltEntryAddr); } write32le(Buf + 7, RelOff); write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); } int64_t X86TargetInfo::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { switch (Type) { default: return 0; case R_386_8: case R_386_PC8: return SignExtend64<8>(*Buf); case R_386_16: case R_386_PC16: return SignExtend64<16>(read16le(Buf)); case R_386_32: case R_386_GOT32: case R_386_GOT32X: case R_386_GOTOFF: case R_386_GOTPC: case R_386_PC32: case R_386_PLT32: case R_386_TLS_LDO_32: case R_386_TLS_LE: return SignExtend64<32>(read32le(Buf)); } } void X86TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // R_386_{PC,}{8,16} are not part of the i386 psABI, but they are // being used for some 16-bit programs such as boot loaders, so // we want to support them. switch (Type) { case R_386_8: checkUInt<8>(Loc, Val, Type); *Loc = Val; break; case R_386_PC8: checkInt<8>(Loc, Val, Type); *Loc = Val; break; case R_386_16: checkUInt<16>(Loc, Val, Type); write16le(Loc, Val); break; case R_386_PC16: checkInt<16>(Loc, Val, Type); write16le(Loc, Val); break; default: checkInt<32>(Loc, Val, Type); write32le(Loc, Val); } } void X86TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // Convert // leal x@tlsgd(, %ebx, 1), // call __tls_get_addr@plt // to // movl %gs:0,%eax // subl $x@ntpoff,%eax const uint8_t Inst[] = { 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax 0x81, 0xe8, 0x00, 0x00, 0x00, 0x00 // subl 0(%ebx), %eax }; memcpy(Loc - 3, Inst, sizeof(Inst)); write32le(Loc + 5, Val); } void X86TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // Convert // leal x@tlsgd(, %ebx, 1), // call __tls_get_addr@plt // to // movl %gs:0, %eax // addl x@gotntpoff(%ebx), %eax const uint8_t Inst[] = { 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax 0x03, 0x83, 0x00, 0x00, 0x00, 0x00 // addl 0(%ebx), %eax }; memcpy(Loc - 3, Inst, sizeof(Inst)); write32le(Loc + 5, Val); } // In some conditions, relocations can be optimized to avoid using GOT. // This function does that for Initial Exec to Local Exec case. void X86TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // Ulrich's document section 6.2 says that @gotntpoff can // be used with MOVL or ADDL instructions. // @indntpoff is similar to @gotntpoff, but for use in // position dependent code. uint8_t Reg = (Loc[-1] >> 3) & 7; if (Type == R_386_TLS_IE) { if (Loc[-1] == 0xa1) { // "movl foo@indntpoff,%eax" -> "movl $foo,%eax" // This case is different from the generic case below because // this is a 5 byte instruction while below is 6 bytes. Loc[-1] = 0xb8; } else if (Loc[-2] == 0x8b) { // "movl foo@indntpoff,%reg" -> "movl $foo,%reg" Loc[-2] = 0xc7; Loc[-1] = 0xc0 | Reg; } else { // "addl foo@indntpoff,%reg" -> "addl $foo,%reg" Loc[-2] = 0x81; Loc[-1] = 0xc0 | Reg; } } else { assert(Type == R_386_TLS_GOTIE); if (Loc[-2] == 0x8b) { // "movl foo@gottpoff(%rip),%reg" -> "movl $foo,%reg" Loc[-2] = 0xc7; Loc[-1] = 0xc0 | Reg; } else { // "addl foo@gotntpoff(%rip),%reg" -> "leal foo(%reg),%reg" Loc[-2] = 0x8d; Loc[-1] = 0x80 | (Reg << 3) | Reg; } } write32le(Loc, Val); } void X86TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { if (Type == R_386_TLS_LDO_32) { write32le(Loc, Val); return; } // Convert // leal foo(%reg),%eax // call ___tls_get_addr // to // movl %gs:0,%eax // nop // leal 0(%esi,1),%esi const uint8_t Inst[] = { 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax 0x90, // nop 0x8d, 0x74, 0x26, 0x00 // leal 0(%esi,1),%esi }; memcpy(Loc - 2, Inst, sizeof(Inst)); } template X86_64TargetInfo::X86_64TargetInfo() { CopyRel = R_X86_64_COPY; GotRel = R_X86_64_GLOB_DAT; PltRel = R_X86_64_JUMP_SLOT; RelativeRel = R_X86_64_RELATIVE; IRelativeRel = R_X86_64_IRELATIVE; TlsGotRel = R_X86_64_TPOFF64; TlsModuleIndexRel = R_X86_64_DTPMOD64; TlsOffsetRel = R_X86_64_DTPOFF64; GotEntrySize = 8; GotPltEntrySize = 8; PltEntrySize = 16; PltHeaderSize = 16; TlsGdRelaxSkip = 2; // Align to the large page size (known as a superpage or huge page). // FreeBSD automatically promotes large, superpage-aligned allocations. DefaultImageBase = 0x200000; // 0xCC is the "int3" (call debug exception handler) instruction. TrapInstr = 0xcccccccc; } template RelExpr X86_64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { case R_X86_64_8: case R_X86_64_16: case R_X86_64_32: case R_X86_64_32S: case R_X86_64_64: case R_X86_64_DTPOFF32: case R_X86_64_DTPOFF64: return R_ABS; case R_X86_64_TPOFF32: return R_TLS; case R_X86_64_TLSLD: return R_TLSLD_PC; case R_X86_64_TLSGD: return R_TLSGD_PC; case R_X86_64_SIZE32: case R_X86_64_SIZE64: return R_SIZE; case R_X86_64_PLT32: return R_PLT_PC; case R_X86_64_PC32: case R_X86_64_PC64: return R_PC; case R_X86_64_GOT32: case R_X86_64_GOT64: return R_GOT_FROM_END; case R_X86_64_GOTPCREL: case R_X86_64_GOTPCRELX: case R_X86_64_REX_GOTPCRELX: case R_X86_64_GOTTPOFF: return R_GOT_PC; case R_X86_64_NONE: return R_NONE; default: error(toString(S.File) + ": unknown relocation type: " + toString(Type)); return R_HINT; } } template void X86_64TargetInfo::writeGotPltHeader(uint8_t *Buf) const { // The first entry holds the value of _DYNAMIC. It is not clear why that is // required, but it is documented in the psabi and the glibc dynamic linker // seems to use it (note that this is relevant for linking ld.so, not any // other program). write64le(Buf, InX::Dynamic->getVA()); } template void X86_64TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const { // See comments in X86TargetInfo::writeGotPlt. write32le(Buf, S.getPltVA() + 6); } template void X86_64TargetInfo::writePltHeader(uint8_t *Buf) const { const uint8_t PltData[] = { 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOTPLT+8(%rip) 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOTPLT+16(%rip) 0x0f, 0x1f, 0x40, 0x00 // nop }; memcpy(Buf, PltData, sizeof(PltData)); uint64_t GotPlt = InX::GotPlt->getVA(); uint64_t Plt = InX::Plt->getVA(); write32le(Buf + 2, GotPlt - Plt + 2); // GOTPLT+8 write32le(Buf + 8, GotPlt - Plt + 4); // GOTPLT+16 } template void X86_64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Inst[] = { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *got(%rip) 0x68, 0x00, 0x00, 0x00, 0x00, // pushq 0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[0] }; memcpy(Buf, Inst, sizeof(Inst)); write32le(Buf + 2, GotPltEntryAddr - PltEntryAddr - 6); write32le(Buf + 7, Index); write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); } template bool X86_64TargetInfo::isPicRel(uint32_t Type) const { return Type != R_X86_64_PC32 && Type != R_X86_64_32 && Type != R_X86_64_TPOFF32; } template void X86_64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // Convert // .byte 0x66 // leaq x@tlsgd(%rip), %rdi // .word 0x6666 // rex64 // call __tls_get_addr@plt // to // mov %fs:0x0,%rax // lea x@tpoff,%rax const uint8_t Inst[] = { 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax 0x48, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00 // lea x@tpoff,%rax }; memcpy(Loc - 4, Inst, sizeof(Inst)); // The original code used a pc relative relocation and so we have to // compensate for the -4 in had in the addend. write32le(Loc + 8, Val + 4); } template void X86_64TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // Convert // .byte 0x66 // leaq x@tlsgd(%rip), %rdi // .word 0x6666 // rex64 // call __tls_get_addr@plt // to // mov %fs:0x0,%rax // addq x@tpoff,%rax const uint8_t Inst[] = { 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax 0x48, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00 // addq x@tpoff,%rax }; memcpy(Loc - 4, Inst, sizeof(Inst)); // Both code sequences are PC relatives, but since we are moving the constant // forward by 8 bytes we have to subtract the value by 8. write32le(Loc + 8, Val - 8); } // In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to // R_X86_64_TPOFF32 so that it does not use GOT. template void X86_64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { uint8_t *Inst = Loc - 3; uint8_t Reg = Loc[-1] >> 3; uint8_t *RegSlot = Loc - 1; // Note that ADD with RSP or R12 is converted to ADD instead of LEA // because LEA with these registers needs 4 bytes to encode and thus // wouldn't fit the space. if (memcmp(Inst, "\x48\x03\x25", 3) == 0) { // "addq foo@gottpoff(%rip),%rsp" -> "addq $foo,%rsp" memcpy(Inst, "\x48\x81\xc4", 3); } else if (memcmp(Inst, "\x4c\x03\x25", 3) == 0) { // "addq foo@gottpoff(%rip),%r12" -> "addq $foo,%r12" memcpy(Inst, "\x49\x81\xc4", 3); } else if (memcmp(Inst, "\x4c\x03", 2) == 0) { // "addq foo@gottpoff(%rip),%r[8-15]" -> "leaq foo(%r[8-15]),%r[8-15]" memcpy(Inst, "\x4d\x8d", 2); *RegSlot = 0x80 | (Reg << 3) | Reg; } else if (memcmp(Inst, "\x48\x03", 2) == 0) { // "addq foo@gottpoff(%rip),%reg -> "leaq foo(%reg),%reg" memcpy(Inst, "\x48\x8d", 2); *RegSlot = 0x80 | (Reg << 3) | Reg; } else if (memcmp(Inst, "\x4c\x8b", 2) == 0) { // "movq foo@gottpoff(%rip),%r[8-15]" -> "movq $foo,%r[8-15]" memcpy(Inst, "\x49\xc7", 2); *RegSlot = 0xc0 | Reg; } else if (memcmp(Inst, "\x48\x8b", 2) == 0) { // "movq foo@gottpoff(%rip),%reg" -> "movq $foo,%reg" memcpy(Inst, "\x48\xc7", 2); *RegSlot = 0xc0 | Reg; } else { error(getErrorLocation(Loc - 3) + "R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only"); } // The original code used a PC relative relocation. // Need to compensate for the -4 it had in the addend. write32le(Loc, Val + 4); } template void X86_64TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // Convert // leaq bar@tlsld(%rip), %rdi // callq __tls_get_addr@PLT // leaq bar@dtpoff(%rax), %rcx // to // .word 0x6666 // .byte 0x66 // mov %fs:0,%rax // leaq bar@tpoff(%rax), %rcx if (Type == R_X86_64_DTPOFF64) { write64le(Loc, Val); return; } if (Type == R_X86_64_DTPOFF32) { write32le(Loc, Val); return; } const uint8_t Inst[] = { 0x66, 0x66, // .word 0x6666 0x66, // .byte 0x66 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00 // mov %fs:0,%rax }; memcpy(Loc - 3, Inst, sizeof(Inst)); } template void X86_64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { switch (Type) { case R_X86_64_8: checkUInt<8>(Loc, Val, Type); *Loc = Val; break; case R_X86_64_16: checkUInt<16>(Loc, Val, Type); write16le(Loc, Val); break; case R_X86_64_32: checkUInt<32>(Loc, Val, Type); write32le(Loc, Val); break; case R_X86_64_32S: case R_X86_64_TPOFF32: case R_X86_64_GOT32: case R_X86_64_GOTPCREL: case R_X86_64_GOTPCRELX: case R_X86_64_REX_GOTPCRELX: case R_X86_64_PC32: case R_X86_64_GOTTPOFF: case R_X86_64_PLT32: case R_X86_64_TLSGD: case R_X86_64_TLSLD: case R_X86_64_DTPOFF32: case R_X86_64_SIZE32: checkInt<32>(Loc, Val, Type); write32le(Loc, Val); break; case R_X86_64_64: case R_X86_64_DTPOFF64: case R_X86_64_GLOB_DAT: case R_X86_64_PC64: case R_X86_64_SIZE64: case R_X86_64_GOT64: write64le(Loc, Val); break; default: llvm_unreachable("unexpected relocation"); } } template RelExpr X86_64TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr RelExpr) const { if (Type != R_X86_64_GOTPCRELX && Type != R_X86_64_REX_GOTPCRELX) return RelExpr; const uint8_t Op = Data[-2]; const uint8_t ModRm = Data[-1]; // FIXME: When PIC is disabled and foo is defined locally in the // lower 32 bit address space, memory operand in mov can be converted into // immediate operand. Otherwise, mov must be changed to lea. We support only // latter relaxation at this moment. if (Op == 0x8b) return R_RELAX_GOT_PC; // Relax call and jmp. if (Op == 0xff && (ModRm == 0x15 || ModRm == 0x25)) return R_RELAX_GOT_PC; // Relaxation of test, adc, add, and, cmp, or, sbb, sub, xor. // If PIC then no relaxation is available. // We also don't relax test/binop instructions without REX byte, // they are 32bit operations and not common to have. assert(Type == R_X86_64_REX_GOTPCRELX); return Config->Pic ? RelExpr : R_RELAX_GOT_PC_NOPIC; } // A subset of relaxations can only be applied for no-PIC. This method // handles such relaxations. Instructions encoding information was taken from: // "Intel 64 and IA-32 Architectures Software Developer's Manual V2" // (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/ // 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf) template void X86_64TargetInfo::relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, uint8_t ModRm) const { const uint8_t Rex = Loc[-3]; // Convert "test %reg, foo@GOTPCREL(%rip)" to "test $foo, %reg". if (Op == 0x85) { // See "TEST-Logical Compare" (4-428 Vol. 2B), // TEST r/m64, r64 uses "full" ModR / M byte (no opcode extension). // ModR/M byte has form XX YYY ZZZ, where // YYY is MODRM.reg(register 2), ZZZ is MODRM.rm(register 1). // XX has different meanings: // 00: The operand's memory address is in reg1. // 01: The operand's memory address is reg1 + a byte-sized displacement. // 10: The operand's memory address is reg1 + a word-sized displacement. // 11: The operand is reg1 itself. // If an instruction requires only one operand, the unused reg2 field // holds extra opcode bits rather than a register code // 0xC0 == 11 000 000 binary. // 0x38 == 00 111 000 binary. // We transfer reg2 to reg1 here as operand. // See "2.1.3 ModR/M and SIB Bytes" (Vol. 2A 2-3). Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3; // ModR/M byte. // Change opcode from TEST r/m64, r64 to TEST r/m64, imm32 // See "TEST-Logical Compare" (4-428 Vol. 2B). Loc[-2] = 0xf7; // Move R bit to the B bit in REX byte. // REX byte is encoded as 0100WRXB, where // 0100 is 4bit fixed pattern. // REX.W When 1, a 64-bit operand size is used. Otherwise, when 0, the // default operand size is used (which is 32-bit for most but not all // instructions). // REX.R This 1-bit value is an extension to the MODRM.reg field. // REX.X This 1-bit value is an extension to the SIB.index field. // REX.B This 1-bit value is an extension to the MODRM.rm field or the // SIB.base field. // See "2.2.1.2 More on REX Prefix Fields " (2-8 Vol. 2A). Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2; write32le(Loc, Val); return; } // If we are here then we need to relax the adc, add, and, cmp, or, sbb, sub // or xor operations. // Convert "binop foo@GOTPCREL(%rip), %reg" to "binop $foo, %reg". // Logic is close to one for test instruction above, but we also // write opcode extension here, see below for details. Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3 | (Op & 0x3c); // ModR/M byte. // Primary opcode is 0x81, opcode extension is one of: // 000b = ADD, 001b is OR, 010b is ADC, 011b is SBB, // 100b is AND, 101b is SUB, 110b is XOR, 111b is CMP. // This value was wrote to MODRM.reg in a line above. // See "3.2 INSTRUCTIONS (A-M)" (Vol. 2A 3-15), // "INSTRUCTION SET REFERENCE, N-Z" (Vol. 2B 4-1) for // descriptions about each operation. Loc[-2] = 0x81; Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2; write32le(Loc, Val); } template void X86_64TargetInfo::relaxGot(uint8_t *Loc, uint64_t Val) const { const uint8_t Op = Loc[-2]; const uint8_t ModRm = Loc[-1]; // Convert "mov foo@GOTPCREL(%rip),%reg" to "lea foo(%rip),%reg". if (Op == 0x8b) { Loc[-2] = 0x8d; write32le(Loc, Val); return; } if (Op != 0xff) { // We are relaxing a rip relative to an absolute, so compensate // for the old -4 addend. assert(!Config->Pic); relaxGotNoPic(Loc, Val + 4, Op, ModRm); return; } // Convert call/jmp instructions. if (ModRm == 0x15) { // ABI says we can convert "call *foo@GOTPCREL(%rip)" to "nop; call foo". // Instead we convert to "addr32 call foo" where addr32 is an instruction // prefix. That makes result expression to be a single instruction. Loc[-2] = 0x67; // addr32 prefix Loc[-1] = 0xe8; // call write32le(Loc, Val); return; } // Convert "jmp *foo@GOTPCREL(%rip)" to "jmp foo; nop". // jmp doesn't return, so it is fine to use nop here, it is just a stub. assert(ModRm == 0x25); Loc[-2] = 0xe9; // jmp Loc[3] = 0x90; // nop write32le(Loc - 1, Val + 1); } // Relocation masks following the #lo(value), #hi(value), #ha(value), // #higher(value), #highera(value), #highest(value), and #highesta(value) // macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi // document. static uint16_t applyPPCLo(uint64_t V) { return V; } static uint16_t applyPPCHi(uint64_t V) { return V >> 16; } static uint16_t applyPPCHa(uint64_t V) { return (V + 0x8000) >> 16; } static uint16_t applyPPCHigher(uint64_t V) { return V >> 32; } static uint16_t applyPPCHighera(uint64_t V) { return (V + 0x8000) >> 32; } static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; } static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; } PPCTargetInfo::PPCTargetInfo() {} void PPCTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { switch (Type) { case R_PPC_ADDR16_HA: write16be(Loc, applyPPCHa(Val)); break; case R_PPC_ADDR16_LO: write16be(Loc, applyPPCLo(Val)); break; case R_PPC_ADDR32: case R_PPC_REL32: write32be(Loc, Val); break; case R_PPC_REL24: or32be(Loc, Val & 0x3FFFFFC); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } RelExpr PPCTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { case R_PPC_REL24: case R_PPC_REL32: return R_PC; default: return R_ABS; } } PPC64TargetInfo::PPC64TargetInfo() { PltRel = GotRel = R_PPC64_GLOB_DAT; RelativeRel = R_PPC64_RELATIVE; GotEntrySize = 8; GotPltEntrySize = 8; PltEntrySize = 32; PltHeaderSize = 0; // We need 64K pages (at least under glibc/Linux, the loader won't // set different permissions on a finer granularity than that). DefaultMaxPageSize = 65536; // The PPC64 ELF ABI v1 spec, says: // // It is normally desirable to put segments with different characteristics // in separate 256 Mbyte portions of the address space, to give the // operating system full paging flexibility in the 64-bit address space. // // And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers // use 0x10000000 as the starting address. DefaultImageBase = 0x10000000; } static uint64_t PPC64TocOffset = 0x8000; uint64_t getPPC64TocBase() { // The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The // TOC starts where the first of these sections starts. We always create a // .got when we see a relocation that uses it, so for us the start is always // the .got. uint64_t TocVA = InX::Got->getVA(); // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000 // thus permitting a full 64 Kbytes segment. Note that the glibc startup // code (crt1.o) assumes that you can get from the TOC base to the // start of the .toc section with only a single (signed) 16-bit relocation. return TocVA + PPC64TocOffset; } RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { default: return R_ABS; case R_PPC64_TOC16: case R_PPC64_TOC16_DS: case R_PPC64_TOC16_HA: case R_PPC64_TOC16_HI: case R_PPC64_TOC16_LO: case R_PPC64_TOC16_LO_DS: return R_GOTREL; case R_PPC64_TOC: return R_PPC_TOC; case R_PPC64_REL24: return R_PPC_PLT_OPD; } } void PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { uint64_t Off = GotPltEntryAddr - getPPC64TocBase(); // FIXME: What we should do, in theory, is get the offset of the function // descriptor in the .opd section, and use that as the offset from %r2 (the // TOC-base pointer). Instead, we have the GOT-entry offset, and that will // be a pointer to the function descriptor in the .opd section. Using // this scheme is simpler, but requires an extra indirection per PLT dispatch. write32be(Buf, 0xf8410028); // std %r2, 40(%r1) write32be(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha write32be(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11) write32be(Buf + 12, 0xe96c0000); // ld %r11,0(%r12) write32be(Buf + 16, 0x7d6903a6); // mtctr %r11 write32be(Buf + 20, 0xe84c0008); // ld %r2,8(%r12) write32be(Buf + 24, 0xe96c0010); // ld %r11,16(%r12) write32be(Buf + 28, 0x4e800420); // bctr } static std::pair toAddr16Rel(uint32_t Type, uint64_t Val) { uint64_t V = Val - PPC64TocOffset; switch (Type) { case R_PPC64_TOC16: return {R_PPC64_ADDR16, V}; case R_PPC64_TOC16_DS: return {R_PPC64_ADDR16_DS, V}; case R_PPC64_TOC16_HA: return {R_PPC64_ADDR16_HA, V}; case R_PPC64_TOC16_HI: return {R_PPC64_ADDR16_HI, V}; case R_PPC64_TOC16_LO: return {R_PPC64_ADDR16_LO, V}; case R_PPC64_TOC16_LO_DS: return {R_PPC64_ADDR16_LO_DS, V}; default: return {Type, Val}; } } void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // For a TOC-relative relocation, proceed in terms of the corresponding // ADDR16 relocation type. std::tie(Type, Val) = toAddr16Rel(Type, Val); switch (Type) { case R_PPC64_ADDR14: { checkAlignment<4>(Loc, Val, Type); // Preserve the AA/LK bits in the branch instruction uint8_t AALK = Loc[3]; write16be(Loc + 2, (AALK & 3) | (Val & 0xfffc)); break; } case R_PPC64_ADDR16: checkInt<16>(Loc, Val, Type); write16be(Loc, Val); break; case R_PPC64_ADDR16_DS: checkInt<16>(Loc, Val, Type); write16be(Loc, (read16be(Loc) & 3) | (Val & ~3)); break; case R_PPC64_ADDR16_HA: case R_PPC64_REL16_HA: write16be(Loc, applyPPCHa(Val)); break; case R_PPC64_ADDR16_HI: case R_PPC64_REL16_HI: write16be(Loc, applyPPCHi(Val)); break; case R_PPC64_ADDR16_HIGHER: write16be(Loc, applyPPCHigher(Val)); break; case R_PPC64_ADDR16_HIGHERA: write16be(Loc, applyPPCHighera(Val)); break; case R_PPC64_ADDR16_HIGHEST: write16be(Loc, applyPPCHighest(Val)); break; case R_PPC64_ADDR16_HIGHESTA: write16be(Loc, applyPPCHighesta(Val)); break; case R_PPC64_ADDR16_LO: write16be(Loc, applyPPCLo(Val)); break; case R_PPC64_ADDR16_LO_DS: case R_PPC64_REL16_LO: write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(Val) & ~3)); break; case R_PPC64_ADDR32: case R_PPC64_REL32: checkInt<32>(Loc, Val, Type); write32be(Loc, Val); break; case R_PPC64_ADDR64: case R_PPC64_REL64: case R_PPC64_TOC: write64be(Loc, Val); break; case R_PPC64_REL24: { uint32_t Mask = 0x03FFFFFC; checkInt<24>(Loc, Val, Type); write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask)); break; } default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } AArch64TargetInfo::AArch64TargetInfo() { CopyRel = R_AARCH64_COPY; RelativeRel = R_AARCH64_RELATIVE; IRelativeRel = R_AARCH64_IRELATIVE; GotRel = R_AARCH64_GLOB_DAT; PltRel = R_AARCH64_JUMP_SLOT; TlsDescRel = R_AARCH64_TLSDESC; TlsGotRel = R_AARCH64_TLS_TPREL64; GotEntrySize = 8; GotPltEntrySize = 8; PltEntrySize = 16; PltHeaderSize = 32; DefaultMaxPageSize = 65536; // It doesn't seem to be documented anywhere, but tls on aarch64 uses variant // 1 of the tls structures and the tcb size is 16. TcbSize = 16; } RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { default: return R_ABS; case R_AARCH64_TLSDESC_ADR_PAGE21: return R_TLSDESC_PAGE; case R_AARCH64_TLSDESC_LD64_LO12: case R_AARCH64_TLSDESC_ADD_LO12: return R_TLSDESC; case R_AARCH64_TLSDESC_CALL: return R_TLSDESC_CALL; case R_AARCH64_TLSLE_ADD_TPREL_HI12: case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: return R_TLS; case R_AARCH64_CALL26: case R_AARCH64_CONDBR19: case R_AARCH64_JUMP26: case R_AARCH64_TSTBR14: return R_PLT_PC; case R_AARCH64_PREL16: case R_AARCH64_PREL32: case R_AARCH64_PREL64: case R_AARCH64_ADR_PREL_LO21: return R_PC; case R_AARCH64_ADR_PREL_PG_HI21: return R_PAGE_PC; case R_AARCH64_LD64_GOT_LO12_NC: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: return R_GOT; case R_AARCH64_ADR_GOT_PAGE: case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: return R_GOT_PAGE_PC; case R_AARCH64_NONE: return R_NONE; } } RelExpr AArch64TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const { if (Expr == R_RELAX_TLS_GD_TO_IE) { if (Type == R_AARCH64_TLSDESC_ADR_PAGE21) return R_RELAX_TLS_GD_TO_IE_PAGE_PC; return R_RELAX_TLS_GD_TO_IE_ABS; } return Expr; } bool AArch64TargetInfo::usesOnlyLowPageBits(uint32_t Type) const { switch (Type) { default: return false; case R_AARCH64_ADD_ABS_LO12_NC: case R_AARCH64_LD64_GOT_LO12_NC: case R_AARCH64_LDST128_ABS_LO12_NC: case R_AARCH64_LDST16_ABS_LO12_NC: case R_AARCH64_LDST32_ABS_LO12_NC: case R_AARCH64_LDST64_ABS_LO12_NC: case R_AARCH64_LDST8_ABS_LO12_NC: case R_AARCH64_TLSDESC_ADD_LO12: case R_AARCH64_TLSDESC_LD64_LO12: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: return true; } } bool AArch64TargetInfo::isPicRel(uint32_t Type) const { return Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64; } void AArch64TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const { write64le(Buf, InX::Plt->getVA()); } // Page(Expr) is the page address of the expression Expr, defined // as (Expr & ~0xFFF). (This applies even if the machine page size // supported by the platform has a different value.) uint64_t getAArch64Page(uint64_t Expr) { return Expr & (~static_cast(0xFFF)); } void AArch64TargetInfo::writePltHeader(uint8_t *Buf) const { const uint8_t PltData[] = { 0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]! 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[2])) 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[2]))] 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[2])) 0x20, 0x02, 0x1f, 0xd6, // br x17 0x1f, 0x20, 0x03, 0xd5, // nop 0x1f, 0x20, 0x03, 0xd5, // nop 0x1f, 0x20, 0x03, 0xd5 // nop }; memcpy(Buf, PltData, sizeof(PltData)); uint64_t Got = InX::GotPlt->getVA(); uint64_t Plt = InX::Plt->getVA(); relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21, getAArch64Page(Got + 16) - getAArch64Page(Plt + 4)); relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16); relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16); } void AArch64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Inst[] = { 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n])) 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[n]))] 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[n])) 0x20, 0x02, 0x1f, 0xd6 // br x17 }; memcpy(Buf, Inst, sizeof(Inst)); relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21, getAArch64Page(GotPltEntryAddr) - getAArch64Page(PltEntryAddr)); relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotPltEntryAddr); relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotPltEntryAddr); } static void write32AArch64Addr(uint8_t *L, uint64_t Imm) { uint32_t ImmLo = (Imm & 0x3) << 29; uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi); } // Return the bits [Start, End] from Val shifted Start bits. // For instance, getBits(0xF0, 4, 8) returns 0xF. static uint64_t getBits(uint64_t Val, int Start, int End) { uint64_t Mask = ((uint64_t)1 << (End + 1 - Start)) - 1; return (Val >> Start) & Mask; } // Update the immediate field in a AARCH64 ldr, str, and add instruction. static void or32AArch64Imm(uint8_t *L, uint64_t Imm) { or32le(L, (Imm & 0xFFF) << 10); } void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { switch (Type) { case R_AARCH64_ABS16: case R_AARCH64_PREL16: checkIntUInt<16>(Loc, Val, Type); write16le(Loc, Val); break; case R_AARCH64_ABS32: case R_AARCH64_PREL32: checkIntUInt<32>(Loc, Val, Type); write32le(Loc, Val); break; case R_AARCH64_ABS64: case R_AARCH64_GLOB_DAT: case R_AARCH64_PREL64: write64le(Loc, Val); break; case R_AARCH64_ADD_ABS_LO12_NC: or32AArch64Imm(Loc, Val); break; case R_AARCH64_ADR_GOT_PAGE: case R_AARCH64_ADR_PREL_PG_HI21: case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case R_AARCH64_TLSDESC_ADR_PAGE21: checkInt<33>(Loc, Val, Type); write32AArch64Addr(Loc, Val >> 12); break; case R_AARCH64_ADR_PREL_LO21: checkInt<21>(Loc, Val, Type); write32AArch64Addr(Loc, Val); break; case R_AARCH64_CALL26: case R_AARCH64_JUMP26: checkInt<28>(Loc, Val, Type); or32le(Loc, (Val & 0x0FFFFFFC) >> 2); break; case R_AARCH64_CONDBR19: checkInt<21>(Loc, Val, Type); or32le(Loc, (Val & 0x1FFFFC) << 3); break; case R_AARCH64_LD64_GOT_LO12_NC: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case R_AARCH64_TLSDESC_LD64_LO12: checkAlignment<8>(Loc, Val, Type); or32le(Loc, (Val & 0xFF8) << 7); break; case R_AARCH64_LDST8_ABS_LO12_NC: or32AArch64Imm(Loc, getBits(Val, 0, 11)); break; case R_AARCH64_LDST16_ABS_LO12_NC: or32AArch64Imm(Loc, getBits(Val, 1, 11)); break; case R_AARCH64_LDST32_ABS_LO12_NC: or32AArch64Imm(Loc, getBits(Val, 2, 11)); break; case R_AARCH64_LDST64_ABS_LO12_NC: or32AArch64Imm(Loc, getBits(Val, 3, 11)); break; case R_AARCH64_LDST128_ABS_LO12_NC: or32AArch64Imm(Loc, getBits(Val, 4, 11)); break; case R_AARCH64_MOVW_UABS_G0_NC: or32le(Loc, (Val & 0xFFFF) << 5); break; case R_AARCH64_MOVW_UABS_G1_NC: or32le(Loc, (Val & 0xFFFF0000) >> 11); break; case R_AARCH64_MOVW_UABS_G2_NC: or32le(Loc, (Val & 0xFFFF00000000) >> 27); break; case R_AARCH64_MOVW_UABS_G3: or32le(Loc, (Val & 0xFFFF000000000000) >> 43); break; case R_AARCH64_TSTBR14: checkInt<16>(Loc, Val, Type); or32le(Loc, (Val & 0xFFFC) << 3); break; case R_AARCH64_TLSLE_ADD_TPREL_HI12: checkInt<24>(Loc, Val, Type); or32AArch64Imm(Loc, Val >> 12); break; case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: case R_AARCH64_TLSDESC_ADD_LO12: or32AArch64Imm(Loc, Val); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } void AArch64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // TLSDESC Global-Dynamic relocation are in the form: // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12] // add x0, x0, :tlsdesc_los:v [R_AARCH64_TLSDESC_ADD_LO12] // .tlsdesccall [R_AARCH64_TLSDESC_CALL] // blr x1 // And it can optimized to: // movz x0, #0x0, lsl #16 // movk x0, #0x10 // nop // nop checkUInt<32>(Loc, Val, Type); switch (Type) { case R_AARCH64_TLSDESC_ADD_LO12: case R_AARCH64_TLSDESC_CALL: write32le(Loc, 0xd503201f); // nop return; case R_AARCH64_TLSDESC_ADR_PAGE21: write32le(Loc, 0xd2a00000 | (((Val >> 16) & 0xffff) << 5)); // movz return; case R_AARCH64_TLSDESC_LD64_LO12: write32le(Loc, 0xf2800000 | ((Val & 0xffff) << 5)); // movk return; default: llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); } } void AArch64TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // TLSDESC Global-Dynamic relocation are in the form: // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12] // add x0, x0, :tlsdesc_los:v [R_AARCH64_TLSDESC_ADD_LO12] // .tlsdesccall [R_AARCH64_TLSDESC_CALL] // blr x1 // And it can optimized to: // adrp x0, :gottprel:v // ldr x0, [x0, :gottprel_lo12:v] // nop // nop switch (Type) { case R_AARCH64_TLSDESC_ADD_LO12: case R_AARCH64_TLSDESC_CALL: write32le(Loc, 0xd503201f); // nop break; case R_AARCH64_TLSDESC_ADR_PAGE21: write32le(Loc, 0x90000000); // adrp relocateOne(Loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, Val); break; case R_AARCH64_TLSDESC_LD64_LO12: write32le(Loc, 0xf9400000); // ldr relocateOne(Loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, Val); break; default: llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); } } void AArch64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { checkUInt<32>(Loc, Val, Type); if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) { // Generate MOVZ. uint32_t RegNo = read32le(Loc) & 0x1f; write32le(Loc, (0xd2a00000 | RegNo) | (((Val >> 16) & 0xffff) << 5)); return; } if (Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) { // Generate MOVK. uint32_t RegNo = read32le(Loc) & 0x1f; write32le(Loc, (0xf2800000 | RegNo) | ((Val & 0xffff) << 5)); return; } llvm_unreachable("invalid relocation for TLS IE to LE relaxation"); } AMDGPUTargetInfo::AMDGPUTargetInfo() { RelativeRel = R_AMDGPU_REL64; GotRel = R_AMDGPU_ABS64; GotEntrySize = 8; } void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { switch (Type) { case R_AMDGPU_ABS32: case R_AMDGPU_GOTPCREL: case R_AMDGPU_GOTPCREL32_LO: case R_AMDGPU_REL32: case R_AMDGPU_REL32_LO: write32le(Loc, Val); break; case R_AMDGPU_ABS64: write64le(Loc, Val); break; case R_AMDGPU_GOTPCREL32_HI: case R_AMDGPU_REL32_HI: write32le(Loc, Val >> 32); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { case R_AMDGPU_ABS32: case R_AMDGPU_ABS64: return R_ABS; case R_AMDGPU_REL32: case R_AMDGPU_REL32_LO: case R_AMDGPU_REL32_HI: return R_PC; case R_AMDGPU_GOTPCREL: case R_AMDGPU_GOTPCREL32_LO: case R_AMDGPU_GOTPCREL32_HI: return R_GOT_PC; default: error(toString(S.File) + ": unknown relocation type: " + toString(Type)); return R_HINT; } } ARMTargetInfo::ARMTargetInfo() { CopyRel = R_ARM_COPY; RelativeRel = R_ARM_RELATIVE; IRelativeRel = R_ARM_IRELATIVE; GotRel = R_ARM_GLOB_DAT; PltRel = R_ARM_JUMP_SLOT; TlsGotRel = R_ARM_TLS_TPOFF32; TlsModuleIndexRel = R_ARM_TLS_DTPMOD32; TlsOffsetRel = R_ARM_TLS_DTPOFF32; GotEntrySize = 4; GotPltEntrySize = 4; PltEntrySize = 16; PltHeaderSize = 20; // ARM uses Variant 1 TLS TcbSize = 8; NeedsThunks = true; } RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { default: return R_ABS; case R_ARM_THM_JUMP11: return R_PC; 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: case R_ARM_THM_CALL: return R_PLT_PC; case R_ARM_GOTOFF32: // (S + A) - GOT_ORG return R_GOTREL; case R_ARM_GOT_BREL: // GOT(S) + A - GOT_ORG return R_GOT_OFF; case R_ARM_GOT_PREL: case R_ARM_TLS_IE32: // GOT(S) + A - P return R_GOT_PC; case R_ARM_SBREL32: return R_ARM_SBREL; case R_ARM_TARGET1: return Config->Target1Rel ? R_PC : R_ABS; case R_ARM_TARGET2: if (Config->Target2 == Target2Policy::Rel) return R_PC; if (Config->Target2 == Target2Policy::Abs) return R_ABS; return R_GOT_PC; case R_ARM_TLS_GD32: return R_TLSGD_PC; case R_ARM_TLS_LDM32: return R_TLSLD_PC; case R_ARM_BASE_PREL: // B(S) + A - P // FIXME: currently B(S) assumed to be .got, this may not hold for all // platforms. return R_GOTONLY_PC; case R_ARM_MOVW_PREL_NC: case R_ARM_MOVT_PREL: case R_ARM_REL32: case R_ARM_THM_MOVW_PREL_NC: case R_ARM_THM_MOVT_PREL: return R_PC; case R_ARM_NONE: return R_NONE; case R_ARM_TLS_LE32: return R_TLS; } } bool ARMTargetInfo::isPicRel(uint32_t Type) const { return (Type == R_ARM_TARGET1 && !Config->Target1Rel) || (Type == R_ARM_ABS32); } uint32_t ARMTargetInfo::getDynRel(uint32_t Type) const { if (Type == R_ARM_TARGET1 && !Config->Target1Rel) return R_ARM_ABS32; if (Type == R_ARM_ABS32) return Type; // Keep it going with a dummy value so that we can find more reloc errors. return R_ARM_ABS32; } void ARMTargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const { write32le(Buf, InX::Plt->getVA()); } void ARMTargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const { // An ARM entry is the address of the ifunc resolver function. write32le(Buf, S.getVA()); } void ARMTargetInfo::writePltHeader(uint8_t *Buf) const { const uint8_t PltData[] = { 0x04, 0xe0, 0x2d, 0xe5, // str lr, [sp,#-4]! 0x04, 0xe0, 0x9f, 0xe5, // ldr lr, L2 0x0e, 0xe0, 0x8f, 0xe0, // L1: add lr, pc, lr 0x08, 0xf0, 0xbe, 0xe5, // ldr pc, [lr, #8] 0x00, 0x00, 0x00, 0x00, // L2: .word &(.got.plt) - L1 - 8 }; memcpy(Buf, PltData, sizeof(PltData)); uint64_t GotPlt = InX::GotPlt->getVA(); uint64_t L1 = InX::Plt->getVA() + 8; write32le(Buf + 16, GotPlt - L1 - 8); } void ARMTargetInfo::addPltHeaderSymbols(InputSectionBase *ISD) const { auto *IS = cast(ISD); addSyntheticLocal("$a", STT_NOTYPE, 0, 0, IS); addSyntheticLocal("$d", STT_NOTYPE, 16, 0, IS); } void ARMTargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { // FIXME: Using simple code sequence with simple relocations. // There is a more optimal sequence but it requires support for the group // relocations. See ELF for the ARM Architecture Appendix A.3 const uint8_t PltData[] = { 0x04, 0xc0, 0x9f, 0xe5, // ldr ip, L2 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc 0x00, 0xf0, 0x9c, 0xe5, // ldr pc, [ip] 0x00, 0x00, 0x00, 0x00, // L2: .word Offset(&(.plt.got) - L1 - 8 }; memcpy(Buf, PltData, sizeof(PltData)); uint64_t L1 = PltEntryAddr + 4; write32le(Buf + 12, GotPltEntryAddr - L1 - 8); } void ARMTargetInfo::addPltSymbols(InputSectionBase *ISD, uint64_t Off) const { auto *IS = cast(ISD); addSyntheticLocal("$a", STT_NOTYPE, Off, 0, IS); addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS); } bool ARMTargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, const SymbolBody &S) const { // If S is an undefined weak symbol in an executable we don't need a Thunk. // In a DSO calls to undefined symbols, including weak ones get PLT entries // which may need a thunk. if (S.isUndefined() && !S.isLocal() && S.symbol()->isWeak() && !Config->Shared) return false; // A state change from ARM to Thumb and vice versa must go through an // interworking thunk if the relocation type is not R_ARM_CALL or // R_ARM_THM_CALL. switch (RelocType) { case R_ARM_PC24: case R_ARM_PLT32: case R_ARM_JUMP24: // Source is ARM, all PLT entries are ARM so no interworking required. // Otherwise we need to interwork if Symbol has bit 0 set (Thumb). if (Expr == R_PC && ((S.getVA() & 1) == 1)) return true; break; case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP24: // Source is Thumb, all PLT entries are ARM so interworking is required. // Otherwise we need to interwork if Symbol has bit 0 clear (ARM). if (Expr == R_PLT_PC || ((S.getVA() & 1) == 0)) return true; break; } return false; } void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { switch (Type) { case R_ARM_ABS32: case R_ARM_BASE_PREL: case R_ARM_GLOB_DAT: case R_ARM_GOTOFF32: case R_ARM_GOT_BREL: case R_ARM_GOT_PREL: case R_ARM_REL32: case R_ARM_RELATIVE: case R_ARM_SBREL32: case R_ARM_TARGET1: case R_ARM_TARGET2: case R_ARM_TLS_GD32: case R_ARM_TLS_IE32: case R_ARM_TLS_LDM32: case R_ARM_TLS_LDO32: case R_ARM_TLS_LE32: case R_ARM_TLS_TPOFF32: case R_ARM_TLS_DTPOFF32: write32le(Loc, Val); break; case R_ARM_TLS_DTPMOD32: write32le(Loc, 1); break; case R_ARM_PREL31: checkInt<31>(Loc, Val, Type); write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000)); break; case R_ARM_CALL: // R_ARM_CALL is used for BL and BLX instructions, depending on the // value of bit 0 of Val, we must select a BL or BLX instruction if (Val & 1) { // If bit 0 of Val is 1 the target is Thumb, we must select a BLX. // The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1' checkInt<26>(Loc, Val, Type); write32le(Loc, 0xfa000000 | // opcode ((Val & 2) << 23) | // H ((Val >> 2) & 0x00ffffff)); // imm24 break; } if ((read32le(Loc) & 0xfe000000) == 0xfa000000) // BLX (always unconditional) instruction to an ARM Target, select an // unconditional BL. write32le(Loc, 0xeb000000 | (read32le(Loc) & 0x00ffffff)); // fall through as BL encoding is shared with B LLVM_FALLTHROUGH; case R_ARM_JUMP24: case R_ARM_PC24: case R_ARM_PLT32: checkInt<26>(Loc, Val, Type); write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff)); break; case R_ARM_THM_JUMP11: checkInt<12>(Loc, Val, Type); write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff)); break; case R_ARM_THM_JUMP19: // Encoding T3: Val = S:J2:J1:imm6:imm11:0 checkInt<21>(Loc, Val, Type); write16le(Loc, (read16le(Loc) & 0xfbc0) | // opcode cond ((Val >> 10) & 0x0400) | // S ((Val >> 12) & 0x003f)); // imm6 write16le(Loc + 2, 0x8000 | // opcode ((Val >> 8) & 0x0800) | // J2 ((Val >> 5) & 0x2000) | // J1 ((Val >> 1) & 0x07ff)); // imm11 break; case R_ARM_THM_CALL: // R_ARM_THM_CALL is used for BL and BLX instructions, depending on the // value of bit 0 of Val, we must select a BL or BLX instruction if ((Val & 1) == 0) { // Ensure BLX destination is 4-byte aligned. As BLX instruction may // only be two byte aligned. This must be done before overflow check Val = alignTo(Val, 4); } // Bit 12 is 0 for BLX, 1 for BL write16le(Loc + 2, (read16le(Loc + 2) & ~0x1000) | (Val & 1) << 12); // Fall through as rest of encoding is the same as B.W LLVM_FALLTHROUGH; case R_ARM_THM_JUMP24: // Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0 // FIXME: Use of I1 and I2 require v6T2ops checkInt<25>(Loc, Val, Type); write16le(Loc, 0xf000 | // opcode ((Val >> 14) & 0x0400) | // S ((Val >> 12) & 0x03ff)); // imm10 write16le(Loc + 2, (read16le(Loc + 2) & 0xd000) | // opcode (((~(Val >> 10)) ^ (Val >> 11)) & 0x2000) | // J1 (((~(Val >> 11)) ^ (Val >> 13)) & 0x0800) | // J2 ((Val >> 1) & 0x07ff)); // imm11 break; case R_ARM_MOVW_ABS_NC: case R_ARM_MOVW_PREL_NC: write32le(Loc, (read32le(Loc) & ~0x000f0fff) | ((Val & 0xf000) << 4) | (Val & 0x0fff)); break; case R_ARM_MOVT_ABS: case R_ARM_MOVT_PREL: checkInt<32>(Loc, Val, Type); write32le(Loc, (read32le(Loc) & ~0x000f0fff) | (((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff)); break; case R_ARM_THM_MOVT_ABS: case R_ARM_THM_MOVT_PREL: // Encoding T1: A = imm4:i:imm3:imm8 checkInt<32>(Loc, Val, Type); write16le(Loc, 0xf2c0 | // opcode ((Val >> 17) & 0x0400) | // i ((Val >> 28) & 0x000f)); // imm4 write16le(Loc + 2, (read16le(Loc + 2) & 0x8f00) | // opcode ((Val >> 12) & 0x7000) | // imm3 ((Val >> 16) & 0x00ff)); // imm8 break; case R_ARM_THM_MOVW_ABS_NC: case R_ARM_THM_MOVW_PREL_NC: // Encoding T3: A = imm4:i:imm3:imm8 write16le(Loc, 0xf240 | // opcode ((Val >> 1) & 0x0400) | // i ((Val >> 12) & 0x000f)); // imm4 write16le(Loc + 2, (read16le(Loc + 2) & 0x8f00) | // opcode ((Val << 4) & 0x7000) | // imm3 (Val & 0x00ff)); // imm8 break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } int64_t ARMTargetInfo::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { switch (Type) { default: return 0; case R_ARM_ABS32: case R_ARM_BASE_PREL: case R_ARM_GOTOFF32: case R_ARM_GOT_BREL: case R_ARM_GOT_PREL: case R_ARM_REL32: case R_ARM_TARGET1: case R_ARM_TARGET2: case R_ARM_TLS_GD32: case R_ARM_TLS_LDM32: case R_ARM_TLS_LDO32: case R_ARM_TLS_IE32: case R_ARM_TLS_LE32: return SignExtend64<32>(read32le(Buf)); case R_ARM_PREL31: return SignExtend64<31>(read32le(Buf)); case R_ARM_CALL: case R_ARM_JUMP24: case R_ARM_PC24: case R_ARM_PLT32: return SignExtend64<26>(read32le(Buf) << 2); case R_ARM_THM_JUMP11: return SignExtend64<12>(read16le(Buf) << 1); case R_ARM_THM_JUMP19: { // Encoding T3: A = S:J2:J1:imm10:imm6:0 uint16_t Hi = read16le(Buf); uint16_t Lo = read16le(Buf + 2); return SignExtend64<20>(((Hi & 0x0400) << 10) | // S ((Lo & 0x0800) << 8) | // J2 ((Lo & 0x2000) << 5) | // J1 ((Hi & 0x003f) << 12) | // imm6 ((Lo & 0x07ff) << 1)); // imm11:0 } case R_ARM_THM_CALL: case R_ARM_THM_JUMP24: { // Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0 // I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S) // FIXME: I1 and I2 require v6T2ops uint16_t Hi = read16le(Buf); uint16_t Lo = read16le(Buf + 2); return SignExtend64<24>(((Hi & 0x0400) << 14) | // S (~((Lo ^ (Hi << 3)) << 10) & 0x00800000) | // I1 (~((Lo ^ (Hi << 1)) << 11) & 0x00400000) | // I2 ((Hi & 0x003ff) << 12) | // imm0 ((Lo & 0x007ff) << 1)); // imm11:0 } // ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and // MOVT is in the range -32768 <= A < 32768 case R_ARM_MOVW_ABS_NC: case R_ARM_MOVT_ABS: case R_ARM_MOVW_PREL_NC: case R_ARM_MOVT_PREL: { uint64_t Val = read32le(Buf) & 0x000f0fff; return SignExtend64<16>(((Val & 0x000f0000) >> 4) | (Val & 0x00fff)); } case R_ARM_THM_MOVW_ABS_NC: case R_ARM_THM_MOVT_ABS: case R_ARM_THM_MOVW_PREL_NC: case R_ARM_THM_MOVT_PREL: { // Encoding T3: A = imm4:i:imm3:imm8 uint16_t Hi = read16le(Buf); uint16_t Lo = read16le(Buf + 2); return SignExtend64<16>(((Hi & 0x000f) << 12) | // imm4 ((Hi & 0x0400) << 1) | // i ((Lo & 0x7000) >> 4) | // imm3 (Lo & 0x00ff)); // imm8 } } } template MipsTargetInfo::MipsTargetInfo() { GotPltHeaderEntriesNum = 2; DefaultMaxPageSize = 65536; GotEntrySize = sizeof(typename ELFT::uint); GotPltEntrySize = sizeof(typename ELFT::uint); PltEntrySize = 16; PltHeaderSize = 32; CopyRel = R_MIPS_COPY; PltRel = R_MIPS_JUMP_SLOT; NeedsThunks = true; if (ELFT::Is64Bits) { RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32; TlsGotRel = R_MIPS_TLS_TPREL64; TlsModuleIndexRel = R_MIPS_TLS_DTPMOD64; TlsOffsetRel = R_MIPS_TLS_DTPREL64; } else { RelativeRel = R_MIPS_REL32; TlsGotRel = R_MIPS_TLS_TPREL32; TlsModuleIndexRel = R_MIPS_TLS_DTPMOD32; TlsOffsetRel = R_MIPS_TLS_DTPREL32; } } template RelExpr MipsTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { // See comment in the calculateMipsRelChain. if (ELFT::Is64Bits || Config->MipsN32Abi) Type &= 0xff; switch (Type) { default: return R_ABS; case R_MIPS_JALR: return R_HINT; case R_MIPS_GPREL16: case R_MIPS_GPREL32: return R_MIPS_GOTREL; case R_MIPS_26: return R_PLT; case R_MIPS_HI16: case R_MIPS_LO16: // R_MIPS_HI16/R_MIPS_LO16 relocations against _gp_disp calculate // offset between start of function and 'gp' value which by default // equal to the start of .got section. In that case we consider these // relocations as relative. if (&S == ElfSym::MipsGpDisp) return R_MIPS_GOT_GP_PC; if (&S == ElfSym::MipsLocalGp) return R_MIPS_GOT_GP; // fallthrough case R_MIPS_GOT_OFST: return R_ABS; case R_MIPS_PC32: case R_MIPS_PC16: case R_MIPS_PC19_S2: case R_MIPS_PC21_S2: case R_MIPS_PC26_S2: case R_MIPS_PCHI16: case R_MIPS_PCLO16: return R_PC; case R_MIPS_GOT16: if (S.isLocal()) return R_MIPS_GOT_LOCAL_PAGE; // fallthrough case R_MIPS_CALL16: case R_MIPS_GOT_DISP: case R_MIPS_TLS_GOTTPREL: return R_MIPS_GOT_OFF; case R_MIPS_CALL_HI16: case R_MIPS_CALL_LO16: case R_MIPS_GOT_HI16: case R_MIPS_GOT_LO16: return R_MIPS_GOT_OFF32; case R_MIPS_GOT_PAGE: return R_MIPS_GOT_LOCAL_PAGE; case R_MIPS_TLS_GD: return R_MIPS_TLSGD; case R_MIPS_TLS_LDM: return R_MIPS_TLSLD; } } template bool MipsTargetInfo::isPicRel(uint32_t Type) const { return Type == R_MIPS_32 || Type == R_MIPS_64; } template uint32_t MipsTargetInfo::getDynRel(uint32_t Type) const { return RelativeRel; } template void MipsTargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const { write32(Buf, InX::Plt->getVA()); } template static int64_t getPcRelocAddend(const uint8_t *Loc) { uint32_t Instr = read32(Loc); uint32_t Mask = 0xffffffff >> (32 - BSIZE); return SignExtend64((Instr & Mask) << SHIFT); } template static void applyMipsPcReloc(uint8_t *Loc, uint32_t Type, uint64_t V) { uint32_t Mask = 0xffffffff >> (32 - BSIZE); uint32_t Instr = read32(Loc); if (SHIFT > 0) checkAlignment<(1 << SHIFT)>(Loc, V, Type); checkInt(Loc, V, Type); write32(Loc, (Instr & ~Mask) | ((V >> SHIFT) & Mask)); } template static void writeMipsHi16(uint8_t *Loc, uint64_t V) { uint32_t Instr = read32(Loc); uint16_t Res = ((V + 0x8000) >> 16) & 0xffff; write32(Loc, (Instr & 0xffff0000) | Res); } template static void writeMipsHigher(uint8_t *Loc, uint64_t V) { uint32_t Instr = read32(Loc); uint16_t Res = ((V + 0x80008000) >> 32) & 0xffff; write32(Loc, (Instr & 0xffff0000) | Res); } template static void writeMipsHighest(uint8_t *Loc, uint64_t V) { uint32_t Instr = read32(Loc); uint16_t Res = ((V + 0x800080008000) >> 48) & 0xffff; write32(Loc, (Instr & 0xffff0000) | Res); } template static void writeMipsLo16(uint8_t *Loc, uint64_t V) { uint32_t Instr = read32(Loc); write32(Loc, (Instr & 0xffff0000) | (V & 0xffff)); } template static bool isMipsR6() { const auto &FirstObj = cast>(*Config->FirstElf); uint32_t Arch = FirstObj.getObj().getHeader()->e_flags & EF_MIPS_ARCH; return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6; } template void MipsTargetInfo::writePltHeader(uint8_t *Buf) const { const endianness E = ELFT::TargetEndianness; if (Config->MipsN32Abi) { write32(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0]) write32(Buf + 4, 0x8dd90000); // lw $25, %lo(&GOTPLT[0])($14) write32(Buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0]) write32(Buf + 12, 0x030ec023); // subu $24, $24, $14 } else { write32(Buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0]) write32(Buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28) write32(Buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0]) write32(Buf + 12, 0x031cc023); // subu $24, $24, $28 } write32(Buf + 16, 0x03e07825); // move $15, $31 write32(Buf + 20, 0x0018c082); // srl $24, $24, 2 write32(Buf + 24, 0x0320f809); // jalr $25 write32(Buf + 28, 0x2718fffe); // subu $24, $24, 2 uint64_t GotPlt = InX::GotPlt->getVA(); writeMipsHi16(Buf, GotPlt); writeMipsLo16(Buf + 4, GotPlt); writeMipsLo16(Buf + 8, GotPlt); } template void MipsTargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const endianness E = ELFT::TargetEndianness; write32(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry) write32(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15) // jr $25 write32(Buf + 8, isMipsR6() ? 0x03200009 : 0x03200008); write32(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry) writeMipsHi16(Buf, GotPltEntryAddr); writeMipsLo16(Buf + 4, GotPltEntryAddr); writeMipsLo16(Buf + 12, GotPltEntryAddr); } template bool MipsTargetInfo::needsThunk(RelExpr Expr, uint32_t Type, const InputFile *File, const SymbolBody &S) const { // Any MIPS PIC code function is invoked with its address in register $t9. // So if we have a branch instruction from non-PIC code to the PIC one // we cannot make the jump directly and need to create a small stubs // to save the target function address. // See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf if (Type != R_MIPS_26) return false; auto *F = dyn_cast_or_null>(File); if (!F) return false; // If current file has PIC code, LA25 stub is not required. if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC) return false; auto *D = dyn_cast(&S); // LA25 is required if target file has PIC code // or target symbol is a PIC symbol. return D && D->isMipsPIC(); } template int64_t MipsTargetInfo::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { const endianness E = ELFT::TargetEndianness; switch (Type) { default: return 0; case R_MIPS_32: case R_MIPS_GPREL32: case R_MIPS_TLS_DTPREL32: case R_MIPS_TLS_TPREL32: return SignExtend64<32>(read32(Buf)); case R_MIPS_26: // FIXME (simon): If the relocation target symbol is not a PLT entry // we should use another expression for calculation: // ((A << 2) | (P & 0xf0000000)) >> 2 return SignExtend64<28>((read32(Buf) & 0x3ffffff) << 2); case R_MIPS_GPREL16: case R_MIPS_LO16: case R_MIPS_PCLO16: case R_MIPS_TLS_DTPREL_HI16: case R_MIPS_TLS_DTPREL_LO16: case R_MIPS_TLS_TPREL_HI16: case R_MIPS_TLS_TPREL_LO16: return SignExtend64<16>(read32(Buf)); case R_MIPS_PC16: return getPcRelocAddend(Buf); case R_MIPS_PC19_S2: return getPcRelocAddend(Buf); case R_MIPS_PC21_S2: return getPcRelocAddend(Buf); case R_MIPS_PC26_S2: return getPcRelocAddend(Buf); case R_MIPS_PC32: return getPcRelocAddend(Buf); } } static std::pair calculateMipsRelChain(uint8_t *Loc, uint32_t Type, uint64_t Val) { // MIPS N64 ABI packs multiple relocations into the single relocation // record. In general, all up to three relocations can have arbitrary // types. In fact, Clang and GCC uses only a few combinations. For now, // we support two of them. That is allow to pass at least all LLVM // test suite cases. // / R_MIPS_SUB / R_MIPS_HI16 | R_MIPS_LO16 // / R_MIPS_64 / R_MIPS_NONE // The first relocation is a 'real' relocation which is calculated // using the corresponding symbol's value. The second and the third // relocations used to modify result of the first one: extend it to // 64-bit, extract high or low part etc. For details, see part 2.9 Relocation // at the https://dmz-portal.mips.com/mw/images/8/82/007-4658-001.pdf uint32_t Type2 = (Type >> 8) & 0xff; uint32_t Type3 = (Type >> 16) & 0xff; if (Type2 == R_MIPS_NONE && Type3 == R_MIPS_NONE) return std::make_pair(Type, Val); if (Type2 == R_MIPS_64 && Type3 == R_MIPS_NONE) return std::make_pair(Type2, Val); if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16)) return std::make_pair(Type3, -Val); error(getErrorLocation(Loc) + "unsupported relocations combination " + Twine(Type)); return std::make_pair(Type & 0xff, Val); } template void MipsTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { const endianness E = ELFT::TargetEndianness; // Thread pointer and DRP offsets from the start of TLS data area. // https://www.linux-mips.org/wiki/NPTL if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16 || Type == R_MIPS_TLS_DTPREL32 || Type == R_MIPS_TLS_DTPREL64) Val -= 0x8000; else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16 || Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64) Val -= 0x7000; if (ELFT::Is64Bits || Config->MipsN32Abi) std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val); switch (Type) { case R_MIPS_32: case R_MIPS_GPREL32: case R_MIPS_TLS_DTPREL32: case R_MIPS_TLS_TPREL32: write32(Loc, Val); break; case R_MIPS_64: case R_MIPS_TLS_DTPREL64: case R_MIPS_TLS_TPREL64: write64(Loc, Val); break; case R_MIPS_26: write32(Loc, (read32(Loc) & ~0x3ffffff) | ((Val >> 2) & 0x3ffffff)); break; case R_MIPS_GOT16: // The R_MIPS_GOT16 relocation's value in "relocatable" linking mode // is updated addend (not a GOT index). In that case write high 16 bits // to store a correct addend value. if (Config->Relocatable) writeMipsHi16(Loc, Val); else { checkInt<16>(Loc, Val, Type); writeMipsLo16(Loc, Val); } break; case R_MIPS_GOT_DISP: case R_MIPS_GOT_PAGE: case R_MIPS_GPREL16: case R_MIPS_TLS_GD: case R_MIPS_TLS_LDM: checkInt<16>(Loc, Val, Type); // fallthrough case R_MIPS_CALL16: case R_MIPS_CALL_LO16: case R_MIPS_GOT_LO16: case R_MIPS_GOT_OFST: case R_MIPS_LO16: case R_MIPS_PCLO16: case R_MIPS_TLS_DTPREL_LO16: case R_MIPS_TLS_GOTTPREL: case R_MIPS_TLS_TPREL_LO16: writeMipsLo16(Loc, Val); break; case R_MIPS_CALL_HI16: case R_MIPS_GOT_HI16: case R_MIPS_HI16: case R_MIPS_PCHI16: case R_MIPS_TLS_DTPREL_HI16: case R_MIPS_TLS_TPREL_HI16: writeMipsHi16(Loc, Val); break; case R_MIPS_HIGHER: writeMipsHigher(Loc, Val); break; case R_MIPS_HIGHEST: writeMipsHighest(Loc, Val); break; case R_MIPS_JALR: // Ignore this optimization relocation for now break; case R_MIPS_PC16: applyMipsPcReloc(Loc, Type, Val); break; case R_MIPS_PC19_S2: applyMipsPcReloc(Loc, Type, Val); break; case R_MIPS_PC21_S2: applyMipsPcReloc(Loc, Type, Val); break; case R_MIPS_PC26_S2: applyMipsPcReloc(Loc, Type, Val); break; case R_MIPS_PC32: applyMipsPcReloc(Loc, Type, Val); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } template bool MipsTargetInfo::usesOnlyLowPageBits(uint32_t Type) const { return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST; } } } Index: vendor/lld/dist/ELF/Writer.cpp =================================================================== --- vendor/lld/dist/ELF/Writer.cpp (revision 319468) +++ vendor/lld/dist/ELF/Writer.cpp (revision 319469) @@ -1,1847 +1,1851 @@ //===- Writer.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Writer.h" #include "Config.h" #include "Filesystem.h" #include "LinkerScript.h" #include "MapFile.h" #include "Memory.h" #include "OutputSections.h" #include "Relocations.h" #include "Strings.h" #include "SymbolTable.h" #include "SyntheticSections.h" #include "Target.h" #include "Threads.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/raw_ostream.h" #include using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support; using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; namespace { // The writer writes a SymbolTable result to a file. template class Writer { public: typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Ehdr Elf_Ehdr; typedef typename ELFT::Phdr Elf_Phdr; void run(); private: void clearOutputSections(); void createSyntheticSections(); void copyLocalSymbols(); void addSectionSymbols(); void addReservedSymbols(); void createSections(); void forEachRelSec(std::function Fn); void sortSections(); void finalizeSections(); void addPredefinedSections(); std::vector createPhdrs(); void removeEmptyPTLoad(); void addPtArmExid(std::vector &Phdrs); void assignFileOffsets(); void assignFileOffsetsBinary(); void setPhdrs(); void fixSectionAlignments(); void fixPredefinedSymbols(); void openFile(); void writeHeader(); void writeSections(); void writeSectionsBinary(); void writeBuildId(); std::unique_ptr Buffer; std::vector OutputSections; std::vector OutputSectionCommands; OutputSectionFactory Factory{OutputSections}; void addRelIpltSymbols(); void addStartEndSymbols(); void addStartStopSymbols(OutputSection *Sec); uint64_t getEntryAddr(); OutputSection *findSection(StringRef Name); OutputSection *findSectionInScript(StringRef Name); OutputSectionCommand *findSectionCommand(StringRef Name); std::vector Phdrs; uint64_t FileSize; uint64_t SectionHeaderOff; }; } // anonymous namespace StringRef elf::getOutputSectionName(StringRef Name) { if (Config->Relocatable) return Name; // If -emit-relocs is given (which is rare), we need to copy // relocation sections to the output. If input section .foo is // output as .bar, we want to rename .rel.foo .rel.bar as well. if (Config->EmitRelocs) { for (StringRef V : {".rel.", ".rela."}) { if (Name.startswith(V)) { StringRef Inner = getOutputSectionName(Name.substr(V.size() - 1)); return Saver.save(V.drop_back() + Inner); } } } for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.", ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.", ".gcc_except_table.", ".tdata.", ".ARM.exidx."}) { StringRef Prefix = V.drop_back(); if (Name.startswith(V) || Name == Prefix) return Prefix; } // CommonSection is identified as "COMMON" in linker scripts. // By default, it should go to .bss section. if (Name == "COMMON") return ".bss"; // ".zdebug_" is a prefix for ZLIB-compressed sections. // Because we decompressed input sections, we want to remove 'z'. if (Name.startswith(".zdebug_")) return Saver.save("." + Name.substr(2)); return Name; } template static bool needsInterpSection() { return !Symtab::X->getSharedFiles().empty() && !Config->DynamicLinker.empty() && !Script->ignoreInterpSection(); } template void elf::writeResult() { Writer().run(); } template void Writer::removeEmptyPTLoad() { auto I = std::remove_if(Phdrs.begin(), Phdrs.end(), [&](const PhdrEntry &P) { if (P.p_type != PT_LOAD) return false; if (!P.First) return true; uint64_t Size = P.Last->Addr + P.Last->Size - P.First->Addr; return Size == 0; }); Phdrs.erase(I, Phdrs.end()); } // This function scans over the input sections and creates mergeable // synthetic sections. It removes MergeInputSections from array and // adds new synthetic ones. Each synthetic section is added to the // location of the first input section it replaces. static void combineMergableSections() { std::vector MergeSections; for (InputSectionBase *&S : InputSections) { MergeInputSection *MS = dyn_cast(S); if (!MS) continue; // We do not want to handle sections that are not alive, so just remove // them instead of trying to merge. if (!MS->Live) continue; StringRef OutsecName = getOutputSectionName(MS->Name); uint64_t Flags = MS->Flags & ~(uint64_t)SHF_GROUP; uint32_t Alignment = std::max(MS->Alignment, MS->Entsize); auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) { return Sec->Name == OutsecName && Sec->Flags == Flags && Sec->Alignment == Alignment; }); if (I == MergeSections.end()) { MergeSyntheticSection *Syn = make(OutsecName, MS->Type, Flags, Alignment); MergeSections.push_back(Syn); I = std::prev(MergeSections.end()); S = Syn; } else { S = nullptr; } (*I)->addSection(MS); } std::vector &V = InputSections; V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); } template static void combineEhFrameSections() { for (InputSectionBase *&S : InputSections) { EhInputSection *ES = dyn_cast(S); if (!ES || !ES->Live) continue; In::EhFrame->addSection(ES); S = nullptr; } std::vector &V = InputSections; V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); } template void Writer::clearOutputSections() { // Clear the OutputSections to make sure it is not used anymore. Any // code from this point on should be using the linker script // commands. for (OutputSection *Sec : OutputSections) Sec->Sections.clear(); OutputSections.clear(); } // The main function of the writer. template void Writer::run() { // Create linker-synthesized sections such as .got or .plt. // Such sections are of type input section. createSyntheticSections(); combineMergableSections(); if (!Config->Relocatable) combineEhFrameSections(); // We need to create some reserved symbols such as _end. Create them. if (!Config->Relocatable) addReservedSymbols(); // Create output sections. Script->OutputSections = &OutputSections; if (Script->Opt.HasSections) { // If linker script contains SECTIONS commands, let it create sections. Script->processCommands(Factory); // Linker scripts may have left some input sections unassigned. // Assign such sections using the default rule. Script->addOrphanSections(Factory); } else { // If linker script does not contain SECTIONS commands, create // output sections by default rules. We still need to give the // linker script a chance to run, because it might contain // non-SECTIONS commands such as ASSERT. createSections(); Script->processCommands(Factory); } if (Config->Discard != DiscardPolicy::All) copyLocalSymbols(); if (Config->CopyRelocs) addSectionSymbols(); // Now that we have a complete set of output sections. This function // completes section contents. For example, we need to add strings // to the string table, and add entries to .got and .plt. // finalizeSections does that. finalizeSections(); if (ErrorCount) return; if (!Script->Opt.HasSections) { if (!Config->Relocatable) fixSectionAlignments(); Script->fabricateDefaultCommands(); + } else { + Script->synchronize(); } for (BaseCommand *Base : Script->Opt.Commands) if (auto *Cmd = dyn_cast(Base)) OutputSectionCommands.push_back(Cmd); + clearOutputSections(); // If -compressed-debug-sections is specified, we need to compress // .debug_* sections. Do it right now because it changes the size of // output sections. - parallelForEach(OutputSections.begin(), OutputSections.end(), - [](OutputSection *S) { S->maybeCompress(); }); + parallelForEach( + OutputSectionCommands.begin(), OutputSectionCommands.end(), + [](OutputSectionCommand *Cmd) { Cmd->maybeCompress(); }); if (Config->Relocatable) { assignFileOffsets(); } else { - Script->synchronize(); - Script->assignAddresses(Phdrs); + Script->assignAddresses(Phdrs, OutputSectionCommands); // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a // 0 sized region. This has to be done late since only after assignAddresses // we know the size of the sections. removeEmptyPTLoad(); if (!Config->OFormatBinary) assignFileOffsets(); else assignFileOffsetsBinary(); setPhdrs(); fixPredefinedSymbols(); } // It does not make sense try to open the file if we have error already. if (ErrorCount) return; // Write the result down to a file. openFile(); if (ErrorCount) return; + if (!Config->OFormatBinary) { writeHeader(); writeSections(); } else { writeSectionsBinary(); } - clearOutputSections(); // Backfill .note.gnu.build-id section content. This is done at last // because the content is usually a hash value of the entire output file. writeBuildId(); if (ErrorCount) return; // Handle -Map option. writeMapFile(OutputSectionCommands); if (ErrorCount) return; if (auto EC = Buffer->commit()) error("failed to write to the output file: " + EC.message()); // Flush the output streams and exit immediately. A full shutdown // is a good test that we are keeping track of all allocated memory, // but actually freeing it is a waste of time in a regular linker run. if (Config->ExitEarly) exitLld(0); } // Initialize Out members. template void Writer::createSyntheticSections() { // Initialize all pointers with NULL. This is needed because // you can call lld::elf::main more than once as a library. memset(&Out::First, 0, sizeof(Out)); auto Add = [](InputSectionBase *Sec) { InputSections.push_back(Sec); }; InX::DynStrTab = make(".dynstr", true); InX::Dynamic = make>(); In::RelaDyn = make>( Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc); InX::ShStrTab = make(".shstrtab", false); Out::ElfHeader = make("", 0, SHF_ALLOC); Out::ElfHeader->Size = sizeof(Elf_Ehdr); Out::ProgramHeaders = make("", 0, SHF_ALLOC); Out::ProgramHeaders->updateAlignment(Config->Wordsize); if (needsInterpSection()) { InX::Interp = createInterpSection(); Add(InX::Interp); } else { InX::Interp = nullptr; } if (!Config->Relocatable) Add(createCommentSection()); if (Config->Strip != StripPolicy::All) { InX::StrTab = make(".strtab", false); InX::SymTab = make>(*InX::StrTab); } if (Config->BuildId != BuildIdKind::None) { InX::BuildId = make(); Add(InX::BuildId); } InX::Common = createCommonSection(); if (InX::Common) Add(InX::Common); InX::Bss = make(".bss"); Add(InX::Bss); InX::BssRelRo = make(".bss.rel.ro"); Add(InX::BssRelRo); // Add MIPS-specific sections. bool HasDynSymTab = !Symtab::X->getSharedFiles().empty() || Config->Pic || Config->ExportDynamic; if (Config->EMachine == EM_MIPS) { if (!Config->Shared && HasDynSymTab) { InX::MipsRldMap = make(); Add(InX::MipsRldMap); } if (auto *Sec = MipsAbiFlagsSection::create()) Add(Sec); if (auto *Sec = MipsOptionsSection::create()) Add(Sec); if (auto *Sec = MipsReginfoSection::create()) Add(Sec); } if (HasDynSymTab) { InX::DynSymTab = make>(*InX::DynStrTab); Add(InX::DynSymTab); In::VerSym = make>(); Add(In::VerSym); if (!Config->VersionDefinitions.empty()) { In::VerDef = make>(); Add(In::VerDef); } In::VerNeed = make>(); Add(In::VerNeed); if (Config->GnuHash) { InX::GnuHashTab = make(); Add(InX::GnuHashTab); } if (Config->SysvHash) { In::HashTab = make>(); Add(In::HashTab); } Add(InX::Dynamic); Add(InX::DynStrTab); Add(In::RelaDyn); } // Add .got. MIPS' .got is so different from the other archs, // it has its own class. if (Config->EMachine == EM_MIPS) { InX::MipsGot = make(); Add(InX::MipsGot); } else { InX::Got = make(); Add(InX::Got); } InX::GotPlt = make(); Add(InX::GotPlt); InX::IgotPlt = make(); Add(InX::IgotPlt); if (Config->GdbIndex) { InX::GdbIndex = make(); Add(InX::GdbIndex); } // We always need to add rel[a].plt to output if it has entries. // Even for static linking it can contain R_[*]_IRELATIVE relocations. In::RelaPlt = make>( Config->IsRela ? ".rela.plt" : ".rel.plt", false /*Sort*/); Add(In::RelaPlt); // The RelaIplt immediately follows .rel.plt (.rel.dyn for ARM) to ensure // that the IRelative relocations are processed last by the dynamic loader In::RelaIplt = make>( (Config->EMachine == EM_ARM) ? ".rel.dyn" : In::RelaPlt->Name, false /*Sort*/); Add(In::RelaIplt); InX::Plt = make(Target->PltHeaderSize); Add(InX::Plt); InX::Iplt = make(0); Add(InX::Iplt); if (!Config->Relocatable) { if (Config->EhFrameHdr) { In::EhFrameHdr = make>(); Add(In::EhFrameHdr); } In::EhFrame = make>(); Add(In::EhFrame); } if (InX::SymTab) Add(InX::SymTab); Add(InX::ShStrTab); if (InX::StrTab) Add(InX::StrTab); } static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName, const SymbolBody &B) { if (B.isFile() || B.isSection()) return false; // If sym references a section in a discarded group, don't keep it. if (Sec == &InputSection::Discarded) return false; if (Config->Discard == DiscardPolicy::None) return true; // In ELF assembly .L symbols are normally discarded by the assembler. // If the assembler fails to do so, the linker discards them if // * --discard-locals is used. // * The symbol is in a SHF_MERGE section, which is normally the reason for // the assembler keeping the .L symbol. if (!SymName.startswith(".L") && !SymName.empty()) return true; if (Config->Discard == DiscardPolicy::Locals) return false; return !Sec || !(Sec->Flags & SHF_MERGE); } static bool includeInSymtab(const SymbolBody &B) { if (!B.isLocal() && !B.symbol()->IsUsedInRegularObj) return false; if (auto *D = dyn_cast(&B)) { // Always include absolute symbols. SectionBase *Sec = D->Section; if (!Sec) return true; if (auto *IS = dyn_cast(Sec)) { Sec = IS->Repl; IS = cast(Sec); // Exclude symbols pointing to garbage-collected sections. if (!IS->Live) return false; } if (auto *S = dyn_cast(Sec)) if (!S->getSectionPiece(D->Value)->Live) return false; } return true; } // Local symbols are not in the linker's symbol table. This function scans // each object file's symbol table to copy local symbols to the output. template void Writer::copyLocalSymbols() { if (!InX::SymTab) return; for (elf::ObjectFile *F : Symtab::X->getObjectFiles()) { for (SymbolBody *B : F->getLocalSymbols()) { if (!B->IsLocal) fatal(toString(F) + ": broken object: getLocalSymbols returns a non-local symbol"); auto *DR = dyn_cast(B); // No reason to keep local undefined symbol in symtab. if (!DR) continue; if (!includeInSymtab(*B)) continue; SectionBase *Sec = DR->Section; if (!shouldKeepInSymtab(Sec, B->getName(), *B)) continue; InX::SymTab->addSymbol(B); } } } template void Writer::addSectionSymbols() { // Create one STT_SECTION symbol for each output section we might // have a relocation with. for (OutputSection *Sec : OutputSections) { if (Sec->Sections.empty()) continue; InputSection *IS = Sec->Sections[0]; if (isa(IS) || IS->Type == SHT_REL || IS->Type == SHT_RELA) continue; auto *Sym = make("", /*IsLocal=*/true, /*StOther=*/0, STT_SECTION, /*Value=*/0, /*Size=*/0, IS, nullptr); InX::SymTab->addSymbol(Sym); } } // Today's loaders have a feature to make segments read-only after // processing dynamic relocations to enhance security. PT_GNU_RELRO // is defined for that. // // This function returns true if a section needs to be put into a // PT_GNU_RELRO segment. bool elf::isRelroSection(const OutputSection *Sec) { if (!Config->ZRelro) return false; uint64_t Flags = Sec->Flags; // Non-allocatable or non-writable sections don't need RELRO because // they are not writable or not even mapped to memory in the first place. // RELRO is for sections that are essentially read-only but need to // be writable only at process startup to allow dynamic linker to // apply relocations. if (!(Flags & SHF_ALLOC) || !(Flags & SHF_WRITE)) return false; // Once initialized, TLS data segments are used as data templates // for a thread-local storage. For each new thread, runtime // allocates memory for a TLS and copy templates there. No thread // are supposed to use templates directly. Thus, it can be in RELRO. if (Flags & SHF_TLS) return true; // .init_array, .preinit_array and .fini_array contain pointers to // functions that are executed on process startup or exit. These // pointers are set by the static linker, and they are not expected // to change at runtime. But if you are an attacker, you could do // interesting things by manipulating pointers in .fini_array, for // example. So they are put into RELRO. uint32_t Type = Sec->Type; if (Type == SHT_INIT_ARRAY || Type == SHT_FINI_ARRAY || Type == SHT_PREINIT_ARRAY) return true; // .got contains pointers to external symbols. They are resolved by // the dynamic linker when a module is loaded into memory, and after // that they are not expected to change. So, it can be in RELRO. - if (InX::Got && Sec == InX::Got->OutSec) + if (InX::Got && Sec == InX::Got->getParent()) return true; // .got.plt contains pointers to external function symbols. They are // by default resolved lazily, so we usually cannot put it into RELRO. // However, if "-z now" is given, the lazy symbol resolution is // disabled, which enables us to put it into RELRO. - if (Sec == InX::GotPlt->OutSec) + if (Sec == InX::GotPlt->getParent()) return Config->ZNow; // .dynamic section contains data for the dynamic linker, and // there's no need to write to it at runtime, so it's better to put // it into RELRO. - if (Sec == InX::Dynamic->OutSec) + if (Sec == InX::Dynamic->getParent()) return true; // .bss.rel.ro is used for copy relocations for read-only symbols. // Since the dynamic linker needs to process copy relocations, the // section cannot be read-only, but once initialized, they shouldn't // change. - if (Sec == InX::BssRelRo->OutSec) + if (Sec == InX::BssRelRo->getParent()) return true; // Sections with some special names are put into RELRO. This is a // bit unfortunate because section names shouldn't be significant in // ELF in spirit. But in reality many linker features depend on // magic section names. StringRef S = Sec->Name; return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" || S == ".eh_frame" || S == ".openbsd.randomdata"; } // We compute a rank for each section. The rank indicates where the // section should be placed in the file. Instead of using simple // numbers (0,1,2...), we use a series of flags. One for each decision // point when placing the section. // Using flags has two key properties: // * It is easy to check if a give branch was taken. // * It is easy two see how similar two ranks are (see getRankProximity). enum RankFlags { RF_NOT_ADDR_SET = 1 << 16, RF_NOT_INTERP = 1 << 15, RF_NOT_ALLOC = 1 << 14, RF_WRITE = 1 << 13, RF_EXEC_WRITE = 1 << 12, RF_EXEC = 1 << 11, RF_NON_TLS_BSS = 1 << 10, RF_NON_TLS_BSS_RO = 1 << 9, RF_NOT_TLS = 1 << 8, RF_BSS = 1 << 7, RF_PPC_NOT_TOCBSS = 1 << 6, RF_PPC_OPD = 1 << 5, RF_PPC_TOCL = 1 << 4, RF_PPC_TOC = 1 << 3, RF_PPC_BRANCH_LT = 1 << 2, RF_MIPS_GPREL = 1 << 1, RF_MIPS_NOT_GOT = 1 << 0 }; static unsigned getSectionRank(const OutputSection *Sec) { unsigned Rank = 0; // We want to put section specified by -T option first, so we // can start assigning VA starting from them later. if (Config->SectionStartMap.count(Sec->Name)) return Rank; Rank |= RF_NOT_ADDR_SET; // Put .interp first because some loaders want to see that section // on the first page of the executable file when loaded into memory. if (Sec->Name == ".interp") return Rank; Rank |= RF_NOT_INTERP; // Allocatable sections go first to reduce the total PT_LOAD size and // so debug info doesn't change addresses in actual code. if (!(Sec->Flags & SHF_ALLOC)) return Rank | RF_NOT_ALLOC; // Sort sections based on their access permission in the following // order: R, RX, RWX, RW. This order is based on the following // considerations: // * Read-only sections come first such that they go in the // PT_LOAD covering the program headers at the start of the file. // * Read-only, executable sections come next, unless the // -no-rosegment option is used. // * Writable, executable sections follow such that .plt on // architectures where it needs to be writable will be placed // between .text and .data. // * Writable sections come last, such that .bss lands at the very // end of the last PT_LOAD. bool IsExec = Sec->Flags & SHF_EXECINSTR; bool IsWrite = Sec->Flags & SHF_WRITE; if (IsExec) { if (IsWrite) Rank |= RF_EXEC_WRITE; else if (!Config->SingleRoRx) Rank |= RF_EXEC; } else { if (IsWrite) Rank |= RF_WRITE; } // If we got here we know that both A and B are in the same PT_LOAD. bool IsTls = Sec->Flags & SHF_TLS; bool IsNoBits = Sec->Type == SHT_NOBITS; // The first requirement we have is to put (non-TLS) nobits sections last. The // reason is that the only thing the dynamic linker will see about them is a // p_memsz that is larger than p_filesz. Seeing that it zeros the end of the // PT_LOAD, so that has to correspond to the nobits sections. bool IsNonTlsNoBits = IsNoBits && !IsTls; if (IsNonTlsNoBits) Rank |= RF_NON_TLS_BSS; // We place nobits RelRo sections before plain r/w ones, and non-nobits RelRo // sections after r/w ones, so that the RelRo sections are contiguous. bool IsRelRo = isRelroSection(Sec); if (IsNonTlsNoBits && !IsRelRo) Rank |= RF_NON_TLS_BSS_RO; if (!IsNonTlsNoBits && IsRelRo) Rank |= RF_NON_TLS_BSS_RO; // The TLS initialization block needs to be a single contiguous block in a R/W // PT_LOAD, so stick TLS sections directly before the other RelRo R/W // sections. The TLS NOBITS sections are placed here as they don't take up // virtual address space in the PT_LOAD. if (!IsTls) Rank |= RF_NOT_TLS; // Within the TLS initialization block, the non-nobits sections need to appear // first. if (IsNoBits) Rank |= RF_BSS; // // Some architectures have additional ordering restrictions for sections // // within the same PT_LOAD. if (Config->EMachine == EM_PPC64) { // PPC64 has a number of special SHT_PROGBITS+SHF_ALLOC+SHF_WRITE sections // that we would like to make sure appear is a specific order to maximize // their coverage by a single signed 16-bit offset from the TOC base // pointer. Conversely, the special .tocbss section should be first among // all SHT_NOBITS sections. This will put it next to the loaded special // PPC64 sections (and, thus, within reach of the TOC base pointer). StringRef Name = Sec->Name; if (Name != ".tocbss") Rank |= RF_PPC_NOT_TOCBSS; if (Name == ".opd") Rank |= RF_PPC_OPD; if (Name == ".toc1") Rank |= RF_PPC_TOCL; if (Name == ".toc") Rank |= RF_PPC_TOC; if (Name == ".branch_lt") Rank |= RF_PPC_BRANCH_LT; } if (Config->EMachine == EM_MIPS) { // All sections with SHF_MIPS_GPREL flag should be grouped together // because data in these sections is addressable with a gp relative address. if (Sec->Flags & SHF_MIPS_GPREL) Rank |= RF_MIPS_GPREL; if (Sec->Name != ".got") Rank |= RF_MIPS_NOT_GOT; } return Rank; } static bool compareSectionsNonScript(const OutputSection *A, const OutputSection *B) { if (A->SortRank != B->SortRank) return A->SortRank < B->SortRank; if (!(A->SortRank & RF_NOT_ADDR_SET)) return Config->SectionStartMap.lookup(A->Name) < Config->SectionStartMap.lookup(B->Name); return false; } // Output section ordering is determined by this function. static bool compareSections(const OutputSection *A, const OutputSection *B) { // For now, put sections mentioned in a linker script // first. Sections not on linker script will have a SectionIndex of // INT_MAX. int AIndex = A->SectionIndex; int BIndex = B->SectionIndex; if (AIndex != BIndex) return AIndex < BIndex; return compareSectionsNonScript(A, B); } void PhdrEntry::add(OutputSection *Sec) { Last = Sec; if (!First) First = Sec; p_align = std::max(p_align, Sec->Alignment); if (p_type == PT_LOAD) Sec->FirstInPtLoad = First; } template static Symbol *addRegular(StringRef Name, SectionBase *Sec, uint64_t Value, uint8_t StOther = STV_HIDDEN, uint8_t Binding = STB_WEAK) { // The linker generated symbols are added as STB_WEAK to allow user defined // ones to override them. return Symtab::X->addRegular(Name, StOther, STT_NOTYPE, Value, /*Size=*/0, Binding, Sec, /*File=*/nullptr); } template static DefinedRegular * addOptionalRegular(StringRef Name, SectionBase *Sec, uint64_t Val, uint8_t StOther = STV_HIDDEN, uint8_t Binding = STB_GLOBAL) { SymbolBody *S = Symtab::X->find(Name); if (!S) return nullptr; if (S->isInCurrentDSO()) return nullptr; return cast( addRegular(Name, Sec, Val, StOther, Binding)->body()); } // The beginning and the ending of .rel[a].plt section are marked // with __rel[a]_iplt_{start,end} symbols if it is a statically linked // executable. The runtime needs these symbols in order to resolve // all IRELATIVE relocs on startup. For dynamic executables, we don't // need these symbols, since IRELATIVE relocs are resolved through GOT // and PLT. For details, see http://www.airs.com/blog/archives/403. template void Writer::addRelIpltSymbols() { if (InX::DynSymTab) return; StringRef S = Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start"; addOptionalRegular(S, In::RelaIplt, 0, STV_HIDDEN, STB_WEAK); S = Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end"; addOptionalRegular(S, In::RelaIplt, -1, STV_HIDDEN, STB_WEAK); } // The linker is expected to define some symbols depending on // the linking result. This function defines such symbols. template void Writer::addReservedSymbols() { if (Config->EMachine == EM_MIPS) { // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer // so that it points to an absolute address which by default is relative // to GOT. Default offset is 0x7ff0. // See "Global Data Symbols" in Chapter 6 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf ElfSym::MipsGp = Symtab::X->addAbsolute("_gp", STV_HIDDEN, STB_LOCAL); // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between // start of function and 'gp' pointer into GOT. if (Symtab::X->find("_gp_disp")) ElfSym::MipsGpDisp = Symtab::X->addAbsolute("_gp_disp", STV_HIDDEN, STB_LOCAL); // The __gnu_local_gp is a magic symbol equal to the current value of 'gp' // pointer. This symbol is used in the code generated by .cpload pseudo-op // in case of using -mno-shared option. // https://sourceware.org/ml/binutils/2004-12/msg00094.html if (Symtab::X->find("__gnu_local_gp")) ElfSym::MipsLocalGp = Symtab::X->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_LOCAL); } // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol // is magical and is used to produce a R_386_GOTPC relocation. // The R_386_GOTPC relocation value doesn't actually depend on the // symbol value, so it could use an index of STN_UNDEF which, according // to the spec, means the symbol value is 0. // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in // the object file. // The situation is even stranger on x86_64 where the assembly doesn't // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as // an undefined symbol in the .o files. // Given that the symbol is effectively unused, we just create a dummy // hidden one to avoid the undefined symbol error. Symtab::X->addIgnored("_GLOBAL_OFFSET_TABLE_"); // __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For // static linking the linker is required to optimize away any references to // __tls_get_addr, so it's not defined anywhere. Create a hidden definition // to avoid the undefined symbol error. if (!InX::DynSymTab) Symtab::X->addIgnored("__tls_get_addr"); // __ehdr_start is the location of ELF file headers. Note that we define // this symbol unconditionally even when using a linker script, which // differs from the behavior implemented by GNU linker which only define // this symbol if ELF headers are in the memory mapped segment. addOptionalRegular("__ehdr_start", Out::ElfHeader, 0, STV_HIDDEN); // If linker script do layout we do not need to create any standart symbols. if (Script->Opt.HasSections) return; auto Add = [](StringRef S) { return addOptionalRegular(S, Out::ElfHeader, 0, STV_DEFAULT); }; ElfSym::Bss = Add("__bss_start"); ElfSym::End1 = Add("end"); ElfSym::End2 = Add("_end"); ElfSym::Etext1 = Add("etext"); ElfSym::Etext2 = Add("_etext"); ElfSym::Edata1 = Add("edata"); ElfSym::Edata2 = Add("_edata"); } // Sort input sections by section name suffixes for // __attribute__((init_priority(N))). static void sortInitFini(OutputSection *S) { if (S) reinterpret_cast(S)->sortInitFini(); } // Sort input sections by the special rule for .ctors and .dtors. static void sortCtorsDtors(OutputSection *S) { if (S) reinterpret_cast(S)->sortCtorsDtors(); } // Sort input sections using the list provided by --symbol-ordering-file. template static void sortBySymbolsOrder(ArrayRef OutputSections) { if (Config->SymbolOrderingFile.empty()) return; // Build a map from symbols to their priorities. Symbols that didn't // appear in the symbol ordering file have the lowest priority 0. // All explicitly mentioned symbols have negative (higher) priorities. DenseMap SymbolOrder; int Priority = -Config->SymbolOrderingFile.size(); for (StringRef S : Config->SymbolOrderingFile) SymbolOrder.insert({S, Priority++}); // Build a map from sections to their priorities. DenseMap SectionOrder; for (elf::ObjectFile *File : Symtab::X->getObjectFiles()) { for (SymbolBody *Body : File->getSymbols()) { auto *D = dyn_cast(Body); if (!D || !D->Section) continue; int &Priority = SectionOrder[D->Section]; Priority = std::min(Priority, SymbolOrder.lookup(D->getName())); } } // Sort sections by priority. for (OutputSection *Base : OutputSections) if (auto *Sec = dyn_cast(Base)) Sec->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); }); } template void Writer::forEachRelSec(std::function Fn) { for (InputSectionBase *IS : InputSections) { if (!IS->Live) continue; // Scan all relocations. Each relocation goes through a series // of tests to determine if it needs special treatment, such as // creating GOT, PLT, copy relocations, etc. // Note that relocations for non-alloc sections are directly // processed by InputSection::relocateNonAlloc. if (!(IS->Flags & SHF_ALLOC)) continue; if (isa(IS) || isa(IS)) Fn(*IS); } if (!Config->Relocatable) { for (EhInputSection *ES : In::EhFrame->Sections) Fn(*ES); } } template void Writer::createSections() { for (InputSectionBase *IS : InputSections) if (IS) Factory.addInputSec(IS, getOutputSectionName(IS->Name)); sortBySymbolsOrder(OutputSections); sortInitFini(findSection(".init_array")); sortInitFini(findSection(".fini_array")); sortCtorsDtors(findSection(".ctors")); sortCtorsDtors(findSection(".dtors")); for (OutputSection *Sec : OutputSections) Sec->assignOffsets(); } // We want to find how similar two ranks are. // The more branches in getSectionRank that match, the more similar they are. // Since each branch corresponds to a bit flag, we can just use // countLeadingZeros. static unsigned getRankProximity(OutputSection *A, OutputSection *B) { return countLeadingZeros(A->SortRank ^ B->SortRank); } // We want to place orphan sections so that they share as much // characteristics with their neighbors as possible. For example, if // both are rw, or both are tls. template static std::vector::iterator findOrphanPos(std::vector::iterator B, std::vector::iterator E) { OutputSection *Sec = *E; // Find the first element that has as close a rank as possible. auto I = std::max_element(B, E, [=](OutputSection *A, OutputSection *B) { return getRankProximity(Sec, A) < getRankProximity(Sec, B); }); if (I == E) return E; // Consider all existing sections with the same proximity. unsigned Proximity = getRankProximity(Sec, *I); while (I != E && getRankProximity(Sec, *I) == Proximity && Sec->SortRank >= (*I)->SortRank) ++I; return I; } template void Writer::sortSections() { // Don't sort if using -r. It is not necessary and we want to preserve the // relative order for SHF_LINK_ORDER sections. if (Config->Relocatable) return; if (Script->Opt.HasSections) Script->adjustSectionsBeforeSorting(); for (OutputSection *Sec : OutputSections) Sec->SortRank = getSectionRank(Sec); if (!Script->Opt.HasSections) { std::stable_sort(OutputSections.begin(), OutputSections.end(), compareSectionsNonScript); return; } // The order of the sections in the script is arbitrary and may not agree with // compareSectionsNonScript. This means that we cannot easily define a // strict weak ordering. To see why, consider a comparison of a section in the // script and one not in the script. We have a two simple options: // * Make them equivalent (a is not less than b, and b is not less than a). // The problem is then that equivalence has to be transitive and we can // have sections a, b and c with only b in a script and a less than c // which breaks this property. // * Use compareSectionsNonScript. Given that the script order doesn't have // to match, we can end up with sections a, b, c, d where b and c are in the // script and c is compareSectionsNonScript less than b. In which case d // can be equivalent to c, a to b and d < a. As a concrete example: // .a (rx) # not in script // .b (rx) # in script // .c (ro) # in script // .d (ro) # not in script // // The way we define an order then is: // * First put script sections at the start and sort the script sections. // * Move each non-script section to its preferred position. We try // to put each section in the last position where it it can share // a PT_LOAD. std::stable_sort(OutputSections.begin(), OutputSections.end(), compareSections); auto I = OutputSections.begin(); auto E = OutputSections.end(); auto NonScriptI = std::find_if(OutputSections.begin(), E, [](OutputSection *S) { return S->SectionIndex == INT_MAX; }); while (NonScriptI != E) { auto Pos = findOrphanPos(I, NonScriptI); // As an optimization, find all sections with the same sort rank // and insert them with one rotate. unsigned Rank = (*NonScriptI)->SortRank; auto End = std::find_if(NonScriptI + 1, E, [=](OutputSection *Sec) { return Sec->SortRank != Rank; }); std::rotate(Pos, NonScriptI, End); NonScriptI = End; } Script->adjustSectionsAfterSorting(); } static void applySynthetic(const std::vector &Sections, std::function Fn) { for (SyntheticSection *SS : Sections) - if (SS && SS->OutSec && !SS->empty()) { + if (SS && SS->getParent() && !SS->empty()) { Fn(SS); - SS->OutSec->assignOffsets(); + SS->getParent()->assignOffsets(); } } // We need to add input synthetic sections early in createSyntheticSections() // to make them visible from linkescript side. But not all sections are always // required to be in output. For example we don't need dynamic section content // sometimes. This function filters out such unused sections from the output. static void removeUnusedSyntheticSections(std::vector &V) { // All input synthetic sections that can be empty are placed after // all regular ones. We iterate over them all and exit at first // non-synthetic. for (InputSectionBase *S : llvm::reverse(InputSections)) { SyntheticSection *SS = dyn_cast(S); if (!SS) return; - if (!SS->empty() || !SS->OutSec) + OutputSection *OS = SS->getParent(); + if (!SS->empty() || !OS) continue; - - SS->OutSec->Sections.erase(std::find(SS->OutSec->Sections.begin(), - SS->OutSec->Sections.end(), SS)); + OS->Sections.erase(std::find(OS->Sections.begin(), OS->Sections.end(), SS)); SS->Live = false; // If there are no other sections in the output section, remove it from the // output. - if (SS->OutSec->Sections.empty()) - V.erase(std::find(V.begin(), V.end(), SS->OutSec)); + if (OS->Sections.empty()) + V.erase(std::find(V.begin(), V.end(), OS)); } } // Create output section objects and add them to OutputSections. template void Writer::finalizeSections() { Out::DebugInfo = findSection(".debug_info"); Out::PreinitArray = findSection(".preinit_array"); Out::InitArray = findSection(".init_array"); Out::FiniArray = findSection(".fini_array"); // The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop // symbols for sections, so that the runtime can get the start and end // addresses of each section by section name. Add such symbols. if (!Config->Relocatable) { addStartEndSymbols(); for (OutputSection *Sec : OutputSections) addStartStopSymbols(Sec); } // Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type. // It should be okay as no one seems to care about the type. // Even the author of gold doesn't remember why gold behaves that way. // https://sourceware.org/ml/binutils/2002-03/msg00360.html if (InX::DynSymTab) addRegular("_DYNAMIC", InX::Dynamic, 0); // Define __rel[a]_iplt_{start,end} symbols if needed. addRelIpltSymbols(); // This responsible for splitting up .eh_frame section into // pieces. The relocation scan uses those pieces, so this has to be // earlier. applySynthetic({In::EhFrame}, [](SyntheticSection *SS) { SS->finalizeContents(); }); // Scan relocations. This must be done after every symbol is declared so that // we can correctly decide if a dynamic relocation is needed. forEachRelSec(scanRelocations); if (InX::Plt && !InX::Plt->empty()) InX::Plt->addSymbols(); if (InX::Iplt && !InX::Iplt->empty()) InX::Iplt->addSymbols(); // Now that we have defined all possible global symbols including linker- // synthesized ones. Visit all symbols to give the finishing touches. for (Symbol *S : Symtab::X->getSymbols()) { SymbolBody *Body = S->body(); if (!includeInSymtab(*Body)) continue; if (InX::SymTab) InX::SymTab->addSymbol(Body); if (InX::DynSymTab && S->includeInDynsym()) { InX::DynSymTab->addSymbol(Body); if (auto *SS = dyn_cast(Body)) if (cast>(SS->File)->isNeeded()) In::VerNeed->addSymbol(SS); } } // Do not proceed if there was an undefined symbol. if (ErrorCount) return; addPredefinedSections(); removeUnusedSyntheticSections(OutputSections); sortSections(); // This is a bit of a hack. A value of 0 means undef, so we set it // to 1 t make __ehdr_start defined. The section number is not // particularly relevant. Out::ElfHeader->SectionIndex = 1; unsigned I = 1; for (OutputSection *Sec : OutputSections) { Sec->SectionIndex = I++; Sec->ShName = InX::ShStrTab->addString(Sec->Name); } // Binary and relocatable output does not have PHDRS. // The headers have to be created before finalize as that can influence the // image base and the dynamic section on mips includes the image base. if (!Config->Relocatable && !Config->OFormatBinary) { Phdrs = Script->hasPhdrsCommands() ? Script->createPhdrs() : createPhdrs(); addPtArmExid(Phdrs); Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size(); } // Dynamic section must be the last one in this list and dynamic // symbol table section (DynSymTab) must be the first one. applySynthetic({InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab, In::HashTab, InX::SymTab, InX::ShStrTab, InX::StrTab, In::VerDef, InX::DynStrTab, InX::GdbIndex, InX::Got, InX::MipsGot, InX::IgotPlt, InX::GotPlt, In::RelaDyn, In::RelaIplt, In::RelaPlt, InX::Plt, InX::Iplt, In::EhFrameHdr, In::VerSym, In::VerNeed, InX::Dynamic}, [](SyntheticSection *SS) { SS->finalizeContents(); }); // Some architectures use small displacements for jump instructions. // It is linker's responsibility to create thunks containing long // jump instructions if jump targets are too far. Create thunks. if (Target->NeedsThunks) { // FIXME: only ARM Interworking and Mips LA25 Thunks are implemented, // these // do not require address information. To support range extension Thunks // we need to assign addresses so that we can tell if jump instructions // are out of range. This will need to turn into a loop that converges // when no more Thunks are added ThunkCreator TC; if (TC.createThunks(OutputSections)) applySynthetic({InX::MipsGot}, [](SyntheticSection *SS) { SS->updateAllocSize(); }); } // Fill other section headers. The dynamic table is finalized // at the end because some tags like RELSZ depend on result // of finalizing other sections. for (OutputSection *Sec : OutputSections) Sec->finalize(); // createThunks may have added local symbols to the static symbol table applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab}, [](SyntheticSection *SS) { SS->postThunkContents(); }); } template void Writer::addPredefinedSections() { // ARM ABI requires .ARM.exidx to be terminated by some piece of data. // We have the terminater synthetic section class. Add that at the end. auto *OS = dyn_cast_or_null(findSection(".ARM.exidx")); if (!OS || OS->Sections.empty() || Config->Relocatable) return; auto *Sentinel = make(); OS->addSection(Sentinel); // If there are linker script commands existing at this point then add the // sentinel to the last of these too. if (OutputSectionCommand *C = Script->getCmd(OS)) { auto ISD = std::find_if(C->Commands.rbegin(), C->Commands.rend(), [](const BaseCommand *Base) { return isa(Base); }); cast(*ISD)->Sections.push_back(Sentinel); } } // The linker is expected to define SECNAME_start and SECNAME_end // symbols for a few sections. This function defines them. template void Writer::addStartEndSymbols() { auto Define = [&](StringRef Start, StringRef End, OutputSection *OS) { // These symbols resolve to the image base if the section does not exist. // A special value -1 indicates end of the section. if (OS) { addOptionalRegular(Start, OS, 0); addOptionalRegular(End, OS, -1); } else { if (Config->Pic) OS = Out::ElfHeader; addOptionalRegular(Start, OS, 0); addOptionalRegular(End, OS, 0); } }; Define("__preinit_array_start", "__preinit_array_end", Out::PreinitArray); Define("__init_array_start", "__init_array_end", Out::InitArray); Define("__fini_array_start", "__fini_array_end", Out::FiniArray); if (OutputSection *Sec = findSection(".ARM.exidx")) Define("__exidx_start", "__exidx_end", Sec); } // If a section name is valid as a C identifier (which is rare because of // the leading '.'), linkers are expected to define __start_ and // __stop_ symbols. They are at beginning and end of the section, // respectively. This is not requested by the ELF standard, but GNU ld and // gold provide the feature, and used by many programs. template void Writer::addStartStopSymbols(OutputSection *Sec) { StringRef S = Sec->Name; if (!isValidCIdentifier(S)) return; addOptionalRegular(Saver.save("__start_" + S), Sec, 0, STV_DEFAULT); addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT); } template OutputSectionCommand *Writer::findSectionCommand(StringRef Name) { for (OutputSectionCommand *Cmd : OutputSectionCommands) if (Cmd->Name == Name) return Cmd; return nullptr; } template OutputSection *Writer::findSectionInScript(StringRef Name) { if (OutputSectionCommand *Cmd = findSectionCommand(Name)) return Cmd->Sec; return nullptr; } template OutputSection *Writer::findSection(StringRef Name) { for (OutputSection *Sec : OutputSections) if (Sec->Name == Name) return Sec; return nullptr; } static bool needsPtLoad(OutputSection *Sec) { if (!(Sec->Flags & SHF_ALLOC)) return false; // Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is // responsible for allocating space for them, not the PT_LOAD that // contains the TLS initialization image. if (Sec->Flags & SHF_TLS && Sec->Type == SHT_NOBITS) return false; return true; } // Linker scripts are responsible for aligning addresses. Unfortunately, most // linker scripts are designed for creating two PT_LOADs only, one RX and one // RW. This means that there is no alignment in the RO to RX transition and we // cannot create a PT_LOAD there. static uint64_t computeFlags(uint64_t Flags) { if (Config->Omagic) return PF_R | PF_W | PF_X; if (Config->SingleRoRx && !(Flags & PF_W)) return Flags | PF_X; return Flags; } // Decide which program headers to create and which sections to include in each // one. template std::vector Writer::createPhdrs() { std::vector Ret; auto AddHdr = [&](unsigned Type, unsigned Flags) -> PhdrEntry * { Ret.emplace_back(Type, Flags); return &Ret.back(); }; // The first phdr entry is PT_PHDR which describes the program header itself. AddHdr(PT_PHDR, PF_R)->add(Out::ProgramHeaders); // PT_INTERP must be the second entry if exists. if (OutputSection *Sec = findSection(".interp")) AddHdr(PT_INTERP, Sec->getPhdrFlags())->add(Sec); // Add the first PT_LOAD segment for regular output sections. uint64_t Flags = computeFlags(PF_R); PhdrEntry *Load = AddHdr(PT_LOAD, Flags); // Add the headers. We will remove them if they don't fit. Load->add(Out::ElfHeader); Load->add(Out::ProgramHeaders); for (OutputSection *Sec : OutputSections) { if (!(Sec->Flags & SHF_ALLOC)) break; if (!needsPtLoad(Sec)) continue; // Segments are contiguous memory regions that has the same attributes // (e.g. executable or writable). There is one phdr for each segment. // Therefore, we need to create a new phdr when the next section has // different flags or is loaded at a discontiguous address using AT linker // script command. uint64_t NewFlags = computeFlags(Sec->getPhdrFlags()); if (Script->hasLMA(Sec) || Flags != NewFlags) { Load = AddHdr(PT_LOAD, NewFlags); Flags = NewFlags; } Load->add(Sec); } // Add a TLS segment if any. PhdrEntry TlsHdr(PT_TLS, PF_R); for (OutputSection *Sec : OutputSections) if (Sec->Flags & SHF_TLS) TlsHdr.add(Sec); if (TlsHdr.First) Ret.push_back(std::move(TlsHdr)); // Add an entry for .dynamic. if (InX::DynSymTab) - AddHdr(PT_DYNAMIC, InX::Dynamic->OutSec->getPhdrFlags()) - ->add(InX::Dynamic->OutSec); + AddHdr(PT_DYNAMIC, InX::Dynamic->getParent()->getPhdrFlags()) + ->add(InX::Dynamic->getParent()); // PT_GNU_RELRO includes all sections that should be marked as // read-only by dynamic linker after proccessing relocations. PhdrEntry RelRo(PT_GNU_RELRO, PF_R); for (OutputSection *Sec : OutputSections) if (needsPtLoad(Sec) && isRelroSection(Sec)) RelRo.add(Sec); if (RelRo.First) Ret.push_back(std::move(RelRo)); // PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr. if (!In::EhFrame->empty() && In::EhFrameHdr && - In::EhFrame->OutSec && In::EhFrameHdr->OutSec) - AddHdr(PT_GNU_EH_FRAME, In::EhFrameHdr->OutSec->getPhdrFlags()) - ->add(In::EhFrameHdr->OutSec); + In::EhFrame->getParent() && In::EhFrameHdr->getParent()) + AddHdr(PT_GNU_EH_FRAME, In::EhFrameHdr->getParent()->getPhdrFlags()) + ->add(In::EhFrameHdr->getParent()); // PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes // the dynamic linker fill the segment with random data. if (OutputSection *Sec = findSection(".openbsd.randomdata")) AddHdr(PT_OPENBSD_RANDOMIZE, Sec->getPhdrFlags())->add(Sec); // PT_GNU_STACK is a special section to tell the loader to make the // pages for the stack non-executable. If you really want an executable // stack, you can pass -z execstack, but that's not recommended for // security reasons. unsigned Perm; if (Config->ZExecstack) Perm = PF_R | PF_W | PF_X; else Perm = PF_R | PF_W; AddHdr(PT_GNU_STACK, Perm)->p_memsz = Config->ZStackSize; // PT_OPENBSD_WXNEEDED is a OpenBSD-specific header to mark the executable // is expected to perform W^X violations, such as calling mprotect(2) or // mmap(2) with PROT_WRITE | PROT_EXEC, which is prohibited by default on // OpenBSD. if (Config->ZWxneeded) AddHdr(PT_OPENBSD_WXNEEDED, PF_X); // Create one PT_NOTE per a group of contiguous .note sections. PhdrEntry *Note = nullptr; for (OutputSection *Sec : OutputSections) { if (Sec->Type == SHT_NOTE) { if (!Note || Script->hasLMA(Sec)) Note = AddHdr(PT_NOTE, PF_R); Note->add(Sec); } else { Note = nullptr; } } return Ret; } template void Writer::addPtArmExid(std::vector &Phdrs) { if (Config->EMachine != EM_ARM) return; auto I = std::find_if( OutputSections.begin(), OutputSections.end(), [](OutputSection *Sec) { return Sec->Type == SHT_ARM_EXIDX; }); if (I == OutputSections.end()) return; // PT_ARM_EXIDX is the ARM EHABI equivalent of PT_GNU_EH_FRAME PhdrEntry ARMExidx(PT_ARM_EXIDX, PF_R); ARMExidx.add(*I); Phdrs.push_back(ARMExidx); } // The first section of each PT_LOAD, the first section in PT_GNU_RELRO and the // first section after PT_GNU_RELRO have to be page aligned so that the dynamic // linker can set the permissions. template void Writer::fixSectionAlignments() { 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; OutputSection *Sec = *(I + 1); if (needsPtLoad(Sec)) Sec->PageAlign = true; } } // Adjusts the file alignment for a given output section and returns // its new file offset. The file offset must be the same with its // virtual address (modulo the page size) so that the loader can load // executables without any address adjustment. static uint64_t getFileAlignment(uint64_t Off, OutputSection *Sec) { OutputSection *First = Sec->FirstInPtLoad; // If the section is not in a PT_LOAD, we just have to align it. if (!First) return alignTo(Off, Sec->Alignment); // The first section in a PT_LOAD has to have congruent offset and address // module the page size. if (Sec == First) return alignTo(Off, Config->MaxPageSize, Sec->Addr); // If two sections share the same PT_LOAD the file offset is calculated // using this formula: Off2 = Off1 + (VA2 - VA1). return First->Offset + Sec->Addr - First->Addr; } static uint64_t setOffset(OutputSection *Sec, uint64_t Off) { if (Sec->Type == SHT_NOBITS) { Sec->Offset = Off; return Off; } Off = getFileAlignment(Off, Sec); Sec->Offset = Off; return Off + Sec->Size; } template void Writer::assignFileOffsetsBinary() { uint64_t Off = 0; - for (OutputSection *Sec : OutputSections) + for (OutputSectionCommand *Cmd : OutputSectionCommands) { + OutputSection *Sec = Cmd->Sec; if (Sec->Flags & SHF_ALLOC) Off = setOffset(Sec, Off); + } FileSize = alignTo(Off, Config->Wordsize); } // Assign file offsets to output sections. template void Writer::assignFileOffsets() { uint64_t Off = 0; Off = setOffset(Out::ElfHeader, Off); Off = setOffset(Out::ProgramHeaders, Off); - for (OutputSection *Sec : OutputSections) - Off = setOffset(Sec, Off); + for (OutputSectionCommand *Cmd : OutputSectionCommands) + Off = setOffset(Cmd->Sec, Off); SectionHeaderOff = alignTo(Off, Config->Wordsize); - FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr); + FileSize = + SectionHeaderOff + (OutputSectionCommands.size() + 1) * sizeof(Elf_Shdr); } // Finalize the program headers. We call this function after we assign // file offsets and VAs to all sections. template void Writer::setPhdrs() { for (PhdrEntry &P : Phdrs) { OutputSection *First = P.First; OutputSection *Last = P.Last; if (First) { P.p_filesz = Last->Offset - First->Offset; if (Last->Type != SHT_NOBITS) P.p_filesz += Last->Size; P.p_memsz = Last->Addr + Last->Size - First->Addr; P.p_offset = First->Offset; P.p_vaddr = First->Addr; if (!P.HasLMA) P.p_paddr = First->getLMA(); } if (P.p_type == PT_LOAD) P.p_align = Config->MaxPageSize; else if (P.p_type == PT_GNU_RELRO) { P.p_align = 1; // The glibc dynamic loader rounds the size down, so we need to round up // to protect the last page. This is a no-op on FreeBSD which always // rounds up. P.p_memsz = alignTo(P.p_memsz, Target->PageSize); } // The TLS pointer goes after PT_TLS. At least glibc will align it, // so round up the size to make sure the offsets are correct. if (P.p_type == PT_TLS) { Out::TlsPhdr = &P; if (P.p_memsz) P.p_memsz = alignTo(P.p_memsz, P.p_align); } } } // The entry point address is chosen in the following ways. // // 1. the '-e' entry command-line option; // 2. the ENTRY(symbol) command in a linker control script; // 3. the value of the symbol start, if present; // 4. the address of the first byte of the .text section, if present; // 5. the address 0. template uint64_t Writer::getEntryAddr() { // Case 1, 2 or 3. As a special case, if the symbol is actually // a number, we'll use that number as an address. if (SymbolBody *B = Symtab::X->find(Config->Entry)) return B->getVA(); uint64_t Addr; if (to_integer(Config->Entry, Addr)) return Addr; // Case 4 if (OutputSection *Sec = findSectionInScript(".text")) { if (Config->WarnMissingEntry) warn("cannot find entry symbol " + Config->Entry + "; defaulting to 0x" + utohexstr(Sec->Addr)); return Sec->Addr; } // Case 5 if (Config->WarnMissingEntry) warn("cannot find entry symbol " + Config->Entry + "; not setting start address"); return 0; } static uint16_t getELFType() { if (Config->Pic) return ET_DYN; if (Config->Relocatable) return ET_REL; return ET_EXEC; } // This function is called after we have assigned address and size // to each section. This function fixes some predefined // symbol values that depend on section address and size. template void Writer::fixPredefinedSymbols() { // _etext is the first location after the last read-only loadable segment. // _edata is the first location after the last read-write loadable segment. // _end is the first location after the uninitialized data region. PhdrEntry *Last = nullptr; PhdrEntry *LastRO = nullptr; PhdrEntry *LastRW = nullptr; for (PhdrEntry &P : Phdrs) { if (P.p_type != PT_LOAD) continue; Last = &P; if (P.p_flags & PF_W) LastRW = &P; else LastRO = &P; } auto Set = [](DefinedRegular *S, OutputSection *Sec, uint64_t Value) { if (S) { S->Section = Sec; S->Value = Value; } }; if (Last) { Set(ElfSym::End1, Last->First, Last->p_memsz); Set(ElfSym::End2, Last->First, Last->p_memsz); } if (LastRO) { Set(ElfSym::Etext1, LastRO->First, LastRO->p_filesz); Set(ElfSym::Etext2, LastRO->First, LastRO->p_filesz); } if (LastRW) { Set(ElfSym::Edata1, LastRW->First, LastRW->p_filesz); Set(ElfSym::Edata2, LastRW->First, LastRW->p_filesz); } if (ElfSym::Bss) ElfSym::Bss->Section = findSectionInScript(".bss"); // Setup MIPS _gp_disp/__gnu_local_gp symbols which should // be equal to the _gp symbol's value. - if (Config->EMachine == EM_MIPS) { - if (!ElfSym::MipsGp->Value) { - // Find GP-relative section with the lowest address - // and use this address to calculate default _gp value. - uint64_t Gp = -1; - for (const OutputSection *OS : OutputSections) - if ((OS->Flags & SHF_MIPS_GPREL) && OS->Addr < Gp) - Gp = OS->Addr; - if (Gp != (uint64_t)-1) - ElfSym::MipsGp->Value = Gp + 0x7ff0; + if (Config->EMachine == EM_MIPS && !ElfSym::MipsGp->Value) { + // Find GP-relative section with the lowest address + // and use this address to calculate default _gp value. + for (const OutputSectionCommand *Cmd : OutputSectionCommands) { + OutputSection *OS = Cmd->Sec; + if (OS->Flags & SHF_MIPS_GPREL) { + ElfSym::MipsGp->Value = OS->Addr + 0x7ff0; + break; + } } } } template void Writer::writeHeader() { uint8_t *Buf = Buffer->getBufferStart(); memcpy(Buf, "\177ELF", 4); // Write the ELF header. auto *EHdr = reinterpret_cast(Buf); EHdr->e_ident[EI_CLASS] = Config->Is64 ? ELFCLASS64 : ELFCLASS32; EHdr->e_ident[EI_DATA] = Config->IsLE ? ELFDATA2LSB : ELFDATA2MSB; EHdr->e_ident[EI_VERSION] = EV_CURRENT; EHdr->e_ident[EI_OSABI] = Config->OSABI; EHdr->e_type = getELFType(); EHdr->e_machine = Config->EMachine; EHdr->e_version = EV_CURRENT; EHdr->e_entry = getEntryAddr(); EHdr->e_shoff = SectionHeaderOff; EHdr->e_ehsize = sizeof(Elf_Ehdr); EHdr->e_phnum = Phdrs.size(); EHdr->e_shentsize = sizeof(Elf_Shdr); EHdr->e_shnum = OutputSectionCommands.size() + 1; - EHdr->e_shstrndx = InX::ShStrTab->OutSec->SectionIndex; + EHdr->e_shstrndx = InX::ShStrTab->getParent()->SectionIndex; if (Config->EMachine == EM_ARM) // We don't currently use any features incompatible with EF_ARM_EABI_VER5, // but we don't have any firm guarantees of conformance. Linux AArch64 // kernels (as of 2016) require an EABI version to be set. EHdr->e_flags = EF_ARM_EABI_VER5; else if (Config->EMachine == EM_MIPS) EHdr->e_flags = getMipsEFlags(); if (!Config->Relocatable) { EHdr->e_phoff = sizeof(Elf_Ehdr); EHdr->e_phentsize = sizeof(Elf_Phdr); } // Write the program header table. auto *HBuf = reinterpret_cast(Buf + EHdr->e_phoff); for (PhdrEntry &P : Phdrs) { HBuf->p_type = P.p_type; HBuf->p_flags = P.p_flags; HBuf->p_offset = P.p_offset; HBuf->p_vaddr = P.p_vaddr; HBuf->p_paddr = P.p_paddr; HBuf->p_filesz = P.p_filesz; HBuf->p_memsz = P.p_memsz; HBuf->p_align = P.p_align; ++HBuf; } // Write the section header table. Note that the first table entry is null. auto *SHdrs = reinterpret_cast(Buf + EHdr->e_shoff); for (OutputSectionCommand *Cmd : OutputSectionCommands) Cmd->Sec->writeHeaderTo(++SHdrs); } // Open a result file. template void Writer::openFile() { if (!Config->Is64 && FileSize > UINT32_MAX) { error("output file too large: " + Twine(FileSize) + " bytes"); return; } unlinkAsync(Config->OutputFile); ErrorOr> BufferOrErr = FileOutputBuffer::create(Config->OutputFile, FileSize, FileOutputBuffer::F_executable); if (auto EC = BufferOrErr.getError()) error("failed to open " + Config->OutputFile + ": " + EC.message()); else Buffer = std::move(*BufferOrErr); } template void Writer::writeSectionsBinary() { uint8_t *Buf = Buffer->getBufferStart(); for (OutputSectionCommand *Cmd : OutputSectionCommands) { OutputSection *Sec = Cmd->Sec; if (Sec->Flags & SHF_ALLOC) Cmd->writeTo(Buf + Sec->Offset); } } // Write section contents to a mmap'ed file. template void Writer::writeSections() { uint8_t *Buf = Buffer->getBufferStart(); // PPC64 needs to process relocations in the .opd section // before processing relocations in code-containing sections. if (auto *OpdCmd = findSectionCommand(".opd")) { Out::Opd = OpdCmd->Sec; Out::OpdBuf = Buf + Out::Opd->Offset; OpdCmd->template writeTo(Buf + Out::Opd->Offset); } OutputSection *EhFrameHdr = (In::EhFrameHdr && !In::EhFrameHdr->empty()) - ? In::EhFrameHdr->OutSec + ? In::EhFrameHdr->getParent() : nullptr; // In -r or -emit-relocs mode, write the relocation sections first as in // ELf_Rel targets we might find out that we need to modify the relocated // section while doing it. for (OutputSectionCommand *Cmd : OutputSectionCommands) { OutputSection *Sec = Cmd->Sec; if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) Cmd->writeTo(Buf + Sec->Offset); } for (OutputSectionCommand *Cmd : OutputSectionCommands) { OutputSection *Sec = Cmd->Sec; if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA) Cmd->writeTo(Buf + Sec->Offset); } // The .eh_frame_hdr depends on .eh_frame section contents, therefore // it should be written after .eh_frame is written. if (EhFrameHdr) { OutputSectionCommand *Cmd = Script->getCmd(EhFrameHdr); Cmd->writeTo(Buf + EhFrameHdr->Offset); } } template void Writer::writeBuildId() { - if (!InX::BuildId || !InX::BuildId->OutSec) + if (!InX::BuildId || !InX::BuildId->getParent()) return; // Compute a hash of all sections of the output file. uint8_t *Start = Buffer->getBufferStart(); uint8_t *End = Start + FileSize; InX::BuildId->writeBuildId({Start, End}); } template void elf::writeResult(); template void elf::writeResult(); template void elf::writeResult(); template void elf::writeResult(); Index: vendor/lld/dist/test/ELF/gc-absolute.s =================================================================== --- vendor/lld/dist/test/ELF/gc-absolute.s (nonexistent) +++ vendor/lld/dist/test/ELF/gc-absolute.s (revision 319469) @@ -0,0 +1,7 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld %t -o %t2 -shared --gc-sections + +.global foo +foo = 0x123 Property changes on: vendor/lld/dist/test/ELF/gc-absolute.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/i386-gotpc-dynamic.s =================================================================== --- vendor/lld/dist/test/ELF/i386-gotpc-dynamic.s (nonexistent) +++ vendor/lld/dist/test/ELF/i386-gotpc-dynamic.s (revision 319469) @@ -0,0 +1,32 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t.so -shared +# RUN: llvm-readobj -s %t.so | FileCheck %s +# RUN: llvm-objdump -d %t.so | FileCheck --check-prefix=DISASM %s + +# CHECK: Section { +# CHECK: Index: 7 +# CHECK-NEXT: Name: .got +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x2030 +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: +# CHECK-NEXT: } + +## 0x1000 + 4144 = 0x2030 +# DISASM: 1000: {{.*}} movl $4144, %eax + +.section .foo,"ax",@progbits +foo: + movl $bar@got-., %eax # R_386_GOTPC + +.local bar +bar: Property changes on: vendor/lld/dist/test/ELF/i386-gotpc-dynamic.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/mips64-eh-abs-reloc.s =================================================================== --- vendor/lld/dist/test/ELF/mips64-eh-abs-reloc.s (nonexistent) +++ vendor/lld/dist/test/ELF/mips64-eh-abs-reloc.s (revision 319469) @@ -0,0 +1,38 @@ +# Having an R_MIPS_64 relocation in eh_frame would previously crash LLD +# REQUIRES: mips +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %s -o %t.o +# RUN: llvm-readobj -r %t.o | FileCheck %s -check-prefix OBJ +# RUN: ld.lld --eh-frame-hdr -shared -z notext -o %t.so %t.o +# RUN: llvm-readobj -r %t.so | FileCheck %s -check-prefix PIC-RELOCS + +# Linking this as a PIE executable would also previously crash +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %S/Inputs/archive2.s -o %t-foo.o +# -pie needs -z notext because of the R_MIPS_64 relocation +# RUN: ld.lld --eh-frame-hdr -Bdynamic -pie -z notext -o %t-pie-dynamic.exe %t.o %t-foo.o +# RUN: llvm-readobj -r %t-pie-dynamic.exe | FileCheck %s -check-prefix PIC-RELOCS + + +# OBJ: Section ({{.*}}) .rela.text { +# OBJ-NEXT: 0x0 R_MIPS_GPREL16/R_MIPS_SUB/R_MIPS_HI16 foo 0x0 +# OBJ-NEXT: } +# OBJ-NEXT: Section ({{.*}}) .rela.eh_frame { +# OBJ-NEXT: 0x1C R_MIPS_64/R_MIPS_NONE/R_MIPS_NONE .text 0x0 +# OBJ-NEXT: } + +# PIC-RELOCS: Relocations [ +# PIC-RELOCS-NEXT: Section (7) .rela.dyn { +# PIC-RELOCS-NEXT: {{0x.+}} R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE - 0x10000 +# PIC-RELOCS-NEXT: } +# PIC-RELOCS-NEXT:] + + +.globl foo + +bar: +.cfi_startproc +lui $11, %hi(%neg(%gp_rel(foo))) +.cfi_endproc + +.globl __start +__start: +b bar Property changes on: vendor/lld/dist/test/ELF/mips64-eh-abs-reloc.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/section-metadata-err.s =================================================================== --- vendor/lld/dist/test/ELF/section-metadata-err.s (nonexistent) +++ vendor/lld/dist/test/ELF/section-metadata-err.s (revision 319469) @@ -0,0 +1,15 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s + +# CHECK: error: Merge and .eh_frame sections are not supported with SHF_LINK_ORDER {{.*}}section-metadata-err.s.tmp.o:(.foo) + +.global _start +_start: +.quad .foo + +.section .foo,"aM",@progbits,8 +.quad 0 + +.section bar,"ao",@progbits,.foo Property changes on: vendor/lld/dist/test/ELF/section-metadata-err.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