diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-06-10 13:44:49 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-06-10 13:44:49 +0000 |
commit | 2079716dfb3fb7e4e24b8b2e85eb6780b981a0af (patch) | |
tree | 3b0c58e50948b450b50b20ae5a38c005128edfb5 | |
parent | b9a1baec33e911ca24f51abf882d454e62047ea6 (diff) |
Notes
85 files changed, 1483 insertions, 737 deletions
diff --git a/COFF/CMakeLists.txt b/COFF/CMakeLists.txt index 14f553e540d9..e56593497000 100644 --- a/COFF/CMakeLists.txt +++ b/COFF/CMakeLists.txt @@ -25,6 +25,7 @@ add_lld_library(lldCOFF LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} + BinaryFormat BitReader Core DebugInfoCodeView diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp index 791d96ee92a5..359dbe69559f 100644 --- a/COFF/Chunks.cpp +++ b/COFF/Chunks.cpp @@ -12,8 +12,8 @@ #include "InputFiles.h" #include "Symbols.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/COFF.h" -#include "llvm/Support/COFF.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" #include "llvm/Support/raw_ostream.h" diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp index 96c328b30518..27b1c48ce3e5 100644 --- a/COFF/Driver.cpp +++ b/COFF/Driver.cpp @@ -18,6 +18,7 @@ #include "lld/Driver/Driver.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/BinaryFormat/Magic.h" #include "llvm/Object/ArchiveWriter.h" #include "llvm/Object/COFFImportFile.h" #include "llvm/Object/COFFModuleDefinition.h" @@ -40,8 +41,6 @@ using namespace llvm; using namespace llvm::object; using namespace llvm::COFF; using llvm::sys::Process; -using llvm::sys::fs::file_magic; -using llvm::sys::fs::identify_magic; namespace lld { namespace coff { @@ -457,17 +456,11 @@ static void createImportLibrary() { static void parseModuleDefs(StringRef Path) { std::unique_ptr<MemoryBuffer> MB = check( MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path); - MemoryBufferRef MBRef = MB->getMemBufferRef(); - - Expected<COFFModuleDefinition> Def = - parseCOFFModuleDefinition(MBRef, Config->Machine); - if (!Def) - fatal(errorToErrorCode(Def.takeError()).message()); + COFFModuleDefinition M = + check(parseCOFFModuleDefinition(MB->getMemBufferRef(), Config->Machine)); - COFFModuleDefinition &M = *Def; if (Config->OutputFile.empty()) Config->OutputFile = Saver.save(M.OutputFile); - if (M.ImageBase) Config->ImageBase = M.ImageBase; if (M.StackReserve) diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp index 258d9fd74b4d..58e8dd329f1f 100644 --- a/COFF/InputFiles.cpp +++ b/COFF/InputFiles.cpp @@ -19,9 +19,9 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/Binary.h" #include "llvm/Object/COFF.h" -#include "llvm/Support/COFF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt index 41da497abe26..c852198bb240 100644 --- a/ELF/CMakeLists.txt +++ b/ELF/CMakeLists.txt @@ -36,6 +36,7 @@ add_lld_library(lldELF LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} Analysis + BinaryFormat BitReader BitWriter Codegen diff --git a/ELF/Config.h b/ELF/Config.h index 54f6dc2acc7c..9c73b4c9c068 100644 --- a/ELF/Config.h +++ b/ELF/Config.h @@ -13,9 +13,9 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/CachePruning.h" #include "llvm/Support/CodeGen.h" -#include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" #include <vector> @@ -67,6 +67,12 @@ struct VersionDefinition { size_t NameOff = 0; // Offset in the string table }; +// Structure for mapping renamed symbols +struct RenamedSymbol { + Symbol *Target; + uint8_t OrigBinding; +}; + // This struct contains the global configuration for the linker. // Most fields are direct mapping from the command line options // and such fields have the same name as the corresponding options. @@ -98,6 +104,7 @@ struct Configuration { std::vector<SymbolVersion> VersionScriptGlobals; std::vector<SymbolVersion> VersionScriptLocals; std::vector<uint8_t> BuildIdVector; + llvm::MapVector<Symbol *, RenamedSymbol> RenamedSymbols; bool AllowMultipleDefinition; bool AsNeeded = false; bool Bsymbolic; diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index 325404447b24..f3943b5cf655 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -185,7 +185,7 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) { // is attempting LTO and using a default ar command that doesn't // understand the LLVM bitcode file. It is a pretty common error, so // we'll handle it as if it had a symbol table. - if (!File->hasSymbolTable()) { + if (!File->isEmpty() && !File->hasSymbolTable()) { for (const auto &P : getArchiveMembers(MBRef)) Files.push_back(make<LazyObjectFile>(P.first, Path, P.second)); return; @@ -970,6 +970,14 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { Symtab.scanShlibUndefined(); Symtab.scanVersionScript(); + // Create wrapped symbols for -wrap option. + for (auto *Arg : Args.filtered(OPT_wrap)) + Symtab.addSymbolWrap(Arg->getValue()); + + // Create alias symbols for -defsym option. + for (std::pair<StringRef, StringRef> &Def : getDefsym(Args)) + Symtab.addSymbolAlias(Def.first, Def.second); + Symtab.addCombinedLTOObject(); if (ErrorCount) return; @@ -979,12 +987,8 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { for (StringRef Sym : Script->Opt.ReferencedSymbols) Symtab.addUndefined(Sym); - for (auto *Arg : Args.filtered(OPT_wrap)) - Symtab.wrap(Arg->getValue()); - - // Handle --defsym=sym=alias option. - for (std::pair<StringRef, StringRef> &Def : getDefsym(Args)) - Symtab.alias(Def.first, Def.second); + // Apply symbol renames for -wrap and -defsym + Symtab.applySymbolRenames(); // Now that we have a complete list of input files. // Beyond this point, no new files are added. diff --git a/ELF/EhFrame.cpp b/ELF/EhFrame.cpp index 90be30a5f0f9..c4e3f65c730e 100644 --- a/ELF/EhFrame.cpp +++ b/ELF/EhFrame.cpp @@ -22,8 +22,8 @@ #include "Relocations.h" #include "Strings.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Object/ELF.h" -#include "llvm/Support/Dwarf.h" #include "llvm/Support/Endian.h" using namespace llvm; diff --git a/ELF/GdbIndex.h b/ELF/GdbIndex.h index 03fec64f9bd5..527667f7280e 100644 --- a/ELF/GdbIndex.h +++ b/ELF/GdbIndex.h @@ -24,7 +24,30 @@ struct AddressEntry { InputSection *Section; uint64_t LowAddress; uint64_t HighAddress; - size_t CuIndex; + uint32_t CuIndex; +}; + +// Struct represents single entry of compilation units list area of gdb index. +// It consist of CU offset in .debug_info section and it's size. +struct CompilationUnitEntry { + uint64_t CuOffset; + uint64_t CuLength; +}; + +// Represents data about symbol and type names which are used +// to build symbol table and constant pool area of gdb index. +struct NameTypeEntry { + StringRef Name; + uint8_t Type; +}; + +// We fill one GdbIndexDataChunk for each object where scan of +// debug information performed. That information futher used +// for filling gdb index section areas. +struct GdbIndexChunk { + std::vector<AddressEntry> AddressArea; + std::vector<CompilationUnitEntry> CompilationUnits; + std::vector<NameTypeEntry> NamesAndTypes; }; // Element of GdbHashTab hash table. diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp index 419ae6816328..536032bdc3a8 100644 --- a/ELF/ICF.cpp +++ b/ELF/ICF.cpp @@ -78,8 +78,8 @@ #include "SymbolTable.h" #include "Threads.h" #include "llvm/ADT/Hashing.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/ELF.h" -#include "llvm/Support/ELF.h" #include <algorithm> #include <atomic> diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index 98189825ccbf..524246ed1d17 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -306,21 +306,23 @@ void elf::ObjectFile<ELFT>::initializeSections( switch (Sec.sh_type) { case SHT_GROUP: { - // We discard comdat sections usually. When -r we should not do that. We - // still do deduplication in this case to simplify implementation, because - // otherwise merging group sections together would requre additional - // regeneration of its contents. - bool New = ComdatGroups - .insert(CachedHashStringRef( - getShtGroupSignature(ObjSections, Sec))) - .second; - if (New && Config->Relocatable) - this->Sections[I] = createInputSection(Sec, SectionStringTable); - else - this->Sections[I] = &InputSection::Discarded; - if (New) + // De-duplicate section groups by their signatures. + StringRef Signature = getShtGroupSignature(ObjSections, Sec); + bool IsNew = ComdatGroups.insert(CachedHashStringRef(Signature)).second; + this->Sections[I] = &InputSection::Discarded; + + // If it is a new section group, we want to keep group members. + // Group leader sections, which contain indices of group members, are + // discarded because they are useless beyond this point. The only + // exception is the -r option because in order to produce re-linkable + // object files, we want to pass through basically everything. + if (IsNew) { + if (Config->Relocatable) + this->Sections[I] = createInputSection(Sec, SectionStringTable); continue; + } + // Otherwise, discard group members. for (uint32_t SecIndex : getShtGroupEntries(Sec)) { if (SecIndex >= Size) fatal(toString(this) + diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index 4af05c1a187b..e82f8c3016fa 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -20,6 +20,7 @@ #include "Target.h" #include "Thunks.h" #include "llvm/Object/Decompressor.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Path.h" @@ -72,6 +73,16 @@ InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags, this->Alignment = V; } +// Drop SHF_GROUP bit unless we are producing a re-linkable object file. +// SHF_GROUP is a marker that a section belongs to some comdat group. +// That flag doesn't make sense in an executable. +static uint64_t getFlags(uint64_t Flags) { + Flags &= ~(uint64_t)SHF_INFO_LINK; + if (!Config->Relocatable) + Flags &= ~(uint64_t)SHF_GROUP; + return Flags; +} + // 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 @@ -94,7 +105,7 @@ template <class ELFT> InputSectionBase::InputSectionBase(elf::ObjectFile<ELFT> *File, const typename ELFT::Shdr *Hdr, StringRef Name, Kind SectionKind) - : InputSectionBase(File, Hdr->sh_flags & ~SHF_INFO_LINK, + : InputSectionBase(File, getFlags(Hdr->sh_flags), getType(Hdr->sh_type, Name), Hdr->sh_entsize, Hdr->sh_link, Hdr->sh_info, Hdr->sh_addralign, getSectionContents(File, Hdr), Name, SectionKind) { @@ -308,23 +319,21 @@ OutputSection *InputSection::getParent() const { return cast_or_null<OutputSection>(Parent); } -void InputSection::copyShtGroup(uint8_t *Buf) { - assert(this->Type == SHT_GROUP); +// Copy SHT_GROUP section contents. Used only for the -r option. +template <class ELFT> void InputSection::copyShtGroup(uint8_t *Buf) { + // ELFT::Word is the 32-bit integral type in the target endianness. + typedef typename ELFT::Word u32; + ArrayRef<u32> From = getDataAs<u32>(); + auto *To = reinterpret_cast<u32 *>(Buf); - ArrayRef<uint32_t> From = getDataAs<uint32_t>(); - uint32_t *To = reinterpret_cast<uint32_t *>(Buf); - - // First entry is a flag word, we leave it unchanged. + // The first entry is not a section number but a flag. *To++ = From[0]; - // Here we adjust indices of sections that belong to group as it - // might change during linking. + // Adjust section numbers because section numbers in an input object + // files are different in the output. ArrayRef<InputSectionBase *> Sections = this->File->getSections(); - for (uint32_t Val : From.slice(1)) { - uint32_t Index = read32(&Val, Config->Endianness); - write32(To++, Sections[Index]->getOutputSection()->SectionIndex, - Config->Endianness); - } + for (uint32_t Idx : From.slice(1)) + *To++ = Sections[Idx]->getOutputSection()->SectionIndex; } InputSectionBase *InputSection::getRelocatedSection() { @@ -682,7 +691,7 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) { // Patch a nop (0x60000000) to a ld. if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == 0x60000000) write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1) - // fallthrough + LLVM_FALLTHROUGH; default: Target->relocateOne(BufLoc, Type, TargetVA); break; @@ -712,10 +721,9 @@ template <class ELFT> void InputSection::writeTo(uint8_t *Buf) { return; } - // If -r is given, linker should keep SHT_GROUP sections. We should fixup - // them, see copyShtGroup(). + // If -r is given, we may have a SHT_GROUP section. if (this->Type == SHT_GROUP) { - copyShtGroup(Buf + OutSecOff); + copyShtGroup<ELFT>(Buf + OutSecOff); return; } diff --git a/ELF/InputSection.h b/ELF/InputSection.h index 97ca2133f905..d262b589219a 100644 --- a/ELF/InputSection.h +++ b/ELF/InputSection.h @@ -325,7 +325,7 @@ private: template <class ELFT, class RelTy> void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels); - void copyShtGroup(uint8_t *Buf); + template <class ELFT> void copyShtGroup(uint8_t *Buf); }; // The list of all input sections. diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp index 6915d9713891..3a536271db4c 100644 --- a/ELF/LTO.cpp +++ b/ELF/LTO.cpp @@ -17,13 +17,13 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/LTO/Caching.h" #include "llvm/LTO/Config.h" #include "llvm/LTO/LTO.h" #include "llvm/Object/SymbolicFile.h" #include "llvm/Support/CodeGen.h" -#include "llvm/Support/ELF.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" @@ -136,6 +136,7 @@ void BitcodeCompiler::add(BitcodeFile &F) { Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym()); if (R.Prevailing) undefine(Sym); + R.LinkerRedefined = Config->RenamedSymbols.count(Sym); } checkError(LTOObj->add(std::move(F.Obj), Resols)); } diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index 1ced3e8e8d71..9dd7ba52be19 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -25,9 +25,9 @@ #include "Writer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/ELF.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" @@ -54,7 +54,7 @@ uint64_t ExprValue::getValue() const { if (Sec) { if (OutputSection *OS = Sec->getOutputSection()) return alignTo(Sec->getOffset(Val) + OS->Addr, Alignment); - error("unable to evaluate expression: input section " + Sec->Name + + error(Loc + ": unable to evaluate expression: input section " + Sec->Name + " has no output section assigned"); } return alignTo(Val, Alignment); @@ -431,6 +431,8 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { if (OutputSection *Sec = Cmd->Sec) { assert(Sec->SectionIndex == INT_MAX); Sec->SectionIndex = I; + if (Cmd->Noload) + Sec->Type = SHT_NOBITS; SecToCommand[Sec] = Cmd; } } @@ -442,7 +444,7 @@ void LinkerScript::fabricateDefaultCommands() { std::vector<BaseCommand *> Commands; // Define start address - uint64_t StartAddr = Config->ImageBase + elf::getHeaderSize(); + uint64_t StartAddr = -1; // The Sections with -T<section> have been sorted in order of ascending // address. We must lower StartAddr if the lowest -T<section address> as @@ -450,8 +452,12 @@ void LinkerScript::fabricateDefaultCommands() { for (auto& KV : Config->SectionStartMap) StartAddr = std::min(StartAddr, KV.second); - Commands.push_back( - make<SymbolAssignment>(".", [=] { return StartAddr; }, "")); + Commands.push_back(make<SymbolAssignment>( + ".", + [=] { + return std::min(StartAddr, Config->ImageBase + elf::getHeaderSize()); + }, + "")); // For each OutputSection that needs a VA fabricate an OutputSectionCommand // with an InputSectionDescription describing the InputSections @@ -870,51 +876,6 @@ void LinkerScript::processNonSectionCommands() { } } -// 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<OutputSectionCommand>(Base); - if (!Cmd) - continue; - ArrayRef<InputSection *> Sections = Cmd->Sec->Sections; - std::vector<InputSection **> ScriptSections; - DenseSet<InputSection *> ScriptSectionsSet; - for (BaseCommand *Base : Cmd->Commands) { - auto *ISD = dyn_cast<InputSectionDescription>(Base); - if (!ISD) - continue; - for (InputSection *&IS : ISD->Sections) { - if (IS->Live) { - ScriptSections.push_back(&IS); - ScriptSectionsSet.insert(IS); - } - } - } - std::vector<InputSection *> Missing; - for (InputSection *IS : Sections) - if (!ScriptSectionsSet.count(IS)) - Missing.push_back(IS); - if (!Missing.empty()) { - auto ISD = make<InputSectionDescription>(""); - 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<PhdrEntry> &Phdrs, ArrayRef<OutputSectionCommand *> OutputSectionCommands, @@ -1071,6 +1032,81 @@ static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) { llvm_unreachable("unsupported Size argument"); } +static bool compareByFilePosition(InputSection *A, InputSection *B) { + // Synthetic doesn't have link order dependecy, stable_sort will keep it last + if (A->kind() == InputSectionBase::Synthetic || + B->kind() == InputSectionBase::Synthetic) + return false; + InputSection *LA = A->getLinkOrderDep(); + InputSection *LB = B->getLinkOrderDep(); + OutputSection *AOut = LA->getParent(); + OutputSection *BOut = LB->getParent(); + if (AOut != BOut) + return AOut->SectionIndex < BOut->SectionIndex; + return LA->OutSecOff < LB->OutSecOff; +} + +template <class ELFT> +static void finalizeShtGroup(OutputSection *OS, + ArrayRef<InputSection *> Sections) { + // sh_link field for SHT_GROUP sections should contain the section index of + // the symbol table. + OS->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<ELFT> *Obj = Sections[0]->getFile<ELFT>(); + assert(Config->Relocatable && Sections.size() == 1); + ArrayRef<SymbolBody *> Symbols = Obj->getSymbols(); + OS->Info = InX::SymTab->getSymbolIndex(Symbols[Sections[0]->Info - 1]); +} + +template <class ELFT> void OutputSectionCommand::finalize() { + // Link order may be distributed across several InputSectionDescriptions + // but sort must consider them all at once. + std::vector<InputSection **> ScriptSections; + std::vector<InputSection *> Sections; + for (BaseCommand *Base : Commands) + if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) + for (InputSection *&IS : ISD->Sections) { + ScriptSections.push_back(&IS); + Sections.push_back(IS); + } + + if ((Sec->Flags & SHF_LINK_ORDER)) { + std::sort(Sections.begin(), Sections.end(), compareByFilePosition); + for (int I = 0, N = Sections.size(); I < N; ++I) + *ScriptSections[I] = Sections[I]; + + // 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 = Sections.front()->getLinkOrderDep()) + Sec->Link = D->getParent()->SectionIndex; + } + + uint32_t Type = Sec->Type; + if (Type == SHT_GROUP) { + finalizeShtGroup<ELFT>(Sec, Sections); + return; + } + + if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL)) + return; + + InputSection *First = Sections[0]; + if (isa<SyntheticSection>(First)) + return; + + Sec->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(); + Sec->Info = S->getOutputSection()->SectionIndex; + Sec->Flags |= SHF_INFO_LINK; +} + // Compress section contents if this section contains debug info. template <class ELFT> void OutputSectionCommand::maybeCompress() { typedef typename ELFT::Chdr Elf_Chdr; @@ -1099,6 +1135,9 @@ template <class ELFT> void OutputSectionCommand::maybeCompress() { } template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) { + if (Sec->Type == SHT_NOBITS) + return; + Sec->Loc = Buf; // We may have already rendered compressed content when using @@ -1110,9 +1149,6 @@ template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) { return; } - if (Sec->Type == SHT_NOBITS) - return; - // Write leading padding. std::vector<InputSection *> Sections; for (BaseCommand *Cmd : Commands) @@ -1156,12 +1192,12 @@ bool LinkerScript::hasLMA(OutputSection *Sec) { ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) { if (S == ".") - return {CurOutSec, Dot - CurOutSec->Addr}; + return {CurOutSec, Dot - CurOutSec->Addr, Loc}; if (SymbolBody *B = findSymbol(S)) { if (auto *D = dyn_cast<DefinedRegular>(B)) - return {D->Section, D->Value}; + return {D->Section, D->Value, Loc}; if (auto *C = dyn_cast<DefinedCommon>(B)) - return {InX::Common, C->Offset}; + return {InX::Common, C->Offset, Loc}; } error(Loc + ": symbol not found: " + S); return 0; @@ -1201,3 +1237,8 @@ template void OutputSectionCommand::maybeCompress<ELF32LE>(); template void OutputSectionCommand::maybeCompress<ELF32BE>(); template void OutputSectionCommand::maybeCompress<ELF64LE>(); template void OutputSectionCommand::maybeCompress<ELF64BE>(); + +template void OutputSectionCommand::finalize<ELF32LE>(); +template void OutputSectionCommand::finalize<ELF32BE>(); +template void OutputSectionCommand::finalize<ELF64LE>(); +template void OutputSectionCommand::finalize<ELF64BE>(); diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h index a708ea7f61d5..1d4c736763fb 100644 --- a/ELF/LinkerScript.h +++ b/ELF/LinkerScript.h @@ -42,15 +42,14 @@ struct ExprValue { uint64_t Val; bool ForceAbsolute; uint64_t Alignment = 1; + std::string Loc; 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) {} + const Twine &Loc) + : Sec(Sec), Val(Val), ForceAbsolute(ForceAbsolute), Loc(Loc.str()) {} + ExprValue(SectionBase *Sec, uint64_t Val, const Twine &Loc) + : ExprValue(Sec, false, Val, Loc) {} + ExprValue(uint64_t Val) : ExprValue(nullptr, Val, "") {} bool isAbsolute() const { return ForceAbsolute || Sec == nullptr; } uint64_t getValue() const; uint64_t getSecAddr() const; @@ -135,7 +134,9 @@ struct OutputSectionCommand : BaseCommand { ConstraintKind Constraint = ConstraintKind::NoConstraint; std::string Location; std::string MemoryRegionName; + bool Noload = false; + template <class ELFT> void finalize(); template <class ELFT> void writeTo(uint8_t *Buf); template <class ELFT> void maybeCompress(); uint32_t getFiller(); @@ -281,7 +282,6 @@ public: void assignOffsets(OutputSectionCommand *Cmd); void placeOrphanSections(); void processNonSectionCommands(); - void synchronize(); void assignAddresses(std::vector<PhdrEntry> &Phdrs, ArrayRef<OutputSectionCommand *> OutputSectionCommands); diff --git a/ELF/Mips.cpp b/ELF/Mips.cpp index ac65672b70fc..af92fb9d24fd 100644 --- a/ELF/Mips.cpp +++ b/ELF/Mips.cpp @@ -16,8 +16,8 @@ #include "SymbolTable.h" #include "Writer.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/ELF.h" -#include "llvm/Support/ELF.h" #include "llvm/Support/MipsABIFlags.h" using namespace llvm; diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index 8357d6b03bb1..008871fd3889 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -16,7 +16,7 @@ #include "SyntheticSections.h" #include "Target.h" #include "Threads.h" -#include "llvm/Support/Dwarf.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/SHA1.h" @@ -70,67 +70,6 @@ OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags) /*Link*/ 0), SectionIndex(INT_MAX) {} -static bool compareByFilePosition(InputSection *A, InputSection *B) { - // Synthetic doesn't have link order dependecy, stable_sort will keep it last - if (A->kind() == InputSectionBase::Synthetic || - B->kind() == InputSectionBase::Synthetic) - return false; - InputSection *LA = A->getLinkOrderDep(); - InputSection *LB = B->getLinkOrderDep(); - OutputSection *AOut = LA->getParent(); - OutputSection *BOut = LB->getParent(); - if (AOut != BOut) - return AOut->SectionIndex < BOut->SectionIndex; - return LA->OutSecOff < LB->OutSecOff; -} - -template <class ELFT> static void finalizeShtGroup(OutputSection *Sec) { - // sh_link field for SHT_GROUP sections should contain the section index of - // the symbol table. - Sec->Link = InX::SymTab->getParent()->SectionIndex; - - // sh_info then contain index of an entry in symbol table section which - // provides signature of the section group. - elf::ObjectFile<ELFT> *Obj = Sec->Sections[0]->getFile<ELFT>(); - assert(Config->Relocatable && Sec->Sections.size() == 1); - ArrayRef<SymbolBody *> Symbols = Obj->getSymbols(); - Sec->Info = InX::SymTab->getSymbolIndex(Symbols[Sec->Sections[0]->Info - 1]); -} - -template <class ELFT> void OutputSection::finalize() { - if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) { - std::sort(Sections.begin(), Sections.end(), compareByFilePosition); - assignOffsets(); - - // We must preserve the link order dependency of sections with the - // SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We - // need to translate the InputSection sh_link to the OutputSection sh_link, - // all InputSections in the OutputSection have the same dependency. - if (auto *D = this->Sections.front()->getLinkOrderDep()) - this->Link = D->getParent()->SectionIndex; - } - - uint32_t Type = this->Type; - if (Type == SHT_GROUP) { - finalizeShtGroup<ELFT>(this); - return; - } - - if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL)) - return; - - InputSection *First = Sections[0]; - if (isa<SyntheticSection>(First)) - return; - - this->Link = InX::SymTab->getParent()->SectionIndex; - // sh_info for SHT_REL[A] sections should contain the section header index of - // the section to which the relocation applies. - InputSectionBase *S = First->getRelocatedSection(); - Info = S->getOutputSection()->SectionIndex; - Flags |= SHF_INFO_LINK; -} - static uint64_t updateOffset(uint64_t Off, InputSection *S) { Off = alignTo(Off, S->Alignment); S->OutSecOff = Off; @@ -162,9 +101,12 @@ void OutputSection::addSection(InputSection *S) { // This function is called after we sort input sections // and scan relocations to setup sections' offsets. void OutputSection::assignOffsets() { + OutputSectionCommand *Cmd = Script->getCmd(this); uint64_t Off = 0; - for (InputSection *S : Sections) - Off = updateOffset(Off, S); + for (BaseCommand *Base : Cmd->Commands) + if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) + for (InputSection *S : ISD->Sections) + Off = updateOffset(Off, S); this->Size = Off; } @@ -333,6 +275,31 @@ void elf::reportDiscarded(InputSectionBase *IS) { void OutputSectionFactory::addInputSec(InputSectionBase *IS, StringRef OutsecName) { + // Sections with the SHT_GROUP attribute reach here only when the - r option + // is given. Such sections define "section groups", and InputFiles.cpp has + // dedup'ed section groups by their signatures. For the -r, we want to pass + // through all SHT_GROUP sections without merging them because merging them + // creates broken section contents. + if (IS->Type == SHT_GROUP) { + OutputSection *Out = nullptr; + addInputSec(IS, OutsecName, Out); + return; + } + + // Imagine .zed : { *(.foo) *(.bar) } script. Both foo and bar may have + // relocation sections .rela.foo and .rela.bar for example. Most tools do + // not allow multiple REL[A] sections for output section. Hence we + // should combine these relocation sections into single output. + // We skip synthetic sections because it can be .rela.dyn/.rela.plt or any + // other REL[A] sections created by linker itself. + if (!isa<SyntheticSection>(IS) && + (IS->Type == SHT_REL || IS->Type == SHT_RELA)) { + auto *Sec = cast<InputSection>(IS); + OutputSection *Out = Sec->getRelocatedSection()->getOutputSection(); + addInputSec(IS, OutsecName, Out->RelocationSection); + return; + } + SectionKey Key = createKey(IS, OutsecName); OutputSection *&Sec = Map[Key]; return addInputSec(IS, OutsecName, Sec); @@ -346,10 +313,6 @@ void OutputSectionFactory::addInputSec(InputSectionBase *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 + @@ -366,9 +329,9 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS, "\n>>> output section " + Sec->Name + ": " + getELFSectionTypeName(Config->EMachine, Sec->Type)); } - Sec->Flags |= Flags; + Sec->Flags |= IS->Flags; } else { - Sec = make<OutputSection>(OutsecName, IS->Type, Flags); + Sec = make<OutputSection>(OutsecName, IS->Type, IS->Flags); OutputSections.push_back(Sec); } @@ -405,8 +368,3 @@ template void OutputSection::writeHeaderTo<ELF32LE>(ELF32LE::Shdr *Shdr); template void OutputSection::writeHeaderTo<ELF32BE>(ELF32BE::Shdr *Shdr); template void OutputSection::writeHeaderTo<ELF64LE>(ELF64LE::Shdr *Shdr); template void OutputSection::writeHeaderTo<ELF64BE>(ELF64BE::Shdr *Shdr); - -template void OutputSection::finalize<ELF32LE>(); -template void OutputSection::finalize<ELF32BE>(); -template void OutputSection::finalize<ELF64LE>(); -template void OutputSection::finalize<ELF64BE>(); diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h index 0f2fe68ca708..7b093fb9dee7 100644 --- a/ELF/OutputSections.h +++ b/ELF/OutputSections.h @@ -67,6 +67,11 @@ public: // formula: Off = Off_first + VA - VA_first. OutputSection *FirstInPtLoad = nullptr; + // Pointer to a relocation section for this section. Usually nullptr because + // we consume relocations, but if --emit-relocs is specified (which is rare), + // it may have a non-null value. + OutputSection *RelocationSection = nullptr; + // The following fields correspond to Elf_Shdr members. uint64_t Size = 0; uint64_t Offset = 0; @@ -78,7 +83,6 @@ public: void sort(std::function<int(InputSectionBase *S)> Order); void sortInitFini(); void sortCtorsDtors(); - template <class ELFT> void finalize(); void assignOffsets(); std::vector<InputSection *> Sections; diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index 54cc6dd89d46..98c1349a2f0d 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -43,6 +43,7 @@ #include "Relocations.h" #include "Config.h" +#include "LinkerScript.h" #include "Memory.h" #include "OutputSections.h" #include "Strings.h" @@ -967,48 +968,51 @@ template <class ELFT> void elf::scanRelocations(InputSectionBase &S) { // 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<ThunkSection *> &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<InputSection *> 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<ThunkSection>(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(); +void ThunkCreator::mergeThunks() { + for (auto &KV : ThunkSections) { + std::vector<InputSection *> *ISR = KV.first; + std::vector<ThunkSection *> &Thunks = KV.second; + + // 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<InputSection *> Tmp; + Tmp.reserve(ISR->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<ThunkSection>(A)) + if (TA && TA->getTargetInputSection() == B) + return true; + return false; + }; + std::merge(ISR->begin(), ISR->end(), Thunks.begin(), Thunks.end(), + std::back_inserter(Tmp), MergeCmp); + *ISR = std::move(Tmp); + } } -ThunkSection *ThunkCreator::getOSThunkSec(ThunkSection *&TS, - OutputSection *OS) { - if (TS == nullptr) { +ThunkSection *ThunkCreator::getOSThunkSec(OutputSection *OS, + std::vector<InputSection *> *ISR) { + if (CurTS == nullptr) { uint32_t Off = 0; for (auto *IS : OS->Sections) { Off = IS->OutSecOff + IS->getSize(); if ((IS->Flags & SHF_EXECINSTR) == 0) break; } - TS = make<ThunkSection>(OS, Off); - ThunkSections[OS].push_back(TS); + CurTS = make<ThunkSection>(OS, Off); + ThunkSections[ISR].push_back(CurTS); } - return TS; + return CurTS; } ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS, OutputSection *OS) { @@ -1017,7 +1021,21 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS, OutputSection *OS) { return TS; auto *TOS = IS->getParent(); TS = make<ThunkSection>(TOS, IS->OutSecOff); - ThunkSections[TOS].push_back(TS); + + // Find InputSectionRange within TOS that IS is in + OutputSectionCommand *C = Script->getCmd(TOS); + std::vector<InputSection *> *Range = nullptr; + for (BaseCommand *BC : C->Commands) + if (auto *ISD = dyn_cast<InputSectionDescription> (BC)) { + InputSection *first = ISD->Sections.front(); + InputSection *last = ISD->Sections.back(); + if (IS->OutSecOff >= first->OutSecOff && + IS->OutSecOff <= last->OutSecOff) { + Range = &ISD->Sections; + break; + } + } + ThunkSections[Range].push_back(TS); ThunkedSections[IS] = TS; return TS; } @@ -1030,6 +1048,27 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(SymbolBody &Body, return std::make_pair(res.first->second, res.second); } +// Call Fn on every executable InputSection accessed via the linker script +// InputSectionDescription::Sections. +void ThunkCreator::forEachExecInputSection( + ArrayRef<OutputSectionCommand *> OutputSections, + std::function<void(OutputSection *, std::vector<InputSection *> *, + InputSection *)> + Fn) { + for (OutputSectionCommand *Cmd : OutputSections) { + OutputSection *OS = Cmd->Sec; + if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR)) + continue; + if (OutputSectionCommand *C = Script->getCmd(OS)) + for (BaseCommand *BC : C->Commands) + if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) { + CurTS = nullptr; + for (InputSection* IS : ISD->Sections) + Fn(OS, &ISD->Sections, IS); + } + } +} + // Process all relocations from the InputSections that have been assigned // to OutputSections and redirect through Thunks if needed. // @@ -1040,42 +1079,41 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(SymbolBody &Body, // // FIXME: All Thunks are assumed to be in range of the relocation. Range // extension Thunks are not yet supported. -bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) { +bool ThunkCreator::createThunks( + ArrayRef<OutputSectionCommand *> 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); + forEachExecInputSection( + OutputSections, [=](OutputSection *OS, std::vector<InputSection*> *ISR, + InputSection *IS) { + 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(OS, ISR); + 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); } - // 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); + mergeThunks(); return !ThunkSections.empty(); } diff --git a/ELF/Relocations.h b/ELF/Relocations.h index 206f0d9423c9..dcbf545cde53 100644 --- a/ELF/Relocations.h +++ b/ELF/Relocations.h @@ -21,6 +21,7 @@ class SymbolBody; class InputSection; class InputSectionBase; class OutputSection; +struct OutputSectionCommand; // List of target-independent relocation types. Relocations read // from files are converted to these types so that the main code @@ -123,12 +124,18 @@ class Thunk; class ThunkCreator { public: // Return true if Thunks have been added to OutputSections - bool createThunks(ArrayRef<OutputSection *> OutputSections); + bool createThunks(ArrayRef<OutputSectionCommand *> OutputSections); private: - void mergeThunks(OutputSection *OS, std::vector<ThunkSection *> &Thunks); - ThunkSection *getOSThunkSec(ThunkSection *&TS, OutputSection *OS); + void mergeThunks(); + ThunkSection *getOSThunkSec(OutputSection *OS, + std::vector<InputSection *> *ISR); ThunkSection *getISThunkSec(InputSection *IS, OutputSection *OS); + void forEachExecInputSection( + ArrayRef<OutputSectionCommand *> OutputSections, + std::function<void(OutputSection *, std::vector<InputSection *> *, + InputSection *)> + Fn); std::pair<Thunk *, bool> getThunk(SymbolBody &Body, uint32_t Type); // Track Symbols that already have a Thunk @@ -138,7 +145,11 @@ private: llvm::DenseMap<InputSection *, ThunkSection *> ThunkedSections; // Track the ThunksSections that need to be inserted into an OutputSection - std::map<OutputSection *, std::vector<ThunkSection *>> ThunkSections; + std::map<std::vector<InputSection *> *, std::vector<ThunkSection *>> + ThunkSections; + + // The ThunkSection for this vector of InputSections + ThunkSection *CurTS; }; // Return a int64_t to make sure we get the sign extension out of the way as diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp index 02212fa8ba14..4a44944fe7ed 100644 --- a/ELF/ScriptParser.cpp +++ b/ELF/ScriptParser.cpp @@ -25,8 +25,8 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/BinaryFormat/ELF.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" @@ -76,6 +76,7 @@ private: BytesDataCommand *readBytesDataCommand(StringRef Tok); uint32_t readFill(); uint32_t parseFill(StringRef Tok); + void readSectionAddressType(OutputSectionCommand *Cmd); OutputSectionCommand *readOutputSectionDescription(StringRef OutSec); std::vector<StringRef> readOutputSectionPhdrs(); InputSectionDescription *readInputSectionDescription(StringRef Tok); @@ -127,16 +128,16 @@ 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"); + error(A.Loc + ": 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()}; + return {A.Sec, A.ForceAbsolute, A.Val + B.getValue(), A.Loc}; } static ExprValue sub(ExprValue A, ExprValue B) { - return {A.Sec, A.Val - B.getValue()}; + return {A.Sec, A.Val - B.getValue(), A.Loc}; } static ExprValue mul(ExprValue A, ExprValue B) { @@ -153,13 +154,13 @@ static ExprValue div(ExprValue A, ExprValue B) { static ExprValue bitAnd(ExprValue A, ExprValue B) { moveAbsRight(A, B); return {A.Sec, A.ForceAbsolute, - (A.getValue() & B.getValue()) - A.getSecAddr()}; + (A.getValue() & B.getValue()) - A.getSecAddr(), A.Loc}; } static ExprValue bitOr(ExprValue A, ExprValue B) { moveAbsRight(A, B); return {A.Sec, A.ForceAbsolute, - (A.getValue() | B.getValue()) - A.getSecAddr()}; + (A.getValue() | B.getValue()) - A.getSecAddr(), A.Loc}; } void ScriptParser::readDynamicList() { @@ -563,16 +564,42 @@ uint32_t ScriptParser::readFill() { return V; } +// Reads an expression and/or the special directive "(NOLOAD)" for an +// output section definition. +// +// An output section name can be followed by an address expression +// and/or by "(NOLOAD)". This grammar is not LL(1) because "(" can be +// interpreted as either the beginning of some expression or "(NOLOAD)". +// +// https://sourceware.org/binutils/docs/ld/Output-Section-Address.html +// https://sourceware.org/binutils/docs/ld/Output-Section-Type.html +void ScriptParser::readSectionAddressType(OutputSectionCommand *Cmd) { + if (consume("(")) { + if (consume("NOLOAD")) { + expect(")"); + Cmd->Noload = true; + return; + } + Cmd->AddrExpr = readExpr(); + expect(")"); + } else { + Cmd->AddrExpr = readExpr(); + } + + if (consume("(")) { + expect("NOLOAD"); + expect(")"); + Cmd->Noload = true; + } +} + OutputSectionCommand * ScriptParser::readOutputSectionDescription(StringRef OutSec) { 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(); - + readSectionAddressType(Cmd); expect(":"); if (consume("AT")) @@ -859,7 +886,9 @@ Expr ScriptParser::readPrimary() { if (Tok == "ADDR") { StringRef Name = readParenLiteral(); OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name); - return [=]() -> ExprValue { return {checkSection(Cmd, Location), 0}; }; + return [=]() -> ExprValue { + return {checkSection(Cmd, Location), 0, Location}; + }; } if (Tok == "ALIGN") { expect("("); diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp index ed8a790c9599..a223aec98624 100644 --- a/ELF/SymbolTable.cpp +++ b/ELF/SymbolTable.cpp @@ -156,7 +156,7 @@ template <class ELFT> void SymbolTable<ELFT>::trace(StringRef Name) { // Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM. // Used to implement --wrap. -template <class ELFT> void SymbolTable<ELFT>::wrap(StringRef Name) { +template <class ELFT> void SymbolTable<ELFT>::addSymbolWrap(StringRef Name) { SymbolBody *B = find(Name); if (!B) return; @@ -164,16 +164,16 @@ template <class ELFT> void SymbolTable<ELFT>::wrap(StringRef Name) { Symbol *Real = addUndefined(Saver.save("__real_" + Name)); Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name)); - // We rename symbols by replacing the old symbol's SymbolBody with the new - // symbol's SymbolBody. This causes all SymbolBody pointers referring to the - // old symbol to instead refer to the new symbol. - memcpy(Real->Body.buffer, Sym->Body.buffer, sizeof(Sym->Body)); - memcpy(Sym->Body.buffer, Wrap->Body.buffer, sizeof(Wrap->Body)); + // Tell LTO not to eliminate this symbol + Wrap->IsUsedInRegularObj = true; + + Config->RenamedSymbols[Real] = RenamedSymbol{Sym, Real->Binding}; + Config->RenamedSymbols[Sym] = RenamedSymbol{Wrap, Sym->Binding}; } // Creates alias for symbol. Used to implement --defsym=ALIAS=SYM. -template <class ELFT> -void SymbolTable<ELFT>::alias(StringRef Alias, StringRef Name) { +template <class ELFT> void SymbolTable<ELFT>::addSymbolAlias(StringRef Alias, + StringRef Name) { SymbolBody *B = find(Name); if (!B) { error("-defsym: undefined symbol: " + Name); @@ -181,7 +181,27 @@ void SymbolTable<ELFT>::alias(StringRef Alias, StringRef Name) { } Symbol *Sym = B->symbol(); Symbol *AliasSym = addUndefined(Alias); - memcpy(AliasSym->Body.buffer, Sym->Body.buffer, sizeof(AliasSym->Body)); + + // Tell LTO not to eliminate this symbol + Sym->IsUsedInRegularObj = true; + Config->RenamedSymbols[AliasSym] = RenamedSymbol{Sym, AliasSym->Binding}; +} + +// Apply symbol renames created by -wrap and -defsym. The renames are created +// before LTO in addSymbolWrap() and addSymbolAlias() to have a chance to inform +// LTO (if LTO is running) not to include these symbols in IPO. Now that the +// symbols are finalized, we can perform the replacement. +template <class ELFT> void SymbolTable<ELFT>::applySymbolRenames() { + for (auto &KV : Config->RenamedSymbols) { + Symbol *Sym = KV.first; + Symbol *Rename = KV.second.Target; + Sym->Binding = KV.second.OrigBinding; + + // We rename symbols by replacing the old symbol's SymbolBody with the new + // symbol's SymbolBody. This causes all SymbolBody pointers referring to the + // old symbol to instead refer to the new symbol. + memcpy(Sym->Body.buffer, Rename->Body.buffer, sizeof(Sym->Body)); + } } static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h index 1a745f9deea5..f38d09760c7e 100644 --- a/ELF/SymbolTable.h +++ b/ELF/SymbolTable.h @@ -39,6 +39,9 @@ template <class ELFT> class SymbolTable { public: void addFile(InputFile *File); void addCombinedLTOObject(); + void addSymbolAlias(StringRef Alias, StringRef Name); + void addSymbolWrap(StringRef Name); + void applySymbolRenames(); ArrayRef<Symbol *> getSymbols() const { return SymVector; } ArrayRef<ObjectFile<ELFT> *> getObjectFiles() const { return ObjectFiles; } @@ -85,8 +88,6 @@ public: SymbolBody *findInCurrentDSO(StringRef Name); void trace(StringRef Name); - void wrap(StringRef Name); - void alias(StringRef Alias, StringRef Name); private: std::vector<SymbolBody *> findByVersion(SymbolVersion Ver); diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp index 67e57d9c8f00..8f9b20477b29 100644 --- a/ELF/Symbols.cpp +++ b/ELF/Symbols.cpp @@ -264,15 +264,14 @@ Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, : SymbolBody(K, Name, IsLocal, StOther, Type) {} template <class ELFT> bool DefinedRegular::isMipsPIC() const { + typedef typename ELFT::Ehdr Elf_Ehdr; if (!Section || !isFunc()) return false; + + auto *Sec = cast<InputSectionBase>(Section); + const Elf_Ehdr *Hdr = Sec->template getFile<ELFT>()->getObj().getHeader(); return (this->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC || - (cast<InputSectionBase>(Section) - ->template getFile<ELFT>() - ->getObj() - .getHeader() - ->e_flags & - EF_MIPS_PIC); + (Hdr->e_flags & EF_MIPS_PIC); } Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index 223fc9a0fd07..5cd6c5f2b914 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -27,9 +27,9 @@ #include "Threads.h" #include "Writer.h" #include "lld/Config/Version.h" +#include "llvm/BinaryFormat/Dwarf.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" @@ -1691,49 +1691,44 @@ static uint32_t hash(StringRef Str) { return R; } -static std::vector<std::pair<uint64_t, uint64_t>> -readCuList(DWARFContext &Dwarf, InputSection *Sec) { - std::vector<std::pair<uint64_t, uint64_t>> Ret; +static std::vector<CompilationUnitEntry> readCuList(DWARFContext &Dwarf, + InputSection *Sec) { + std::vector<CompilationUnitEntry> Ret; for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units()) Ret.push_back({Sec->OutSecOff + CU->getOffset(), CU->getLength() + 4}); return Ret; } -static InputSection *findSection(ArrayRef<InputSectionBase *> Arr, - uint64_t Offset) { - for (InputSectionBase *S : Arr) - if (auto *IS = dyn_cast_or_null<InputSection>(S)) - if (IS != &InputSection::Discarded && IS->Live && - Offset >= IS->getOffsetInFile() && - Offset < IS->getOffsetInFile() + IS->getSize()) - return IS; - return nullptr; -} - -static std::vector<AddressEntry> -readAddressArea(DWARFContext &Dwarf, InputSection *Sec, size_t CurrentCU) { +static std::vector<AddressEntry> readAddressArea(DWARFContext &Dwarf, + InputSection *Sec) { std::vector<AddressEntry> Ret; + uint32_t CurrentCu = 0; for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units()) { DWARFAddressRangesVector Ranges; CU->collectAddressRanges(Ranges); ArrayRef<InputSectionBase *> 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; + for (DWARFAddressRange &R : Ranges) { + InputSectionBase *S = Sections[R.SectionIndex]; + if (!S || S == &InputSection::Discarded || !S->Live) + continue; + // Range list with zero size has no effect. + if (R.LowPC == R.HighPC) + continue; + Ret.push_back({cast<InputSection>(S), R.LowPC, R.HighPC, CurrentCu}); + } + ++CurrentCu; } return Ret; } -static std::vector<std::pair<StringRef, uint8_t>> -readPubNamesAndTypes(DWARFContext &Dwarf, bool IsLE) { +static std::vector<NameTypeEntry> readPubNamesAndTypes(DWARFContext &Dwarf, + bool IsLE) { StringRef Data[] = {Dwarf.getGnuPubNamesSection(), Dwarf.getGnuPubTypesSection()}; - std::vector<std::pair<StringRef, uint8_t>> Ret; + std::vector<NameTypeEntry> Ret; for (StringRef D : Data) { DWARFDebugPubTable PubTable(D, IsLE, true); for (const DWARFDebugPubTable::Set &Set : PubTable.getData()) @@ -1743,52 +1738,77 @@ readPubNamesAndTypes(DWARFContext &Dwarf, bool IsLE) { return Ret; } -class ObjInfoTy : public llvm::LoadedObjectInfo { - uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override { - auto &S = static_cast<const object::ELFSectionRef &>(Sec); - if (S.getFlags() & ELF::SHF_ALLOC) - return S.getOffset(); - return 0; - } +static std::vector<InputSection *> getDebugInfoSections() { + std::vector<InputSection *> Ret; + for (InputSectionBase *S : InputSections) + if (InputSection *IS = dyn_cast<InputSection>(S)) + if (IS->getParent() && IS->Name == ".debug_info") + Ret.push_back(IS); + return Ret; +} - std::unique_ptr<llvm::LoadedObjectInfo> clone() const override { return {}; } -}; +void GdbIndexSection::buildIndex() { + std::vector<InputSection *> V = getDebugInfoSections(); + if (V.empty()) + return; + + for (InputSection *Sec : V) + Chunks.push_back(readDwarf(Sec)); + + uint32_t CuId = 0; + for (GdbIndexChunk &D : Chunks) { + for (AddressEntry &E : D.AddressArea) + E.CuIndex += CuId; + + // Populate constant pool area. + for (NameTypeEntry &NameType : D.NamesAndTypes) { + uint32_t Hash = hash(NameType.Name); + size_t Offset = StringPool.add(NameType.Name); + + bool IsNew; + GdbSymbol *Sym; + std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset); + if (IsNew) { + Sym->CuVectorIndex = CuVectors.size(); + CuVectors.resize(CuVectors.size() + 1); + } -void GdbIndexSection::readDwarf(InputSection *Sec) { + CuVectors[Sym->CuVectorIndex].insert(CuId | (NameType.Type << 24)); + } + + CuId += D.CompilationUnits.size(); + } +} + +GdbIndexChunk GdbIndexSection::readDwarf(InputSection *Sec) { Expected<std::unique_ptr<object::ObjectFile>> Obj = object::ObjectFile::createObjectFile(Sec->File->MB); if (!Obj) { error(toString(Sec->File) + ": error creating DWARF context"); - return; + return {}; } - ObjInfoTy ObjInfo; - DWARFContextInMemory Dwarf(*Obj.get(), &ObjInfo); - - size_t CuId = CompilationUnits.size(); - for (std::pair<uint64_t, uint64_t> &P : readCuList(Dwarf, Sec)) - CompilationUnits.push_back(P); - - for (AddressEntry &Ent : readAddressArea(Dwarf, Sec, CuId)) - AddressArea.push_back(Ent); - - std::vector<std::pair<StringRef, uint8_t>> NamesAndTypes = - readPubNamesAndTypes(Dwarf, Config->IsLE); + DWARFContextInMemory Dwarf(*Obj.get()); - for (std::pair<StringRef, uint8_t> &Pair : NamesAndTypes) { - uint32_t Hash = hash(Pair.first); - size_t Offset = StringPool.add(Pair.first); + GdbIndexChunk Ret; + Ret.CompilationUnits = readCuList(Dwarf, Sec); + Ret.AddressArea = readAddressArea(Dwarf, Sec); + Ret.NamesAndTypes = readPubNamesAndTypes(Dwarf, Config->IsLE); + return Ret; +} - bool IsNew; - GdbSymbol *Sym; - std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset); - if (IsNew) { - Sym->CuVectorIndex = CuVectors.size(); - CuVectors.resize(CuVectors.size() + 1); - } +static size_t getCuSize(std::vector<GdbIndexChunk> &C) { + size_t Ret = 0; + for (GdbIndexChunk &D : C) + Ret += D.CompilationUnits.size(); + return Ret; +} - CuVectors[Sym->CuVectorIndex].insert((Pair.second << 24) | (uint32_t)CuId); - } +static size_t getAddressAreaSize(std::vector<GdbIndexChunk> &C) { + size_t Ret = 0; + for (GdbIndexChunk &D : C) + Ret += D.AddressArea.size(); + return Ret; } void GdbIndexSection::finalizeContents() { @@ -1796,17 +1816,14 @@ void GdbIndexSection::finalizeContents() { return; Finalized = true; - for (InputSectionBase *S : InputSections) - if (InputSection *IS = dyn_cast<InputSection>(S)) - if (IS->getParent() && IS->Name == ".debug_info") - readDwarf(IS); + buildIndex(); 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; + CuTypesOffset = CuListOffset + getCuSize(Chunks) * CompilationUnitSize; + SymTabOffset = CuTypesOffset + getAddressAreaSize(Chunks) * AddressEntrySize; ConstantPoolOffset = SymTabOffset + SymbolTable.getCapacity() * SymTabEntrySize; @@ -1835,19 +1852,24 @@ void GdbIndexSection::writeTo(uint8_t *Buf) { Buf += 24; // Write the CU list. - for (std::pair<uint64_t, uint64_t> CU : CompilationUnits) { - write64le(Buf, CU.first); - write64le(Buf + 8, CU.second); - Buf += 16; + for (GdbIndexChunk &D : Chunks) { + for (CompilationUnitEntry &Cu : D.CompilationUnits) { + write64le(Buf, Cu.CuOffset); + write64le(Buf + 8, Cu.CuLength); + Buf += 16; + } } // Write the address area. - for (AddressEntry &E : AddressArea) { - 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; + for (GdbIndexChunk &D : Chunks) { + for (AddressEntry &E : D.AddressArea) { + 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. diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h index b47d2fab24ec..c807043c9dc2 100644 --- a/ELF/SyntheticSections.h +++ b/ELF/SyntheticSections.h @@ -509,20 +509,23 @@ public: size_t getSize() const override; bool empty() const override; - // Pairs of [CU Offset, CU length]. - std::vector<std::pair<uint64_t, uint64_t>> CompilationUnits; - - llvm::StringTableBuilder StringPool; - + // Symbol table is a hash table for types and names. + // It is the area of gdb index. GdbHashTab SymbolTable; - // The CU vector portion of the constant pool. + // CU vector is a part of constant pool area of section. std::vector<std::set<uint32_t>> CuVectors; - std::vector<AddressEntry> AddressArea; + // String pool is also a part of constant pool, it follows CU vectors. + llvm::StringTableBuilder StringPool; + + // Each chunk contains information gathered from a debug sections of single + // object and used to build different areas of gdb index. + std::vector<GdbIndexChunk> Chunks; private: - void readDwarf(InputSection *Sec); + GdbIndexChunk readDwarf(InputSection *Sec); + void buildIndex(); uint32_t CuTypesOffset; uint32_t SymTabOffset; diff --git a/ELF/Target.cpp b/ELF/Target.cpp index b6c6e7089365..ee5a7690fc64 100644 --- a/ELF/Target.cpp +++ b/ELF/Target.cpp @@ -35,8 +35,8 @@ #include "Thunks.h" #include "Writer.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/ELF.h" -#include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" using namespace llvm; @@ -537,7 +537,17 @@ void X86TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, write16le(Loc, Val); break; case R_386_PC16: - checkInt<16>(Loc, Val, Type); + // R_386_PC16 is normally used with 16 bit code. In that situation + // the PC is 16 bits, just like the addend. This means that it can + // point from any 16 bit address to any other if the possibility + // of wrapping is included. + // The only restriction we have to check then is that the destination + // address fits in 16 bits. That is impossible to do here. The problem is + // that we are passed the final value, which already had the + // current location subtracted from it. + // We just check that Val fits in 17 bits. This misses some cases, but + // should have no false positives. + checkInt<17>(Loc, Val, Type); write16le(Loc, Val); break; default: @@ -2085,7 +2095,7 @@ RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S, return R_MIPS_GOT_GP_PC; if (&S == ElfSym::MipsLocalGp) return R_MIPS_GOT_GP; - // fallthrough + LLVM_FALLTHROUGH; case R_MIPS_GOT_OFST: return R_ABS; case R_MIPS_PC32: @@ -2099,7 +2109,7 @@ RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S, case R_MIPS_GOT16: if (S.isLocal()) return R_MIPS_GOT_LOCAL_PAGE; - // fallthrough + LLVM_FALLTHROUGH; case R_MIPS_CALL16: case R_MIPS_GOT_DISP: case R_MIPS_TLS_GOTTPREL: @@ -2353,7 +2363,7 @@ void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type, case R_MIPS_TLS_GD: case R_MIPS_TLS_LDM: checkInt<16>(Loc, Val, Type); - // fallthrough + LLVM_FALLTHROUGH; case R_MIPS_CALL16: case R_MIPS_CALL_LO16: case R_MIPS_GOT_LO16: diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp index da2b13677513..752a881d7867 100644 --- a/ELF/Thunks.cpp +++ b/ELF/Thunks.cpp @@ -30,8 +30,8 @@ #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/Casting.h" -#include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" @@ -143,7 +143,7 @@ void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal( Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), &IS); + Offset | 0x1, size(), &IS); addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS); } @@ -176,7 +176,7 @@ void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { 0x60, 0x47, // bx r12 }; uint64_t S = getARMThunkDestVA(Destination); - uint64_t P = ThunkSym->getVA(); + uint64_t P = ThunkSym->getVA() & ~0x1; memcpy(Buf, Data, sizeof(Data)); Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, S - P - 12); Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, S - P - 8); @@ -185,7 +185,7 @@ void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal( Saver.save("__ThumbV7PILongThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), &IS); + Offset | 0x1, size(), &IS); addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS); } diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index f68e07fc69d7..ad95a8acced4 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -93,21 +93,14 @@ private: } // anonymous namespace StringRef elf::getOutputSectionName(StringRef Name) { + // ".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)); + 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.", @@ -122,10 +115,6 @@ StringRef elf::getOutputSectionName(StringRef Name) { 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; } @@ -257,18 +246,7 @@ template <class ELFT> void Writer<ELFT>::run() { if (ErrorCount) return; - if (!Script->Opt.HasSections) - Script->fabricateDefaultCommands(); - else - Script->synchronize(); - - for (BaseCommand *Base : Script->Opt.Commands) - if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) - OutputSectionCommands.push_back(Cmd); - - clearOutputSections(); - - if (!Script->Opt.HasSections &&!Config->Relocatable) + if (!Script->Opt.HasSections && !Config->Relocatable) fixSectionAlignments(); // If -compressed-debug-sections is specified, we need to compress @@ -278,22 +256,24 @@ template <class ELFT> void Writer<ELFT>::run() { OutputSectionCommands.begin(), OutputSectionCommands.end(), [](OutputSectionCommand *Cmd) { Cmd->maybeCompress<ELFT>(); }); - if (Config->Relocatable) { - assignFileOffsets(); - } else { - Script->assignAddresses(Phdrs, OutputSectionCommands); + 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(); + // 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(); + if (!Config->OFormatBinary) + assignFileOffsets(); + else + assignFileOffsetsBinary(); + + setPhdrs(); - setPhdrs(); + if (Config->Relocatable) { + for (OutputSectionCommand *Cmd : OutputSectionCommands) + Cmd->Sec->Addr = 0; + } else { fixPredefinedSymbols(); } @@ -915,7 +895,14 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() { // 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<ELFT>("__ehdr_start", Out::ElfHeader, 0, STV_HIDDEN); + // __executable_start is not documented, but the expectation of at + // least the android libc is that it points to the elf header too. + // __dso_handle symbol is passed to cxa_finalize as a marker to identify + // each DSO. The address of the symbol doesn't matter as long as they are + // different in different DSOs, so we chose the start address of the DSO. + for (const char *Name : + {"__ehdr_start", "__executable_start", "__dso_handle"}) + addOptionalRegular<ELFT>(Name, Out::ElfHeader, 0, STV_HIDDEN); // If linker script do layout we do not need to create any standart symbols. if (Script->Opt.HasSections) @@ -1011,9 +998,6 @@ template <class ELFT> void Writer<ELFT>::createSections() { 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. @@ -1116,10 +1100,8 @@ template <class ELFT> void Writer<ELFT>::sortSections() { static void applySynthetic(const std::vector<SyntheticSection *> &Sections, std::function<void(SyntheticSection *)> Fn) { for (SyntheticSection *SS : Sections) - if (SS && SS->getParent() && !SS->empty()) { + if (SS && SS->getParent() && !SS->empty()) Fn(SS); - SS->getParent()->assignOffsets(); - } } // We need to add input synthetic sections early in createSyntheticSections() @@ -1225,6 +1207,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { Sec->ShName = InX::ShStrTab->addString(Sec->Name); } + if (!Script->Opt.HasSections) + Script->fabricateDefaultCommands(); + for (BaseCommand *Base : Script->Opt.Commands) + if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) + OutputSectionCommands.push_back(Cmd); + // 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. @@ -1234,6 +1222,14 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size(); } + clearOutputSections(); + + // Compute the size of .rela.dyn and .rela.plt early since we need + // them to populate .dynamic. + for (SyntheticSection *SS : {In<ELFT>::RelaDyn, In<ELFT>::RelaPlt}) + if (SS->getParent() && !SS->empty()) + SS->getParent()->assignOffsets(); + // 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, @@ -1257,15 +1253,16 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { // 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)) + if (TC.createThunks(OutputSectionCommands)) 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<ELFT>(); + for (OutputSectionCommand *Cmd : OutputSectionCommands) + Cmd->finalize<ELFT>(); // createThunks may have added local symbols to the static symbol table applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab}, diff --git a/include/lld/Core/Reader.h b/include/lld/Core/Reader.h index 5105eb1aa2be..32d04249f378 100644 --- a/include/lld/Core/Reader.h +++ b/include/lld/Core/Reader.h @@ -13,14 +13,13 @@ #include "lld/Core/LLVM.h" #include "lld/Core/Reference.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Magic.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include <memory> #include <vector> -using llvm::sys::fs::file_magic; - namespace llvm { namespace yaml { class IO; @@ -45,7 +44,7 @@ public: /// The method is called with: /// 1) the file_magic enumeration returned by identify_magic() /// 2) the whole file content buffer if the above is not enough. - virtual bool canParse(file_magic magic, MemoryBufferRef mb) const = 0; + virtual bool canParse(llvm::file_magic magic, MemoryBufferRef mb) const = 0; /// \brief Parse a supplied buffer (already filled with the contents of a /// file) and create a File object. diff --git a/include/lld/ReaderWriter/MachOLinkingContext.h b/include/lld/ReaderWriter/MachOLinkingContext.h index a9e80f50b23d..9eefa8c4d944 100644 --- a/include/lld/ReaderWriter/MachOLinkingContext.h +++ b/include/lld/ReaderWriter/MachOLinkingContext.h @@ -16,8 +16,8 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSet.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/MachO.h" #include <set> using llvm::MachO::HeaderFileType; diff --git a/lib/Core/CMakeLists.txt b/lib/Core/CMakeLists.txt index f2bf90509295..85046b93f34f 100644 --- a/lib/Core/CMakeLists.txt +++ b/lib/Core/CMakeLists.txt @@ -18,9 +18,10 @@ add_lld_library(lldCore ${LLD_INCLUDE_DIR}/lld/Core LINK_COMPONENTS + BinaryFormat MC Support - + LINK_LIBS ${LLVM_PTHREAD_LIB} diff --git a/lib/Core/Reader.cpp b/lib/Core/Reader.cpp index 24652abec688..5d8bbbbfe4d7 100644 --- a/lib/Core/Reader.cpp +++ b/lib/Core/Reader.cpp @@ -11,12 +11,16 @@ #include "lld/Core/File.h" #include "lld/Core/Reference.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Magic.h" #include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include <algorithm> #include <memory> +using llvm::file_magic; +using llvm::identify_magic; + namespace lld { YamlIOTaggedDocumentHandler::~YamlIOTaggedDocumentHandler() = default; @@ -33,7 +37,7 @@ ErrorOr<std::unique_ptr<File>> Registry::loadFile(std::unique_ptr<MemoryBuffer> mb) const { // Get file magic. StringRef content(mb->getBufferStart(), mb->getBufferSize()); - llvm::sys::fs::file_magic fileType = llvm::sys::fs::identify_magic(content); + file_magic fileType = identify_magic(content); // Ask each registered reader if it can handle this file type or extension. for (const std::unique_ptr<Reader> &reader : _readers) { diff --git a/lib/Core/SymbolTable.cpp b/lib/Core/SymbolTable.cpp index cacea5f30847..583c65acb5d3 100644 --- a/lib/Core/SymbolTable.cpp +++ b/lib/Core/SymbolTable.cpp @@ -161,7 +161,7 @@ bool SymbolTable::addByName(const Atom &newAtom) { llvm::errs() << "Size mismatch: " << existing->name() << " (" << existingSize << ") " << newAtom.name() << " (" << newSize << ")\n"; - // fallthrough + LLVM_FALLTHROUGH; } case MCR_Error: llvm::errs() << "Duplicate symbols: " diff --git a/lib/Driver/DarwinLdDriver.cpp b/lib/Driver/DarwinLdDriver.cpp index 9b4aede19aa2..c859c9802349 100644 --- a/lib/Driver/DarwinLdDriver.cpp +++ b/lib/Driver/DarwinLdDriver.cpp @@ -18,30 +18,30 @@ #include "lld/Core/File.h" #include "lld/Core/Instrumentation.h" #include "lld/Core/LLVM.h" +#include "lld/Core/LinkingContext.h" #include "lld/Core/Node.h" #include "lld/Core/PassManager.h" #include "lld/Core/Resolver.h" #include "lld/Core/SharedLibraryFile.h" #include "lld/Core/Simple.h" -#include "lld/Core/LinkingContext.h" #include "lld/ReaderWriter/MachOLinkingContext.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" -#include "llvm/Option/Option.h" #include "llvm/Option/OptTable.h" +#include "llvm/Option/Option.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/Format.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" diff --git a/lib/ReaderWriter/FileArchive.cpp b/lib/ReaderWriter/FileArchive.cpp index 799f947a8c82..762d0871db06 100644 --- a/lib/ReaderWriter/FileArchive.cpp +++ b/lib/ReaderWriter/FileArchive.cpp @@ -11,15 +11,16 @@ #include "lld/Core/File.h" #include "lld/Core/LLVM.h" #include "lld/Core/Reader.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Magic.h" #include "llvm/Object/Archive.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/Object/Error.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include <memory> #include <set> @@ -30,6 +31,8 @@ #include <vector> using llvm::object::Archive; +using llvm::file_magic; +using llvm::identify_magic; namespace lld { @@ -201,7 +204,7 @@ public: ArchiveReader(bool logLoading) : _logLoading(logLoading) {} bool canParse(file_magic magic, MemoryBufferRef) const override { - return magic == llvm::sys::fs::file_magic::archive; + return magic == file_magic::archive; } ErrorOr<std::unique_ptr<File>> loadFile(std::unique_ptr<MemoryBuffer> mb, diff --git a/lib/ReaderWriter/MachO/ExecutableAtoms.h b/lib/ReaderWriter/MachO/ExecutableAtoms.h index acced33b7e74..ab14e6d8c3e7 100644 --- a/lib/ReaderWriter/MachO/ExecutableAtoms.h +++ b/lib/ReaderWriter/MachO/ExecutableAtoms.h @@ -13,7 +13,7 @@ #include "Atoms.h" #include "File.h" -#include "llvm/Support/MachO.h" +#include "llvm/BinaryFormat/MachO.h" #include "lld/Core/DefinedAtom.h" #include "lld/Core/File.h" diff --git a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp index db4a96823e74..7e7b559b150a 100644 --- a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp @@ -22,11 +22,11 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Demangle/Demangle.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Host.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/Path.h" #include <algorithm> diff --git a/lib/ReaderWriter/MachO/MachONormalizedFile.h b/lib/ReaderWriter/MachO/MachONormalizedFile.h index 60d76d4b5c9b..31b24dfd1025 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFile.h +++ b/lib/ReaderWriter/MachO/MachONormalizedFile.h @@ -48,10 +48,10 @@ #include "lld/ReaderWriter/MachOLinkingContext.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorOr.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/YAMLTraits.h" using llvm::BumpPtrAllocator; diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp index 23c7ea17f7e7..edbe576f0086 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp @@ -21,24 +21,25 @@ /// | normalized | /// +------------+ -#include "MachONormalizedFile.h" #include "ArchHandler.h" +#include "MachONormalizedFile.h" #include "MachONormalizedFileBinaryUtils.h" #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" #include "lld/Core/SharedLibraryFile.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/BinaryFormat/Magic.h" #include "llvm/Object/MachO.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Errc.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/Host.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include <functional> @@ -46,6 +47,7 @@ using namespace llvm::MachO; using llvm::object::ExportEntry; +using llvm::file_magic; using llvm::object::MachOObjectFile; namespace lld { @@ -531,8 +533,7 @@ public: MachOObjectReader(MachOLinkingContext &ctx) : _ctx(ctx) {} bool canParse(file_magic magic, MemoryBufferRef mb) const override { - return (magic == llvm::sys::fs::file_magic::macho_object && - mb.getBufferSize() > 32); + return (magic == file_magic::macho_object && mb.getBufferSize() > 32); } ErrorOr<std::unique_ptr<File>> @@ -553,8 +554,8 @@ public: bool canParse(file_magic magic, MemoryBufferRef mb) const override { switch (magic) { - case llvm::sys::fs::file_magic::macho_dynamically_linked_shared_lib: - case llvm::sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub: + case file_magic::macho_dynamically_linked_shared_lib: + case file_magic::macho_dynamically_linked_shared_lib_stub: return mb.getBufferSize() > 32; default: return false; diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h index d69c5389e9d6..b38f7059228f 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h +++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h @@ -14,12 +14,12 @@ #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Host.h" #include "llvm/Support/LEB128.h" -#include "llvm/Support/MachO.h" #include <system_error> namespace lld { diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp index e853faf9112e..bac41d2a52bf 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp @@ -25,11 +25,12 @@ #include "MachONormalizedFileBinaryUtils.h" #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" -#include "llvm/ADT/ilist.h" -#include "llvm/ADT/ilist_node.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/ilist.h" +#include "llvm/ADT/ilist_node.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" @@ -37,7 +38,6 @@ #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/Format.h" #include "llvm/Support/Host.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include <functional> diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp index ddd3259842e2..e58e3d2e7a4b 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp @@ -20,19 +20,19 @@ /// | Atoms | /// +-------+ -#include "MachONormalizedFile.h" #include "ArchHandler.h" #include "DebugInfo.h" +#include "MachONormalizedFile.h" #include "MachONormalizedFileBinaryUtils.h" #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" -#include "llvm/Support/MachO.h" #include <map> #include <system_error> #include <unordered_set> @@ -515,6 +515,7 @@ void Util::organizeSections() { // Main executables, need a zero-page segment segmentForName("__PAGEZERO"); // Fall into next case. + LLVM_FALLTHROUGH; case llvm::MachO::MH_DYLIB: case llvm::MachO::MH_BUNDLE: // All dynamic code needs TEXT segment to hold the load commands. diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp index 4b17f7b3a85f..18fb71f16bcf 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp @@ -20,20 +20,20 @@ /// | Atoms | /// +-------+ -#include "MachONormalizedFile.h" #include "ArchHandler.h" #include "Atoms.h" #include "File.h" +#include "MachONormalizedFile.h" #include "MachONormalizedFileBinaryUtils.h" #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/Dwarf.h" #include "llvm/Support/Error.h" #include "llvm/Support/Format.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp index 218170965eca..fe67fc88c467 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp @@ -23,17 +23,16 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" #include <system_error> - using llvm::StringRef; using namespace llvm::yaml; using namespace llvm::MachO; diff --git a/lib/ReaderWriter/MachO/WriterMachO.cpp b/lib/ReaderWriter/MachO/WriterMachO.cpp index f08487f21ac1..c457e7b55a43 100644 --- a/lib/ReaderWriter/MachO/WriterMachO.cpp +++ b/lib/ReaderWriter/MachO/WriterMachO.cpp @@ -12,10 +12,10 @@ #include "lld/Core/File.h" #include "lld/Core/Writer.h" #include "lld/ReaderWriter/MachOLinkingContext.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileOutputBuffer.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/raw_ostream.h" #include <system_error> diff --git a/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp index 59ca43079a6d..4c88eb1d1476 100644 --- a/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp +++ b/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp @@ -26,6 +26,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/Magic.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" @@ -43,6 +44,7 @@ #include <system_error> #include <vector> +using llvm::file_magic; using llvm::yaml::MappingTraits; using llvm::yaml::ScalarEnumerationTraits; using llvm::yaml::ScalarTraits; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index cef2e2c68ae1..1dbd1b7699ea 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -29,7 +29,7 @@ if (NOT LLD_BUILT_STANDALONE) list(APPEND LLD_TEST_DEPS FileCheck count not llvm-ar llvm-as llvm-dis llvm-dwarfdump llvm-nm llc llvm-config llvm-objdump llvm-readobj yaml2obj obj2yaml - llvm-mc llvm-lib llvm-pdbdump opt + llvm-mc llvm-lib llvm-pdbutil opt ) endif() diff --git a/test/COFF/pdb-none.test b/test/COFF/pdb-none.test index 7e428693aec4..b4da5922ee7b 100644 --- a/test/COFF/pdb-none.test +++ b/test/COFF/pdb-none.test @@ -3,7 +3,7 @@ # RUN: lld-link /debug /debugtype:pdata /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \ # RUN: %t1.obj %t2.obj -# RUN: llvm-pdbdump pdb2yaml -pdb-stream %t.pdb | FileCheck %s +# RUN: llvm-pdbutil pdb2yaml -pdb-stream %t.pdb | FileCheck %s # CHECK: PdbStream: # CHECK-NEXT: Age: 0 diff --git a/test/COFF/pdb.test b/test/COFF/pdb.test index f1fa4ec7c2b6..57286611ffcd 100644 --- a/test/COFF/pdb.test +++ b/test/COFF/pdb.test @@ -3,10 +3,10 @@ # RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \ # RUN: %t1.obj %t2.obj -# RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory -pdb-stream \ +# RUN: llvm-pdbutil pdb2yaml -stream-metadata -stream-directory -pdb-stream \ # RUN: -dbi-stream -ipi-stream -tpi-stream %t.pdb | FileCheck %s -# RUN: llvm-pdbdump raw -modules -section-map -section-headers -section-contribs \ +# RUN: llvm-pdbutil raw -modules -section-map -section-headers -section-contribs \ # RUN: -tpi-records %t.pdb | FileCheck -check-prefix RAW %s # CHECK: MSF: diff --git a/test/ELF/Inputs/relocatable-comdat-multiple.s b/test/ELF/Inputs/relocatable-comdat-multiple.s new file mode 100644 index 000000000000..837a6bb06d09 --- /dev/null +++ b/test/ELF/Inputs/relocatable-comdat-multiple.s @@ -0,0 +1,2 @@ +.section .text.c,"axG",@progbits,bbb,comdat +.section .text.d,"axG",@progbits,bbb,comdat diff --git a/test/ELF/aarch64-undefined-weak.s b/test/ELF/aarch64-undefined-weak.s index 74fef669ed74..e611b6da6607 100644 --- a/test/ELF/aarch64-undefined-weak.s +++ b/test/ELF/aarch64-undefined-weak.s @@ -33,13 +33,13 @@ _start: // CHECK: Disassembly of section .text: // 131076 = 0x20004 -// CHECK: 20000: 01 80 00 14 b #131076 -// CHECK-NEXT: 20004: 02 80 00 94 bl #131080 -// CHECK-NEXT: 20008: 60 00 10 54 b.eq #131084 -// CHECK-NEXT: 2000c: 81 00 10 b4 cbz x1, #131088 -// CHECK-NEXT: 20010: 00 00 00 10 adr x0, #0 -// CHECK-NEXT: 20014: 00 00 00 90 adrp x0, #0 -// CHECK: 20018: 00 00 00 00 .word 0x00000000 -// CHECK-NEXT: 2001c: 00 00 00 00 .word 0x00000000 -// CHECK-NEXT: 20020: 00 00 00 00 .word 0x00000000 -// CHECK-NEXT: 20024: 00 00 .short 0x0000 +// CHECK: 20000: {{.*}} b #131076 +// CHECK-NEXT: 20004: {{.*}} bl #131080 +// CHECK-NEXT: 20008: {{.*}} b.eq #131084 +// CHECK-NEXT: 2000c: {{.*}} cbz x1, #131088 +// CHECK-NEXT: 20010: {{.*}} adr x0, #0 +// CHECK-NEXT: 20014: {{.*}} adrp x0, #0 +// CHECK: 20018: {{.*}} .word 0x00000000 +// CHECK-NEXT: 2001c: {{.*}} .word 0x00000000 +// CHECK-NEXT: 20020: {{.*}} .word 0x00000000 +// CHECK-NEXT: 20024: {{.*}} .short 0x0000 diff --git a/test/ELF/amdgpu-globals.s b/test/ELF/amdgpu-globals.s index 17dfc82ef8f3..e32159b332e7 100644 --- a/test/ELF/amdgpu-globals.s +++ b/test/ELF/amdgpu-globals.s @@ -1,130 +1,56 @@ # RUN: llvm-mc -filetype=obj -triple amdgcn--amdhsa -mcpu=kaveri %s -o %t.o -# RUN: ld.lld %t.o -o %t +# RUN: ld.lld -shared %t.o -o %t # RUN: llvm-readobj -sections -symbols -program-headers %t | FileCheck %s # REQUIRES: amdgpu - .amdgpu_hsa_module_global module_global_program - .size module_global_program, 4 - .hsadata_global_program -module_global_program: - .long 0 ; 0x0 +.type glob0, @object +.data + .globl glob0 +glob0: + .long 1 + .size glob0, 4 - .amdgpu_hsa_program_global program_global_program - .size program_global_program, 4 - .hsadata_global_program -program_global_program: - .long 0 ; 0x0 - - .amdgpu_hsa_module_global module_global_agent - .size module_global_agent, 4 - .hsadata_global_agent -module_global_agent: - .long 0 ; 0x0 - - .amdgpu_hsa_program_global program_global_agent - .size program_global_agent, 4 - .hsadata_global_agent -program_global_agent: - .long 0 ; 0x0 - - .amdgpu_hsa_module_global module_global_readonly - .size module_global_readonly, 4 - .hsatext -module_global_readonly: - .long 0 ; 0x0 - - .amdgpu_hsa_program_global program_global_readonly - .size program_global_readonly, 4 - .hsatext -program_global_readonly: - .long 0 ; 0x0 - -# CHECK: Section { -# CHECK: Name: .hsatext -# CHECK: Type: SHT_PROGBITS -# CHECK: Flags [ (0xC00007) -# CHECK: SHF_ALLOC (0x2) -# CHECK: SHF_AMDGPU_HSA_AGENT (0x800000) -# CHECK: SHF_AMDGPU_HSA_CODE (0x400000) -# CHECK: SHF_EXECINSTR (0x4) -# CHECK: SHF_WRITE (0x1) -# CHECK: ] -# CHECK: Address: [[HSATEXT_ADDR:[0-9xa-f]+]] -# CHECK: } +.type glob1, @object +.section .rodata, #alloc + .globl glob1 +glob1: + .long 2 + .size glob1, 4 # CHECK: Section { -# CHECK: Name: .hsadata_global_program -# CHECK: Type: SHT_PROGBITS (0x1) -# CHECK: Flags [ (0x100003) -# CHECK: SHF_ALLOC (0x2) -# CHECK: SHF_AMDGPU_HSA_GLOBAL (0x100000) -# CHECK: SHF_WRITE (0x1) -# CHECK: ] -# CHECK: Address: [[HSADATA_GLOBAL_PROGRAM_ADDR:[0-9xa-f]+]] +# CHECK: Name: .rodata +# CHECK: Type: SHT_PROGBITS +# CHECK: Flags [ (0x2) +# CHECK: SHF_ALLOC (0x2) +# CHECK: ] +# CHECK: Address: [[RODATA_ADDR:[0-9xa-f]+]] # CHECK: } # CHECK: Section { -# CHECK: Name: .hsadata_global_agent -# CHECK: Type: SHT_PROGBITS (0x1) -# CHECK: Flags [ (0x900003) -# CHECK: SHF_ALLOC (0x2) -# CHECK: SHF_AMDGPU_HSA_AGENT (0x800000) -# CHECK: SHF_AMDGPU_HSA_GLOBAL (0x100000) -# CHECK: SHF_WRITE (0x1) -# CHECK: ] -# CHECK: } - -# CHECK: Symbol { -# CHECK: Name: module_global_agent -# CHECK: Value: -# CHECK: Size: 4 -# CHECK: Binding: Local -# CHECK: Section: .hsadata_global_agent -# CHECK: } - -# CHECK: Symbol { -# CHECK: Name: module_global_program -# CHECK: Value: -# CHECK: Size: 4 -# CHECK: Binding: Local -# CHECK: Section: .hsadata_global_program -# CHECK: } - -# CHECK: Symbol { -# CHECK: Name: module_global_readonly -# CHECK: Value: -# CHECK: Size: 4 -# CHECK: Binding: Local -# CHECK: Type: Object -# CHECK: Section: .hsatext -# CHECK: } - -# CHECK: Symbol { -# CHECK: Name: program_global_agent -# CHECK: Value: -# CHECK: Size: 4 -# CHECK: Binding: Global -# CHECK: Type: Object -# CHECK: Section: .hsadata_global_agent +# CHECK: Name: .data +# CHECK: Type: SHT_PROGBITS +# CHECK: Flags [ (0x3) +# CHECK: SHF_ALLOC (0x2) +# CHECK: SHF_WRITE (0x1) +# CHECK: ] +# CHECK: Address: [[DATA_ADDR:[0-9xa-f]+]] # CHECK: } # CHECK: Symbol { -# CHECK: Name: program_global_program -# CHECK: Value: -# CHECK: Size: 4 -# CHECK: Binding: Global -# CHECK: Type: Object -# CHECK: Section: .hsadata_global_program +# CHECK: Name: glob0 +# CHECK: Value: [[DATA_ADDR]] +# CHECK: Size: 4 +# CHECK: Type: Object +# CHECK: Section: .data # CHECK: } # CHECK: Symbol { -# CHECK: Name: program_global_readonly -# CHECK: Value: -# CHECK: Size: 4 -# CHECK: Binding: Global -# CHECK: Type: Object -# CHECK: Section: .hsatext +# CHECK: Name: glob1 +# CHECK: Value: [[RODATA_ADDR]] +# CHECK: Size: 4 +# CHECK: Type: Object +# CHECK: Section: .rodata # CHECK: } # CHECK: ProgramHeader { diff --git a/test/ELF/amdgpu-kernels.s b/test/ELF/amdgpu-kernels.s index 62a8cb74a541..c76613f1a336 100644 --- a/test/ELF/amdgpu-kernels.s +++ b/test/ELF/amdgpu-kernels.s @@ -1,5 +1,5 @@ # RUN: llvm-mc -filetype=obj -triple amdgcn--amdhsa -mcpu=kaveri %s -o %t.o -# RUN: ld.lld %t.o -o %t +# RUN: ld.lld -shared %t.o -o %t # RUN: llvm-readobj -sections -symbols -program-headers %t | FileCheck %s # REQUIRES: amdgpu @@ -7,7 +7,7 @@ .hsa_code_object_version 1,0 .hsa_code_object_isa 7,0,0,"AMD","AMDGPU" -.hsatext +.text .globl kernel0 .align 256 .amdgpu_hsa_kernel kernel0 @@ -27,16 +27,12 @@ kernel1: # CHECK: Section { -# CHECK: Name: .hsatext +# CHECK: Name: .text # CHECK: Type: SHT_PROGBITS -# CHECK: Flags [ (0xC00007) +# CHECK: Flags [ (0x6) # CHECK: SHF_ALLOC (0x2) -# CHECK: SHF_AMDGPU_HSA_AGENT (0x800000) -# CHECK: SHF_AMDGPU_HSA_CODE (0x400000) # CHECK: SHF_EXECINSTR (0x4) -# CHECK: SHF_WRITE (0x1) # CHECK: ] -# CHECK: Address: [[HSATEXT_ADDR:[0-9xa-f]+]] # CHECK: } # CHECK: Symbol { @@ -45,7 +41,7 @@ kernel1: # CHECK: Size: 4 # CHECK: Binding: Global # CHECK: Type: AMDGPU_HSA_KERNEL -# CHECK: Section: .hsatext +# CHECK: Section: .text # CHECK: } # CHECK: Symbol { @@ -54,7 +50,7 @@ kernel1: # CHECK: Size: 8 # CHECK: Binding: Global # CHECK: Type: AMDGPU_HSA_KERNEL -# CHECK: Section: .hsatext +# CHECK: Section: .text # CHECK: } # CHECK: ProgramHeader { diff --git a/test/ELF/arm-icf-exidx.s b/test/ELF/arm-icf-exidx.s index cb801b7f2420..6af30285db67 100644 --- a/test/ELF/arm-icf-exidx.s +++ b/test/ELF/arm-icf-exidx.s @@ -19,13 +19,15 @@ g: .section .text.h .global __aeabi_unwind_cpp_pr0 __aeabi_unwind_cpp_pr0: + nop bx lr // CHECK: Disassembly of section .text: // CHECK-NEXT: f: // CHECK-NEXT: 11000: 1e ff 2f e1 bx lr // CHECK: __aeabi_unwind_cpp_pr0: -// CHECK-NEXT: 11004: 1e ff 2f e1 bx lr +// CHECK-NEXT: 11004: 00 f0 20 e3 nop +// CHECK-NEXT: 11008: 1e ff 2f e1 bx lr // CHECK: Contents of section .ARM.exidx: // CHECK-NEXT: 100d4 2c0f0000 b0b0b080 280f0000 01000000 diff --git a/test/ELF/arm-thumb-no-undefined-thunk.s b/test/ELF/arm-thumb-no-undefined-thunk.s index f668c8c278de..af2d3eb52044 100644 --- a/test/ELF/arm-thumb-no-undefined-thunk.s +++ b/test/ELF/arm-thumb-no-undefined-thunk.s @@ -19,6 +19,6 @@ _start: // CHECK: Disassembly of section .text: // CHECK-NEXT: _start: // 69636 = 0x11004 = next instruction -// CHECK: 11000: 11 f0 02 f8 bl #69636 -// CHECK-NEXT: 11004: 11 f0 04 b8 b.w #69640 -// CHECK-NEXT: 11008: 11 f0 06 b8 b.w #69644 +// CHECK: 11000: {{.*}} bl #69636 +// CHECK-NEXT: 11004: {{.*}} b.w #69640 +// CHECK-NEXT: 11008: {{.*}} b.w #69644 diff --git a/test/ELF/arm-thumb-thunk-symbols.s b/test/ELF/arm-thumb-thunk-symbols.s new file mode 100644 index 000000000000..42046f802f96 --- /dev/null +++ b/test/ELF/arm-thumb-thunk-symbols.s @@ -0,0 +1,42 @@ +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t +// RUN: ld.lld %t -o %t2 2>&1 +// RUN: llvm-readobj --symbols %t2 | FileCheck %s +// RUN: ld.lld --shared %t -o %t3 2>&1 +// RUN: llvm-readobj --symbols %t3 | FileCheck -check-prefix=CHECK-PI %s +// REQUIRES: arm + +// Check that the symbols generated for Thunks have the correct symbol type +// of STT_FUNC and the correct value of bit 0 (0 for ARM 1 for Thumb) + .syntax unified + .section .text.thumb, "ax", %progbits + .thumb + .balign 0x1000 + .globl thumb_fn + .type thumb_fn, %function +thumb_fn: + b.w arm_fn + + .section .text.arm, "ax", %progbits + .arm + .balign 0x1000 + .globl arm_fn + .type arm_fn, %function +arm_fn: + b thumb_fn + +// CHECK: Name: __Thumbv7ABSLongThunk_arm_fn +// CHECK-NEXT: Value: 0x11005 +// CHECK-NEXT: Size: 10 +// CHECK-NEXT: Binding: Local (0x0) +// CHECK-NEXT: Type: Function (0x2) +// CHECK: Name: __ARMv7ABSLongThunk_thumb_fn +// CHECK-NEXT: Value: 0x11010 +// CHECK-NEXT: Size: 12 +// CHECK-NEXT: Binding: Local (0x0) +// CHECK-NEXT: Type: Function (0x2) + +// CHECK-PI: Name: __ThumbV7PILongThunk_arm_fn +// CHECK-PI-NEXT: Value: 0x1005 +// CHECK-PI-NEXT: Size: 12 +// CHECK-PI-NEXT: Binding: Local (0x0) +// CHECK-PI-NEXT: Type: Function (0x2) diff --git a/test/ELF/arm-thumb-undefined-weak.s b/test/ELF/arm-thumb-undefined-weak.s index 087f8e71cb21..792b81e3603a 100644 --- a/test/ELF/arm-thumb-undefined-weak.s +++ b/test/ELF/arm-thumb-undefined-weak.s @@ -29,10 +29,10 @@ _start: // CHECK: Disassembly of section .text: // 69636 = 0x11004 -// CHECK: 11000: 11 f0 02 80 beq.w #69636 -// CHECK-NEXT: 11004: 11 f0 04 b8 b.w #69640 -// CHECK-NEXT: 11008: 11 f0 06 f8 bl #69644 +// CHECK: 11000: {{.*}} beq.w #69636 +// CHECK-NEXT: 11004: {{.*}} b.w #69640 +// CHECK-NEXT: 11008: {{.*}} bl #69644 // blx is transformed into bl so we don't change state -// CHECK-NEXT: 1100c: 11 f0 08 f8 bl #69648 -// CHECK-NEXT: 11010: c0 f2 00 00 movt r0, #0 -// CHECK-NEXT: 11014: 40 f2 00 00 movw r0, #0 +// CHECK-NEXT: 1100c: {{.*}} bl #69648 +// CHECK-NEXT: 11010: {{.*}} movt r0, #0 +// CHECK-NEXT: 11014: {{.*}} movw r0, #0 diff --git a/test/ELF/arm-undefined-weak.s b/test/ELF/arm-undefined-weak.s index df67b467e263..5d77b1b4e698 100644 --- a/test/ELF/arm-undefined-weak.s +++ b/test/ELF/arm-undefined-weak.s @@ -29,11 +29,11 @@ _start: // CHECK: Disassembly of section .text: // 69636 = 0x11004 -// CHECK: 11000: 01 44 00 ea b #69636 -// CHECK-NEXT: 11004: 02 44 00 eb bl #69640 +// CHECK: 11000: {{.*}} b #69636 +// CHECK-NEXT: 11004: {{.*}} bl #69640 // blx is transformed into bl so we don't change state -// CHECK-NEXT: 11008: 03 44 00 eb bl #69644 -// CHECK-NEXT: 1100c: 00 00 40 e3 movt r0, #0 -// CHECK-NEXT: 11010: 00 00 00 e3 movw r0, #0 -// CHECK: 11014: 00 00 00 00 .word 0x00000000 +// CHECK-NEXT: 11008: {{.*}} bl #69644 +// CHECK-NEXT: 1100c: {{.*}} movt r0, #0 +// CHECK-NEXT: 11010: {{.*}} movw r0, #0 +// CHECK: 11014: {{.*}} .word 0x00000000 diff --git a/test/ELF/dso_handle.s b/test/ELF/dso_handle.s new file mode 100644 index 000000000000..99e2594ef814 --- /dev/null +++ b/test/ELF/dso_handle.s @@ -0,0 +1,19 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld -shared %t.o -o %t +# RUN: llvm-readobj -symbols %t | FileCheck %s +# CHECK: Name: __dso_handle +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Local +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other [ +# CHECK-NEXT: STV_HIDDEN +# CHECK-NEXT: ] +# CHECK-NEXT: Section: .dynsym + +.text +.global foo, __dso_handle +foo: + lea __dso_handle(%rip),%rax diff --git a/test/ELF/ehdr_start.s b/test/ELF/ehdr_start.s index 32bcf4b84751..94e0fedcfc52 100644 --- a/test/ELF/ehdr_start.s +++ b/test/ELF/ehdr_start.s @@ -13,10 +13,21 @@ # CHECK-NEXT: ] # CHECK-NEXT: Section: .text (0x1) +# CHECK: Name: __executable_start +# CHECK-NEXT: Value: 0x200000 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Local +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other [ +# CHECK-NEXT: STV_HIDDEN +# CHECK-NEXT: ] +# CHECK-NEXT: Section: .text + .text .global _start, __ehdr_start _start: .quad __ehdr_start + .quad __executable_start # RUN: ld.lld -r %t.o -o %t.r # RUN: llvm-readobj -symbols %t.r | FileCheck %s --check-prefix=RELOCATABLE diff --git a/test/ELF/emit-relocs-merge.s b/test/ELF/emit-relocs-merge.s index 3fecca23b735..c700c337e334 100644 --- a/test/ELF/emit-relocs-merge.s +++ b/test/ELF/emit-relocs-merge.s @@ -8,7 +8,7 @@ # CHECK-NEXT: 0x1000 R_X86_64_64 zed 0x0 # CHECK-NEXT: 0x1008 R_X86_64_64 zed 0x0 # CHECK-NEXT: } -# CHECK-NEXT: Section ({{.*}}) .rela.data { +# CHECK-NEXT: Section ({{.*}}) .rela.data.foo { # CHECK-NEXT: 0x1000 R_X86_64_64 zed 0x0 # CHECK-NEXT: 0x1008 R_X86_64_64 zed 0x0 # CHECK-NEXT: } diff --git a/test/ELF/gdb-index-empty.s b/test/ELF/gdb-index-empty.s index 933afed33e2f..24f20803a008 100644 --- a/test/ELF/gdb-index-empty.s +++ b/test/ELF/gdb-index-empty.s @@ -8,109 +8,73 @@ # echo "void _start() { __builtin_unreachable(); }" | \ # clang -Os -g -S -o gdb-index-empty.s -x c - -Xclang -fdebug-compilation-dir -Xclang . - .text - .file "-" - .globl _start - .type _start,@function -_start: # @_start +.text +.globl _start +.type _start,@function +_start: .Lfunc_begin0: - .cfi_startproc -# BB#0: # %entry .Lfunc_end0: - .size _start, .Lfunc_end0-_start - .cfi_endproc - .file 1 "<stdin>" - .section .debug_str,"MS",@progbits,1 -.Linfo_string0: - .asciz "clang version 5.0.0 " # string offset=0 -.Linfo_string1: - .asciz "-" # string offset=21 -.Linfo_string2: - .asciz "." # string offset=23 -.Linfo_string3: - .asciz "_start" # string offset=25 - .section .debug_loc,"",@progbits - .section .debug_abbrev,"",@progbits - .byte 1 # Abbreviation Code - .byte 17 # DW_TAG_compile_unit - .byte 1 # DW_CHILDREN_yes - .byte 37 # DW_AT_producer - .byte 14 # DW_FORM_strp - .byte 19 # DW_AT_language - .byte 5 # DW_FORM_data2 - .byte 3 # DW_AT_name - .byte 14 # DW_FORM_strp - .byte 16 # DW_AT_stmt_list - .byte 23 # DW_FORM_sec_offset - .byte 27 # DW_AT_comp_dir - .byte 14 # DW_FORM_strp - .byte 17 # DW_AT_low_pc - .byte 1 # DW_FORM_addr - .byte 18 # DW_AT_high_pc - .byte 6 # DW_FORM_data4 - .byte 0 # EOM(1) - .byte 0 # EOM(2) - .byte 2 # Abbreviation Code - .byte 46 # DW_TAG_subprogram - .byte 0 # DW_CHILDREN_no - .byte 17 # DW_AT_low_pc - .byte 1 # DW_FORM_addr - .byte 18 # DW_AT_high_pc - .byte 6 # DW_FORM_data4 - .byte 64 # DW_AT_frame_base - .byte 24 # DW_FORM_exprloc - .byte 3 # DW_AT_name - .byte 14 # DW_FORM_strp - .byte 58 # DW_AT_decl_file - .byte 11 # DW_FORM_data1 - .byte 59 # DW_AT_decl_line - .byte 11 # DW_FORM_data1 - .byte 63 # DW_AT_external - .byte 25 # DW_FORM_flag_present - .byte 0 # EOM(1) - .byte 0 # EOM(2) - .byte 0 # EOM(3) - .section .debug_info,"",@progbits -.Lcu_begin0: - .long 60 # Length of Unit - .short 4 # DWARF version number - .long .debug_abbrev # Offset Into Abbrev. Section - .byte 8 # Address Size (in bytes) - .byte 1 # Abbrev [1] 0xb:0x35 DW_TAG_compile_unit - .long .Linfo_string0 # DW_AT_producer - .short 12 # DW_AT_language - .long .Linfo_string1 # DW_AT_name - .long .Lline_table_start0 # DW_AT_stmt_list - .long .Linfo_string2 # DW_AT_comp_dir - .quad .Lfunc_begin0 # DW_AT_low_pc - .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc - .byte 2 # Abbrev [2] 0x2a:0x15 DW_TAG_subprogram - .quad .Lfunc_begin0 # DW_AT_low_pc - .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc - .byte 1 # DW_AT_frame_base - .byte 87 - .long .Linfo_string3 # DW_AT_name - .byte 1 # DW_AT_decl_file - .byte 1 # DW_AT_decl_line - # DW_AT_external - .byte 0 # End Of Children Mark - .section .debug_ranges,"",@progbits - .section .debug_macinfo,"",@progbits -.Lcu_macro_begin0: - .byte 0 # End Of Macro List Mark - .section .debug_pubnames,"",@progbits - .long .LpubNames_end0-.LpubNames_begin0 # Length of Public Names Info -.LpubNames_begin0: - .short 2 # DWARF Version - .long .Lcu_begin0 # Offset of Compilation Unit Info - .long 64 # Compilation Unit Length - .long 42 # DIE offset - .asciz "_start" # External Name - .long 0 # End Mark -.LpubNames_end0: +.section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 14 # DW_FORM_strp + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 0 # DW_CHILDREN_no + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) - .ident "clang version 5.0.0 " - .section ".note.GNU-stack","",@progbits - .section .debug_line,"",@progbits -.Lline_table_start0: +.section .debug_info,"",@progbits + .long 60 # Length of Unit + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x35 DW_TAG_compile_unit + .long 0 # DW_AT_producer + .short 12 # DW_AT_language + .long 0 # DW_AT_name + .long 0 # DW_AT_stmt_list + .long 0 # DW_AT_comp_dir + .quad .Lfunc_begin0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .byte 2 # Abbrev [2] 0x2a:0x15 DW_TAG_subprogram + .quad .Lfunc_begin0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 87 + .long 0 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .byte 0 # End Of Children Mark diff --git a/test/ELF/i386-reloc-large-addend.s b/test/ELF/i386-reloc-large-addend.s new file mode 100644 index 000000000000..b644640404e2 --- /dev/null +++ b/test/ELF/i386-reloc-large-addend.s @@ -0,0 +1,15 @@ +// RUN: llvm-mc %s -o %t.o -triple i386-pc-linux-code16 -filetype=obj + +// RUN: echo ".global foo; foo = 0x1" > %t1.s +// RUN: llvm-mc %t1.s -o %t1.o -triple i386-pc-linux -filetype=obj + +// RUN: ld.lld -Ttext 0x7000 %t.o %t1.o -o %t +// RUN: llvm-objdump -d -triple=i386-pc-linux-code16 %t | FileCheck %s + +// CHECK: Disassembly of section .text: +// CHECK-NEXT: _start: +// CHECK-NEXT: 7000: e9 fe 1f jmp 8190 +// 0x1 + 0x9000 - 0x7003 == 8190 + .global _start +_start: +jmp foo + 0x9000 diff --git a/test/ELF/i386-reloc-range.s b/test/ELF/i386-reloc-range.s new file mode 100644 index 000000000000..47447d0efa32 --- /dev/null +++ b/test/ELF/i386-reloc-range.s @@ -0,0 +1,22 @@ +// RUN: llvm-mc %s -o %t.o -triple i386-pc-linux-code16 -filetype=obj + +// RUN: echo ".global foo; foo = 0x10202" > %t1.s +// RUN: llvm-mc %t1.s -o %t1.o -triple i386-pc-linux -filetype=obj +// RUN: echo ".global foo; foo = 0x10203" > %t2.s +// RUN: llvm-mc %t2.s -o %t2.o -triple i386-pc-linux -filetype=obj + +// RUN: ld.lld -Ttext 0x200 %t.o %t1.o -o %t1 +// RUN: llvm-objdump -d -triple=i386-pc-linux-code16 %t1 | FileCheck %s + +// CHECK: Disassembly of section .text: +// CHECK-NEXT: _start: +// CHECK-NEXT: 200: {{.*}} jmp -1 +// 0x10202 - 0x203 == 0xffff + +// RUN: not ld.lld -Ttext 0x200 %t.o %t2.o -o %t2 2>&1 | FileCheck --check-prefix=ERR %s + +// ERR: {{.*}}:(.text+0x1): relocation R_386_PC16 out of range + + .global _start +_start: + jmp foo diff --git a/test/ELF/icf-comdat.s b/test/ELF/icf-comdat.s new file mode 100644 index 000000000000..28c0a586bf03 --- /dev/null +++ b/test/ELF/icf-comdat.s @@ -0,0 +1,23 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld %t -o %t2 --icf=all --verbose | FileCheck %s + +# CHECK: selected .text.f1 +# CHECK: removed .text.f2 + +.globl _start, f1, f2 +_start: + ret + +.section .text.f1,"ax" +f1: + mov $60, %rax + mov $42, %rdi + syscall + +.section .text.f2,"axG",@progbits,foo,comdat +f2: + mov $60, %rax + mov $42, %rdi + syscall diff --git a/test/ELF/linkerscript/early-assign-symbol.s b/test/ELF/linkerscript/early-assign-symbol.s index 21940c088393..0626e66e6fb6 100644 --- a/test/ELF/linkerscript/early-assign-symbol.s +++ b/test/ELF/linkerscript/early-assign-symbol.s @@ -7,7 +7,7 @@ # RUN: echo "SECTIONS { aaa = ABSOLUTE(foo - 1) + 1; .text : { *(.text*) } }" > %t2.script # RUN: not ld.lld -o %t --script %t2.script %t.o 2>&1 | FileCheck %s -# CHECK: error: unable to evaluate expression: input section .text has no output section assigned +# CHECK: error: {{.*}}.script:1: unable to evaluate expression: input section .text has no output section assigned .section .text .globl foo diff --git a/test/ELF/linkerscript/emit-relocs-multiple.s b/test/ELF/linkerscript/emit-relocs-multiple.s new file mode 100644 index 000000000000..b04ca1be7a15 --- /dev/null +++ b/test/ELF/linkerscript/emit-relocs-multiple.s @@ -0,0 +1,20 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "SECTIONS { .zed : { *(.foo) *(.bar) } }" > %t.script +# RUN: ld.lld --emit-relocs --script %t.script %t.o -o %t1 +# RUN: llvm-readobj -r %t1 | FileCheck %s + +# CHECK: Relocations [ +# CHECK-NEXT: Section {{.*}} .rela.foo { +# CHECK-NEXT: 0x1 R_X86_64_32 .zed 0x0 +# CHECK-NEXT: 0x6 R_X86_64_32 .zed 0x5 +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.section .foo,"ax",@progbits +aaa: + movl $aaa, %edx + +.section .bar,"ax",@progbits +bbb: + movl $bbb, %edx diff --git a/test/ELF/linkerscript/expr-invalid-sec.s b/test/ELF/linkerscript/expr-invalid-sec.s index 9476be3c3b14..5687751b6806 100644 --- a/test/ELF/linkerscript/expr-invalid-sec.s +++ b/test/ELF/linkerscript/expr-invalid-sec.s @@ -3,4 +3,4 @@ # RUN: echo "SECTIONS { foo = ADDR(.text) + ADDR(.text); };" > %t.script # RUN: not ld.lld -o %t.so --script %t.script %t.o -shared 2>&1 | FileCheck %s -# CHECK: At least one side of the expression must be absolute +# CHECK: error: {{.*}}.script:1: at least one side of the expression must be absolute diff --git a/test/ELF/linkerscript/noload.s b/test/ELF/linkerscript/noload.s new file mode 100644 index 000000000000..9d0e085a0504 --- /dev/null +++ b/test/ELF/linkerscript/noload.s @@ -0,0 +1,46 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "SECTIONS { \ +# RUN: .data_noload_a (NOLOAD) : { *(.data_noload_a) } \ +# RUN: .data_noload_b (0x10000) (NOLOAD) : { *(.data_noload_b) } };" > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o +# RUN: llvm-readobj --symbols -sections %t + +# CHECK: Section { +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Name: .data_noload_a +# CHECK-NEXT: Type: SHT_NOBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: Size: 4096 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 1 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 3 +# CHECK-NEXT: Name: .data_noload_b +# CHECK-NEXT: Type: SHT_NOBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x10000 +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: Size: 4096 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 1 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } + +.section .data_noload_a,"aw",@progbits +.zero 4096 + +.section .data_noload_b,"aw",@progbits +.zero 4096 diff --git a/test/ELF/lto/Inputs/defsym-bar.ll b/test/ELF/lto/Inputs/defsym-bar.ll new file mode 100644 index 000000000000..748c7b23f6a8 --- /dev/null +++ b/test/ELF/lto/Inputs/defsym-bar.ll @@ -0,0 +1,21 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @this_is_bar1() +declare void @this_is_bar2() +declare void @this_is_bar3() + +define hidden void @bar1() { + call void @this_is_bar1() + ret void +} + +define hidden void @bar2() { + call void @this_is_bar2() + ret void +} + +define hidden void @bar3() { + call void @this_is_bar3() + ret void +} diff --git a/test/ELF/lto/Inputs/wrap-bar.ll b/test/ELF/lto/Inputs/wrap-bar.ll new file mode 100644 index 000000000000..407ebfbf6ec3 --- /dev/null +++ b/test/ELF/lto/Inputs/wrap-bar.ll @@ -0,0 +1,14 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define hidden void @bar() { + ret void +} + +define hidden void @__real_bar() { + ret void +} + +define hidden void @__wrap_bar() { + ret void +} diff --git a/test/ELF/lto/defsym.ll b/test/ELF/lto/defsym.ll new file mode 100644 index 000000000000..4c2fe45b3c53 --- /dev/null +++ b/test/ELF/lto/defsym.ll @@ -0,0 +1,28 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t.o +; RUN: llvm-as %S/Inputs/defsym-bar.ll -o %t1.o +; RUN: ld.lld %t.o %t1.o -shared -o %t.so -defsym=bar2=bar3 +; RUN: llvm-objdump -d %t.so | FileCheck %s + +; Call to bar2() should not be inlined and should be routed to bar3() +; Symbol bar3 should not be eliminated + +; CHECK: foo: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq +; CHECK-NEXT: callq{{.*}}<bar3> +; CHECK-NEXT: callq + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @bar1() +declare void @bar2() +declare void @bar3() + +define void @foo() { + call void @bar1() + call void @bar2() + call void @bar3() + ret void +} diff --git a/test/ELF/lto/wrap-1.ll b/test/ELF/lto/wrap-1.ll new file mode 100644 index 000000000000..b61dfaeb5903 --- /dev/null +++ b/test/ELF/lto/wrap-1.ll @@ -0,0 +1,35 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t.o +; RUN: ld.lld %t.o -o %t.out -wrap=bar -save-temps +; RUN: llvm-readobj -t %t.out | FileCheck %s +; RUN: cat %t.out.resolution.txt | FileCheck -check-prefix=RESOLS %s + +; CHECK: Name: __wrap_bar +; CHECK-NEXT: Value: +; CHECK-NEXT: Size: +; CHECK-NEXT: Binding: Global +; CHECK-NEXT: Type: Function + +; Make sure that the 'r' (linker redefined) bit is set for bar and __wrap_bar +; in the resolutions file. +; RESOLS: ,bar,r +; RESOLS: ,__wrap_bar,px +; RESOLS: ,__real_bar,pxr + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @bar() + +define void @_start() { + call void @bar() + ret void +} + +define void @__wrap_bar() { + ret void +} + +define void @__real_bar() { + ret void +} diff --git a/test/ELF/lto/wrap-2.ll b/test/ELF/lto/wrap-2.ll new file mode 100644 index 000000000000..b2e33f83138e --- /dev/null +++ b/test/ELF/lto/wrap-2.ll @@ -0,0 +1,36 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t.o +; RUN: llvm-as %S/Inputs/wrap-bar.ll -o %t1.o +; RUN: ld.lld %t.o %t1.o -shared -o %t.so -wrap=bar +; RUN: llvm-objdump -d %t.so | FileCheck %s +; RUN: llvm-readobj -t %t.so | FileCheck -check-prefix=BIND %s + +; Make sure that calls in foo() are not eliminated and that bar is +; routed to __wrap_bar and __real_bar is routed to bar. + +; CHECK: foo: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq{{.*}}<__wrap_bar> +; CHECK-NEXT: callq{{.*}}<bar> + +; Check that bar and __wrap_bar retain their original binding. +; BIND: Name: bar +; BIND-NEXT: Value: +; BIND-NEXT: Size: +; BIND-NEXT: Binding: Local +; BIND: Name: __wrap_bar +; BIND-NEXT: Value: +; BIND-NEXT: Size: +; BIND-NEXT: Binding: Local + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @bar() +declare void @__real_bar() + +define void @foo() { + call void @bar() + call void @__real_bar() + ret void +} diff --git a/test/ELF/mips-npic-call-pic-script.s b/test/ELF/mips-npic-call-pic-script.s new file mode 100644 index 000000000000..6028989ee4cb --- /dev/null +++ b/test/ELF/mips-npic-call-pic-script.s @@ -0,0 +1,255 @@ +# REQUIRES: mips +# Check LA25 stubs creation. This stub code is necessary when +# non-PIC code calls PIC function. +# RUN: echo "SECTIONS { .out 0x20000 : { *(.text.*) . = . + 0x100 ; *(.text) } }" > %t1.script +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ +# RUN: %p/Inputs/mips-fpic.s -o %t-fpic.o +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ +# RUN: %p/Inputs/mips-fnpic.s -o %t-fnpic.o +# RUN: ld.lld -r %t-fpic.o %t-fnpic.o -o %t-sto-pic.o +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ +# RUN: %p/Inputs/mips-pic.s -o %t-pic.o +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-npic.o +# RUN: ld.lld --script %t1.script %t-npic.o %t-pic.o %t-sto-pic.o -o %t.exe +# RUN: llvm-objdump -d %t.exe | FileCheck %s + +# CHECK: Disassembly of section .out: +# CHECK-NEXT: __LA25Thunk_foo1a: +# CHECK-NEXT: 20000: 3c 19 00 02 lui $25, 2 +# CHECK-NEXT: 20004: 08 00 80 08 j 131104 <foo1a> +# CHECK-NEXT: 20008: 27 39 00 20 addiu $25, $25, 32 +# CHECK-NEXT: 2000c: 00 00 00 00 nop +# CHECK: __LA25Thunk_foo1b: +# CHECK-NEXT: 20010: 3c 19 00 02 lui $25, 2 +# CHECK-NEXT: 20014: 08 00 80 09 j 131108 <foo1b> +# CHECK-NEXT: 20018: 27 39 00 24 addiu $25, $25, 36 +# CHECK-NEXT: 2001c: 00 00 00 00 nop +# CHECK: foo1a: +# CHECK-NEXT: 20020: 00 00 00 00 nop +# CHECK: foo1b: +# CHECK-NEXT: 20024: 00 00 00 00 nop +# CHECK: __LA25Thunk_foo2: +# CHECK-NEXT: 20028: 3c 19 00 02 lui $25, 2 +# CHECK-NEXT: 2002c: 08 00 80 10 j 131136 <foo2> +# CHECK-NEXT: 20030: 27 39 00 40 addiu $25, $25, 64 +# CHECK-NEXT: 20034: 00 00 00 00 nop +# CHECK-NEXT: 20038: 00 00 00 00 nop +# CHECK-NEXT: 2003c: 00 00 00 00 nop +# CHECK: foo2: +# CHECK-NEXT: 20040: 00 00 00 00 nop +# CHECK-NEXT: 20044: 00 00 00 00 nop +# CHECK-NEXT: 20048: 00 00 00 00 nop +# CHECK-NEXT: 2004c: 00 00 00 00 nop +# CHECK-NEXT: 20050: 00 00 00 00 nop +# CHECK-NEXT: 20054: 00 00 00 00 nop +# CHECK-NEXT: 20058: 00 00 00 00 nop +# CHECK-NEXT: 2005c: 00 00 00 00 nop +# CHECK-NEXT: 20060: 00 00 00 00 nop +# CHECK-NEXT: 20064: 00 00 00 00 nop +# CHECK-NEXT: 20068: 00 00 00 00 nop +# CHECK-NEXT: 2006c: 00 00 00 00 nop +# CHECK-NEXT: 20070: 00 00 00 00 nop +# CHECK-NEXT: 20074: 00 00 00 00 nop +# CHECK-NEXT: 20078: 00 00 00 00 nop +# CHECK-NEXT: 2007c: 00 00 00 00 nop +# CHECK-NEXT: 20080: 00 00 00 00 nop +# CHECK-NEXT: 20084: 00 00 00 00 nop +# CHECK-NEXT: 20088: 00 00 00 00 nop +# CHECK-NEXT: 2008c: 00 00 00 00 nop +# CHECK-NEXT: 20090: 00 00 00 00 nop +# CHECK-NEXT: 20094: 00 00 00 00 nop +# CHECK-NEXT: 20098: 00 00 00 00 nop +# CHECK-NEXT: 2009c: 00 00 00 00 nop +# CHECK-NEXT: 200a0: 00 00 00 00 nop +# CHECK-NEXT: 200a4: 00 00 00 00 nop +# CHECK-NEXT: 200a8: 00 00 00 00 nop +# CHECK-NEXT: 200ac: 00 00 00 00 nop +# CHECK-NEXT: 200b0: 00 00 00 00 nop +# CHECK-NEXT: 200b4: 00 00 00 00 nop +# CHECK-NEXT: 200b8: 00 00 00 00 nop +# CHECK-NEXT: 200bc: 00 00 00 00 nop +# CHECK-NEXT: 200c0: 00 00 00 00 nop +# CHECK-NEXT: 200c4: 00 00 00 00 nop +# CHECK-NEXT: 200c8: 00 00 00 00 nop +# CHECK-NEXT: 200cc: 00 00 00 00 nop +# CHECK-NEXT: 200d0: 00 00 00 00 nop +# CHECK-NEXT: 200d4: 00 00 00 00 nop +# CHECK-NEXT: 200d8: 00 00 00 00 nop +# CHECK-NEXT: 200dc: 00 00 00 00 nop +# CHECK-NEXT: 200e0: 00 00 00 00 nop +# CHECK-NEXT: 200e4: 00 00 00 00 nop +# CHECK-NEXT: 200e8: 00 00 00 00 nop +# CHECK-NEXT: 200ec: 00 00 00 00 nop +# CHECK-NEXT: 200f0: 00 00 00 00 nop +# CHECK-NEXT: 200f4: 00 00 00 00 nop +# CHECK-NEXT: 200f8: 00 00 00 00 nop +# CHECK-NEXT: 200fc: 00 00 00 00 nop +# CHECK-NEXT: 20100: 00 00 00 00 nop +# CHECK-NEXT: 20104: 00 00 00 00 nop +# CHECK-NEXT: 20108: 00 00 00 00 nop +# CHECK-NEXT: 2010c: 00 00 00 00 nop +# CHECK-NEXT: 20110: 00 00 00 00 nop +# CHECK-NEXT: 20114: 00 00 00 00 nop +# CHECK-NEXT: 20118: 00 00 00 00 nop +# CHECK-NEXT: 2011c: 00 00 00 00 nop +# CHECK-NEXT: 20120: 00 00 00 00 nop +# CHECK-NEXT: 20124: 00 00 00 00 nop +# CHECK-NEXT: 20128: 00 00 00 00 nop +# CHECK-NEXT: 2012c: 00 00 00 00 nop +# CHECK-NEXT: 20130: 00 00 00 00 nop +# CHECK-NEXT: 20134: 00 00 00 00 nop +# CHECK-NEXT: 20138: 00 00 00 00 nop +# CHECK-NEXT: 2013c: 00 00 00 00 nop +# CHECK-NEXT: 20140: 00 00 00 00 nop +# CHECK-NEXT: 20144: 00 00 00 00 nop +# CHECK-NEXT: 20148: 00 00 00 00 nop +# CHECK-NEXT: 2014c: 00 00 00 00 nop +# CHECK: __start: +# CHECK-NEXT: 20150: 0c 00 80 00 jal 131072 <__LA25Thunk_foo1a> +# CHECK-NEXT: 20154: 00 00 00 00 nop +# CHECK-NEXT: 20158: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2> +# CHECK-NEXT: 2015c: 00 00 00 00 nop +# CHECK-NEXT: 20160: 0c 00 80 04 jal 131088 <__LA25Thunk_foo1b> +# CHECK-NEXT: 20164: 00 00 00 00 nop +# CHECK-NEXT: 20168: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2> +# CHECK-NEXT: 2016c: 00 00 00 00 nop +# CHECK-NEXT: 20170: 0c 00 80 60 jal 131456 <__LA25Thunk_fpic> +# CHECK-NEXT: 20174: 00 00 00 00 nop +# CHECK-NEXT: 20178: 0c 00 80 68 jal 131488 <fnpic> +# CHECK-NEXT: 2017c: 00 00 00 00 nop +# CHECK: __LA25Thunk_fpic: +# CHECK-NEXT: 20180: 3c 19 00 02 lui $25, 2 +# CHECK-NEXT: 20184: 08 00 80 64 j 131472 <fpic> +# CHECK-NEXT: 20188: 27 39 01 90 addiu $25, $25, 400 +# CHECK-NEXT: 2018c: 00 00 00 00 nop +# CHECK: fpic: +# CHECK-NEXT: 20190: 00 00 00 00 nop +# CHECK-NEXT: 20194: 00 00 00 00 nop +# CHECK-NEXT: 20198: 00 00 00 00 nop +# CHECK-NEXT: 2019c: 00 00 00 00 nop +# CHECK: fnpic: +# CHECK-NEXT: 201a0: 00 00 00 00 nop + + .text + .globl __start +__start: + jal foo1a + jal foo2 + jal foo1b + jal foo2 + jal fpic + jal fnpic + +# Test script with orphans added to existing OutputSection, the .text.1 and +# .text.2 sections will be added to .text +# RUN: echo "SECTIONS { .text 0x20000 : { *(.text) } }" > %t2.script +# RUN: ld.lld --script %t2.script %t-npic.o %t-pic.o %t-sto-pic.o -o %t2.exe +# RUN: llvm-objdump -d %t2.exe | FileCheck -check-prefix=ORPH1 %s +# ORPH1: Disassembly of section .text: +# ORPH1-NEXT: __start: +# ORPH1-NEXT: 20000: 0c 00 80 15 jal 131156 <__LA25Thunk_foo1a> +# ORPH1-NEXT: 20004: 00 00 00 00 nop +# ORPH1-NEXT: 20008: 0c 00 80 22 jal 131208 <__LA25Thunk_foo2> +# ORPH1-NEXT: 2000c: 00 00 00 00 nop +# ORPH1-NEXT: 20010: 0c 00 80 19 jal 131172 <__LA25Thunk_foo1b> +# ORPH1-NEXT: 20014: 00 00 00 00 nop +# ORPH1-NEXT: 20018: 0c 00 80 22 jal 131208 <__LA25Thunk_foo2> +# ORPH1-NEXT: 2001c: 00 00 00 00 nop +# ORPH1-NEXT: 20020: 0c 00 80 0c jal 131120 <__LA25Thunk_fpic> +# ORPH1-NEXT: 20024: 00 00 00 00 nop +# ORPH1-NEXT: 20028: 0c 00 80 14 jal 131152 <fnpic> +# ORPH1-NEXT: 2002c: 00 00 00 00 nop +# ORPH1: __LA25Thunk_fpic: +# ORPH1-NEXT: 20030: 3c 19 00 02 lui $25, 2 +# ORPH1-NEXT: 20034: 08 00 80 10 j 131136 <fpic> +# ORPH1-NEXT: 20038: 27 39 00 40 addiu $25, $25, 64 +# ORPH1-NEXT: 2003c: 00 00 00 00 nop +# ORPH1: fpic: +# ORPH1-NEXT: 20040: 00 00 00 00 nop +# ORPH1-NEXT: 20044: 00 00 00 00 nop +# ORPH1-NEXT: 20048: 00 00 00 00 nop +# ORPH1-NEXT: 2004c: 00 00 00 00 nop +# ORPH1: fnpic: +# ORPH1-NEXT: 20050: 00 00 00 00 nop +# ORPH1: __LA25Thunk_foo1a: +# ORPH1-NEXT: 20054: 3c 19 00 02 lui $25, 2 +# ORPH1-NEXT: 20058: 08 00 80 20 j 131200 <foo1a> +# ORPH1-NEXT: 2005c: 27 39 00 80 addiu $25, $25, 128 +# ORPH1-NEXT: 20060: 00 00 00 00 nop +# ORPH1: __LA25Thunk_foo1b: +# ORPH1-NEXT: 20064: 3c 19 00 02 lui $25, 2 +# ORPH1-NEXT: 20068: 08 00 80 21 j 131204 <foo1b> +# ORPH1-NEXT: 2006c: 27 39 00 84 addiu $25, $25, 132 +# ORPH1-NEXT: 20070: 00 00 00 00 nop +# ORPH1-NEXT: 20074: 00 00 00 00 nop +# ORPH1-NEXT: 20078: 00 00 00 00 nop +# ORPH1-NEXT: 2007c: 00 00 00 00 nop +# ORPH1: foo1a: +# ORPH1-NEXT: 20080: 00 00 00 00 nop +# ORPH1: foo1b: +# ORPH1-NEXT: 20084: 00 00 00 00 nop +# ORPH1: __LA25Thunk_foo2: +# ORPH1-NEXT: 20088: 3c 19 00 02 lui $25, 2 +# ORPH1-NEXT: 2008c: 08 00 80 28 j 131232 <foo2> +# ORPH1-NEXT: 20090: 27 39 00 a0 addiu $25, $25, 160 +# ORPH1-NEXT: 20094: 00 00 00 00 nop +# ORPH1-NEXT: 20098: 00 00 00 00 nop +# ORPH1-NEXT: 2009c: 00 00 00 00 nop +# ORPH1: foo2: +# ORPH1-NEXT: 200a0: 00 00 00 00 nop + +# Test script with orphans added to new OutputSection, the .text.1 and +# .text.2 sections will form a new OutputSection .text +# RUN: echo "SECTIONS { .out 0x20000 : { *(.text) } }" > %t3.script +# RUN: ld.lld --script %t3.script %t-npic.o %t-pic.o %t-sto-pic.o -o %t3.exe +# RUN: llvm-objdump -d %t3.exe | FileCheck -check-prefix=ORPH2 %s +# ORPH2: Disassembly of section .out: +# ORPH2-NEXT: __start: +# ORPH2-NEXT: 20000: 0c 00 80 18 jal 131168 <__LA25Thunk_foo1a> +# ORPH2-NEXT: 20004: 00 00 00 00 nop +# ORPH2-NEXT: 20008: 0c 00 80 22 jal 131208 <__LA25Thunk_foo2> +# ORPH2-NEXT: 2000c: 00 00 00 00 nop +# ORPH2-NEXT: 20010: 0c 00 80 1c jal 131184 <__LA25Thunk_foo1b> +# ORPH2-NEXT: 20014: 00 00 00 00 nop +# ORPH2-NEXT: 20018: 0c 00 80 22 jal 131208 <__LA25Thunk_foo2> +# ORPH2-NEXT: 2001c: 00 00 00 00 nop +# ORPH2-NEXT: 20020: 0c 00 80 0c jal 131120 <__LA25Thunk_fpic> +# ORPH2-NEXT: 20024: 00 00 00 00 nop +# ORPH2-NEXT: 20028: 0c 00 80 14 jal 131152 <fnpic> +# ORPH2-NEXT: 2002c: 00 00 00 00 nop +# ORPH2: __LA25Thunk_fpic: +# ORPH2-NEXT: 20030: 3c 19 00 02 lui $25, 2 +# ORPH2-NEXT: 20034: 08 00 80 10 j 131136 <fpic> +# ORPH2-NEXT: 20038: 27 39 00 40 addiu $25, $25, 64 +# ORPH2-NEXT: 2003c: 00 00 00 00 nop +# ORPH2: fpic: +# ORPH2-NEXT: 20040: 00 00 00 00 nop +# ORPH2-NEXT: 20044: 00 00 00 00 nop +# ORPH2-NEXT: 20048: 00 00 00 00 nop +# ORPH2-NEXT: 2004c: 00 00 00 00 nop +# ORPH2: fnpic: +# ORPH2-NEXT: 20050: 00 00 00 00 nop +# ORPH2-NEXT: Disassembly of section .text: +# ORPH2-NEXT: __LA25Thunk_foo1a: +# ORPH2-NEXT: 20060: 3c 19 00 02 lui $25, 2 +# ORPH2-NEXT: 20064: 08 00 80 20 j 131200 <foo1a> +# ORPH2-NEXT: 20068: 27 39 00 80 addiu $25, $25, 128 +# ORPH2-NEXT: 2006c: 00 00 00 00 nop +# ORPH2: __LA25Thunk_foo1b: +# ORPH2-NEXT: 20070: 3c 19 00 02 lui $25, 2 +# ORPH2-NEXT: 20074: 08 00 80 21 j 131204 <foo1b> +# ORPH2-NEXT: 20078: 27 39 00 84 addiu $25, $25, 132 +# ORPH2-NEXT: 2007c: 00 00 00 00 nop +# ORPH2: foo1a: +# ORPH2-NEXT: 20080: 00 00 00 00 nop +# ORPH2: foo1b: +# ORPH2-NEXT: 20084: 00 00 00 00 nop +# ORPH2: __LA25Thunk_foo2: +# ORPH2-NEXT: 20088: 3c 19 00 02 lui $25, 2 +# ORPH2-NEXT: 2008c: 08 00 80 28 j 131232 <foo2> +# ORPH2-NEXT: 20090: 27 39 00 a0 addiu $25, $25, 160 +# ORPH2-NEXT: 20094: 00 00 00 00 nop +# ORPH2-NEXT: 20098: 00 00 00 00 nop +# ORPH2-NEXT: 2009c: 00 00 00 00 nop +# ORPH2: foo2: +# ORPH2-NEXT: 200a0: 00 00 00 00 nop diff --git a/test/ELF/relocatable-comdat-multiple.s b/test/ELF/relocatable-comdat-multiple.s new file mode 100644 index 000000000000..4c3e7ce7f6d4 --- /dev/null +++ b/test/ELF/relocatable-comdat-multiple.s @@ -0,0 +1,31 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/relocatable-comdat-multiple.s -o %t2.o +# RUN: ld.lld -r %t.o %t2.o -o %t +# RUN: llvm-readobj -elf-section-groups %t | FileCheck %s + +# CHECK: Groups { +# CHECK-NEXT: Group { +# CHECK-NEXT: Name: .group +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Type: COMDAT +# CHECK-NEXT: Signature: aaa +# CHECK-NEXT: Section(s) in group [ +# CHECK-NEXT: .text.a +# CHECK-NEXT: .text.b +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: Group { +# CHECK-NEXT: Name: .group +# CHECK-NEXT: Index: 5 +# CHECK-NEXT: Type: COMDAT +# CHECK-NEXT: Signature: bbb +# CHECK-NEXT: Section(s) in group [ +# CHECK-NEXT: .text.c +# CHECK-NEXT: .text.d +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: } + +.section .text.a,"axG",@progbits,aaa,comdat +.section .text.b,"axG",@progbits,aaa,comdat diff --git a/test/ELF/relocatable-compressed-input.s b/test/ELF/relocatable-compressed-input.s new file mode 100644 index 000000000000..bdfb2073a1e0 --- /dev/null +++ b/test/ELF/relocatable-compressed-input.s @@ -0,0 +1,45 @@ +# REQUIRES: zlib + +# RUN: llvm-mc -compress-debug-sections=zlib-gnu -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 +# RUN: llvm-readobj -sections %t1 | FileCheck -check-prefix=GNU %s +# GNU: Name: .zdebug_str + +# RUN: ld.lld %t1 -o %t2 -r +# RUN: llvm-readobj -sections -section-data %t2 | FileCheck %s + +## Check we decompress section and remove ".z" prefix specific for zlib-gnu compression. +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .debug_str +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_MERGE +# CHECK-NEXT: SHF_STRINGS +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: 1 +# CHECK-NEXT: EntrySize: 1 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: {{.*}} |short unsigned i| +# CHECK-NEXT: 0010: {{.*}} |nt.unsigned int.| +# CHECK-NEXT: 0020: {{.*}} |long unsigned in| +# CHECK-NEXT: 0030: {{.*}} |t.char.unsigned | +# CHECK-NEXT: 0040: {{.*}} |char.| +# CHECK-NEXT: ) +# CHECK-NEXT: } + +.section .debug_str,"MS",@progbits,1 +.LASF2: + .string "short unsigned int" +.LASF3: + .string "unsigned int" +.LASF0: + .string "long unsigned int" +.LASF8: + .string "char" +.LASF1: + .string "unsigned char" diff --git a/test/ELF/relocatable-empty-archive.s b/test/ELF/relocatable-empty-archive.s new file mode 100644 index 000000000000..545ef7bfc24c --- /dev/null +++ b/test/ELF/relocatable-empty-archive.s @@ -0,0 +1,10 @@ +# REQUIRES: x86 +# RUN: rm -f %t.a +# RUN: llvm-ar rc %t.a +# RUN: ld.lld -m elf_x86_64 %t.a -o %t -r +# RUN: llvm-readobj -file-headers %t | FileCheck %s + +# CHECK: Format: ELF64-x86-64 +# CHECK: Arch: x86_64 +# CHECK: AddressSize: 64bit +# CHECK: Type: Relocatable diff --git a/unittests/DriverTests/DarwinLdDriverTest.cpp b/unittests/DriverTests/DarwinLdDriverTest.cpp index ea7fcc7eafcb..d81f1543f453 100644 --- a/unittests/DriverTests/DarwinLdDriverTest.cpp +++ b/unittests/DriverTests/DarwinLdDriverTest.cpp @@ -14,7 +14,7 @@ #include "lld/Driver/Driver.h" #include "lld/ReaderWriter/MachOLinkingContext.h" -#include "llvm/Support/MachO.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" diff --git a/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp b/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp index a3c445a93619..3e8793a0ef48 100644 --- a/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp +++ b/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp @@ -7,14 +7,14 @@ // //===----------------------------------------------------------------------===// -#include "gtest/gtest.h" #include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h" #include "lld/ReaderWriter/MachOLinkingContext.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Error.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/YAMLTraits.h" +#include "gtest/gtest.h" #include <cstdint> #include <memory> diff --git a/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp b/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp index 51196e6eeba6..210fecbf0866 100644 --- a/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp +++ b/unittests/MachOTests/MachONormalizedFileBinaryWriterTests.cpp @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "gtest/gtest.h" #include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/MachO.h" +#include "gtest/gtest.h" #include <cassert> #include <memory> #include <system_error> diff --git a/unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp b/unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp index 8205ea97520a..a0176bb671b7 100644 --- a/unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp +++ b/unittests/MachOTests/MachONormalizedFileToAtomsTests.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "gtest/gtest.h" #include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h" #include "lld/Core/Atom.h" #include "lld/Core/DefinedAtom.h" @@ -15,9 +14,10 @@ #include "lld/Core/UndefinedAtom.h" #include "lld/ReaderWriter/MachOLinkingContext.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Error.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/YAMLTraits.h" +#include "gtest/gtest.h" #include <cstdint> #include <memory> diff --git a/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp b/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp index e41b7ecd801c..6bbde72d3dd1 100644 --- a/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp +++ b/unittests/MachOTests/MachONormalizedFileYAMLTests.cpp @@ -7,18 +7,18 @@ // //===----------------------------------------------------------------------===// -#include "gtest/gtest.h" #include "../../lib/ReaderWriter/MachO/MachONormalizedFile.h" #include "lld/ReaderWriter/MachOLinkingContext.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Error.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" #include <cstdint> #include <memory> -#include <system_error> #include <string> +#include <system_error> using llvm::StringRef; using llvm::MemoryBuffer; |