From 4aed7ea6f89a091aede10ccf0fb45b3ce12c710d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 17 Jan 2018 17:29:21 -0500 Subject: update embedded LLD to 6.0.0rc1 --- deps/lld/ELF/InputFiles.cpp | 623 +++++++++++++++++++++++++------------------- 1 file changed, 352 insertions(+), 271 deletions(-) (limited to 'deps/lld/ELF/InputFiles.cpp') diff --git a/deps/lld/ELF/InputFiles.cpp b/deps/lld/ELF/InputFiles.cpp index c609615fcc..f514870ca8 100644 --- a/deps/lld/ELF/InputFiles.cpp +++ b/deps/lld/ELF/InputFiles.cpp @@ -8,13 +8,13 @@ //===----------------------------------------------------------------------===// #include "InputFiles.h" -#include "Error.h" #include "InputSection.h" #include "LinkerScript.h" -#include "Memory.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" @@ -23,6 +23,8 @@ #include "llvm/LTO/LTO.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELFObjectFile.h" +#include "llvm/Support/ARMAttributeParser.h" +#include "llvm/Support/ARMBuildAttributes.h" #include "llvm/Support/Path.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/raw_ostream.h" @@ -30,31 +32,29 @@ using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; +using namespace llvm::sys; using namespace llvm::sys::fs; using namespace lld; using namespace lld::elf; +std::vector elf::BinaryFiles; +std::vector elf::BitcodeFiles; +std::vector elf::ObjectFiles; +std::vector elf::SharedFiles; + TarWriter *elf::Tar; InputFile::InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} -namespace { -// In ELF object file all section addresses are zero. If we have multiple -// .text sections (when using -ffunction-section or comdat group) then -// LLVM DWARF parser will not be able to parse .debug_line correctly, unless -// we assign each section some unique address. This callback method assigns -// each section an address equal to its offset in ELF object file. -class ObjectInfo : public LoadedObjectInfoHelper { -public: - uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override { - return static_cast(Sec).getOffset(); - } -}; -} - Optional elf::readFile(StringRef Path) { + // The --chroot option changes our virtual root directory. + // This is useful when you are dealing with files created by --reproduce. + if (!Config->Chroot.empty() && Path.startswith("/")) + Path = Saver.save(Config->Chroot + Path); + log(Path); + auto MBOrErr = MemoryBuffer::getFile(Path); if (auto EC = MBOrErr.getError()) { error("cannot open " + Path + ": " + EC.message()); @@ -70,28 +70,132 @@ Optional elf::readFile(StringRef Path) { return MBRef; } -template void elf::ObjectFile::initializeDwarfLine() { - std::unique_ptr Obj = - check(object::ObjectFile::createObjectFile(this->MB), toString(this)); +// Concatenates arguments to construct a string representing an error location. +static std::string createFileLineMsg(StringRef Path, unsigned Line) { + std::string Filename = path::filename(Path); + std::string Lineno = ":" + std::to_string(Line); + if (Filename == Path) + return Filename + Lineno; + return Filename + Lineno + " (" + Path.str() + Lineno + ")"; +} - ObjectInfo ObjInfo; - DWARFContextInMemory Dwarf(*Obj, &ObjInfo); +template +static std::string getSrcMsgAux(ObjFile &File, const Symbol &Sym, + InputSectionBase &Sec, uint64_t Offset) { + // In DWARF, functions and variables are stored to different places. + // First, lookup a function for a given offset. + if (Optional Info = File.getDILineInfo(&Sec, Offset)) + return createFileLineMsg(Info->FileName, Info->Line); + + // If it failed, lookup again as a variable. + if (Optional> FileLine = + File.getVariableLoc(Sym.getName())) + return createFileLineMsg(FileLine->first, FileLine->second); + + // File.SourceFile contains STT_FILE symbol, and that is a last resort. + return File.SourceFile; +} + +std::string InputFile::getSrcMsg(const Symbol &Sym, InputSectionBase &Sec, + uint64_t Offset) { + if (kind() != ObjKind) + return ""; + switch (Config->EKind) { + default: + llvm_unreachable("Invalid kind"); + case ELF32LEKind: + return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); + case ELF32BEKind: + return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); + case ELF64LEKind: + return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); + case ELF64BEKind: + return getSrcMsgAux(cast>(*this), Sym, Sec, Offset); + } +} + +template void ObjFile::initializeDwarf() { + DWARFContext Dwarf(make_unique>(this)); + const DWARFObject &Obj = Dwarf.getDWARFObj(); DwarfLine.reset(new DWARFDebugLine); - DWARFDataExtractor LineData(Dwarf.getLineSection(), Config->IsLE, + DWARFDataExtractor LineData(Obj, Obj.getLineSection(), Config->IsLE, Config->Wordsize); // The second parameter is offset in .debug_line section // for compilation unit (CU) of interest. We have only one // CU (object file), so offset is always 0. - DwarfLine->getOrParseLineTable(LineData, 0); + // FIXME: Provide the associated DWARFUnit if there is one. DWARF v5 + // needs it in order to find indirect strings. + const DWARFDebugLine::LineTable *LT = + DwarfLine->getOrParseLineTable(LineData, 0, nullptr); + + // Return if there is no debug information about CU available. + if (!Dwarf.getNumCompileUnits()) + return; + + // Loop over variable records and insert them to VariableLoc. + DWARFCompileUnit *CU = Dwarf.getCompileUnitAtIndex(0); + for (const auto &Entry : CU->dies()) { + DWARFDie Die(CU, &Entry); + // Skip all tags that are not variables. + if (Die.getTag() != dwarf::DW_TAG_variable) + continue; + + // Skip if a local variable because we don't need them for generating error + // messages. In general, only non-local symbols can fail to be linked. + if (!dwarf::toUnsigned(Die.find(dwarf::DW_AT_external), 0)) + continue; + + // Get the source filename index for the variable. + unsigned File = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_file), 0); + if (!LT->hasFileAtIndex(File)) + continue; + + // Get the line number on which the variable is declared. + unsigned Line = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_line), 0); + + // Get the name of the variable and add the collected information to + // VariableLoc. Usually Name is non-empty, but it can be empty if the input + // object file lacks some debug info. + StringRef Name = dwarf::toString(Die.find(dwarf::DW_AT_name), ""); + if (!Name.empty()) + VariableLoc.insert({Name, {File, Line}}); + } +} + +// Returns the pair of file name and line number describing location of data +// object (variable, array, etc) definition. +template +Optional> +ObjFile::getVariableLoc(StringRef Name) { + llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); }); + + // There is always only one CU so it's offset is 0. + const DWARFDebugLine::LineTable *LT = DwarfLine->getLineTable(0); + if (!LT) + return None; + + // Return if we have no debug information about data object. + auto It = VariableLoc.find(Name); + if (It == VariableLoc.end()) + return None; + + // Take file name string from line table. + std::string FileName; + if (!LT->getFileNameByIndex( + It->second.first /* File */, nullptr, + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FileName)) + return None; + + return std::make_pair(FileName, It->second.second /*Line*/); } // Returns source line information for a given offset // using DWARF debug info. template -Optional elf::ObjectFile::getDILineInfo(InputSectionBase *S, - uint64_t Offset) { - llvm::call_once(InitDwarfLine, [this]() { initializeDwarfLine(); }); +Optional ObjFile::getDILineInfo(InputSectionBase *S, + uint64_t Offset) { + llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); }); // The offset to CU is 0. const DWARFDebugLine::LineTable *Tbl = DwarfLine->getLineTable(0); @@ -112,8 +216,7 @@ Optional elf::ObjectFile::getDILineInfo(InputSectionBase *S, // Returns source line information for a given offset // using DWARF debug info. template -std::string elf::ObjectFile::getLineInfo(InputSectionBase *S, - uint64_t Offset) { +std::string ObjFile::getLineInfo(InputSectionBase *S, uint64_t Offset) { if (Optional Info = getDILineInfo(S, Offset)) return Info->FileName + ":" + std::to_string(Info->Line); return ""; @@ -145,50 +248,41 @@ ELFFileBase::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) { } template -typename ELFT::SymRange ELFFileBase::getGlobalSymbols() { - return makeArrayRef(Symbols.begin() + FirstNonLocal, Symbols.end()); +typename ELFT::SymRange ELFFileBase::getGlobalELFSyms() { + return makeArrayRef(ELFSyms.begin() + FirstNonLocal, ELFSyms.end()); } template uint32_t ELFFileBase::getSectionIndex(const Elf_Sym &Sym) const { - return check(getObj().getSectionIndex(&Sym, Symbols, SymtabSHNDX), - toString(this)); + return CHECK(getObj().getSectionIndex(&Sym, ELFSyms, SymtabSHNDX), this); } template void ELFFileBase::initSymtab(ArrayRef Sections, const Elf_Shdr *Symtab) { FirstNonLocal = Symtab->sh_info; - Symbols = check(getObj().symbols(Symtab), toString(this)); - if (FirstNonLocal == 0 || FirstNonLocal > Symbols.size()) + ELFSyms = CHECK(getObj().symbols(Symtab), this); + if (FirstNonLocal == 0 || FirstNonLocal > ELFSyms.size()) fatal(toString(this) + ": invalid sh_info in symbol table"); - StringTable = check(getObj().getStringTableForSymtab(*Symtab, Sections), - toString(this)); + StringTable = + CHECK(getObj().getStringTableForSymtab(*Symtab, Sections), this); } template -elf::ObjectFile::ObjectFile(MemoryBufferRef M, StringRef ArchiveName) - : ELFFileBase(Base::ObjectKind, M) { +ObjFile::ObjFile(MemoryBufferRef M, StringRef ArchiveName) + : ELFFileBase(Base::ObjKind, M) { this->ArchiveName = ArchiveName; } -template -ArrayRef elf::ObjectFile::getLocalSymbols() { - if (this->SymbolBodies.empty()) - return this->SymbolBodies; - return makeArrayRef(this->SymbolBodies).slice(1, this->FirstNonLocal - 1); -} - -template -ArrayRef elf::ObjectFile::getSymbols() { - if (this->SymbolBodies.empty()) - return this->SymbolBodies; - return makeArrayRef(this->SymbolBodies).slice(1); +template ArrayRef ObjFile::getLocalSymbols() { + if (this->Symbols.empty()) + return {}; + return makeArrayRef(this->Symbols).slice(1, this->FirstNonLocal - 1); } template -void elf::ObjectFile::parse(DenseSet &ComdatGroups) { +void ObjFile::parse(DenseSet &ComdatGroups) { // Read section and symbol tables. initializeSections(ComdatGroups); initializeSymbols(); @@ -198,19 +292,17 @@ void elf::ObjectFile::parse(DenseSet &ComdatGroups) { // They are identified and deduplicated by group name. This function // returns a group name. template -StringRef -elf::ObjectFile::getShtGroupSignature(ArrayRef Sections, - const Elf_Shdr &Sec) { +StringRef ObjFile::getShtGroupSignature(ArrayRef Sections, + const Elf_Shdr &Sec) { // Group signatures are stored as symbol names in object files. // sh_info contains a symbol index, so we fetch a symbol and read its name. - if (this->Symbols.empty()) + if (this->ELFSyms.empty()) this->initSymtab( - Sections, - check(object::getSection(Sections, Sec.sh_link), toString(this))); + Sections, CHECK(object::getSection(Sections, Sec.sh_link), this)); - const Elf_Sym *Sym = check( - object::getSymbol(this->Symbols, Sec.sh_info), toString(this)); - StringRef Signature = check(Sym->getName(this->StringTable), toString(this)); + const Elf_Sym *Sym = + CHECK(object::getSymbol(this->ELFSyms, Sec.sh_info), this); + StringRef Signature = CHECK(Sym->getName(this->StringTable), this); // As a special case, if a symbol is a section symbol and has no name, // we use a section name as a signature. @@ -225,32 +317,22 @@ elf::ObjectFile::getShtGroupSignature(ArrayRef Sections, } template -ArrayRef::Elf_Word> -elf::ObjectFile::getShtGroupEntries(const Elf_Shdr &Sec) { +ArrayRef::Elf_Word> +ObjFile::getShtGroupEntries(const Elf_Shdr &Sec) { const ELFFile &Obj = this->getObj(); - ArrayRef Entries = check( - Obj.template getSectionContentsAsArray(&Sec), toString(this)); + ArrayRef Entries = + CHECK(Obj.template getSectionContentsAsArray(&Sec), this); if (Entries.empty() || Entries[0] != GRP_COMDAT) fatal(toString(this) + ": unsupported SHT_GROUP format"); return Entries.slice(1); } -template -bool elf::ObjectFile::shouldMerge(const Elf_Shdr &Sec) { +template bool ObjFile::shouldMerge(const Elf_Shdr &Sec) { // We don't merge sections if -O0 (default is -O1). This makes sometimes // the linker significantly faster, although the output will be bigger. if (Config->Optimize == 0) return false; - // Do not merge sections if generating a relocatable object. It makes - // the code simpler because we do not need to update relocation addends - // to reflect changes introduced by merging. Instead of that we write - // such "merge" sections into separate OutputSections and keep SHF_MERGE - // / SHF_STRINGS flags and sh_entsize value to be able to perform merging - // later during a final linking. - if (Config->Relocatable) - return false; - // A mergeable section with size 0 is useless because they don't have // any data to merge. A mergeable string section with size 0 can be // argued as invalid because it doesn't end with a null character. @@ -276,29 +358,19 @@ bool elf::ObjectFile::shouldMerge(const Elf_Shdr &Sec) { if (Flags & SHF_WRITE) fatal(toString(this) + ": writable SHF_MERGE section is not supported"); - // Don't try to merge if the alignment is larger than the sh_entsize and this - // is not SHF_STRINGS. - // - // Since this is not a SHF_STRINGS, we would need to pad after every entity. - // It would be equivalent for the producer of the .o to just set a larger - // sh_entsize. - if (Flags & SHF_STRINGS) - return true; - - return Sec.sh_addralign <= EntSize; + return true; } template -void elf::ObjectFile::initializeSections( +void ObjFile::initializeSections( DenseSet &ComdatGroups) { const ELFFile &Obj = this->getObj(); - ArrayRef ObjSections = - check(this->getObj().sections(), toString(this)); + ArrayRef ObjSections = CHECK(this->getObj().sections(), this); uint64_t Size = ObjSections.size(); this->Sections.resize(Size); this->SectionStringTable = - check(Obj.getSectionStringTable(ObjSections), toString(this)); + CHECK(Obj.getSectionStringTable(ObjSections), this); for (size_t I = 0, E = ObjSections.size(); I < E; I++) { if (this->Sections[I] == &InputSection::Discarded) @@ -344,8 +416,7 @@ void elf::ObjectFile::initializeSections( this->initSymtab(ObjSections, &Sec); break; case SHT_SYMTAB_SHNDX: - this->SymtabSHNDX = - check(Obj.getSHNDXTable(Sec, ObjSections), toString(this)); + this->SymtabSHNDX = CHECK(Obj.getSHNDXTable(Sec, ObjSections), this); break; case SHT_STRTAB: case SHT_NULL: @@ -358,16 +429,58 @@ void elf::ObjectFile::initializeSections( // have a SHF_LINK_ORDER dependency, this is identified by the sh_link. if (Sec.sh_flags & SHF_LINK_ORDER) { if (Sec.sh_link >= this->Sections.size()) - fatal(toString(this) + ": invalid sh_link index: " + - Twine(Sec.sh_link)); + fatal(toString(this) + + ": invalid sh_link index: " + Twine(Sec.sh_link)); this->Sections[Sec.sh_link]->DependentSections.push_back( - this->Sections[I]); + cast(this->Sections[I])); } } } +// The ARM support in lld makes some use of instructions that are not available +// on all ARM architectures. Namely: +// - Use of BLX instruction for interworking between ARM and Thumb state. +// - Use of the extended Thumb branch encoding in relocation. +// - Use of the MOVT/MOVW instructions in Thumb Thunks. +// The ARM Attributes section contains information about the architecture chosen +// at compile time. We follow the convention that if at least one input object +// is compiled with an architecture that supports these features then lld is +// permitted to use them. +static void updateSupportedARMFeatures(const ARMAttributeParser &Attributes) { + if (!Attributes.hasAttribute(ARMBuildAttrs::CPU_arch)) + return; + auto Arch = Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch); + switch (Arch) { + case ARMBuildAttrs::Pre_v4: + case ARMBuildAttrs::v4: + case ARMBuildAttrs::v4T: + // Architectures prior to v5 do not support BLX instruction + break; + case ARMBuildAttrs::v5T: + case ARMBuildAttrs::v5TE: + case ARMBuildAttrs::v5TEJ: + case ARMBuildAttrs::v6: + case ARMBuildAttrs::v6KZ: + case ARMBuildAttrs::v6K: + Config->ARMHasBlx = true; + // Architectures used in pre-Cortex processors do not support + // The J1 = 1 J2 = 1 Thumb branch range extension, with the exception + // of Architecture v6T2 (arm1156t2-s and arm1156t2f-s) that do. + break; + default: + // All other Architectures have BLX and extended branch encoding + Config->ARMHasBlx = true; + Config->ARMJ1J2BranchEncoding = true; + if (Arch != ARMBuildAttrs::v6_M && Arch != ARMBuildAttrs::v6S_M) + // All Architectures used in Cortex processors with the exception + // of v6-M and v6S-M have the MOVT and MOVW instructions. + Config->ARMHasMovtMovw = true; + break; + } +} + template -InputSectionBase *elf::ObjectFile::getRelocTarget(const Elf_Shdr &Sec) { +InputSectionBase *ObjFile::getRelocTarget(const Elf_Shdr &Sec) { uint32_t Idx = Sec.sh_info; if (Idx >= this->Sections.size()) fatal(toString(this) + ": invalid relocated section index: " + Twine(Idx)); @@ -386,29 +499,32 @@ InputSectionBase *elf::ObjectFile::getRelocTarget(const Elf_Shdr &Sec) { // Create a regular InputSection class that has the same contents // as a given section. -InputSectionBase *toRegularSection(MergeInputSection *Sec) { - auto *Ret = make(Sec->Flags, Sec->Type, Sec->Alignment, - Sec->Data, Sec->Name); - Ret->File = Sec->File; - return Ret; +static InputSection *toRegularSection(MergeInputSection *Sec) { + return make(Sec->File, Sec->Flags, Sec->Type, Sec->Alignment, + Sec->Data, Sec->Name); } template -InputSectionBase * -elf::ObjectFile::createInputSection(const Elf_Shdr &Sec) { +InputSectionBase *ObjFile::createInputSection(const Elf_Shdr &Sec) { StringRef Name = getSectionName(Sec); switch (Sec.sh_type) { - case SHT_ARM_ATTRIBUTES: - // FIXME: ARM meta-data section. Retain the first attribute section - // we see. The eglibc ARM dynamic loaders require the presence of an - // attribute section for dlopen to work. - // In a full implementation we would merge all attribute sections. + case SHT_ARM_ATTRIBUTES: { + if (Config->EMachine != EM_ARM) + break; + ARMAttributeParser Attributes; + ArrayRef Contents = check(this->getObj().getSectionContents(&Sec)); + Attributes.Parse(Contents, /*isLittle*/ Config->EKind == ELF32LEKind); + updateSupportedARMFeatures(Attributes); + // FIXME: Retain the first attribute section we see. The eglibc ARM + // dynamic loaders require the presence of an attribute section for dlopen + // to work. In a full implementation we would merge all attribute sections. if (InX::ARMAttributes == nullptr) { - InX::ARMAttributes = make(this, &Sec, Name); + InX::ARMAttributes = make(*this, Sec, Name); return InX::ARMAttributes; } return &InputSection::Discarded; + } case SHT_RELA: case SHT_REL: { // Find the relocation target section and associate this @@ -423,7 +539,7 @@ elf::ObjectFile::createInputSection(const Elf_Shdr &Sec) { // If -r is given, we do not interpret or apply relocation // but just copy relocation sections to output. if (Config->Relocatable) - return make(this, &Sec, Name); + return make(*this, Sec, Name); if (Target->FirstRelocation) fatal(toString(this) + @@ -443,13 +559,12 @@ elf::ObjectFile::createInputSection(const Elf_Shdr &Sec) { size_t NumRelocations; if (Sec.sh_type == SHT_RELA) { - ArrayRef Rels = - check(this->getObj().relas(&Sec), toString(this)); + ArrayRef Rels = CHECK(this->getObj().relas(&Sec), this); Target->FirstRelocation = Rels.begin(); NumRelocations = Rels.size(); Target->AreRelocsRela = true; } else { - ArrayRef Rels = check(this->getObj().rels(&Sec), toString(this)); + ArrayRef Rels = CHECK(this->getObj().rels(&Sec), this); Target->FirstRelocation = Rels.begin(); NumRelocations = Rels.size(); Target->AreRelocsRela = false; @@ -462,7 +577,7 @@ elf::ObjectFile::createInputSection(const Elf_Shdr &Sec) { // However, if -emit-relocs is given, we need to leave them in the output. // (Some post link analysis tools need this information.) if (Config->EmitRelocs) { - InputSection *RelocSec = make(this, &Sec, Name); + InputSection *RelocSec = make(*this, Sec, Name); // We will not emit relocation section if target was discarded. Target->DependentSections.push_back(RelocSec); return RelocSec; @@ -497,18 +612,6 @@ elf::ObjectFile::createInputSection(const Elf_Shdr &Sec) { return &InputSection::Discarded; } - if (Config->Strip != StripPolicy::None && Name.startswith(".debug")) - return &InputSection::Discarded; - - // If -gdb-index is given, LLD creates .gdb_index section, and that - // section serves the same purpose as .debug_gnu_pub{names,types} sections. - // If that's the case, we want to eliminate .debug_gnu_pub{names,types} - // because they are redundant and can waste large amount of disk space - // (for example, they are about 400 MiB in total for a clang debug build.) - if (Config->GdbIndex && - (Name == ".debug_gnu_pubnames" || Name == ".debug_gnu_pubtypes")) - return &InputSection::Discarded; - // The linkonce feature is a sort of proto-comdat. Some glibc i386 object // files contain definitions of symbol "__x86.get_pc_thunk.bx" in linkonce // sections. Drop those sections to avoid duplicate symbol errors. @@ -521,54 +624,32 @@ elf::ObjectFile::createInputSection(const Elf_Shdr &Sec) { // .eh_frame_hdr section for runtime. So we handle them with a special // class. For relocatable outputs, they are just passed through. if (Name == ".eh_frame" && !Config->Relocatable) - return make(this, &Sec, Name); + return make(*this, Sec, Name); if (shouldMerge(Sec)) - return make(this, &Sec, Name); - return make(this, &Sec, Name); + return make(*this, Sec, Name); + return make(*this, Sec, Name); } template -StringRef elf::ObjectFile::getSectionName(const Elf_Shdr &Sec) { - return check(this->getObj().getSectionName(&Sec, SectionStringTable), - toString(this)); +StringRef ObjFile::getSectionName(const Elf_Shdr &Sec) { + return CHECK(this->getObj().getSectionName(&Sec, SectionStringTable), this); } -template void elf::ObjectFile::initializeSymbols() { - SymbolBodies.reserve(this->Symbols.size()); - for (const Elf_Sym &Sym : this->Symbols) - SymbolBodies.push_back(createSymbolBody(&Sym)); +template void ObjFile::initializeSymbols() { + this->Symbols.reserve(this->ELFSyms.size()); + for (const Elf_Sym &Sym : this->ELFSyms) + this->Symbols.push_back(createSymbol(&Sym)); } -template -InputSectionBase *elf::ObjectFile::getSection(const Elf_Sym &Sym) const { - uint32_t Index = this->getSectionIndex(Sym); - if (Index >= this->Sections.size()) - fatal(toString(this) + ": invalid section index: " + Twine(Index)); - InputSectionBase *S = this->Sections[Index]; - - // We found that GNU assembler 2.17.50 [FreeBSD] 2007-07-03 could - // generate broken objects. STT_SECTION/STT_NOTYPE symbols can be - // associated with SHT_REL[A]/SHT_SYMTAB/SHT_STRTAB sections. - // In this case it is fine for section to be null here as we do not - // allocate sections of these types. - if (!S) { - if (Index == 0 || Sym.getType() == STT_SECTION || - Sym.getType() == STT_NOTYPE) - return nullptr; - fatal(toString(this) + ": invalid section index: " + Twine(Index)); - } - - if (S == &InputSection::Discarded) - return S; - return S->Repl; -} - -template -SymbolBody *elf::ObjectFile::createSymbolBody(const Elf_Sym *Sym) { +template Symbol *ObjFile::createSymbol(const Elf_Sym *Sym) { int Binding = Sym->getBinding(); - InputSectionBase *Sec = getSection(*Sym); + uint32_t SecIdx = this->getSectionIndex(*Sym); + if (SecIdx >= this->Sections.size()) + fatal(toString(this) + ": invalid section index: " + Twine(SecIdx)); + + InputSectionBase *Sec = this->Sections[SecIdx]; uint8_t StOther = Sym->st_other; uint8_t Type = Sym->getType(); uint64_t Value = Sym->st_value; @@ -576,34 +657,29 @@ SymbolBody *elf::ObjectFile::createSymbolBody(const Elf_Sym *Sym) { if (Binding == STB_LOCAL) { if (Sym->getType() == STT_FILE) - SourceFile = check(Sym->getName(this->StringTable), toString(this)); + SourceFile = CHECK(Sym->getName(this->StringTable), this); if (this->StringTable.size() <= Sym->st_name) fatal(toString(this) + ": invalid symbol name offset"); StringRefZ Name = this->StringTable.data() + Sym->st_name; if (Sym->st_shndx == SHN_UNDEF) - return make(Name, /*IsLocal=*/true, StOther, Type, this); + return make(this, Name, Binding, StOther, Type); - return make(Name, /*IsLocal=*/true, StOther, Type, Value, - Size, Sec, this); + return make(this, Name, Binding, StOther, Type, Value, Size, Sec); } - StringRef Name = check(Sym->getName(this->StringTable), toString(this)); + StringRef Name = CHECK(Sym->getName(this->StringTable), this); switch (Sym->st_shndx) { case SHN_UNDEF: - return elf::Symtab::X - ->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type, - /*CanOmitFromDynSym=*/false, this) - ->body(); + return Symtab->addUndefined(Name, Binding, StOther, Type, + /*CanOmitFromDynSym=*/false, this); case SHN_COMMON: if (Value == 0 || Value >= UINT32_MAX) fatal(toString(this) + ": common symbol '" + Name + "' has invalid alignment: " + Twine(Value)); - return elf::Symtab::X - ->addCommon(Name, Size, Value, Binding, StOther, Type, this) - ->body(); + return Symtab->addCommon(Name, Size, Value, Binding, StOther, Type, *this); } switch (Binding) { @@ -613,13 +689,10 @@ SymbolBody *elf::ObjectFile::createSymbolBody(const Elf_Sym *Sym) { case STB_WEAK: case STB_GNU_UNIQUE: if (Sec == &InputSection::Discarded) - return elf::Symtab::X - ->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type, - /*CanOmitFromDynSym=*/false, this) - ->body(); - return elf::Symtab::X - ->addRegular(Name, StOther, Type, Value, Size, Binding, Sec, this) - ->body(); + return Symtab->addUndefined(Name, Binding, StOther, Type, + /*CanOmitFromDynSym=*/false, this); + return Symtab->addRegular(Name, StOther, Type, Value, Size, Binding, Sec, + this); } } @@ -630,14 +703,14 @@ ArchiveFile::ArchiveFile(std::unique_ptr &&File) template void ArchiveFile::parse() { Symbols.reserve(File->getNumberOfSymbols()); for (const Archive::Symbol &Sym : File->symbols()) - Symbols.push_back(Symtab::X->addLazyArchive(this, Sym)); + Symbols.push_back(Symtab->addLazyArchive(Sym.getName(), *this, Sym)); } // Returns a buffer pointing to a member file containing a given symbol. std::pair ArchiveFile::getMember(const Archive::Symbol *Sym) { Archive::Child C = - check(Sym->getMember(), toString(this) + + CHECK(Sym->getMember(), toString(this) + ": could not get the member for symbol " + Sym->getName()); @@ -645,14 +718,13 @@ ArchiveFile::getMember(const Archive::Symbol *Sym) { return {MemoryBufferRef(), 0}; MemoryBufferRef Ret = - check(C.getMemoryBufferRef(), + CHECK(C.getMemoryBufferRef(), toString(this) + ": could not get the buffer for the member defining symbol " + Sym->getName()); if (C.getParent()->isThin() && Tar) - Tar->append(relativeToRoot(check(C.getFullName(), toString(this))), - Ret.getBuffer()); + Tar->append(relativeToRoot(CHECK(C.getFullName(), this)), Ret.getBuffer()); if (C.getParent()->isThin()) return {Ret, 0}; return {Ret, C.getChildOffset()}; @@ -661,22 +733,14 @@ ArchiveFile::getMember(const Archive::Symbol *Sym) { template SharedFile::SharedFile(MemoryBufferRef M, StringRef DefaultSoName) : ELFFileBase(Base::SharedKind, M), SoName(DefaultSoName), - AsNeeded(Config->AsNeeded) {} - -template -const typename ELFT::Shdr * -SharedFile::getSection(const Elf_Sym &Sym) const { - return check( - this->getObj().getSection(&Sym, this->Symbols, this->SymtabSHNDX), - toString(this)); -} + IsNeeded(!Config->AsNeeded) {} // Partially parse the shared object file so that we can call // getSoName on this object. template void SharedFile::parseSoName() { const Elf_Shdr *DynamicSec = nullptr; const ELFFile Obj = this->getObj(); - ArrayRef Sections = check(Obj.sections(), toString(this)); + ArrayRef Sections = CHECK(Obj.sections(), this); // Search for .dynsym, .dynamic, .symtab, .gnu.version and .gnu.version_d. for (const Elf_Shdr &Sec : Sections) { @@ -690,8 +754,7 @@ template void SharedFile::parseSoName() { DynamicSec = &Sec; break; case SHT_SYMTAB_SHNDX: - this->SymtabSHNDX = - check(Obj.getSHNDXTable(Sec, Sections), toString(this)); + this->SymtabSHNDX = CHECK(Obj.getSHNDXTable(Sec, Sections), this); break; case SHT_GNU_versym: this->VersymSec = &Sec; @@ -702,15 +765,14 @@ template void SharedFile::parseSoName() { } } - if (this->VersymSec && this->Symbols.empty()) + if (this->VersymSec && this->ELFSyms.empty()) error("SHT_GNU_versym should be associated with symbol table"); // Search for a DT_SONAME tag to initialize this->SoName. if (!DynamicSec) return; ArrayRef Arr = - check(Obj.template getSectionContentsAsArray(DynamicSec), - toString(this)); + CHECK(Obj.template getSectionContentsAsArray(DynamicSec), this); for (const Elf_Dyn &Dyn : Arr) { if (Dyn.d_tag == DT_SONAME) { uint64_t Val = Dyn.getVal(); @@ -767,11 +829,14 @@ SharedFile::parseVerdefs(const Elf_Versym *&Versym) { template void SharedFile::parseRest() { // Create mapping from version identifiers to Elf_Verdef entries. const Elf_Versym *Versym = nullptr; - std::vector Verdefs = parseVerdefs(Versym); + Verdefs = parseVerdefs(Versym); + + ArrayRef Sections = CHECK(this->getObj().sections(), this); - Elf_Sym_Range Syms = this->getGlobalSymbols(); + // Add symbols to the symbol table. + Elf_Sym_Range Syms = this->getGlobalELFSyms(); for (const Elf_Sym &Sym : Syms) { - unsigned VersymIndex = 0; + unsigned VersymIndex = VER_NDX_GLOBAL; if (Versym) { VersymIndex = Versym->vs_index; ++Versym; @@ -779,28 +844,54 @@ template void SharedFile::parseRest() { bool Hidden = VersymIndex & VERSYM_HIDDEN; VersymIndex = VersymIndex & ~VERSYM_HIDDEN; - StringRef Name = check(Sym.getName(this->StringTable), toString(this)); + StringRef Name = CHECK(Sym.getName(this->StringTable), this); if (Sym.isUndefined()) { Undefs.push_back(Name); continue; } - // Ignore local symbols. - if (Versym && VersymIndex == VER_NDX_LOCAL) + if (Sym.getBinding() == STB_LOCAL) { + warn("found local symbol '" + Name + + "' in global part of symbol table in file " + toString(this)); continue; + } + + const Elf_Verdef *Ver = nullptr; + if (VersymIndex != VER_NDX_GLOBAL) { + if (VersymIndex >= Verdefs.size() || VersymIndex == VER_NDX_LOCAL) { + error("corrupt input file: version definition index " + + Twine(VersymIndex) + " for symbol " + Name + + " is out of bounds\n>>> defined in " + toString(this)); + continue; + } + Ver = Verdefs[VersymIndex]; + } else { + VersymIndex = 0; + } - const Elf_Verdef *V = - VersymIndex == VER_NDX_GLOBAL ? nullptr : Verdefs[VersymIndex]; + // We do not usually care about alignments of data in shared object + // files because the loader takes care of it. However, if we promote a + // DSO symbol to point to .bss due to copy relocation, we need to keep + // the original alignment requirements. We infer it here. + uint64_t Alignment = 1; + if (Sym.st_value) + Alignment = 1ULL << countTrailingZeros((uint64_t)Sym.st_value); + if (0 < Sym.st_shndx && Sym.st_shndx < Sections.size()) { + uint64_t SecAlign = Sections[Sym.st_shndx].sh_addralign; + Alignment = std::min(Alignment, SecAlign); + } + if (Alignment > UINT32_MAX) + error(toString(this) + ": alignment too large: " + Name); if (!Hidden) - elf::Symtab::X->addShared(this, Name, Sym, V); + Symtab->addShared(Name, *this, Sym, Alignment, VersymIndex); // Also add the symbol with the versioned name to handle undefined symbols // with explicit versions. - if (V) { - StringRef VerName = this->StringTable.data() + V->getAux()->vda_name; + if (Ver) { + StringRef VerName = this->StringTable.data() + Ver->getAux()->vda_name; Name = Saver.save(Name + "@" + VerName); - elf::Symtab::X->addShared(this, Name, Sym, V); + Symtab->addShared(Name, *this, Sym, Alignment, VersymIndex); } } } @@ -855,7 +946,7 @@ BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName, MemoryBufferRef MBRef(MB.getBuffer(), Saver.save(ArchiveName + MB.getBufferIdentifier() + utostr(OffsetInArchive))); - Obj = check(lto::InputFile::create(MBRef), toString(this)); + Obj = CHECK(lto::InputFile::create(MBRef), this); Triple T(Obj->getTargetTriple()); EKind = getBitcodeELFKind(T); @@ -877,7 +968,7 @@ static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) { template static Symbol *createBitcodeSymbol(const std::vector &KeptComdats, const lto::InputFile::Symbol &ObjSym, - BitcodeFile *F) { + BitcodeFile &F) { StringRef NameRef = Saver.save(ObjSym.getName()); uint32_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL; @@ -887,22 +978,20 @@ static Symbol *createBitcodeSymbol(const std::vector &KeptComdats, int C = ObjSym.getComdatIndex(); if (C != -1 && !KeptComdats[C]) - return Symtab::X->addUndefined(NameRef, /*IsLocal=*/false, Binding, - Visibility, Type, CanOmitFromDynSym, - F); + return Symtab->addUndefined(NameRef, Binding, Visibility, Type, + CanOmitFromDynSym, &F); if (ObjSym.isUndefined()) - return Symtab::X->addUndefined(NameRef, /*IsLocal=*/false, Binding, - Visibility, Type, CanOmitFromDynSym, - F); + return Symtab->addUndefined(NameRef, Binding, Visibility, Type, + CanOmitFromDynSym, &F); if (ObjSym.isCommon()) - return Symtab::X->addCommon(NameRef, ObjSym.getCommonSize(), - ObjSym.getCommonAlignment(), Binding, - Visibility, STT_OBJECT, F); + return Symtab->addCommon(NameRef, ObjSym.getCommonSize(), + ObjSym.getCommonAlignment(), Binding, Visibility, + STT_OBJECT, F); - return Symtab::X->addBitcode(NameRef, Binding, Visibility, Type, - CanOmitFromDynSym, F); + return Symtab->addBitcode(NameRef, Binding, Visibility, Type, + CanOmitFromDynSym, F); } template @@ -912,7 +1001,7 @@ void BitcodeFile::parse(DenseSet &ComdatGroups) { KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(S)).second); for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) - Symbols.push_back(createBitcodeSymbol(KeptComdats, ObjSym, this)); + Symbols.push_back(createBitcodeSymbol(KeptComdats, ObjSym, *this)); } static ELFKind getELFKind(MemoryBufferRef MB) { @@ -935,10 +1024,10 @@ static ELFKind getELFKind(MemoryBufferRef MB) { return (Endian == ELFDATA2LSB) ? ELF64LEKind : ELF64BEKind; } -template void BinaryFile::parse() { +void BinaryFile::parse() { ArrayRef Data = toArrayRef(MB.getBuffer()); - auto *Section = - make(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 8, Data, ".data"); + auto *Section = make(nullptr, SHF_ALLOC | SHF_WRITE, + SHT_PROGBITS, 8, Data, ".data"); Sections.push_back(Section); // For each input file foo that is embedded to a result as a binary @@ -947,18 +1036,15 @@ template void BinaryFile::parse() { // characters in a filename are replaced with underscore. std::string S = "_binary_" + MB.getBufferIdentifier().str(); for (size_t I = 0; I < S.size(); ++I) - if (!isalnum(S[I])) + if (!isAlnum(S[I])) S[I] = '_'; - elf::Symtab::X->addRegular(Saver.save(S + "_start"), STV_DEFAULT, - STT_OBJECT, 0, 0, STB_GLOBAL, Section, - nullptr); - elf::Symtab::X->addRegular(Saver.save(S + "_end"), STV_DEFAULT, - STT_OBJECT, Data.size(), 0, STB_GLOBAL, - Section, nullptr); - elf::Symtab::X->addRegular(Saver.save(S + "_size"), STV_DEFAULT, - STT_OBJECT, Data.size(), 0, STB_GLOBAL, - nullptr, nullptr); + Symtab->addRegular(Saver.save(S + "_start"), STV_DEFAULT, STT_OBJECT, 0, 0, + STB_GLOBAL, Section, nullptr); + Symtab->addRegular(Saver.save(S + "_end"), STV_DEFAULT, STT_OBJECT, + Data.size(), 0, STB_GLOBAL, Section, nullptr); + Symtab->addRegular(Saver.save(S + "_size"), STV_DEFAULT, STT_OBJECT, + Data.size(), 0, STB_GLOBAL, nullptr, nullptr); } static bool isBitcode(MemoryBufferRef MB) { @@ -973,13 +1059,13 @@ InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName, switch (getELFKind(MB)) { case ELF32LEKind: - return make>(MB, ArchiveName); + return make>(MB, ArchiveName); case ELF32BEKind: - return make>(MB, ArchiveName); + return make>(MB, ArchiveName); case ELF64LEKind: - return make>(MB, ArchiveName); + return make>(MB, ArchiveName); case ELF64BEKind: - return make>(MB, ArchiveName); + return make>(MB, ArchiveName); default: llvm_unreachable("getELFKind"); } @@ -1000,53 +1086,53 @@ InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) { } } -MemoryBufferRef LazyObjectFile::getBuffer() { +MemoryBufferRef LazyObjFile::getBuffer() { if (Seen) return MemoryBufferRef(); Seen = true; return MB; } -InputFile *LazyObjectFile::fetch() { +InputFile *LazyObjFile::fetch() { MemoryBufferRef MBRef = getBuffer(); if (MBRef.getBuffer().empty()) return nullptr; return createObjectFile(MBRef, ArchiveName, OffsetInArchive); } -template void LazyObjectFile::parse() { - for (StringRef Sym : getSymbols()) - Symtab::X->addLazyObject(Sym, *this); +template void LazyObjFile::parse() { + for (StringRef Sym : getSymbolNames()) + Symtab->addLazyObject(Sym, *this); } -template std::vector LazyObjectFile::getElfSymbols() { +template std::vector LazyObjFile::getElfSymbols() { typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::SymRange Elf_Sym_Range; - const ELFFile Obj(this->MB.getBuffer()); - ArrayRef Sections = check(Obj.sections(), toString(this)); + ELFFile Obj = check(ELFFile::create(this->MB.getBuffer())); + ArrayRef Sections = CHECK(Obj.sections(), this); for (const Elf_Shdr &Sec : Sections) { if (Sec.sh_type != SHT_SYMTAB) continue; - Elf_Sym_Range Syms = check(Obj.symbols(&Sec), toString(this)); + Elf_Sym_Range Syms = CHECK(Obj.symbols(&Sec), this); uint32_t FirstNonLocal = Sec.sh_info; StringRef StringTable = - check(Obj.getStringTableForSymtab(Sec, Sections), toString(this)); + CHECK(Obj.getStringTableForSymtab(Sec, Sections), this); std::vector V; for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal)) if (Sym.st_shndx != SHN_UNDEF) - V.push_back(check(Sym.getName(StringTable), toString(this))); + V.push_back(CHECK(Sym.getName(StringTable), this)); return V; } return {}; } -std::vector LazyObjectFile::getBitcodeSymbols() { +std::vector LazyObjFile::getBitcodeSymbols() { std::unique_ptr Obj = - check(lto::InputFile::create(this->MB), toString(this)); + CHECK(lto::InputFile::create(this->MB), this); std::vector V; for (const lto::InputFile::Symbol &Sym : Obj->symbols()) if (!Sym.isUndefined()) @@ -1055,7 +1141,7 @@ std::vector LazyObjectFile::getBitcodeSymbols() { } // Returns a vector of globally-visible defined symbol names. -std::vector LazyObjectFile::getSymbols() { +std::vector LazyObjFile::getSymbolNames() { if (isBitcode(this->MB)) return getBitcodeSymbols(); @@ -1083,27 +1169,22 @@ template void BitcodeFile::parse(DenseSet &); template void BitcodeFile::parse(DenseSet &); template void BitcodeFile::parse(DenseSet &); -template void LazyObjectFile::parse(); -template void LazyObjectFile::parse(); -template void LazyObjectFile::parse(); -template void LazyObjectFile::parse(); +template void LazyObjFile::parse(); +template void LazyObjFile::parse(); +template void LazyObjFile::parse(); +template void LazyObjFile::parse(); template class elf::ELFFileBase; template class elf::ELFFileBase; template class elf::ELFFileBase; template class elf::ELFFileBase; -template class elf::ObjectFile; -template class elf::ObjectFile; -template class elf::ObjectFile; -template class elf::ObjectFile; +template class elf::ObjFile; +template class elf::ObjFile; +template class elf::ObjFile; +template class elf::ObjFile; template class elf::SharedFile; template class elf::SharedFile; template class elf::SharedFile; template class elf::SharedFile; - -template void BinaryFile::parse(); -template void BinaryFile::parse(); -template void BinaryFile::parse(); -template void BinaryFile::parse(); -- cgit v1.2.3 From 38aed5af8bdefd13a355fc0728c6ad57e5efa3ff Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 7 Feb 2018 17:38:02 -0500 Subject: update embedded LLD to 6.0.0rc2 --- deps/lld-prebuilt/ELF/Options.inc | 4 +- deps/lld/ELF/AArch64ErrataFix.cpp | 3 +- deps/lld/ELF/Arch/X86.cpp | 144 ++++++++++++++++++++- deps/lld/ELF/Arch/X86_64.cpp | 127 +++++++++++++++++- deps/lld/ELF/Config.h | 1 + deps/lld/ELF/Driver.cpp | 3 +- deps/lld/ELF/InputFiles.cpp | 8 ++ deps/lld/ELF/LinkerScript.cpp | 53 +++++--- deps/lld/ELF/LinkerScript.h | 10 +- deps/lld/ELF/Options.td | 4 +- deps/lld/ELF/OutputSections.h | 5 +- deps/lld/ELF/ScriptParser.cpp | 15 ++- deps/lld/ELF/SymbolTable.cpp | 3 +- deps/lld/ELF/Writer.cpp | 6 +- deps/lld/ELF/Writer.h | 7 + .../lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp | 1 + deps/lld/test/ELF/Inputs/as-needed-lazy.s | 3 + .../lld/test/ELF/Inputs/mips-gp-dips-corrupt-ver.s | 14 ++ .../test/ELF/Inputs/mips-gp-dips-corrupt-ver.so | Bin 0 -> 2160 bytes deps/lld/test/ELF/as-needed-lazy.s | 14 ++ deps/lld/test/ELF/i386-retpoline-nopic.s | 65 ++++++++++ deps/lld/test/ELF/i386-retpoline-pic.s | 62 +++++++++ deps/lld/test/ELF/linkerscript/at-self-reference.s | 63 +++++++++ deps/lld/test/ELF/linkerscript/at2.s | 81 ++++++++++++ deps/lld/test/ELF/linkerscript/at3.s | 38 ++++++ deps/lld/test/ELF/linkerscript/merge-header-load.s | 21 +++ .../test/ELF/linkerscript/parse-section-in-addr.s | 10 ++ deps/lld/test/ELF/mips-gp-disp-ver.s | 15 +++ deps/lld/test/ELF/pie.s | 2 +- deps/lld/test/ELF/x86-64-retpoline-znow.s | 53 ++++++++ deps/lld/test/ELF/x86-64-retpoline.s | 66 ++++++++++ 31 files changed, 856 insertions(+), 45 deletions(-) create mode 100644 deps/lld/test/ELF/Inputs/as-needed-lazy.s create mode 100644 deps/lld/test/ELF/Inputs/mips-gp-dips-corrupt-ver.s create mode 100755 deps/lld/test/ELF/Inputs/mips-gp-dips-corrupt-ver.so create mode 100644 deps/lld/test/ELF/as-needed-lazy.s create mode 100644 deps/lld/test/ELF/i386-retpoline-nopic.s create mode 100644 deps/lld/test/ELF/i386-retpoline-pic.s create mode 100644 deps/lld/test/ELF/linkerscript/at-self-reference.s create mode 100644 deps/lld/test/ELF/linkerscript/at2.s create mode 100644 deps/lld/test/ELF/linkerscript/at3.s create mode 100644 deps/lld/test/ELF/linkerscript/merge-header-load.s create mode 100644 deps/lld/test/ELF/linkerscript/parse-section-in-addr.s create mode 100644 deps/lld/test/ELF/mips-gp-disp-ver.s create mode 100644 deps/lld/test/ELF/x86-64-retpoline-znow.s create mode 100644 deps/lld/test/ELF/x86-64-retpoline.s (limited to 'deps/lld/ELF/InputFiles.cpp') diff --git a/deps/lld-prebuilt/ELF/Options.inc b/deps/lld-prebuilt/ELF/Options.inc index 640f1bdcc6..17659f0290 100644 --- a/deps/lld-prebuilt/ELF/Options.inc +++ b/deps/lld-prebuilt/ELF/Options.inc @@ -230,6 +230,8 @@ OPTION(prefix_2, "no-merge-exidx-entries", no_merge_exidx_entries, Flag, INVALID OPTION(prefix_2, "no-mmap-output-file", no_mmap_output_file, Flag, INVALID, INVALID, nullptr, 0, 0, nullptr, nullptr, nullptr) OPTION(prefix_3, "no-omagic", no_omagic, Flag, INVALID, INVALID, nullptr, 0, 0, "Do not set the text data sections to be writable", "", nullptr) +OPTION(prefix_2, "no-pie", no_pie, Flag, INVALID, INVALID, nullptr, 0, 0, + "Do not create a position independent executable", nullptr, nullptr) OPTION(prefix_2, "no-print-gc-sections", no_print_gc_sections, Flag, INVALID, INVALID, nullptr, 0, 0, "Do not list removed unused sections", nullptr, nullptr) OPTION(prefix_2, "no-rosegment", no_rosegment, Flag, INVALID, INVALID, nullptr, 0, 0, @@ -247,8 +249,6 @@ OPTION(prefix_2, "no-whole-archive", no_whole_archive, Flag, INVALID, INVALID, n OPTION(prefix_2, "noinhibit-exec", noinhibit_exec, Flag, INVALID, INVALID, nullptr, 0, 0, "Retain the executable output file whenever it is still usable", nullptr, nullptr) OPTION(prefix_2, "non_shared", alias_Bstatic_non_shared, Flag, INVALID, Bstatic, nullptr, 0, 0, nullptr, nullptr, nullptr) -OPTION(prefix_2, "nopie", nopie, Flag, INVALID, INVALID, nullptr, 0, 0, - "Do not create a position independent executable", nullptr, nullptr) OPTION(prefix_2, "nostdlib", nostdlib, Flag, INVALID, INVALID, nullptr, 0, 0, "Only search directories specified on the command line", nullptr, nullptr) OPTION(prefix_1, "N", alias_omagic, Flag, INVALID, omagic, nullptr, 0, 0, nullptr, nullptr, nullptr) diff --git a/deps/lld/ELF/AArch64ErrataFix.cpp b/deps/lld/ELF/AArch64ErrataFix.cpp index 9c0d536dea..48273d0eb3 100644 --- a/deps/lld/ELF/AArch64ErrataFix.cpp +++ b/deps/lld/ELF/AArch64ErrataFix.cpp @@ -47,6 +47,7 @@ using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; +using namespace llvm::support; using namespace llvm::support::endian; using namespace lld; @@ -357,7 +358,7 @@ static uint64_t scanCortexA53Errata843419(InputSection *IS, uint64_t &Off, uint64_t PatchOff = 0; const uint8_t *Buf = IS->Data.begin(); - const uint32_t *InstBuf = reinterpret_cast(Buf + Off); + const ulittle32_t *InstBuf = reinterpret_cast(Buf + Off); uint32_t Instr1 = *InstBuf++; uint32_t Instr2 = *InstBuf++; uint32_t Instr3 = *InstBuf++; diff --git a/deps/lld/ELF/Arch/X86.cpp b/deps/lld/ELF/Arch/X86.cpp index 10517bef14..09c16db53e 100644 --- a/deps/lld/ELF/Arch/X86.cpp +++ b/deps/lld/ELF/Arch/X86.cpp @@ -21,7 +21,7 @@ using namespace lld; using namespace lld::elf; namespace { -class X86 final : public TargetInfo { +class X86 : public TargetInfo { public: X86(); RelExpr getRelExpr(RelType Type, const Symbol &S, @@ -399,7 +399,145 @@ void X86::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { memcpy(Loc - 2, Inst, sizeof(Inst)); } +namespace { +class RetpolinePic : public X86 { +public: + RetpolinePic(); + void writeGotPlt(uint8_t *Buf, const Symbol &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; +}; + +class RetpolineNoPic : public X86 { +public: + RetpolineNoPic(); + void writeGotPlt(uint8_t *Buf, const Symbol &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; +}; +} // namespace + +RetpolinePic::RetpolinePic() { + PltHeaderSize = 48; + PltEntrySize = 32; +} + +void RetpolinePic::writeGotPlt(uint8_t *Buf, const Symbol &S) const { + write32le(Buf, S.getPltVA() + 17); +} + +void RetpolinePic::writePltHeader(uint8_t *Buf) const { + const uint8_t Insn[] = { + 0xff, 0xb3, 0, 0, 0, 0, // 0: pushl GOTPLT+4(%ebx) + 0x50, // 6: pushl %eax + 0x8b, 0x83, 0, 0, 0, 0, // 7: mov GOTPLT+8(%ebx), %eax + 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: call next + 0xf3, 0x90, // 12: loop: pause + 0x0f, 0xae, 0xe8, // 14: lfence + 0xeb, 0xf9, // 17: jmp loop + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16 + 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp) + 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx + 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp) + 0x89, 0xc8, // 2b: mov %ecx, %eax + 0x59, // 2d: pop %ecx + 0xc3, // 2e: ret + }; + memcpy(Buf, Insn, sizeof(Insn)); + + uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); + uint32_t GotPlt = InX::GotPlt->getVA() - Ebx; + write32le(Buf + 2, GotPlt + 4); + write32le(Buf + 9, GotPlt + 8); +} + +void RetpolinePic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Insn[] = { + 0x50, // pushl %eax + 0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax + 0xe8, 0, 0, 0, 0, // call plt+0x20 + 0xe9, 0, 0, 0, 0, // jmp plt+0x12 + 0x68, 0, 0, 0, 0, // pushl $reloc_offset + 0xe9, 0, 0, 0, 0, // jmp plt+0 + }; + memcpy(Buf, Insn, sizeof(Insn)); + + uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); + write32le(Buf + 3, GotPltEntryAddr - Ebx); + write32le(Buf + 8, -Index * PltEntrySize - PltHeaderSize - 12 + 32); + write32le(Buf + 13, -Index * PltEntrySize - PltHeaderSize - 17 + 18); + write32le(Buf + 18, RelOff); + write32le(Buf + 23, -Index * PltEntrySize - PltHeaderSize - 27); +} + +RetpolineNoPic::RetpolineNoPic() { + PltHeaderSize = 48; + PltEntrySize = 32; +} + +void RetpolineNoPic::writeGotPlt(uint8_t *Buf, const Symbol &S) const { + write32le(Buf, S.getPltVA() + 16); +} + +void RetpolineNoPic::writePltHeader(uint8_t *Buf) const { + const uint8_t PltData[] = { + 0xff, 0x35, 0, 0, 0, 0, // 0: pushl GOTPLT+4 + 0x50, // 6: pushl %eax + 0xa1, 0, 0, 0, 0, // 7: mov GOTPLT+8, %eax + 0xe8, 0x0f, 0x00, 0x00, 0x00, // c: call next + 0xf3, 0x90, // 11: loop: pause + 0x0f, 0xae, 0xe8, // 13: lfence + 0xeb, 0xf9, // 16: jmp loop + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 18: int3 + 0xcc, 0xcc, 0xcc, // 1f: int3; .align 16 + 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp) + 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx + 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp) + 0x89, 0xc8, // 2b: mov %ecx, %eax + 0x59, // 2d: pop %ecx + 0xc3, // 2e: ret + }; + memcpy(Buf, PltData, sizeof(PltData)); + + uint32_t GotPlt = InX::GotPlt->getVA(); + write32le(Buf + 2, GotPlt + 4); + write32le(Buf + 8, GotPlt + 8); +} + +void RetpolineNoPic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Insn[] = { + 0x50, // 0: pushl %eax + 0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax + 0xe8, 0, 0, 0, 0, // 6: call plt+0x20 + 0xe9, 0, 0, 0, 0, // b: jmp plt+0x11 + 0x68, 0, 0, 0, 0, // 10: pushl $reloc_offset + 0xe9, 0, 0, 0, 0, // 15: jmp plt+0 + }; + memcpy(Buf, Insn, sizeof(Insn)); + + write32le(Buf + 2, GotPltEntryAddr); + write32le(Buf + 7, -Index * PltEntrySize - PltHeaderSize - 11 + 32); + write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16 + 17); + write32le(Buf + 17, RelOff); + write32le(Buf + 22, -Index * PltEntrySize - PltHeaderSize - 26); +} + TargetInfo *elf::getX86TargetInfo() { - static X86 Target; - return &Target; + if (Config->ZRetpolineplt) { + if (Config->Pic) { + static RetpolinePic T; + return &T; + } + static RetpolineNoPic T; + return &T; + } + + static X86 T; + return &T; } diff --git a/deps/lld/ELF/Arch/X86_64.cpp b/deps/lld/ELF/Arch/X86_64.cpp index c977d9247d..3db391e9f0 100644 --- a/deps/lld/ELF/Arch/X86_64.cpp +++ b/deps/lld/ELF/Arch/X86_64.cpp @@ -23,7 +23,7 @@ using namespace lld; using namespace lld::elf; namespace { -template class X86_64 final : public TargetInfo { +template class X86_64 : public TargetInfo { public: X86_64(); RelExpr getRelExpr(RelType Type, const Symbol &S, @@ -460,12 +460,125 @@ void X86_64::relaxGot(uint8_t *Loc, uint64_t Val) const { write32le(Loc - 1, Val + 1); } -TargetInfo *elf::getX32TargetInfo() { - static X86_64 Target; - return &Target; +namespace { +template class Retpoline : public X86_64 { +public: + Retpoline(); + void writeGotPlt(uint8_t *Buf, const Symbol &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; +}; + +template class RetpolineZNow : public X86_64 { +public: + RetpolineZNow(); + void writeGotPlt(uint8_t *Buf, const Symbol &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; +}; +} // namespace + +template Retpoline::Retpoline() { + TargetInfo::PltHeaderSize = 48; + TargetInfo::PltEntrySize = 32; +} + +template +void Retpoline::writeGotPlt(uint8_t *Buf, const Symbol &S) const { + write32le(Buf, S.getPltVA() + 17); +} + +template void Retpoline::writePltHeader(uint8_t *Buf) const { + const uint8_t Insn[] = { + 0xff, 0x35, 0, 0, 0, 0, // 0: pushq GOTPLT+8(%rip) + 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 6: mov GOTPLT+16(%rip), %r11 + 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: callq next + 0xf3, 0x90, // 12: loop: pause + 0x0f, 0xae, 0xe8, // 14: lfence + 0xeb, 0xf9, // 17: jmp loop + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16 + 0x4c, 0x89, 0x1c, 0x24, // 20: next: mov %r11, (%rsp) + 0xc3, // 24: ret + }; + memcpy(Buf, Insn, sizeof(Insn)); + + uint64_t GotPlt = InX::GotPlt->getVA(); + uint64_t Plt = InX::Plt->getVA(); + write32le(Buf + 2, GotPlt - Plt - 6 + 8); + write32le(Buf + 9, GotPlt - Plt - 13 + 16); +} + +template +void Retpoline::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Insn[] = { + 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 0: mov foo@GOTPLT(%rip), %r11 + 0xe8, 0, 0, 0, 0, // 7: callq plt+0x20 + 0xe9, 0, 0, 0, 0, // c: jmp plt+0x12 + 0x68, 0, 0, 0, 0, // 11: pushq + 0xe9, 0, 0, 0, 0, // 16: jmp plt+0 + }; + memcpy(Buf, Insn, sizeof(Insn)); + + uint64_t Off = TargetInfo::PltHeaderSize + TargetInfo::PltEntrySize * Index; + + write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7); + write32le(Buf + 8, -Off - 12 + 32); + write32le(Buf + 13, -Off - 17 + 18); + write32le(Buf + 18, Index); + write32le(Buf + 23, -Off - 27); +} + +template RetpolineZNow::RetpolineZNow() { + TargetInfo::PltHeaderSize = 32; + TargetInfo::PltEntrySize = 16; +} + +template +void RetpolineZNow::writePltHeader(uint8_t *Buf) const { + const uint8_t Insn[] = { + 0xe8, 0x0b, 0x00, 0x00, 0x00, // 0: call next + 0xf3, 0x90, // 5: loop: pause + 0x0f, 0xae, 0xe8, // 7: lfence + 0xeb, 0xf9, // a: jmp loop + 0xcc, 0xcc, 0xcc, 0xcc, // c: int3; .align 16 + 0x4c, 0x89, 0x1c, 0x24, // 10: next: mov %r11, (%rsp) + 0xc3, // 14: ret + }; + memcpy(Buf, Insn, sizeof(Insn)); } -TargetInfo *elf::getX86_64TargetInfo() { - static X86_64 Target; - return &Target; +template +void RetpolineZNow::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Insn[] = { + 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // mov foo@GOTPLT(%rip), %r11 + 0xe9, 0, 0, 0, 0, // jmp plt+0 + }; + memcpy(Buf, Insn, sizeof(Insn)); + + write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7); + write32le(Buf + 8, + -Index * TargetInfo::PltEntrySize - TargetInfo::PltHeaderSize - 12); } + +template TargetInfo *getTargetInfo() { + if (Config->ZRetpolineplt) { + if (Config->ZNow) { + static RetpolineZNow T; + return &T; + } + static Retpoline T; + return &T; + } + + static X86_64 T; + return &T; +} + +TargetInfo *elf::getX32TargetInfo() { return getTargetInfo(); } +TargetInfo *elf::getX86_64TargetInfo() { return getTargetInfo(); } diff --git a/deps/lld/ELF/Config.h b/deps/lld/ELF/Config.h index 74c325cb7c..ed42572096 100644 --- a/deps/lld/ELF/Config.h +++ b/deps/lld/ELF/Config.h @@ -159,6 +159,7 @@ struct Configuration { bool ZRelro; bool ZRodynamic; bool ZText; + bool ZRetpolineplt; bool ExitEarly; bool ZWxneeded; DiscardPolicy Discard; diff --git a/deps/lld/ELF/Driver.cpp b/deps/lld/ELF/Driver.cpp index b159fe63eb..6de8ed59e5 100644 --- a/deps/lld/ELF/Driver.cpp +++ b/deps/lld/ELF/Driver.cpp @@ -638,7 +638,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->Optimize = args::getInteger(Args, OPT_O, 1); Config->OrphanHandling = getOrphanHandling(Args); Config->OutputFile = Args.getLastArgValue(OPT_o); - Config->Pie = Args.hasFlag(OPT_pie, OPT_nopie, false); + Config->Pie = Args.hasFlag(OPT_pie, OPT_no_pie, false); Config->PrintGcSections = Args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false); Config->Rpath = getRpath(Args); @@ -674,6 +674,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->ZNow = hasZOption(Args, "now"); Config->ZOrigin = hasZOption(Args, "origin"); Config->ZRelro = !hasZOption(Args, "norelro"); + Config->ZRetpolineplt = hasZOption(Args, "retpolineplt"); Config->ZRodynamic = hasZOption(Args, "rodynamic"); Config->ZStackSize = args::getZOptionValue(Args, OPT_z, "stack-size", 0); Config->ZText = !hasZOption(Args, "notext"); diff --git a/deps/lld/ELF/InputFiles.cpp b/deps/lld/ELF/InputFiles.cpp index f514870ca8..ccf4b3d767 100644 --- a/deps/lld/ELF/InputFiles.cpp +++ b/deps/lld/ELF/InputFiles.cpp @@ -856,6 +856,14 @@ template void SharedFile::parseRest() { continue; } + if (Config->EMachine == EM_MIPS) { + // FIXME: MIPS BFD linker puts _gp_disp symbol into DSO files + // and incorrectly assigns VER_NDX_LOCAL to this section global + // symbol. Here is a workaround for this bug. + if (Versym && VersymIndex == VER_NDX_LOCAL && Name == "_gp_disp") + continue; + } + const Elf_Verdef *Ver = nullptr; if (VersymIndex != VER_NDX_GLOBAL) { if (VersymIndex >= Verdefs.size() || VersymIndex == VER_NDX_LOCAL) { diff --git a/deps/lld/ELF/LinkerScript.cpp b/deps/lld/ELF/LinkerScript.cpp index 16b306da46..23c3a11a9d 100644 --- a/deps/lld/ELF/LinkerScript.cpp +++ b/deps/lld/ELF/LinkerScript.cpp @@ -589,8 +589,12 @@ void LinkerScript::output(InputSection *S) { // If there is a memory region associated with this input section, then // place the section in that region and update the region index. + if (Ctx->LMARegion) + Ctx->LMARegion->CurPos += Pos - Before; + // FIXME: should we also produce overflow errors for LMARegion? + if (Ctx->MemRegion) { - uint64_t &CurOffset = Ctx->MemRegionOffset[Ctx->MemRegion]; + uint64_t &CurOffset = Ctx->MemRegion->CurPos; CurOffset += Pos - Before; uint64_t CurSize = CurOffset - Ctx->MemRegion->Origin; if (CurSize > Ctx->MemRegion->Length) { @@ -608,13 +612,6 @@ void LinkerScript::switchTo(OutputSection *Sec) { Ctx->OutSec = Sec; Ctx->OutSec->Addr = advance(0, Ctx->OutSec->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 (Ctx->LMAOffset) - Ctx->OutSec->LMAOffset = Ctx->LMAOffset(); } // This function searches for a memory region to place the given output @@ -624,9 +621,8 @@ MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *Sec) { // If a memory region name was specified in the output section command, // then try to find that region first. if (!Sec->MemoryRegionName.empty()) { - auto It = MemoryRegions.find(Sec->MemoryRegionName); - if (It != MemoryRegions.end()) - return It->second; + if (MemoryRegion *M = MemoryRegions.lookup(Sec->MemoryRegionName)) + return M; error("memory region '" + Sec->MemoryRegionName + "' not declared"); return nullptr; } @@ -659,16 +655,25 @@ void LinkerScript::assignOffsets(OutputSection *Sec) { setDot(Sec->AddrExpr, Sec->Location, false); Ctx->MemRegion = Sec->MemRegion; + Ctx->LMARegion = Sec->LMARegion; if (Ctx->MemRegion) - Dot = Ctx->MemRegionOffset[Ctx->MemRegion]; - - if (Sec->LMAExpr) { - uint64_t D = Dot; - Ctx->LMAOffset = [=] { return Sec->LMAExpr().getValue() - D; }; - } + Dot = Ctx->MemRegion->CurPos; switchTo(Sec); + if (Sec->LMAExpr) + Ctx->LMAOffset = Sec->LMAExpr().getValue() - Dot; + + if (MemoryRegion *MR = Sec->LMARegion) + Ctx->LMAOffset = MR->CurPos - Dot; + + // 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 (PhdrEntry *L = Ctx->OutSec->PtLoad) + L->LMAOffset = Ctx->LMAOffset; + // The Size previously denoted how many InputSections had been added to this // section, and was used for sorting SHF_LINK_ORDER sections. Reset it to // compute the actual size value. @@ -689,7 +694,9 @@ void LinkerScript::assignOffsets(OutputSection *Sec) { Cmd->Offset = Dot - Ctx->OutSec->Addr; Dot += Cmd->Size; if (Ctx->MemRegion) - Ctx->MemRegionOffset[Ctx->MemRegion] += Cmd->Size; + Ctx->MemRegion->CurPos += Cmd->Size; + if (Ctx->LMARegion) + Ctx->LMARegion->CurPos += Cmd->Size; Ctx->OutSec->Size = Dot - Ctx->OutSec->Addr; continue; } @@ -788,6 +795,12 @@ void LinkerScript::adjustSectionsAfterSorting() { if (auto *Sec = dyn_cast(Base)) { if (!Sec->Live) continue; + if (!Sec->LMARegionName.empty()) { + if (MemoryRegion *M = MemoryRegions.lookup(Sec->LMARegionName)) + Sec->LMARegion = M; + else + error("memory region '" + Sec->LMARegionName + "' not declared"); + } Sec->MemRegion = findMemoryRegion(Sec); // Handle align (e.g. ".foo : ALIGN(16) { ... }"). if (Sec->AlignExpr) @@ -878,8 +891,8 @@ void LinkerScript::allocateHeaders(std::vector &Phdrs) { LinkerScript::AddressState::AddressState() { for (auto &MRI : Script->MemoryRegions) { - const MemoryRegion *MR = MRI.second; - MemRegionOffset[MR] = MR->Origin; + MemoryRegion *MR = MRI.second; + MR->CurPos = MR->Origin; } } diff --git a/deps/lld/ELF/LinkerScript.h b/deps/lld/ELF/LinkerScript.h index 11131dda8e..0d7578cd2f 100644 --- a/deps/lld/ELF/LinkerScript.h +++ b/deps/lld/ELF/LinkerScript.h @@ -118,11 +118,17 @@ enum class ConstraintKind { NoConstraint, ReadOnly, ReadWrite }; // target memory. Instances of the struct are created by parsing the // MEMORY command. struct MemoryRegion { + MemoryRegion(StringRef Name, uint64_t Origin, uint64_t Length, uint32_t Flags, + uint32_t NegFlags) + : Name(Name), Origin(Origin), Length(Length), Flags(Flags), + NegFlags(NegFlags) {} + std::string Name; uint64_t Origin; uint64_t Length; uint32_t Flags; uint32_t NegFlags; + uint64_t CurPos = 0; }; // This struct represents one section match pattern in SECTIONS() command. @@ -200,8 +206,8 @@ class LinkerScript final { uint64_t ThreadBssOffset = 0; OutputSection *OutSec = nullptr; MemoryRegion *MemRegion = nullptr; - llvm::DenseMap MemRegionOffset; - std::function LMAOffset; + MemoryRegion *LMARegion = nullptr; + uint64_t LMAOffset = 0; }; llvm::DenseMap NameToOutputSection; diff --git a/deps/lld/ELF/Options.td b/deps/lld/ELF/Options.td index 20027e90ae..7350467281 100644 --- a/deps/lld/ELF/Options.td +++ b/deps/lld/ELF/Options.td @@ -202,6 +202,8 @@ def no_gnu_unique: F<"no-gnu-unique">, def no_merge_exidx_entries: F<"no-merge-exidx-entries">, HelpText<"Disable merging .ARM.exidx entries">; +def no_pie: F<"no-pie">, HelpText<"Do not create a position independent executable">; + def no_threads: F<"no-threads">, HelpText<"Do not run the linker multi-threaded">; @@ -211,8 +213,6 @@ def no_whole_archive: F<"no-whole-archive">, def noinhibit_exec: F<"noinhibit-exec">, HelpText<"Retain the executable output file whenever it is still usable">; -def nopie: F<"nopie">, HelpText<"Do not create a position independent executable">; - def no_omagic: Flag<["--"], "no-omagic">, MetaVarName<"">, HelpText<"Do not set the text data sections to be writable">; diff --git a/deps/lld/ELF/OutputSections.h b/deps/lld/ELF/OutputSections.h index b2845773e9..c006eae0c0 100644 --- a/deps/lld/ELF/OutputSections.h +++ b/deps/lld/ELF/OutputSections.h @@ -49,7 +49,7 @@ public: static bool classof(const BaseCommand *C); - uint64_t getLMA() const { return Addr + LMAOffset; } + uint64_t getLMA() const { return PtLoad ? Addr + PtLoad->LMAOffset : Addr; } template void writeHeaderTo(typename ELFT::Shdr *SHdr); unsigned SectionIndex; @@ -78,7 +78,6 @@ public: // The following fields correspond to Elf_Shdr members. uint64_t Offset = 0; - uint64_t LMAOffset = 0; uint64_t Addr = 0; uint32_t ShName = 0; @@ -89,6 +88,7 @@ public: // The following members are normally only used in linker scripts. MemoryRegion *MemRegion = nullptr; + MemoryRegion *LMARegion = nullptr; Expr AddrExpr; Expr AlignExpr; Expr LMAExpr; @@ -99,6 +99,7 @@ public: ConstraintKind Constraint = ConstraintKind::NoConstraint; std::string Location; std::string MemoryRegionName; + std::string LMARegionName; bool Noload = false; template void finalize(); diff --git a/deps/lld/ELF/ScriptParser.cpp b/deps/lld/ELF/ScriptParser.cpp index 4263944981..3d2606db8d 100644 --- a/deps/lld/ELF/ScriptParser.cpp +++ b/deps/lld/ELF/ScriptParser.cpp @@ -709,6 +709,14 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) { if (consume(">")) Cmd->MemoryRegionName = next(); + if (consume("AT")) { + expect(">"); + Cmd->LMARegionName = next(); + } + + if (Cmd->LMAExpr && !Cmd->LMARegionName.empty()) + error("section can't have both LMA and a load region"); + Cmd->Phdrs = readOutputSectionPhdrs(); if (consume("=")) @@ -922,7 +930,10 @@ ByteCommand *ScriptParser::readByteCommand(StringRef Tok) { StringRef ScriptParser::readParenLiteral() { expect("("); + bool Orig = InExpr; + InExpr = false; StringRef Tok = next(); + InExpr = Orig; expect(")"); return Tok; } @@ -1282,8 +1293,8 @@ void ScriptParser::readMemory() { // Add the memory region to the region map. if (Script->MemoryRegions.count(Name)) setError("region '" + Name + "' already defined"); - MemoryRegion *MR = make(); - *MR = {Name, Origin, Length, Flags, NegFlags}; + MemoryRegion *MR = + make(Name, Origin, Length, Flags, NegFlags); Script->MemoryRegions[Name] = MR; } } diff --git a/deps/lld/ELF/SymbolTable.cpp b/deps/lld/ELF/SymbolTable.cpp index b6bf219988..c3a00bea4a 100644 --- a/deps/lld/ELF/SymbolTable.cpp +++ b/deps/lld/ELF/SymbolTable.cpp @@ -491,12 +491,13 @@ void SymbolTable::addShared(StringRef Name, SharedFile &File, if (WasInserted || ((S->isUndefined() || S->isLazy()) && S->getVisibility() == STV_DEFAULT)) { uint8_t Binding = S->Binding; + bool WasUndefined = S->isUndefined(); replaceSymbol(S, File, Name, Sym.getBinding(), Sym.st_other, Sym.getType(), Sym.st_value, Sym.st_size, Alignment, VerdefIndex); if (!WasInserted) { S->Binding = Binding; - if (!S->isWeak() && !Config->GcSections) + if (!S->isWeak() && !Config->GcSections && WasUndefined) File.IsNeeded = true; } } diff --git a/deps/lld/ELF/Writer.cpp b/deps/lld/ELF/Writer.cpp index 5feff456ff..1c3b6495a0 100644 --- a/deps/lld/ELF/Writer.cpp +++ b/deps/lld/ELF/Writer.cpp @@ -822,6 +822,8 @@ void PhdrEntry::add(OutputSection *Sec) { p_align = std::max(p_align, Sec->Alignment); if (p_type == PT_LOAD) Sec->PtLoad = this; + if (Sec->LMAExpr) + ASectionHasLMA = true; } // The beginning and the ending of .rel[a].plt section are marked @@ -1626,7 +1628,9 @@ template std::vector Writer::createPhdrs() { // different flags or is loaded at a discontiguous address using AT linker // script command. uint64_t NewFlags = computeFlags(Sec->getPhdrFlags()); - if (Sec->LMAExpr || Flags != NewFlags) { + if ((Sec->LMAExpr && Load->ASectionHasLMA) || + Sec->MemRegion != Load->FirstSec->MemRegion || Flags != NewFlags) { + Load = AddHdr(PT_LOAD, NewFlags); Flags = NewFlags; } diff --git a/deps/lld/ELF/Writer.h b/deps/lld/ELF/Writer.h index d247068bab..f48f9d1e01 100644 --- a/deps/lld/ELF/Writer.h +++ b/deps/lld/ELF/Writer.h @@ -44,6 +44,13 @@ struct PhdrEntry { OutputSection *FirstSec = nullptr; OutputSection *LastSec = nullptr; bool HasLMA = false; + + // True if one of the sections in this program header has a LMA specified via + // linker script: AT(addr). We never allow 2 or more sections with LMA in the + // same program header. + bool ASectionHasLMA = false; + + uint64_t LMAOffset = 0; }; void addReservedSymbols(); diff --git a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp index b207c85523..aee9959ca6 100644 --- a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp +++ b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp @@ -621,6 +621,7 @@ void ArchHandler_x86_64::applyFixupFinal( // Fall into llvm_unreachable(). break; } + llvm_unreachable("invalid x86_64 Reference Kind"); } void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref, diff --git a/deps/lld/test/ELF/Inputs/as-needed-lazy.s b/deps/lld/test/ELF/Inputs/as-needed-lazy.s new file mode 100644 index 0000000000..7f9c360dda --- /dev/null +++ b/deps/lld/test/ELF/Inputs/as-needed-lazy.s @@ -0,0 +1,3 @@ +.global foo +foo: + nop diff --git a/deps/lld/test/ELF/Inputs/mips-gp-dips-corrupt-ver.s b/deps/lld/test/ELF/Inputs/mips-gp-dips-corrupt-ver.s new file mode 100644 index 0000000000..42bd32a1e7 --- /dev/null +++ b/deps/lld/test/ELF/Inputs/mips-gp-dips-corrupt-ver.s @@ -0,0 +1,14 @@ +# Source file for mips-gp-dips-corrupt-ver.so +# +# % cat gpdisp.ver +# LLD_1.0.0 { global: foo; }; +# +# % as mips-gp-dips-corrupt-ver.s -o mips-gp-dips-corrupt-ver.o +# % ld -shared -o mips-gp-dips-corrupt-ver.so \ +# --version-script gpdisp.ver mips-gp-dips-corrupt-ver.o + + .global foo + .text +foo: + lui $t0, %hi(_gp_disp) + addi $t0, $t0, %lo(_gp_disp) diff --git a/deps/lld/test/ELF/Inputs/mips-gp-dips-corrupt-ver.so b/deps/lld/test/ELF/Inputs/mips-gp-dips-corrupt-ver.so new file mode 100755 index 0000000000..289ffa538f Binary files /dev/null and b/deps/lld/test/ELF/Inputs/mips-gp-dips-corrupt-ver.so differ diff --git a/deps/lld/test/ELF/as-needed-lazy.s b/deps/lld/test/ELF/as-needed-lazy.s new file mode 100644 index 0000000000..e892b9980a --- /dev/null +++ b/deps/lld/test/ELF/as-needed-lazy.s @@ -0,0 +1,14 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/as-needed-lazy.s -o %t2.o +# RUN: ld.lld %t2.o -o %t2.so -shared +# RUN: rm -f %t2.a +# RUN: llvm-ar rc %t2.a %t2.o +# RUN: ld.lld %t1.o %t2.a --as-needed %t2.so -o %t +# RUN: llvm-readobj -d %t | FileCheck %s + +# CHECK-NOT: NEEDED + +.global _start +_start: + nop diff --git a/deps/lld/test/ELF/i386-retpoline-nopic.s b/deps/lld/test/ELF/i386-retpoline-nopic.s new file mode 100644 index 0000000000..79dd5a63cd --- /dev/null +++ b/deps/lld/test/ELF/i386-retpoline-nopic.s @@ -0,0 +1,65 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %p/Inputs/shared.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so + +// RUN: ld.lld %t1.o %t2.so -o %t.exe -z retpolineplt +// RUN: llvm-objdump -d -s %t.exe | FileCheck %s + +// CHECK: Disassembly of section .plt: +// CHECK-NEXT: .plt: +// CHECK-NEXT: 11010: ff 35 04 20 01 00 pushl 73732 +// CHECK-NEXT: 11016: 50 pushl %eax +// CHECK-NEXT: 11017: a1 08 20 01 00 movl 73736, %eax +// CHECK-NEXT: 1101c: e8 0f 00 00 00 calll 15 <.plt+0x20> +// CHECK-NEXT: 11021: f3 90 pause +// CHECK-NEXT: 11023: 0f ae e8 lfence +// CHECK-NEXT: 11026: eb f9 jmp -7 <.plt+0x11> +// CHECK-NEXT: 11028: cc int3 +// CHECK-NEXT: 11029: cc int3 +// CHECK-NEXT: 1102a: cc int3 +// CHECK-NEXT: 1102b: cc int3 +// CHECK-NEXT: 1102c: cc int3 +// CHECK-NEXT: 1102d: cc int3 +// CHECK-NEXT: 1102e: cc int3 +// CHECK-NEXT: 1102f: cc int3 +// CHECK-NEXT: 11030: 89 0c 24 movl %ecx, (%esp) +// CHECK-NEXT: 11033: 8b 4c 24 04 movl 4(%esp), %ecx +// CHECK-NEXT: 11037: 89 44 24 04 movl %eax, 4(%esp) +// CHECK-NEXT: 1103b: 89 c8 movl %ecx, %eax +// CHECK-NEXT: 1103d: 59 popl %ecx +// CHECK-NEXT: 1103e: c3 retl +// CHECK-NEXT: 1103f: cc int3 +// CHECK-NEXT: 11040: 50 pushl %eax +// CHECK-NEXT: 11041: a1 0c 20 01 00 movl 73740, %eax +// CHECK-NEXT: 11046: e8 e5 ff ff ff calll -27 <.plt+0x20> +// CHECK-NEXT: 1104b: e9 d1 ff ff ff jmp -47 <.plt+0x11> +// CHECK-NEXT: 11050: 68 00 00 00 00 pushl $0 +// CHECK-NEXT: 11055: e9 b6 ff ff ff jmp -74 <.plt> +// CHECK-NEXT: 1105a: cc int3 +// CHECK-NEXT: 1105b: cc int3 +// CHECK-NEXT: 1105c: cc int3 +// CHECK-NEXT: 1105d: cc int3 +// CHECK-NEXT: 1105e: cc int3 +// CHECK-NEXT: 1105f: cc int3 +// CHECK-NEXT: 11060: 50 pushl %eax +// CHECK-NEXT: 11061: a1 10 20 01 00 movl 73744, %eax +// CHECK-NEXT: 11066: e8 c5 ff ff ff calll -59 <.plt+0x20> +// CHECK-NEXT: 1106b: e9 b1 ff ff ff jmp -79 <.plt+0x11> +// CHECK-NEXT: 11070: 68 08 00 00 00 pushl $8 +// CHECK-NEXT: 11075: e9 96 ff ff ff jmp -106 <.plt> +// CHECK-NEXT: 1107a: cc int3 +// CHECK-NEXT: 1107b: cc int3 +// CHECK-NEXT: 1107c: cc int3 +// CHECK-NEXT: 1107d: cc int3 +// CHECK-NEXT: 1107e: cc int3 +// CHECK-NEXT: 1107f: cc int3 + +// CHECK: Contents of section .got.plt: +// CHECK-NEXT: 00300100 00000000 00000000 50100100 +// CHECK-NEXT: 70100100 + +.global _start +_start: + jmp bar@PLT + jmp zed@PLT diff --git a/deps/lld/test/ELF/i386-retpoline-pic.s b/deps/lld/test/ELF/i386-retpoline-pic.s new file mode 100644 index 0000000000..3555950b16 --- /dev/null +++ b/deps/lld/test/ELF/i386-retpoline-pic.s @@ -0,0 +1,62 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux -position-independent %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux -position-independent %p/Inputs/shared.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so + +// RUN: ld.lld %t1.o %t2.so -o %t.exe -z retpolineplt -pie +// RUN: llvm-objdump -d -s %t.exe | FileCheck %s + +// CHECK: Disassembly of section .plt: +// CHECK-NEXT: .plt: +// CHECK-NEXT: 1010: ff b3 04 20 00 00 pushl 8196(%ebx) +// CHECK-NEXT: 1016: 50 pushl %eax +// CHECK-NEXT: 1017: 8b 83 08 20 00 00 movl 8200(%ebx), %eax +// CHECK-NEXT: 101d: e8 0e 00 00 00 calll 14 <.plt+0x20> +// CHECK-NEXT: 1022: f3 90 pause +// CHECK-NEXT: 1024: 0f ae e8 lfence +// CHECK-NEXT: 1027: eb f9 jmp -7 <.plt+0x12> +// CHECK-NEXT: 1029: cc int3 +// CHECK-NEXT: 102a: cc int3 +// CHECK-NEXT: 102b: cc int3 +// CHECK-NEXT: 102c: cc int3 +// CHECK-NEXT: 102d: cc int3 +// CHECK-NEXT: 102e: cc int3 +// CHECK-NEXT: 102f: cc int3 +// CHECK-NEXT: 1030: 89 0c 24 movl %ecx, (%esp) +// CHECK-NEXT: 1033: 8b 4c 24 04 movl 4(%esp), %ecx +// CHECK-NEXT: 1037: 89 44 24 04 movl %eax, 4(%esp) +// CHECK-NEXT: 103b: 89 c8 movl %ecx, %eax +// CHECK-NEXT: 103d: 59 popl %ecx +// CHECK-NEXT: 103e: c3 retl +// CHECK-NEXT: 103f: cc int3 +// CHECK-NEXT: 1040: 50 pushl %eax +// CHECK-NEXT: 1041: 8b 83 0c 20 00 00 movl 8204(%ebx), %eax +// CHECK-NEXT: 1047: e8 e4 ff ff ff calll -28 <.plt+0x20> +// CHECK-NEXT: 104c: e9 d1 ff ff ff jmp -47 <.plt+0x12> +// CHECK-NEXT: 1051: 68 00 00 00 00 pushl $0 +// CHECK-NEXT: 1056: e9 b5 ff ff ff jmp -75 <.plt> +// CHECK-NEXT: 105b: cc int3 +// CHECK-NEXT: 105c: cc int3 +// CHECK-NEXT: 105d: cc int3 +// CHECK-NEXT: 105e: cc int3 +// CHECK-NEXT: 105f: cc int3 +// CHECK-NEXT: 1060: 50 pushl %eax +// CHECK-NEXT: 1061: 8b 83 10 20 00 00 movl 8208(%ebx), %eax +// CHECK-NEXT: 1067: e8 c4 ff ff ff calll -60 <.plt+0x20> +// CHECK-NEXT: 106c: e9 b1 ff ff ff jmp -79 <.plt+0x12> +// CHECK-NEXT: 1071: 68 08 00 00 00 pushl $8 +// CHECK-NEXT: 1076: e9 95 ff ff ff jmp -107 <.plt> +// CHECK-NEXT: 107b: cc int3 +// CHECK-NEXT: 107c: cc int3 +// CHECK-NEXT: 107d: cc int3 +// CHECK-NEXT: 107e: cc int3 +// CHECK-NEXT: 107f: cc int3 + +// CHECK: Contents of section .got.plt: +// CHECK-NEXT: 2000 00300000 00000000 00000000 51100000 +// CHECK-NEXT: 2010 71100000 + +.global _start +_start: + jmp bar@PLT + jmp zed@PLT diff --git a/deps/lld/test/ELF/linkerscript/at-self-reference.s b/deps/lld/test/ELF/linkerscript/at-self-reference.s new file mode 100644 index 0000000000..7208a4b9fc --- /dev/null +++ b/deps/lld/test/ELF/linkerscript/at-self-reference.s @@ -0,0 +1,63 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "SECTIONS { \ +# RUN: . = 0x1000; \ +# RUN: .aaa : AT(ADDR(.aaa)) { *(.aaa) } \ +# RUN: .bbb : AT(ADDR(.bbb)) { *(.bbb) } \ +# RUN: }" > %t.script +# RUN: ld.lld %t --script %t.script -o %t2 +# RUN: llvm-readobj -program-headers %t2 | FileCheck %s + +# CHECK: ProgramHeaders [ +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: VirtualAddress: 0x1000 +# CHECK-NEXT: PhysicalAddress: 0x1000 +# CHECK-NEXT: FileSize: 3 +# CHECK-NEXT: MemSize: 3 +# CHECK-NEXT: Flags [ (0x5) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_X (0x1) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x1008 +# CHECK-NEXT: VirtualAddress: 0x1008 +# CHECK-NEXT: PhysicalAddress: 0x1008 +# CHECK-NEXT: FileSize: 9 +# CHECK-NEXT: MemSize: 9 +# CHECK-NEXT: Flags [ (0x5) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_X (0x1) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_GNU_STACK (0x6474E551) +# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: VirtualAddress: 0x0 +# CHECK-NEXT: PhysicalAddress: 0x0 +# CHECK-NEXT: FileSize: 0 +# CHECK-NEXT: MemSize: 0 +# CHECK-NEXT: Flags [ (0x6) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_W (0x2) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 0 +# CHECK-NEXT: } +# CHECK-NEXT:] + +.global _start +_start: + nop + + +.section .aaa, "a" +.asciz "aa" + +.section .bbb, "a" +.align 8 +.quad 0 diff --git a/deps/lld/test/ELF/linkerscript/at2.s b/deps/lld/test/ELF/linkerscript/at2.s new file mode 100644 index 0000000000..1545b1d826 --- /dev/null +++ b/deps/lld/test/ELF/linkerscript/at2.s @@ -0,0 +1,81 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "MEMORY { \ +# RUN: AX (ax) : ORIGIN = 0x2000, LENGTH = 0x100 \ +# RUN: AW (aw) : ORIGIN = 0x3000, LENGTH = 0x100 \ +# RUN: FLASH (ax) : ORIGIN = 0x6000, LENGTH = 0x100 \ +# RUN: RAM (aw) : ORIGIN = 0x7000, LENGTH = 0x100 } \ +# RUN: SECTIONS { \ +# RUN: .foo1 : { *(.foo1) } > AX AT>FLASH \ +# RUN: .foo2 : { *(.foo2) } > AX \ +# RUN: .bar1 : { *(.bar1) } > AW AT> RAM \ +# RUN: .bar2 : { *(.bar2) } > AW AT > RAM \ +# RUN: .bar3 : { *(.bar3) } > AW AT >RAM \ +# RUN: }" > %t.script +# RUN: ld.lld %t --script %t.script -o %t2 +# RUN: llvm-readobj -program-headers %t2 | FileCheck %s +# RUN: llvm-objdump -section-headers %t2 | FileCheck %s --check-prefix=SECTIONS + +# CHECK: ProgramHeaders [ +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: VirtualAddress: 0x2000 +# CHECK-NEXT: PhysicalAddress: 0x6000 +# CHECK-NEXT: FileSize: 16 +# CHECK-NEXT: MemSize: 16 +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: PF_X +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD +# CHECK-NEXT: Offset: 0x2000 +# CHECK-NEXT: VirtualAddress: 0x3000 +# CHECK-NEXT: PhysicalAddress: 0x7000 +# CHECK-NEXT: FileSize: 24 +# CHECK-NEXT: MemSize: 24 +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: PF_W +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } + +# SECTIONS: Sections: +# SECTIONS-NEXT: Idx Name Size Address +# SECTIONS-NEXT: 0 00000000 0000000000000000 +# SECTIONS-NEXT: 1 .foo1 00000008 0000000000002000 +# SECTIONS-NEXT: 2 .foo2 00000008 0000000000002008 +# SECTIONS-NEXT: 3 .text 00000000 0000000000002010 +# SECTIONS-NEXT: 4 .bar1 00000008 0000000000003000 +# SECTIONS-NEXT: 5 .bar2 00000008 0000000000003008 +# SECTIONS-NEXT: 6 .bar3 00000008 0000000000003010 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "MEMORY { \ +# RUN: FLASH (ax) : ORIGIN = 0x2000, LENGTH = 0x100 \ +# RUN: RAM (aw) : ORIGIN = 0x5000, LENGTH = 0x100 } \ +# RUN: SECTIONS { \ +# RUN: .foo1 : AT(0x500) { *(.foo1) } > FLASH AT>FLASH \ +# RUN: }" > %t2.script +# RUN: not ld.lld %t --script %t2.script -o %t2 2>&1 | \ +# RUN: FileCheck %s --check-prefix=ERR +# ERR: error: section can't have both LMA and a load region + +.section .foo1, "ax" +.quad 0 + +.section .foo2, "ax" +.quad 0 + +.section .bar1, "aw" +.quad 0 + +.section .bar2, "aw" +.quad 0 + +.section .bar3, "aw" +.quad 0 diff --git a/deps/lld/test/ELF/linkerscript/at3.s b/deps/lld/test/ELF/linkerscript/at3.s new file mode 100644 index 0000000000..10bbfc6e96 --- /dev/null +++ b/deps/lld/test/ELF/linkerscript/at3.s @@ -0,0 +1,38 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "MEMORY { \ +# RUN: FOO (ax) : ORIGIN = 0x1000, LENGTH = 0x100 \ +# RUN: BAR (ax) : ORIGIN = 0x2000, LENGTH = 0x100 \ +# RUN: ZED (ax) : ORIGIN = 0x3000, LENGTH = 0x100 \ +# RUN: FLASH (ax) : ORIGIN = 0x6000, LENGTH = 0x200 \ +# RUN: } \ +# RUN: SECTIONS { \ +# RUN: .foo1 : { *(.foo1) } > FOO AT>FLASH \ +# RUN: .foo2 : { *(.foo2) BYTE(0x42) } > BAR AT>FLASH \ +# RUN: .foo3 : { *(.foo3) } > ZED AT>FLASH \ +# RUN: }" > %t.script +# RUN: ld.lld %t.o --script %t.script -o %t +# RUN: llvm-readelf -sections -program-headers %t | FileCheck %s + +# CHECK: .foo1 PROGBITS 0000000000001000 001000 +# CHECK: .foo2 PROGBITS 0000000000002000 002000 +# CHECK: .foo3 PROGBITS 0000000000003000 003000 + +# CHECK: Program Headers: +# CHECK-NOT: LOAD + +# CHECK: Type Offset VirtAddr PhysAddr +# CHECK-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000006000 +# CHECK-NEXT: LOAD 0x002000 0x0000000000002000 0x0000000000006008 +# CHECK-NEXT: LOAD 0x003000 0x0000000000003000 0x0000000000006011 + +# CHECK-NOT: LOAD + +.section .foo1, "a" +.quad 0 + +.section .foo2, "ax" +.quad 0 + +.section .foo3, "ax" +.quad 0 diff --git a/deps/lld/test/ELF/linkerscript/merge-header-load.s b/deps/lld/test/ELF/linkerscript/merge-header-load.s new file mode 100644 index 0000000000..5fb866abef --- /dev/null +++ b/deps/lld/test/ELF/linkerscript/merge-header-load.s @@ -0,0 +1,21 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "SECTIONS { \ +# RUN: . = 0xffffffff80000200; \ +# RUN: .text : AT (0x4200) { *(.text) } \ +# RUN: }" > %t.script +# RUN: ld.lld %t.o --script %t.script -o %t +# RUN: llvm-readelf -program-headers %t | FileCheck %s + +# Test that we put the header in the first PT_LOAD. We used to create a PT_LOAD +# just for it and it would have a different virtual to physical address delta. + +# CHECK: Program Headers: +# CHECK: Type Offset VirtAddr PhysAddr +# CHECK-NEXT: PHDR 0x000040 0xffffffff80000040 0x0000000000004040 +# CHECK-NEXT: LOAD 0x000000 0xffffffff80000000 0x0000000000004000 +# CHECK-NOT: LOAD + +.global _start +_start: +nop diff --git a/deps/lld/test/ELF/linkerscript/parse-section-in-addr.s b/deps/lld/test/ELF/linkerscript/parse-section-in-addr.s new file mode 100644 index 0000000000..7a79f64631 --- /dev/null +++ b/deps/lld/test/ELF/linkerscript/parse-section-in-addr.s @@ -0,0 +1,10 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o + +# RUN: echo "SECTIONS { \ +# RUN: .foo-bar : AT(ADDR(.foo-bar)) { *(.text) } \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t.so --script %t.script %t.o -shared +# RUN: llvm-readelf -S %t.so | FileCheck %s + +# CHECK: .foo-bar diff --git a/deps/lld/test/ELF/mips-gp-disp-ver.s b/deps/lld/test/ELF/mips-gp-disp-ver.s new file mode 100644 index 0000000000..134a056a36 --- /dev/null +++ b/deps/lld/test/ELF/mips-gp-disp-ver.s @@ -0,0 +1,15 @@ +# MIPS BFD linker puts _gp_disp symbol into DSO files and assigns zero +# version definition index to it. This value means 'unversioned local symbol' +# while _gp_disp is a section global symbol. We have to handle this bug +# in the LLD because BFD linker is used for building MIPS toolchain +# libraries. This test checks such handling. + +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o +# RUN: ld.lld %t.o %S/Inputs/mips-gp-dips-corrupt-ver.so + +# REQUIRES: mips + + .global __start + .text +__start: + lw $t0, %got(foo)($gp) diff --git a/deps/lld/test/ELF/pie.s b/deps/lld/test/ELF/pie.s index 5964db5c93..3efd6e337c 100644 --- a/deps/lld/test/ELF/pie.s +++ b/deps/lld/test/ELF/pie.s @@ -48,7 +48,7 @@ # CHECK: Type: PT_DYNAMIC ## Check -nopie -# RUN: ld.lld -nopie %t1.o -o %t2 +# RUN: ld.lld -no-pie %t1.o -o %t2 # RUN: llvm-readobj -file-headers -r %t2 | FileCheck %s --check-prefix=NOPIE # NOPIE-NOT: Type: SharedObject diff --git a/deps/lld/test/ELF/x86-64-retpoline-znow.s b/deps/lld/test/ELF/x86-64-retpoline-znow.s new file mode 100644 index 0000000000..6464e2c097 --- /dev/null +++ b/deps/lld/test/ELF/x86-64-retpoline-znow.s @@ -0,0 +1,53 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so + +// RUN: ld.lld -shared %t1.o %t2.so -o %t.exe -z retpolineplt -z now +// RUN: llvm-objdump -d -s %t.exe | FileCheck %s + +// CHECK: Disassembly of section .plt: +// CHECK-NEXT: .plt: +// CHECK-NEXT: 1010: e8 0b 00 00 00 callq 11 <.plt+0x10> +// CHECK-NEXT: 1015: f3 90 pause +// CHECK-NEXT: 1017: 0f ae e8 lfence +// CHECK-NEXT: 101a: eb f9 jmp -7 <.plt+0x5> +// CHECK-NEXT: 101c: cc int3 +// CHECK-NEXT: 101d: cc int3 +// CHECK-NEXT: 101e: cc int3 +// CHECK-NEXT: 101f: cc int3 +// CHECK-NEXT: 1020: 4c 89 1c 24 movq %r11, (%rsp) +// CHECK-NEXT: 1024: c3 retq +// CHECK-NEXT: 1025: cc int3 +// CHECK-NEXT: 1026: cc int3 +// CHECK-NEXT: 1027: cc int3 +// CHECK-NEXT: 1028: cc int3 +// CHECK-NEXT: 1029: cc int3 +// CHECK-NEXT: 102a: cc int3 +// CHECK-NEXT: 102b: cc int3 +// CHECK-NEXT: 102c: cc int3 +// CHECK-NEXT: 102d: cc int3 +// CHECK-NEXT: 102e: cc int3 +// CHECK-NEXT: 102f: cc int3 +// CHECK-NEXT: 1030: 4c 8b 1d c1 10 00 00 movq 4289(%rip), %r11 +// CHECK-NEXT: 1037: e9 d4 ff ff ff jmp -44 <.plt> +// CHECK-NEXT: 103c: cc int3 +// CHECK-NEXT: 103d: cc int3 +// CHECK-NEXT: 103e: cc int3 +// CHECK-NEXT: 103f: cc int3 +// CHECK-NEXT: 1040: 4c 8b 1d b9 10 00 00 movq 4281(%rip), %r11 +// CHECK-NEXT: 1047: e9 c4 ff ff ff jmp -60 <.plt> +// CHECK-NEXT: 104c: cc int3 +// CHECK-NEXT: 104d: cc int3 +// CHECK-NEXT: 104e: cc int3 +// CHECK-NEXT: 104f: cc int3 + +// CHECK: Contents of section .got.plt: +// CHECK-NEXT: 20e0 00200000 00000000 00000000 00000000 +// CHECK-NEXT: 20f0 00000000 00000000 00000000 00000000 +// CHECK-NEXT: 2100 00000000 00000000 + +.global _start +_start: + jmp bar@PLT + jmp zed@PLT diff --git a/deps/lld/test/ELF/x86-64-retpoline.s b/deps/lld/test/ELF/x86-64-retpoline.s new file mode 100644 index 0000000000..535f565331 --- /dev/null +++ b/deps/lld/test/ELF/x86-64-retpoline.s @@ -0,0 +1,66 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so + +// RUN: ld.lld -shared %t1.o %t2.so -o %t.exe -z retpolineplt +// RUN: llvm-objdump -d -s %t.exe | FileCheck %s + +// CHECK: Disassembly of section .plt: +// CHECK-NEXT: .plt: +// CHECK-NEXT: 1010: ff 35 f2 0f 00 00 pushq 4082(%rip) +// CHECK-NEXT: 1016: 4c 8b 1d f3 0f 00 00 movq 4083(%rip), %r11 +// CHECK-NEXT: 101d: e8 0e 00 00 00 callq 14 <.plt+0x20> +// CHECK-NEXT: 1022: f3 90 pause +// CHECK-NEXT: 1024: 0f ae e8 lfence +// CHECK-NEXT: 1027: eb f9 jmp -7 <.plt+0x12> +// CHECK-NEXT: 1029: cc int3 +// CHECK-NEXT: 102a: cc int3 +// CHECK-NEXT: 102b: cc int3 +// CHECK-NEXT: 102c: cc int3 +// CHECK-NEXT: 102d: cc int3 +// CHECK-NEXT: 102e: cc int3 +// CHECK-NEXT: 102f: cc int3 +// CHECK-NEXT: 1030: 4c 89 1c 24 movq %r11, (%rsp) +// CHECK-NEXT: 1034: c3 retq +// CHECK-NEXT: 1035: cc int3 +// CHECK-NEXT: 1036: cc int3 +// CHECK-NEXT: 1037: cc int3 +// CHECK-NEXT: 1038: cc int3 +// CHECK-NEXT: 1039: cc int3 +// CHECK-NEXT: 103a: cc int3 +// CHECK-NEXT: 103b: cc int3 +// CHECK-NEXT: 103c: cc int3 +// CHECK-NEXT: 103d: cc int3 +// CHECK-NEXT: 103e: cc int3 +// CHECK-NEXT: 103f: cc int3 +// CHECK-NEXT: 1040: 4c 8b 1d d1 0f 00 00 movq 4049(%rip), %r11 +// CHECK-NEXT: 1047: e8 e4 ff ff ff callq -28 <.plt+0x20> +// CHECK-NEXT: 104c: e9 d1 ff ff ff jmp -47 <.plt+0x12> +// CHECK-NEXT: 1051: 68 00 00 00 00 pushq $0 +// CHECK-NEXT: 1056: e9 b5 ff ff ff jmp -75 <.plt> +// CHECK-NEXT: 105b: cc int3 +// CHECK-NEXT: 105c: cc int3 +// CHECK-NEXT: 105d: cc int3 +// CHECK-NEXT: 105e: cc int3 +// CHECK-NEXT: 105f: cc int3 +// CHECK-NEXT: 1060: 4c 8b 1d b9 0f 00 00 movq 4025(%rip), %r11 +// CHECK-NEXT: 1067: e8 c4 ff ff ff callq -60 <.plt+0x20> +// CHECK-NEXT: 106c: e9 b1 ff ff ff jmp -79 <.plt+0x12> +// CHECK-NEXT: 1071: 68 01 00 00 00 pushq $1 +// CHECK-NEXT: 1076: e9 95 ff ff ff jmp -107 <.plt> +// CHECK-NEXT: 107b: cc int3 +// CHECK-NEXT: 107c: cc int3 +// CHECK-NEXT: 107d: cc int3 +// CHECK-NEXT: 107e: cc int3 +// CHECK-NEXT: 107f: cc int3 + +// CHECK: Contents of section .got.plt: +// CHECK-NEXT: 2000 00300000 00000000 00000000 00000000 +// CHECK-NEXT: 2010 00000000 00000000 51100000 00000000 +// CHECK-NEXT: 2020 71100000 00000000 + +.global _start +_start: + jmp bar@PLT + jmp zed@PLT -- cgit v1.2.3