diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-05-29 16:26:20 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-05-29 16:26:20 +0000 |
commit | bef2946c219dc621608bcc9e47f8b973e5ef5c70 (patch) | |
tree | 1e4dfae199fc27167ed7496693938fec2dab65c2 | |
parent | c53addf38e24e4dafe992aafb3ae928bfa8fdb0a (diff) | |
download | src-test2-bef2946c219dc621608bcc9e47f8b973e5ef5c70.tar.gz src-test2-bef2946c219dc621608bcc9e47f8b973e5ef5c70.zip |
Notes
47 files changed, 1009 insertions, 475 deletions
diff --git a/COFF/ICF.cpp b/COFF/ICF.cpp index 3b7cc424f0a2..da8ca360542a 100644 --- a/COFF/ICF.cpp +++ b/COFF/ICF.cpp @@ -56,7 +56,6 @@ private: std::vector<SectionChunk *> Chunks; int Cnt = 0; - std::atomic<uint32_t> NextId = {1}; std::atomic<bool> Repeat = {false}; }; @@ -98,10 +97,10 @@ void ICF::segregate(size_t Begin, size_t End, bool Constant) { }); size_t Mid = Bound - Chunks.begin(); - // Split [Begin, End) into [Begin, Mid) and [Mid, End). - uint32_t Id = NextId++; + // Split [Begin, End) into [Begin, Mid) and [Mid, End). We use Mid as an + // equivalence class ID because every group ends with a unique index. for (size_t I = Begin; I < Mid; ++I) - Chunks[I]->Class[(Cnt + 1) % 2] = Id; + Chunks[I]->Class[(Cnt + 1) % 2] = Mid; // If we created a group, we need to iterate the main loop again. if (Mid != End) @@ -186,6 +185,7 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) { // call Fn sequentially. if (Chunks.size() < 1024) { forEachClassRange(0, Chunks.size(), Fn); + ++Cnt; return; } @@ -193,9 +193,10 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) { size_t NumShards = 256; size_t Step = Chunks.size() / NumShards; for_each_n(parallel::par, size_t(0), NumShards, [&](size_t I) { - forEachClassRange(I * Step, (I + 1) * Step, Fn); + size_t End = (I == NumShards - 1) ? Chunks.size() : (I + 1) * Step; + forEachClassRange(I * Step, End, Fn); }); - forEachClassRange(Step * NumShards, Chunks.size(), Fn); + ++Cnt; } // Merge identical COMDAT sections. @@ -203,22 +204,20 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) { // contents and relocations are all the same. void ICF::run(const std::vector<Chunk *> &Vec) { // Collect only mergeable sections and group by hash value. + uint32_t NextId = 1; for (Chunk *C : Vec) { - auto *SC = dyn_cast<SectionChunk>(C); - if (!SC) - continue; - - if (isEligible(SC)) { - // Set MSB to 1 to avoid collisions with non-hash classs. - SC->Class[0] = getHash(SC) | (1 << 31); - Chunks.push_back(SC); - } else { - SC->Class[0] = NextId++; + if (auto *SC = dyn_cast<SectionChunk>(C)) { + if (isEligible(SC)) + Chunks.push_back(SC); + else + SC->Class[0] = NextId++; } } - if (Chunks.empty()) - return; + // Initially, we use hash values to partition sections. + for (SectionChunk *SC : Chunks) + // Set MSB to 1 to avoid collisions with non-hash classs. + SC->Class[0] = getHash(SC) | (1 << 31); // From now on, sections in Chunks are ordered so that sections in // the same group are consecutive in the vector. @@ -229,14 +228,12 @@ void ICF::run(const std::vector<Chunk *> &Vec) { // Compare static contents and assign unique IDs for each static content. forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); }); - ++Cnt; // Split groups by comparing relocations until convergence is obtained. do { Repeat = false; forEachClass( [&](size_t Begin, size_t End) { segregate(Begin, End, false); }); - ++Cnt; } while (Repeat); log("ICF needed " + Twine(Cnt) + " iterations"); diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp index 6e6465cd5d62..258d9fd74b4d 100644 --- a/COFF/InputFiles.cpp +++ b/COFF/InputFiles.cpp @@ -48,13 +48,11 @@ namespace coff { /// alias to Target. static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F, SymbolBody *Source, SymbolBody *Target) { - auto *U = dyn_cast<Undefined>(Source); - if (!U) - return; - else if (!U->WeakAlias) + if (auto *U = dyn_cast<Undefined>(Source)) { + if (U->WeakAlias && U->WeakAlias != Target) + Symtab->reportDuplicate(Source->symbol(), F); U->WeakAlias = Target; - else if (U->WeakAlias != Target) - Symtab->reportDuplicate(Source->symbol(), F); + } } ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} @@ -153,8 +151,10 @@ void ObjectFile::initializeSymbols() { uint32_t NumSymbols = COFFObj->getNumberOfSymbols(); SymbolBodies.reserve(NumSymbols); SparseSymbolBodies.resize(NumSymbols); + SmallVector<std::pair<SymbolBody *, uint32_t>, 8> WeakAliases; int32_t LastSectionNumber = 0; + for (uint32_t I = 0; I < NumSymbols; ++I) { // Get a COFFSymbolRef object. ErrorOr<COFFSymbolRef> SymOrErr = COFFObj->getSymbol(I); @@ -185,9 +185,12 @@ void ObjectFile::initializeSymbols() { I += Sym.getNumberOfAuxSymbols(); LastSectionNumber = Sym.getSectionNumber(); } - for (auto WeakAlias : WeakAliases) - checkAndSetWeakAlias(Symtab, this, WeakAlias.first, - SparseSymbolBodies[WeakAlias.second]); + + for (auto &KV : WeakAliases) { + SymbolBody *Sym = KV.first; + uint32_t Idx = KV.second; + checkAndSetWeakAlias(Symtab, this, Sym, SparseSymbolBodies[Idx]); + } } SymbolBody *ObjectFile::createUndefined(COFFSymbolRef Sym) { diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h index 9e32b3b9f9d6..9449f24ac241 100644 --- a/COFF/InputFiles.h +++ b/COFF/InputFiles.h @@ -10,6 +10,7 @@ #ifndef LLD_COFF_INPUT_FILES_H #define LLD_COFF_INPUT_FILES_H +#include "Config.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" @@ -161,7 +162,9 @@ private: // for details about the format. class ImportFile : public InputFile { public: - explicit ImportFile(MemoryBufferRef M) : InputFile(ImportKind, M) {} + explicit ImportFile(MemoryBufferRef M) + : InputFile(ImportKind, M), Live(!Config->DoGC) {} + static bool classof(const InputFile *F) { return F->kind() == ImportKind; } DefinedImportData *ImpSym = nullptr; @@ -176,6 +179,14 @@ public: StringRef ExternalName; const coff_import_header *Hdr; Chunk *Location = nullptr; + + // We want to eliminate dllimported symbols if no one actually refers them. + // This "Live" bit is used to keep track of which import library members + // are actually in use. + // + // If the Live bit is turned off by MarkLive, Writer will ignore dllimported + // symbols provided by this import library member. + bool Live; }; // Used for LTO. diff --git a/COFF/MarkLive.cpp b/COFF/MarkLive.cpp index 0156d238b672..25e5cc350673 100644 --- a/COFF/MarkLive.cpp +++ b/COFF/MarkLive.cpp @@ -37,19 +37,26 @@ void markLive(const std::vector<Chunk *> &Chunks) { Worklist.push_back(C); }; + auto AddSym = [&](SymbolBody *B) { + if (auto *Sym = dyn_cast<DefinedRegular>(B)) + Enqueue(Sym->getChunk()); + else if (auto *Sym = dyn_cast<DefinedImportData>(B)) + Sym->File->Live = true; + else if (auto *Sym = dyn_cast<DefinedImportThunk>(B)) + Sym->WrappedSym->File->Live = true; + }; + // Add GC root chunks. for (SymbolBody *B : Config->GCRoot) - if (auto *D = dyn_cast<DefinedRegular>(B)) - Enqueue(D->getChunk()); + AddSym(B); while (!Worklist.empty()) { SectionChunk *SC = Worklist.pop_back_val(); assert(SC->isLive() && "We mark as live when pushing onto the worklist!"); // Mark all symbols listed in the relocation table for this section. - for (SymbolBody *S : SC->symbols()) - if (auto *D = dyn_cast<DefinedRegular>(S)) - Enqueue(D->getChunk()); + for (SymbolBody *B : SC->symbols()) + AddSym(B); // Mark associative sections if any. for (SectionChunk *C : SC->children()) diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp index 0266148cc6c9..a3b3ab7bbab0 100644 --- a/COFF/PDB.cpp +++ b/COFF/PDB.cpp @@ -99,6 +99,12 @@ static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder, static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder, codeview::TypeTableBuilder &TypeTable, codeview::TypeTableBuilder &IDTable) { + // Follow type servers. If the same type server is encountered more than + // once for this instance of `PDBTypeServerHandler` (for example if many + // object files reference the same TypeServer), the types from the + // TypeServer will only be visited once. + pdb::PDBTypeServerHandler Handler; + // Visit all .debug$T sections to add them to Builder. for (ObjectFile *File : Symtab->ObjectFiles) { ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T"); @@ -109,16 +115,11 @@ static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder, codeview::CVTypeArray Types; BinaryStreamReader Reader(Stream); SmallVector<TypeIndex, 128> SourceToDest; - // Follow type servers. If the same type server is encountered more than - // once for this instance of `PDBTypeServerHandler` (for example if many - // object files reference the same TypeServer), the types from the - // TypeServer will only be visited once. - pdb::PDBTypeServerHandler Handler; Handler.addSearchPath(llvm::sys::path::parent_path(File->getName())); if (auto EC = Reader.readArray(Types, Reader.getLength())) fatal(EC, "Reader::readArray failed"); - if (auto Err = codeview::mergeTypeStreams(IDTable, TypeTable, SourceToDest, - &Handler, Types)) + if (auto Err = codeview::mergeTypeAndIdRecords( + IDTable, TypeTable, SourceToDest, &Handler, Types)) fatal(Err, "codeview::mergeTypeStreams failed"); } diff --git a/COFF/Symbols.cpp b/COFF/Symbols.cpp index 993e920ce7f7..5c185a511dd7 100644 --- a/COFF/Symbols.cpp +++ b/COFF/Symbols.cpp @@ -61,16 +61,19 @@ COFFSymbolRef DefinedCOFF::getCOFFSymbol() { return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(Sym)); } +static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) { + if (Machine == AMD64) + return make<ImportThunkChunkX64>(S); + if (Machine == I386) + return make<ImportThunkChunkX86>(S); + assert(Machine == ARMNT); + return make<ImportThunkChunkARM>(S); +} + DefinedImportThunk::DefinedImportThunk(StringRef Name, DefinedImportData *S, uint16_t Machine) - : Defined(DefinedImportThunkKind, Name) { - switch (Machine) { - case AMD64: Data = make<ImportThunkChunkX64>(S); return; - case I386: Data = make<ImportThunkChunkX86>(S); return; - case ARMNT: Data = make<ImportThunkChunkARM>(S); return; - default: llvm_unreachable("unknown machine type"); - } -} + : Defined(DefinedImportThunkKind, Name), WrappedSym(S), + Data(makeImportThunk(S, Machine)) {} Defined *Undefined::getWeakAlias() { // A weak alias may be a weak alias to another symbol, so check recursively. diff --git a/COFF/Symbols.h b/COFF/Symbols.h index 1b83f73ff20c..801fc87f91d9 100644 --- a/COFF/Symbols.h +++ b/COFF/Symbols.h @@ -300,7 +300,6 @@ public: void setLocation(Chunk *AddressTable) { File->Location = AddressTable; } uint16_t getOrdinal() { return File->Hdr->OrdinalHint; } -private: ImportFile *File; }; @@ -320,6 +319,8 @@ public: uint64_t getRVA() { return Data->getRVA(); } Chunk *getChunk() { return Data; } + DefinedImportData *WrappedSym; + private: Chunk *Data; }; diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp index cf3ad7ef045c..fb1f3cae5bb2 100644 --- a/COFF/Writer.cpp +++ b/COFF/Writer.cpp @@ -365,6 +365,9 @@ void Writer::createImportTables() { // the same order as in the command line. (That affects DLL // initialization order, and this ordering is MSVC-compatible.) for (ImportFile *File : Symtab->ImportFiles) { + if (!File->Live) + continue; + std::string DLL = StringRef(File->DLLName).lower(); if (Config->DLLOrder.count(DLL) == 0) Config->DLLOrder[DLL] = Config->DLLOrder.size(); @@ -372,19 +375,28 @@ void Writer::createImportTables() { OutputSection *Text = createSection(".text"); for (ImportFile *File : Symtab->ImportFiles) { + if (!File->Live) + continue; + if (DefinedImportThunk *Thunk = File->ThunkSym) Text->addChunk(Thunk->getChunk()); + if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) { + if (!File->ThunkSym) + fatal("cannot delay-load " + toString(File) + + " due to import of data: " + toString(*File->ImpSym)); DelayIdata.add(File->ImpSym); } else { Idata.add(File->ImpSym); } } + if (!Idata.empty()) { OutputSection *Sec = createSection(".idata"); for (Chunk *C : Idata.getChunks()) Sec->addChunk(C); } + if (!DelayIdata.empty()) { Defined *Helper = cast<Defined>(Config->DelayLoadHelper); DelayIdata.create(Helper); @@ -437,6 +449,14 @@ Optional<coff_symbol16> Writer::createSymbol(Defined *Def) { if (!D->getChunk()->isLive()) return None; + if (auto *Sym = dyn_cast<DefinedImportData>(Def)) + if (!Sym->File->Live) + return None; + + if (auto *Sym = dyn_cast<DefinedImportThunk>(Def)) + if (!Sym->WrappedSym->File->Live) + return None; + coff_symbol16 Sym; StringRef Name = Def->getName(); if (Name.size() > COFF::NameSize) { @@ -491,14 +511,17 @@ void Writer::createSymbolAndStringTable() { Sec->setStringTableOff(addEntryToStringTable(Name)); } - for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) - for (SymbolBody *B : File->getSymbols()) - if (auto *D = dyn_cast<Defined>(B)) - if (!D->WrittenToSymtab) { - D->WrittenToSymtab = true; - if (Optional<coff_symbol16> Sym = createSymbol(D)) - OutputSymtab.push_back(*Sym); - } + for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) { + for (SymbolBody *B : File->getSymbols()) { + auto *D = dyn_cast<Defined>(B); + if (!D || D->WrittenToSymtab) + continue; + D->WrittenToSymtab = true; + + if (Optional<coff_symbol16> Sym = createSymbol(D)) + OutputSymtab.push_back(*Sym); + } + } OutputSection *LastSection = OutputSections.back(); // We position the symbol table to be adjacent to the end of the last section. @@ -782,19 +805,15 @@ void Writer::writeBuildId() { if (BuildId == nullptr) return; - MD5 Hash; - MD5::MD5Result Res; - - Hash.update(ArrayRef<uint8_t>{Buffer->getBufferStart(), - Buffer->getBufferEnd()}); - Hash.final(Res); - assert(BuildId->DI->Signature.CVSignature == OMF::Signature::PDB70 && "only PDB 7.0 is supported"); - assert(sizeof(Res) == sizeof(BuildId->DI->PDB70.Signature) && + assert(sizeof(BuildId->DI->PDB70.Signature) == 16 && "signature size mismatch"); - memcpy(BuildId->DI->PDB70.Signature, Res.Bytes.data(), - sizeof(codeview::PDB70DebugInfo::Signature)); + + // Compute an MD5 hash. + ArrayRef<uint8_t> Buf(Buffer->getBufferStart(), Buffer->getBufferEnd()); + memcpy(BuildId->DI->PDB70.Signature, MD5::hash(Buf).data(), 16); + // TODO(compnerd) track the Age BuildId->DI->PDB70.Age = 1; } diff --git a/ELF/Config.h b/ELF/Config.h index 57a0e5a5ec73..54f6dc2acc7c 100644 --- a/ELF/Config.h +++ b/ELF/Config.h @@ -145,6 +145,7 @@ struct Configuration { bool ZNow; bool ZOrigin; bool ZRelro; + bool ZRodynamic; bool ZText; bool ExitEarly; bool ZWxneeded; diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index 737c6a6bf114..325404447b24 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -572,10 +572,14 @@ static std::pair<bool, bool> getHashStyle(opt::InputArgList &Args) { // -build-id=sha1 are actually tree hashes for performance reasons. static std::pair<BuildIdKind, std::vector<uint8_t>> getBuildId(opt::InputArgList &Args) { - if (Args.hasArg(OPT_build_id)) + auto *Arg = Args.getLastArg(OPT_build_id, OPT_build_id_eq); + if (!Arg) + return {BuildIdKind::None, {}}; + + if (Arg->getOption().getID() == OPT_build_id) return {BuildIdKind::Fast, {}}; - StringRef S = getString(Args, OPT_build_id_eq, "none"); + StringRef S = Arg->getValue(); if (S == "md5") return {BuildIdKind::Md5, {}}; if (S == "sha1" || S == "tree") @@ -688,6 +692,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->ZNow = hasZOption(Args, "now"); Config->ZOrigin = hasZOption(Args, "origin"); Config->ZRelro = !hasZOption(Args, "norelro"); + Config->ZRodynamic = hasZOption(Args, "rodynamic"); Config->ZStackSize = getZOptionValue(Args, "stack-size", 0); Config->ZText = !hasZOption(Args, "notext"); Config->ZWxneeded = hasZOption(Args, "wxneeded"); diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp index 3722d4e3ed2f..419ae6816328 100644 --- a/ELF/ICF.cpp +++ b/ELF/ICF.cpp @@ -326,9 +326,9 @@ void ICF<ELFT>::forEachClass(std::function<void(size_t, size_t)> Fn) { size_t NumShards = 256; size_t Step = Sections.size() / NumShards; parallelForEachN(0, NumShards, [&](size_t I) { - forEachClassRange(I * Step, (I + 1) * Step, Fn); + size_t End = (I == NumShards - 1) ? Sections.size() : (I + 1) * Step; + forEachClassRange(I * Step, End, Fn); }); - forEachClassRange(Step * NumShards, Sections.size(), Fn); ++Cnt; } diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index fe036a644f41..98189825ccbf 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -281,18 +281,20 @@ bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) { template <class ELFT> void elf::ObjectFile<ELFT>::initializeSections( DenseSet<CachedHashStringRef> &ComdatGroups) { + const ELFFile<ELFT> &Obj = this->getObj(); + ArrayRef<Elf_Shdr> ObjSections = check(this->getObj().sections(), toString(this)); - const ELFFile<ELFT> &Obj = this->getObj(); uint64_t Size = ObjSections.size(); this->Sections.resize(Size); - unsigned I = -1; + StringRef SectionStringTable = check(Obj.getSectionStringTable(ObjSections), toString(this)); - for (const Elf_Shdr &Sec : ObjSections) { - ++I; + + for (size_t I = 0, E = ObjSections.size(); I < E; I++) { if (this->Sections[I] == &InputSection::Discarded) continue; + const Elf_Shdr &Sec = ObjSections[I]; // SHF_EXCLUDE'ed sections are discarded by the linker. However, // if -r is given, we'll let the final link discard such sections. @@ -303,13 +305,22 @@ void elf::ObjectFile<ELFT>::initializeSections( } switch (Sec.sh_type) { - case SHT_GROUP: - this->Sections[I] = &InputSection::Discarded; - if (ComdatGroups - .insert( - CachedHashStringRef(getShtGroupSignature(ObjSections, Sec))) - .second) + 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) continue; + for (uint32_t SecIndex : getShtGroupEntries(Sec)) { if (SecIndex >= Size) fatal(toString(this) + @@ -317,6 +328,7 @@ void elf::ObjectFile<ELFT>::initializeSections( this->Sections[SecIndex] = &InputSection::Discarded; } break; + } case SHT_SYMTAB: this->initSymtab(ObjSections, &Sec); break; diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index e8cfd21c4c49..466656efbf08 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -23,6 +23,7 @@ #include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Threading.h" #include <mutex> using namespace llvm; @@ -172,7 +173,8 @@ void InputSectionBase::uncompress() { if (Error E = Dec.decompress({OutputBuf, Size})) fatal(toString(this) + ": decompress failed: " + llvm::toString(std::move(E))); - Data = ArrayRef<uint8_t>((uint8_t *)OutputBuf, Size); + this->Data = ArrayRef<uint8_t>((uint8_t *)OutputBuf, Size); + this->Flags &= ~(uint64_t)SHF_COMPRESSED; } uint64_t SectionBase::getOffset(const DefinedRegular &Sym) const { @@ -293,6 +295,24 @@ bool InputSectionBase::classof(const SectionBase *S) { return S->kind() != Output; } +void InputSection::copyShtGroup(uint8_t *Buf) { + assert(this->Type == SHT_GROUP); + + 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. + *To++ = From[0]; + + // Here we adjust indices of sections that belong to group as it + // might change during linking. + ArrayRef<InputSectionBase *> Sections = this->File->getSections(); + for (uint32_t Val : From.slice(1)) { + uint32_t Index = read32(&Val, Config->Endianness); + write32(To++, Sections[Index]->OutSec->SectionIndex, Config->Endianness); + } +} + InputSectionBase *InputSection::getRelocatedSection() { assert(this->Type == SHT_RELA || this->Type == SHT_REL); ArrayRef<InputSectionBase *> Sections = this->File->getSections(); @@ -678,6 +698,13 @@ 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 (this->Type == SHT_GROUP) { + copyShtGroup(Buf + OutSecOff); + return; + } + // Copy section contents from source object file to output file // and then apply relocations. memcpy(Buf + OutSecOff, Data.data(), Data.size()); @@ -866,7 +893,7 @@ const SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) const { // it is not just an addition to a base output offset. uint64_t MergeInputSection::getOffset(uint64_t Offset) const { // Initialize OffsetMap lazily. - std::call_once(InitOffsetMap, [&] { + llvm::call_once(InitOffsetMap, [&] { OffsetMap.reserve(Pieces.size()); for (const SectionPiece &Piece : Pieces) OffsetMap[Piece.InputOff] = Piece.OutputOff; diff --git a/ELF/InputSection.h b/ELF/InputSection.h index 303c398b58cd..4ef4328e8a5d 100644 --- a/ELF/InputSection.h +++ b/ELF/InputSection.h @@ -18,6 +18,7 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Object/ELF.h" +#include "llvm/Support/Threading.h" #include <mutex> namespace lld { @@ -248,7 +249,7 @@ private: std::vector<uint32_t> Hashes; mutable llvm::DenseMap<uint64_t, uint64_t> OffsetMap; - mutable std::once_flag InitOffsetMap; + mutable llvm::once_flag InitOffsetMap; llvm::DenseSet<uint64_t> LiveOffsets; }; @@ -318,6 +319,8 @@ public: private: template <class ELFT, class RelTy> void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels); + + void copyShtGroup(uint8_t *Buf); }; // The list of all input sections. diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp index dd435173101a..6915d9713891 100644 --- a/ELF/LTO.cpp +++ b/ELF/LTO.cpp @@ -73,7 +73,12 @@ static std::unique_ptr<lto::LTO> createLTO() { Conf.Options = InitTargetOptionsFromCodeGenFlags(); Conf.Options.RelaxELFRelocations = true; - Conf.RelocModel = Config->Pic ? Reloc::PIC_ : Reloc::Static; + if (Config->Relocatable) + Conf.RelocModel = None; + else if (Config->Pic) + Conf.RelocModel = Reloc::PIC_; + else + Conf.RelocModel = Reloc::Static; Conf.CodeModel = GetCodeModelFromCMModel(); Conf.DisableVerify = Config->DisableVerify; Conf.DiagHandler = diagnosticHandler; diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index c303f0524ad4..492b81c1fa76 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -20,6 +20,8 @@ #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" +#include "Target.h" +#include "Threads.h" #include "Writer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" @@ -198,6 +200,15 @@ bool OutputSectionCommand::classof(const BaseCommand *C) { return C->Kind == OutputSectionKind; } +// Fill [Buf, Buf + Size) with Filler. +// This is used for linker script "=fillexp" command. +static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) { + size_t I = 0; + for (; I + 4 < Size; I += 4) + memcpy(Buf + I, &Filler, 4); + memcpy(Buf + I, &Filler, Size - I); +} + bool InputSectionDescription::classof(const BaseCommand *C) { return C->Kind == InputSectionKind; } @@ -263,16 +274,16 @@ static bool matchConstraints(ArrayRef<InputSectionBase *> Sections, (!IsRW && Kind == ConstraintKind::ReadOnly); } -static void sortSections(InputSectionBase **Begin, InputSectionBase **End, +static void sortSections(InputSection **Begin, InputSection **End, SortSectionPolicy K) { if (K != SortSectionPolicy::Default && K != SortSectionPolicy::None) std::stable_sort(Begin, End, getComparator(K)); } // Compute and remember which sections the InputSectionDescription matches. -std::vector<InputSectionBase *> +std::vector<InputSection *> LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { - std::vector<InputSectionBase *> Ret; + std::vector<InputSection *> Ret; // Collects all sections that satisfy constraints of Cmd. for (const SectionPattern &Pat : Cmd->SectionPatterns) { @@ -294,7 +305,7 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { !Pat.SectionPat.match(Sec->Name)) continue; - Ret.push_back(Sec); + Ret.push_back(cast<InputSection>(Sec)); Sec->Assigned = true; } @@ -309,8 +320,8 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { // --sort-section is handled as an inner SORT command. // 3. If one SORT command is given, and if it is SORT_NONE, don't sort. // 4. If no SORT command is given, sort according to --sort-section. - InputSectionBase **Begin = Ret.data() + SizeBefore; - InputSectionBase **End = Ret.data() + Ret.size(); + InputSection **Begin = Ret.data() + SizeBefore; + InputSection **End = Ret.data() + Ret.size(); if (Pat.SortOuter != SortSectionPolicy::None) { if (Pat.SortInner == SortSectionPolicy::Default) sortSections(Begin, End, Config->SortSection); @@ -493,7 +504,7 @@ void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) { Sec->SectionIndex = Index; } auto *ISD = make<InputSectionDescription>(""); - ISD->Sections.push_back(S); + ISD->Sections.push_back(cast<InputSection>(S)); Cmd->Commands.push_back(ISD); } } @@ -684,7 +695,6 @@ void LinkerScript::adjustSectionsBeforeSorting() { // '.' is assigned to, but creating these section should not have any bad // consequeces and gives us a section to put the symbol in. uint64_t Flags = SHF_ALLOC; - uint32_t Type = SHT_PROGBITS; for (int I = 0, E = Opt.Commands.size(); I != E; ++I) { auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I]); @@ -692,14 +702,13 @@ void LinkerScript::adjustSectionsBeforeSorting() { continue; if (OutputSection *Sec = Cmd->Sec) { Flags = Sec->Flags; - Type = Sec->Type; continue; } if (isAllSectionDescription(*Cmd)) continue; - auto *OutSec = make<OutputSection>(Cmd->Name, Type, Flags); + auto *OutSec = make<OutputSection>(Cmd->Name, SHT_PROGBITS, Flags); OutSec->SectionIndex = I; OutputSections->push_back(OutSec); Cmd->Sec = OutSec; @@ -875,20 +884,20 @@ void LinkerScript::synchronize() { if (!Cmd) continue; ArrayRef<InputSection *> Sections = Cmd->Sec->Sections; - std::vector<InputSectionBase **> ScriptSections; - DenseSet<InputSectionBase *> ScriptSectionsSet; + std::vector<InputSection **> ScriptSections; + DenseSet<InputSection *> ScriptSectionsSet; for (BaseCommand *Base : Cmd->Commands) { auto *ISD = dyn_cast<InputSectionDescription>(Base); if (!ISD) continue; - for (InputSectionBase *&IS : ISD->Sections) { + for (InputSection *&IS : ISD->Sections) { if (IS->Live) { ScriptSections.push_back(&IS); ScriptSectionsSet.insert(IS); } } } - std::vector<InputSectionBase *> Missing; + std::vector<InputSection *> Missing; for (InputSection *IS : Sections) if (!ScriptSectionsSet.count(IS)) Missing.push_back(IS); @@ -896,7 +905,7 @@ void LinkerScript::synchronize() { auto ISD = make<InputSectionDescription>(""); ISD->Sections = Missing; Cmd->Commands.push_back(ISD); - for (InputSectionBase *&IS : ISD->Sections) + for (InputSection *&IS : ISD->Sections) if (IS->Live) ScriptSections.push_back(&IS); } @@ -1034,10 +1043,12 @@ OutputSectionCommand *LinkerScript::getCmd(OutputSection *Sec) const { return I->second; } -Optional<uint32_t> LinkerScript::getFiller(OutputSection *Sec) { - if (OutputSectionCommand *Cmd = getCmd(Sec)) - return Cmd->Filler; - return None; +uint32_t OutputSectionCommand::getFiller() { + if (Filler) + return *Filler; + if (Sec->Flags & SHF_EXECINSTR) + return Target->TrapInstr; + return 0; } static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) { @@ -1053,11 +1064,45 @@ static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) { llvm_unreachable("unsupported Size argument"); } -void LinkerScript::writeDataBytes(OutputSection *Sec, uint8_t *Buf) { - if (OutputSectionCommand *Cmd = getCmd(Sec)) - for (BaseCommand *Base : Cmd->Commands) - if (auto *Data = dyn_cast<BytesDataCommand>(Base)) - writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size); +template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) { + Sec->Loc = Buf; + + // We may have already rendered compressed content when using + // -compress-debug-sections option. Write it together with header. + if (!Sec->CompressedData.empty()) { + memcpy(Buf, Sec->ZDebugHeader.data(), Sec->ZDebugHeader.size()); + memcpy(Buf + Sec->ZDebugHeader.size(), Sec->CompressedData.data(), + Sec->CompressedData.size()); + return; + } + + // Write leading padding. + ArrayRef<InputSection *> Sections = Sec->Sections; + uint32_t Filler = getFiller(); + if (Filler) + fill(Buf, Sections.empty() ? Sec->Size : Sections[0]->OutSecOff, Filler); + + parallelForEachN(0, Sections.size(), [=](size_t I) { + InputSection *IS = Sections[I]; + IS->writeTo<ELFT>(Buf); + + // Fill gaps between sections. + if (Filler) { + uint8_t *Start = Buf + IS->OutSecOff + IS->getSize(); + uint8_t *End; + if (I + 1 == Sections.size()) + End = Buf + Sec->Size; + else + End = Buf + Sections[I + 1]->OutSecOff; + fill(Start, End - Start, Filler); + } + }); + + // Linker scripts may have BYTE()-family commands with which you + // can write arbitrary bytes to the output. Process them if any. + for (BaseCommand *Base : Commands) + if (auto *Data = dyn_cast<BytesDataCommand>(Base)) + writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size); } bool LinkerScript::hasLMA(OutputSection *Sec) { @@ -1104,3 +1149,8 @@ size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) { error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS"); return 0; } + +template void OutputSectionCommand::writeTo<ELF32LE>(uint8_t *Buf); +template void OutputSectionCommand::writeTo<ELF32BE>(uint8_t *Buf); +template void OutputSectionCommand::writeTo<ELF64LE>(uint8_t *Buf); +template void OutputSectionCommand::writeTo<ELF64BE>(uint8_t *Buf); diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h index d0a4d83d72b0..e56e569d4e72 100644 --- a/ELF/LinkerScript.h +++ b/ELF/LinkerScript.h @@ -130,6 +130,9 @@ struct OutputSectionCommand : BaseCommand { ConstraintKind Constraint = ConstraintKind::NoConstraint; std::string Location; std::string MemoryRegionName; + + template <class ELFT> void writeTo(uint8_t *Buf); + uint32_t getFiller(); }; // This struct represents one section match pattern in SECTIONS() command. @@ -157,7 +160,7 @@ struct InputSectionDescription : BaseCommand { // will be associated with this InputSectionDescription. std::vector<SectionPattern> SectionPatterns; - std::vector<InputSectionBase *> Sections; + std::vector<InputSection *> Sections; }; // Represents an ASSERT(). @@ -213,11 +216,10 @@ struct ScriptConfiguration { class LinkerScript final { llvm::DenseMap<OutputSection *, OutputSectionCommand *> SecToCommand; - OutputSectionCommand *getCmd(OutputSection *Sec) const; void assignSymbol(SymbolAssignment *Cmd, bool InSec); void setDot(Expr E, const Twine &Loc, bool InSec); - std::vector<InputSectionBase *> + std::vector<InputSection *> computeInputSections(const InputSectionDescription *); std::vector<InputSectionBase *> @@ -244,6 +246,7 @@ class LinkerScript final { MemoryRegion *CurMemRegion = nullptr; public: + OutputSectionCommand *getCmd(OutputSection *Sec) const; bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); } uint64_t getDot() { return Dot; } OutputSection *getOutputSection(const Twine &Loc, StringRef S); @@ -263,7 +266,6 @@ public: std::vector<PhdrEntry> createPhdrs(); bool ignoreInterpSection(); - llvm::Optional<uint32_t> getFiller(OutputSection *Sec); bool hasLMA(OutputSection *Sec); bool shouldKeep(InputSectionBase *S); void assignOffsets(OutputSectionCommand *Cmd); @@ -272,7 +274,6 @@ public: void synchronize(); void assignAddresses(std::vector<PhdrEntry> &Phdrs); - void writeDataBytes(OutputSection *Sec, uint8_t *Buf); void addSymbol(SymbolAssignment *Cmd); void processCommands(OutputSectionFactory &Factory); diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp index 7b82eceba02a..806e99e3d9dd 100644 --- a/ELF/MapFile.cpp +++ b/ELF/MapFile.cpp @@ -132,12 +132,17 @@ void elf::writeMapFile(llvm::ArrayRef<BaseCommand *> Script) { OS << OSec->Name << '\n'; // Dump symbols for each input section. - for (InputSection *IS : OSec->Sections) { - writeHeader<ELFT>(OS, OSec->Addr + IS->OutSecOff, IS->getSize(), - IS->Alignment); - OS << indent(1) << toString(IS) << '\n'; - for (DefinedRegular *Sym : SectionSyms[IS]) - OS << SymStr[Sym] << '\n'; + for (BaseCommand *Base : Cmd->Commands) { + auto *ISD = dyn_cast<InputSectionDescription>(Base); + if (!ISD) + continue; + for (InputSection *IS : ISD->Sections) { + writeHeader<ELFT>(OS, OSec->Addr + IS->OutSecOff, IS->getSize(), + IS->Alignment); + OS << indent(1) << toString(IS) << '\n'; + for (DefinedRegular *Sym : SectionSyms[IS]) + OS << SymStr[Sym] << '\n'; + } } } } diff --git a/ELF/Options.td b/ELF/Options.td index 65a0e72d2320..335c7ade6db2 100644 --- a/ELF/Options.td +++ b/ELF/Options.td @@ -313,6 +313,7 @@ def alias_o_output2 : Separate<["--"], "output">, Alias<o>; def alias_pie_pic_executable: F<"pic-executable">, Alias<pie>; def alias_print_map_M: Flag<["-"], "M">, Alias<print_map>; def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>; +def alias_reproduce_eq: J<"reproduce=">, Alias<reproduce>; def alias_retain_symbols_file: S<"retain-symbols-file">, Alias<retain_symbols_file>; def alias_rpath_R: JoinedOrSeparate<["-"], "R">, Alias<rpath>; def alias_rpath_rpath: J<"rpath=">, Alias<rpath>; diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index dcefd03766d7..d82fdcdc31ba 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -103,7 +103,7 @@ template <class ELFT> void OutputSection::maybeCompress() { // Write section contents to a temporary buffer and compress it. std::vector<uint8_t> Buf(Size); - writeTo<ELFT>(Buf.data()); + Script->getCmd(this)->writeTo<ELFT>(Buf.data()); if (Error E = zlib::compress(toStringRef(Buf), CompressedData)) fatal("compress failed: " + llvm::toString(std::move(E))); @@ -112,6 +112,19 @@ template <class ELFT> void OutputSection::maybeCompress() { Flags |= SHF_COMPRESSED; } +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->OutSec->SectionIndex; + + // sh_link 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); @@ -126,6 +139,11 @@ template <class ELFT> void OutputSection::finalize() { } uint32_t Type = this->Type; + if (Type == SHT_GROUP) { + finalizeShtGroup<ELFT>(this); + return; + } + if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL)) return; @@ -259,69 +277,6 @@ void OutputSection::sortCtorsDtors() { std::stable_sort(Sections.begin(), Sections.end(), compCtors); } -// Fill [Buf, Buf + Size) with Filler. -// This is used for linker script "=fillexp" command. -static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) { - size_t I = 0; - for (; I + 4 < Size; I += 4) - memcpy(Buf + I, &Filler, 4); - memcpy(Buf + I, &Filler, Size - I); -} - -uint32_t OutputSection::getFiller() { - // Determine what to fill gaps between InputSections with, as specified by the - // linker script. If nothing is specified and this is an executable section, - // fall back to trap instructions to prevent bad diassembly and detect invalid - // jumps to padding. - if (Optional<uint32_t> Filler = Script->getFiller(this)) - return *Filler; - if (Flags & SHF_EXECINSTR) - return Target->TrapInstr; - return 0; -} - -template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) { - Loc = Buf; - - // We may have already rendered compressed content when using - // -compress-debug-sections option. Write it together with header. - if (!CompressedData.empty()) { - memcpy(Buf, ZDebugHeader.data(), ZDebugHeader.size()); - memcpy(Buf + ZDebugHeader.size(), CompressedData.data(), - CompressedData.size()); - return; - } - - // Write leading padding. - uint32_t Filler = getFiller(); - if (Filler) - fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, Filler); - - parallelForEachN(0, Sections.size(), [=](size_t I) { - InputSection *Sec = Sections[I]; - Sec->writeTo<ELFT>(Buf); - - // Fill gaps between sections. - if (Filler) { - uint8_t *Start = Buf + Sec->OutSecOff + Sec->getSize(); - uint8_t *End; - if (I + 1 == Sections.size()) - End = Buf + Size; - else - End = Buf + Sections[I + 1]->OutSecOff; - fill(Start, End - Start, Filler); - } - }); - - // Linker scripts may have BYTE()-family commands with which you - // can write arbitrary bytes to the output. Process them if any. - Script->writeDataBytes(this, Buf); -} - -static uint64_t getOutFlags(InputSectionBase *S) { - return S->Flags & ~SHF_GROUP & ~SHF_COMPRESSED; -} - static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) { // The ELF spec just says // ---------------------------------------------------------------- @@ -418,7 +373,10 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS, return; } - uint64_t Flags = getOutFlags(IS); + 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 + @@ -484,8 +442,3 @@ template void OutputSection::maybeCompress<ELF32LE>(); template void OutputSection::maybeCompress<ELF32BE>(); template void OutputSection::maybeCompress<ELF64LE>(); template void OutputSection::maybeCompress<ELF64BE>(); - -template void OutputSection::writeTo<ELF32LE>(uint8_t *Buf); -template void OutputSection::writeTo<ELF32BE>(uint8_t *Buf); -template void OutputSection::writeTo<ELF64LE>(uint8_t *Buf); -template void OutputSection::writeTo<ELF64BE>(uint8_t *Buf); diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h index 413871b60cf7..08655a9ed67b 100644 --- a/ELF/OutputSections.h +++ b/ELF/OutputSections.h @@ -82,8 +82,6 @@ public: void sort(std::function<int(InputSectionBase *S)> Order); void sortInitFini(); void sortCtorsDtors(); - uint32_t getFiller(); - template <class ELFT> void writeTo(uint8_t *Buf); template <class ELFT> void finalize(); template <class ELFT> void maybeCompress(); void assignOffsets(); diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index 599f1441a47f..d3db32613a8a 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -1005,10 +1005,11 @@ DynamicSection<ELFT>::DynamicSection() ".dynamic") { this->Entsize = ELFT::Is64Bits ? 16 : 8; - // .dynamic section is not writable on MIPS. + // .dynamic section is not writable on MIPS and on Fuchsia OS + // which passes -z rodynamic. // See "Special Section" in Chapter 4 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - if (Config->EMachine == EM_MIPS) + if (Config->EMachine == EM_MIPS || Config->ZRodynamic) this->Flags = SHF_ALLOC; addEntries(); @@ -1053,7 +1054,15 @@ template <class ELFT> void DynamicSection<ELFT>::addEntries() { if (DtFlags1) add({DT_FLAGS_1, DtFlags1}); - if (!Config->Shared && !Config->Relocatable) + // DT_DEBUG is a pointer to debug informaion used by debuggers at runtime. We + // need it for each process, so we don't write it for DSOs. The loader writes + // the pointer into this entry. + // + // DT_DEBUG is the only .dynamic entry that needs to be written to. Some + // systems (currently only Fuchsia OS) provide other means to give the + // debugger this information. Such systems may choose make .dynamic read-only. + // If the target is such a system (used -z rodynamic) don't write DT_DEBUG. + if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic) add({DT_DEBUG, (uint64_t)0}); } @@ -1778,11 +1787,10 @@ void GdbIndexSection::readDwarf(InputSection *Sec) { std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset); if (IsNew) { Sym->CuVectorIndex = CuVectors.size(); - CuVectors.push_back({{CuId, Pair.second}}); - continue; + CuVectors.resize(CuVectors.size() + 1); } - CuVectors[Sym->CuVectorIndex].push_back({CuId, Pair.second}); + CuVectors[Sym->CuVectorIndex].insert((Pair.second << 24) | (uint32_t)CuId); } } @@ -1806,7 +1814,7 @@ void GdbIndexSection::finalizeContents() { ConstantPoolOffset = SymTabOffset + SymbolTable.getCapacity() * SymTabEntrySize; - for (std::vector<std::pair<uint32_t, uint8_t>> &CuVec : CuVectors) { + for (std::set<uint32_t> &CuVec : CuVectors) { CuVectorsOffset.push_back(CuVectorsSize); CuVectorsSize += OffsetTypeSize * (CuVec.size() + 1); } @@ -1859,14 +1867,11 @@ void GdbIndexSection::writeTo(uint8_t *Buf) { } // Write the CU vectors into the constant pool. - for (std::vector<std::pair<uint32_t, uint8_t>> &CuVec : CuVectors) { + for (std::set<uint32_t> &CuVec : CuVectors) { write32le(Buf, CuVec.size()); Buf += 4; - for (std::pair<uint32_t, uint8_t> &P : CuVec) { - uint32_t Index = P.first; - uint8_t Flags = P.second; - Index |= Flags << 24; - write32le(Buf, Index); + for (uint32_t Val : CuVec) { + write32le(Buf, Val); Buf += 4; } } @@ -2173,17 +2178,6 @@ MipsRldMapSection::MipsRldMapSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize, ".rld_map") {} -void MipsRldMapSection::writeTo(uint8_t *Buf) { - // Apply filler from linker script. - Optional<uint32_t> Fill = Script->getFiller(this->OutSec); - if (!Fill || *Fill == 0) - return; - - uint64_t Filler = *Fill; - Filler = (Filler << 32) | Filler; - memcpy(Buf, &Filler, getSize()); -} - ARMExidxSentinelSection::ARMExidxSentinelSection() : SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX, Config->Wordsize, ".ARM.exidx") {} @@ -2194,7 +2188,7 @@ ARMExidxSentinelSection::ARMExidxSentinelSection() // | PREL31 upper bound of code that has exception tables | EXIDX_CANTUNWIND | void ARMExidxSentinelSection::writeTo(uint8_t *Buf) { // Get the InputSection before us, we are by definition last - auto RI = cast<OutputSection>(this->OutSec)->Sections.rbegin(); + auto RI = this->OutSec->Sections.rbegin(); InputSection *LE = *(++RI); InputSection *LC = cast<InputSection>(LE->getLinkOrderDep()); uint64_t S = LC->OutSec->Addr + LC->getOffset(LC->getSize()); diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h index c5ffb88c1366..61cc03de222e 100644 --- a/ELF/SyntheticSections.h +++ b/ELF/SyntheticSections.h @@ -27,6 +27,8 @@ #include "llvm/ADT/MapVector.h" #include "llvm/MC/StringTableBuilder.h" +#include <set> + namespace lld { namespace elf { @@ -515,7 +517,7 @@ public: GdbHashTab SymbolTable; // The CU vector portion of the constant pool. - std::vector<std::vector<std::pair<uint32_t, uint8_t>>> CuVectors; + std::vector<std::set<uint32_t>> CuVectors; std::vector<AddressEntry> AddressArea; @@ -709,7 +711,7 @@ class MipsRldMapSection : public SyntheticSection { public: MipsRldMapSection(); size_t getSize() const override { return Config->Wordsize; } - void writeTo(uint8_t *Buf) override; + void writeTo(uint8_t *Buf) override {} }; class ARMExidxSentinelSection : public SyntheticSection { diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 7a21d2b9f13d..e539d8ffce6e 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -46,6 +46,7 @@ public: void run(); private: + void clearOutputSections(); void createSyntheticSections(); void copyLocalSymbols(); void addSectionSymbols(); @@ -80,6 +81,8 @@ private: void addStartStopSymbols(OutputSection *Sec); uint64_t getEntryAddr(); OutputSection *findSection(StringRef Name); + OutputSection *findSectionInScript(StringRef Name); + OutputSectionCommand *findSectionCommand(StringRef Name); std::vector<PhdrEntry> Phdrs; @@ -161,7 +164,7 @@ static void combineMergableSections() { continue; StringRef OutsecName = getOutputSectionName(MS->Name); - uint64_t Flags = MS->Flags & ~(uint64_t)(SHF_GROUP | SHF_COMPRESSED); + uint64_t Flags = MS->Flags & ~(uint64_t)SHF_GROUP; uint32_t Alignment = std::max<uint32_t>(MS->Alignment, MS->Entsize); auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) { @@ -198,6 +201,15 @@ template <class ELFT> static void combineEhFrameSections() { V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); } +template <class ELFT> void Writer<ELFT>::clearOutputSections() { + // Clear the OutputSections to make sure it is not used anymore. Any + // code from this point on should be using the linker script + // commands. + for (OutputSection *Sec : OutputSections) + Sec->Sections.clear(); + OutputSections.clear(); +} + // The main function of the writer. template <class ELFT> void Writer<ELFT>::run() { // Create linker-synthesized sections such as .got or .plt. @@ -244,13 +256,21 @@ template <class ELFT> void Writer<ELFT>::run() { if (ErrorCount) return; + if (!Script->Opt.HasSections) { + if (!Config->Relocatable) + fixSectionAlignments(); + Script->fabricateDefaultCommands(); + } + + // If -compressed-debug-sections is specified, we need to compress + // .debug_* sections. Do it right now because it changes the size of + // output sections. + parallelForEach(OutputSections.begin(), OutputSections.end(), + [](OutputSection *S) { S->maybeCompress<ELFT>(); }); + if (Config->Relocatable) { assignFileOffsets(); } else { - if (!Script->Opt.HasSections) { - fixSectionAlignments(); - Script->fabricateDefaultCommands(); - } Script->synchronize(); Script->assignAddresses(Phdrs); @@ -281,6 +301,7 @@ template <class ELFT> void Writer<ELFT>::run() { } else { writeSectionsBinary(); } + clearOutputSections(); // Backfill .note.gnu.build-id section content. This is done at last // because the content is usually a hash value of the entire output file. @@ -288,10 +309,6 @@ template <class ELFT> void Writer<ELFT>::run() { if (ErrorCount) return; - // Clear the OutputSections to make sure it is not used anymore. Any - // code from this point on should be using the linker script - // commands. - OutputSections.clear(); // Handle -Map option. writeMapFile<ELFT>(Script->Opt.Commands); @@ -631,10 +648,11 @@ bool elf::isRelroSection(const OutputSection *Sec) { // * It is easy to check if a give branch was taken. // * It is easy two see how similar two ranks are (see getRankProximity). enum RankFlags { - RF_NOT_ADDR_SET = 1 << 15, - RF_NOT_INTERP = 1 << 14, - RF_NOT_ALLOC = 1 << 13, - RF_WRITE = 1 << 12, + RF_NOT_ADDR_SET = 1 << 16, + RF_NOT_INTERP = 1 << 15, + RF_NOT_ALLOC = 1 << 14, + RF_WRITE = 1 << 13, + RF_EXEC_WRITE = 1 << 12, RF_EXEC = 1 << 11, RF_NON_TLS_BSS = 1 << 10, RF_NON_TLS_BSS_RO = 1 << 9, @@ -669,19 +687,29 @@ static unsigned getSectionRank(const OutputSection *Sec) { if (!(Sec->Flags & SHF_ALLOC)) return Rank | RF_NOT_ALLOC; - // We want the read only sections first so that they go in the PT_LOAD - // covering the program headers at the start of the file. - if (Sec->Flags & SHF_WRITE) - Rank |= RF_WRITE; - - if (Sec->Flags & SHF_EXECINSTR) { - // For a corresponding reason, put non exec sections first (the program - // header PT_LOAD is not executable). - // We only do that if we are not using linker scripts, since with linker - // scripts ro and rx sections are in the same PT_LOAD, so their relative - // order is not important. The same applies for -no-rosegment. - if ((Rank & RF_WRITE) || !Config->SingleRoRx) + // Sort sections based on their access permission in the following + // order: R, RX, RWX, RW. This order is based on the following + // considerations: + // * Read-only sections come first such that they go in the + // PT_LOAD covering the program headers at the start of the file. + // * Read-only, executable sections come next, unless the + // -no-rosegment option is used. + // * Writable, executable sections follow such that .plt on + // architectures where it needs to be writable will be placed + // between .text and .data. + // * Writable sections come last, such that .bss lands at the very + // end of the last PT_LOAD. + bool IsExec = Sec->Flags & SHF_EXECINSTR; + bool IsWrite = Sec->Flags & SHF_WRITE; + + if (IsExec) { + if (IsWrite) + Rank |= RF_EXEC_WRITE; + else if (!Config->SingleRoRx) Rank |= RF_EXEC; + } else { + if (IsWrite) + Rank |= RF_WRITE; } // If we got here we know that both A and B are in the same PT_LOAD. @@ -778,12 +806,6 @@ static bool compareSections(const OutputSection *A, const OutputSection *B) { return compareSectionsNonScript(A, B); } -// Program header entry -PhdrEntry::PhdrEntry(unsigned Type, unsigned Flags) { - p_type = Type; - p_flags = Flags; -} - void PhdrEntry::add(OutputSection *Sec) { Last = Sec; if (!First) @@ -1239,12 +1261,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { for (OutputSection *Sec : OutputSections) Sec->finalize<ELFT>(); - // If -compressed-debug-sections is specified, we need to compress - // .debug_* sections. Do it right now because it changes the size of - // output sections. - parallelForEach(OutputSections.begin(), OutputSections.end(), - [](OutputSection *S) { S->maybeCompress<ELFT>(); }); - // createThunks may have added local symbols to the static symbol table applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab}, [](SyntheticSection *SS) { SS->postThunkContents(); }); @@ -1297,6 +1313,21 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) { addOptionalRegular<ELFT>(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT); } +template <class ELFT> +OutputSectionCommand *Writer<ELFT>::findSectionCommand(StringRef Name) { + for (BaseCommand *Base : Script->Opt.Commands) + if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) + if (Cmd->Name == Name) + return Cmd; + return nullptr; +} + +template <class ELFT> OutputSection *Writer<ELFT>::findSectionInScript(StringRef Name) { + if (OutputSectionCommand *Cmd = findSectionCommand(Name)) + return Cmd->Sec; + return nullptr; +} + template <class ELFT> OutputSection *Writer<ELFT>::findSection(StringRef Name) { for (OutputSection *Sec : OutputSections) if (Sec->Name == Name) @@ -1583,7 +1614,7 @@ template <class ELFT> uint64_t Writer<ELFT>::getEntryAddr() { return Addr; // Case 4 - if (OutputSection *Sec = findSection(".text")) { + if (OutputSection *Sec = findSectionInScript(".text")) { if (Config->WarnMissingEntry) warn("cannot find entry symbol " + Config->Entry + "; defaulting to 0x" + utohexstr(Sec->Addr)); @@ -1609,18 +1640,6 @@ static uint16_t getELFType() { // to each section. This function fixes some predefined // symbol values that depend on section address and size. template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() { - auto Set = [](DefinedRegular *S1, DefinedRegular *S2, OutputSection *Sec, - uint64_t Value) { - if (S1) { - S1->Section = Sec; - S1->Value = Value; - } - if (S2) { - S2->Section = Sec; - S2->Value = Value; - } - }; - // _etext is the first location after the last read-only loadable segment. // _edata is the first location after the last read-write loadable segment. // _end is the first location after the uninitialized data region. @@ -1636,15 +1655,29 @@ template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() { else LastRO = &P; } - if (Last) - Set(ElfSym::End1, ElfSym::End2, Last->First, Last->p_memsz); - if (LastRO) - Set(ElfSym::Etext1, ElfSym::Etext2, LastRO->First, LastRO->p_filesz); - if (LastRW) - Set(ElfSym::Edata1, ElfSym::Edata2, LastRW->First, LastRW->p_filesz); + + auto Set = [](DefinedRegular *S, OutputSection *Sec, uint64_t Value) { + if (S) { + S->Section = Sec; + S->Value = Value; + } + }; + + if (Last) { + Set(ElfSym::End1, Last->First, Last->p_memsz); + Set(ElfSym::End2, Last->First, Last->p_memsz); + } + if (LastRO) { + Set(ElfSym::Etext1, LastRO->First, LastRO->p_filesz); + Set(ElfSym::Etext2, LastRO->First, LastRO->p_filesz); + } + if (LastRW) { + Set(ElfSym::Edata1, LastRW->First, LastRW->p_filesz); + Set(ElfSym::Edata2, LastRW->First, LastRW->p_filesz); + } if (ElfSym::Bss) - ElfSym::Bss->Section = findSection(".bss"); + ElfSym::Bss->Section = findSectionInScript(".bss"); // Setup MIPS _gp_disp/__gnu_local_gp symbols which should // be equal to the _gp symbol's value. @@ -1736,9 +1769,14 @@ template <class ELFT> void Writer<ELFT>::openFile() { template <class ELFT> void Writer<ELFT>::writeSectionsBinary() { uint8_t *Buf = Buffer->getBufferStart(); - for (OutputSection *Sec : OutputSections) + for (BaseCommand *Base : Script->Opt.Commands) { + auto *Cmd = dyn_cast<OutputSectionCommand>(Base); + if (!Cmd) + continue; + OutputSection *Sec = Cmd->Sec; if (Sec->Flags & SHF_ALLOC) - Sec->writeTo<ELFT>(Buf + Sec->Offset); + Cmd->writeTo<ELFT>(Buf + Sec->Offset); + } } // Write section contents to a mmap'ed file. @@ -1747,31 +1785,45 @@ template <class ELFT> void Writer<ELFT>::writeSections() { // PPC64 needs to process relocations in the .opd section // before processing relocations in code-containing sections. - Out::Opd = findSection(".opd"); - if (Out::Opd) { + if (auto *OpdCmd = findSectionCommand(".opd")) { + Out::Opd = OpdCmd->Sec; Out::OpdBuf = Buf + Out::Opd->Offset; - Out::Opd->template writeTo<ELFT>(Buf + Out::Opd->Offset); + OpdCmd->template writeTo<ELFT>(Buf + Out::Opd->Offset); } OutputSection *EhFrameHdr = - In<ELFT>::EhFrameHdr ? In<ELFT>::EhFrameHdr->OutSec : nullptr; + (In<ELFT>::EhFrameHdr && !In<ELFT>::EhFrameHdr->empty()) + ? In<ELFT>::EhFrameHdr->OutSec + : nullptr; // In -r or -emit-relocs mode, write the relocation sections first as in // ELf_Rel targets we might find out that we need to modify the relocated // section while doing it. - for (OutputSection *Sec : OutputSections) + for (BaseCommand *Base : Script->Opt.Commands) { + auto *Cmd = dyn_cast<OutputSectionCommand>(Base); + if (!Cmd) + continue; + OutputSection *Sec = Cmd->Sec; if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) - Sec->writeTo<ELFT>(Buf + Sec->Offset); + Cmd->writeTo<ELFT>(Buf + Sec->Offset); + } - for (OutputSection *Sec : OutputSections) + for (BaseCommand *Base : Script->Opt.Commands) { + auto *Cmd = dyn_cast<OutputSectionCommand>(Base); + if (!Cmd) + continue; + OutputSection *Sec = Cmd->Sec; if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA) - Sec->writeTo<ELFT>(Buf + Sec->Offset); + Cmd->writeTo<ELFT>(Buf + Sec->Offset); + } // The .eh_frame_hdr depends on .eh_frame section contents, therefore // it should be written after .eh_frame is written. - if (EhFrameHdr && !EhFrameHdr->Sections.empty()) - EhFrameHdr->writeTo<ELFT>(Buf + EhFrameHdr->Offset); + if (EhFrameHdr) { + OutputSectionCommand *Cmd = Script->getCmd(EhFrameHdr); + Cmd->writeTo<ELFT>(Buf + EhFrameHdr->Offset); + } } template <class ELFT> void Writer<ELFT>::writeBuildId() { diff --git a/ELF/Writer.h b/ELF/Writer.h index 17fbda394a20..e935b6419de6 100644 --- a/ELF/Writer.h +++ b/ELF/Writer.h @@ -30,7 +30,7 @@ bool isRelroSection(const OutputSection *Sec); // Each contains type, access flags and range of output sections that will be // placed in it. struct PhdrEntry { - PhdrEntry(unsigned Type, unsigned Flags); + PhdrEntry(unsigned Type, unsigned Flags) : p_type(Type), p_flags(Flags) {} void add(OutputSection *Sec); uint64_t p_paddr = 0; diff --git a/test/COFF/Inputs/delayimports-error.yaml b/test/COFF/Inputs/delayimports-error.yaml new file mode 100644 index 000000000000..60b395938dfd --- /dev/null +++ b/test/COFF/Inputs/delayimports-error.yaml @@ -0,0 +1,29 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [] +sections: + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: 0000000000000000 +symbols: + - Name: .data + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: datasym + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/Inputs/import.yaml b/test/COFF/Inputs/import.yaml index 493400143d6c..b7ae026de29b 100644 --- a/test/COFF/Inputs/import.yaml +++ b/test/COFF/Inputs/import.yaml @@ -7,6 +7,13 @@ sections: Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] Alignment: 4 SectionData: 0000000000000000 + Relocations: + - VirtualAddress: 0 + SymbolName: exportfn1 + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: exportfn2 + Type: IMAGE_REL_AMD64_ADDR32NB symbols: - Name: .text Value: 0 @@ -16,7 +23,7 @@ symbols: StorageClass: IMAGE_SYM_CLASS_STATIC SectionDefinition: Length: 8 - NumberOfRelocations: 0 + NumberOfRelocations: 2 NumberOfLinenumbers: 0 CheckSum: 0 Number: 0 diff --git a/test/COFF/Inputs/oldname.yaml b/test/COFF/Inputs/oldname.yaml new file mode 100644 index 000000000000..42ee5b2269bd --- /dev/null +++ b/test/COFF/Inputs/oldname.yaml @@ -0,0 +1,26 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_UNKNOWN + Characteristics: [ ] +sections: + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: '' +symbols: + - Name: exportfn1 + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: exportfn1_alias + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_WEAK_EXTERNAL + WeakExternal: + TagIndex: 0 + Characteristics: IMAGE_WEAK_EXTERN_SEARCH_ALIAS +... diff --git a/test/COFF/delayimports-error.test b/test/COFF/delayimports-error.test new file mode 100644 index 000000000000..3fea1bc099c2 --- /dev/null +++ b/test/COFF/delayimports-error.test @@ -0,0 +1,46 @@ +# RUN: mkdir -p %t.dir +# RUN: yaml2obj < %p/Inputs/delayimports-error.yaml > %t1.obj +# RUN: lld-link /out:%t.dir/foo.dll /dll %t1.obj /export:datasym,DATA /noentry + +# RUN: yaml2obj < %s > %t2.obj +# RUN: not lld-link /out:%t.exe /entry:main %t2.obj %t.dir/foo.lib /delayload:foo.dll \ +# RUN: /alternatename:__delayLoadHelper2=main /opt:noref >& %t.log +# RUN: FileCheck %s < %t.log + +# CHECK: cannot delay-load foo.dll due to import of data: __imp_datasym + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 0000000000000000 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __imp_datasym + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/dllimport-gc.test b/test/COFF/dllimport-gc.test new file mode 100644 index 000000000000..54ae773e793f --- /dev/null +++ b/test/COFF/dllimport-gc.test @@ -0,0 +1,58 @@ +# REQUIRES: winres + +# RUN: yaml2obj < %p/Inputs/export.yaml > %t-lib.obj +# RUN: lld-link /out:%t.dll /dll %t-lib.obj /implib:%t.lib /export:exportfn1 + +# RUN: yaml2obj < %p/Inputs/oldname.yaml > %t-oldname.obj + +# RUN: yaml2obj < %s > %t.obj + +# RUN: lld-link /out:%t1.exe /entry:main %t.obj %t-oldname.obj %t.lib +# RUN: llvm-readobj -coff-imports %t1.exe | FileCheck -check-prefix=REF %s +# REF-NOT: Symbol: exportfn1 + +# RUN: lld-link /out:%t2.exe /entry:main %t.obj %t-oldname.obj %t.lib /opt:noref +# RUN: llvm-readobj -coff-imports %t2.exe | FileCheck -check-prefix=NOREF %s +# NOREF: Symbol: exportfn1 + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 0000000000000000 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: exportfn1 + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: exportfn1_alias + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/ELF/Inputs/rodynamic.s b/test/ELF/Inputs/rodynamic.s new file mode 100644 index 000000000000..a06f4bef0084 --- /dev/null +++ b/test/ELF/Inputs/rodynamic.s @@ -0,0 +1,4 @@ +.global foo +.type foo, @function +foo: + ret diff --git a/test/ELF/amdgpu-globals.s b/test/ELF/amdgpu-globals.s index f30c0ed40157..17dfc82ef8f3 100644 --- a/test/ELF/amdgpu-globals.s +++ b/test/ELF/amdgpu-globals.s @@ -41,6 +41,19 @@ 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: } + +# CHECK: Section { # CHECK: Name: .hsadata_global_program # CHECK: Type: SHT_PROGBITS (0x1) # CHECK: Flags [ (0x100003) @@ -62,19 +75,6 @@ program_global_readonly: # CHECK: ] # CHECK: } -# 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: } - # CHECK: Symbol { # CHECK: Name: module_global_agent # CHECK: Value: diff --git a/test/ELF/build-id.s b/test/ELF/build-id.s index ffd8d7744f70..2d193478df71 100644 --- a/test/ELF/build-id.s +++ b/test/ELF/build-id.s @@ -33,6 +33,10 @@ # RUN: ld.lld --build-id=md5 --build-id=none %t -o %t2 # RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=NONE %s +# RUN: ld.lld --build-id --build-id=none %t -o %t2 +# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=NONE %s +# RUN: ld.lld --build-id=none --build-id %t -o %t2 +# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=DEFAULT %s .globl _start _start: diff --git a/test/ELF/gc-sections.s b/test/ELF/gc-sections.s index f100153ec358..0ae6fa4f06de 100644 --- a/test/ELF/gc-sections.s +++ b/test/ELF/gc-sections.s @@ -10,10 +10,10 @@ # NOGC: Name: .eh_frame # NOGC: Name: .text -# NOGC: Name: .ctors -# NOGC: Name: .dtors # NOGC: Name: .init # NOGC: Name: .fini +# NOGC: Name: .ctors +# NOGC: Name: .dtors # NOGC: Name: .debug_pubtypes # NOGC: Name: .comment # NOGC: Name: a @@ -25,10 +25,10 @@ # GC1: Name: .eh_frame # GC1: Name: .text -# GC1: Name: .ctors -# GC1: Name: .dtors # GC1: Name: .init # GC1: Name: .fini +# GC1: Name: .ctors +# GC1: Name: .dtors # GC1: Name: .debug_pubtypes # GC1: Name: .comment # GC1: Name: a @@ -40,10 +40,10 @@ # GC2: Name: .eh_frame # GC2: Name: .text -# GC2: Name: .ctors -# GC2: Name: .dtors # GC2: Name: .init # GC2: Name: .fini +# GC2: Name: .ctors +# GC2: Name: .dtors # GC2: Name: .debug_pubtypes # GC2: Name: .comment # GC2: Name: a diff --git a/test/ELF/gdb-index-dup-types.s b/test/ELF/gdb-index-dup-types.s new file mode 100644 index 000000000000..e0bed33eed4d --- /dev/null +++ b/test/ELF/gdb-index-dup-types.s @@ -0,0 +1,60 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld --gdb-index %t.o -o %t +# RUN: llvm-dwarfdump -debug-dump=gdb_index %t | FileCheck %s + +## Testcase is based on output produced by gcc version 5.4.1 20160904 +## it has duplicate entries in .debug_gnu_pubtypes which seems to be +## compiler bug. In that case it is useless to have them in .gdb_index +## and we filter such entries out to reduce size of .gdb_index. + +## CHECK: Constant pool offset = {{.*}}, has 1 CU vectors: +## CHECK-NOT: 0(0x0): 0x90000000 0x90000000 + +.section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 0 # DW_CHILDREN_no + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .ascii "\260B" # DW_AT_GNU_dwo_name + .byte 14 # DW_FORM_strp + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .ascii "\264B" # DW_AT_GNU_pubnames + .byte 25 # DW_FORM_flag_present + .ascii "\261B" # DW_AT_GNU_dwo_id + .byte 7 # DW_FORM_data8 + .ascii "\263B" # DW_AT_GNU_addr_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + +.section .debug_info,"",@progbits +.Lcu_begin0: + .long 32 # 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:0x19 DW_TAG_compile_unit + .long 0 # DW_AT_stmt_list + .long 0 # DW_AT_GNU_dwo_name + .long 0 # DW_AT_comp_dir + .quad 0 # DW_AT_GNU_dwo_id + .long 0 # DW_AT_GNU_addr_base + +.section .debug_gnu_pubtypes,"",@progbits +.long .LpubTypes_end0-.LpubTypes_begin0 # Length of Public Types Info +.LpubTypes_begin0: + .short 2 # DWARF Version + .long .Lcu_begin0 # Offset of Compilation Unit Info + .long 36 # Compilation Unit Length + .long 36 # DIE offset + .byte 144 # Kind: TYPE, STATIC + .asciz "int" # External Name + .long 36 # DIE offset + .byte 144 # Kind: TYPE, STATIC + .asciz "int" # External Name + .long 0 # End Mark +.LpubTypes_end0: diff --git a/test/ELF/i386-tls-ie-shared.s b/test/ELF/i386-tls-ie-shared.s index 8becc3199f95..f419eb45dfb9 100644 --- a/test/ELF/i386-tls-ie-shared.s +++ b/test/ELF/i386-tls-ie-shared.s @@ -13,8 +13,8 @@ // GOTRELSHARED-NEXT: SHF_ALLOC // GOTRELSHARED-NEXT: SHF_WRITE // GOTRELSHARED-NEXT: ] -// GOTRELSHARED-NEXT: Address: 0x1058 -// GOTRELSHARED-NEXT: Offset: 0x1058 +// GOTRELSHARED-NEXT: Address: 0x2058 +// GOTRELSHARED-NEXT: Offset: 0x2058 // GOTRELSHARED-NEXT: Size: 16 // GOTRELSHARED-NEXT: Link: 0 // GOTRELSHARED-NEXT: Info: 0 @@ -23,44 +23,44 @@ // GOTRELSHARED-NEXT: } // GOTRELSHARED: Relocations [ // GOTRELSHARED-NEXT: Section ({{.*}}) .rel.dyn { -// GOTRELSHARED-NEXT: 0x2002 R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT: 0x200A R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT: 0x2013 R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT: 0x201C R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT: 0x2024 R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT: 0x202D R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT: 0x2036 R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT: 0x203F R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT: 0x1058 R_386_TLS_TPOFF tlslocal0 0x0 -// GOTRELSHARED-NEXT: 0x105C R_386_TLS_TPOFF tlslocal1 0x0 -// GOTRELSHARED-NEXT: 0x1060 R_386_TLS_TPOFF tlsshared0 0x0 -// GOTRELSHARED-NEXT: 0x1064 R_386_TLS_TPOFF tlsshared1 0x0 +// GOTRELSHARED-NEXT: 0x1002 R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT: 0x100A R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT: 0x1013 R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT: 0x101C R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT: 0x1024 R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT: 0x102D R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT: 0x1036 R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT: 0x103F R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT: 0x2058 R_386_TLS_TPOFF tlslocal0 0x0 +// GOTRELSHARED-NEXT: 0x205C R_386_TLS_TPOFF tlslocal1 0x0 +// GOTRELSHARED-NEXT: 0x2060 R_386_TLS_TPOFF tlsshared0 0x0 +// GOTRELSHARED-NEXT: 0x2064 R_386_TLS_TPOFF tlsshared1 0x0 // GOTRELSHARED-NEXT: } // GOTRELSHARED-NEXT: ] // GOTRELSHARED: 0x6FFFFFFA RELCOUNT 8 // DISASMSHARED: Disassembly of section test: // DISASMSHARED-NEXT: _start: -// (.got)[0] = 0x2050 = 8272 -// (.got)[1] = 0x2054 = 8276 -// (.got)[2] = 0x2058 = 8280 -// (.got)[3] = 0x205C = 8284 -// DISASMSHARED-NEXT: 2000: 8b 0d 58 10 00 00 movl 4184, %ecx -// DISASMSHARED-NEXT: 2006: 65 8b 01 movl %gs:(%ecx), %eax -// DISASMSHARED-NEXT: 2009: a1 58 10 00 00 movl 4184, %eax -// DISASMSHARED-NEXT: 200e: 65 8b 00 movl %gs:(%eax), %eax -// DISASMSHARED-NEXT: 2011: 03 0d 58 10 00 00 addl 4184, %ecx -// DISASMSHARED-NEXT: 2017: 65 8b 01 movl %gs:(%ecx), %eax -// DISASMSHARED-NEXT: 201a: 8b 0d 5c 10 00 00 movl 4188, %ecx -// DISASMSHARED-NEXT: 2020: 65 8b 01 movl %gs:(%ecx), %eax -// DISASMSHARED-NEXT: 2023: a1 5c 10 00 00 movl 4188, %eax -// DISASMSHARED-NEXT: 2028: 65 8b 00 movl %gs:(%eax), %eax -// DISASMSHARED-NEXT: 202b: 03 0d 5c 10 00 00 addl 4188, %ecx -// DISASMSHARED-NEXT: 2031: 65 8b 01 movl %gs:(%ecx), %eax -// DISASMSHARED-NEXT: 2034: 8b 0d 60 10 00 00 movl 4192, %ecx -// DISASMSHARED-NEXT: 203a: 65 8b 01 movl %gs:(%ecx), %eax -// DISASMSHARED-NEXT: 203d: 03 0d 64 10 00 00 addl 4196, %ecx -// DISASMSHARED-NEXT: 2043: 65 8b 01 movl %gs:(%ecx), %eax +// (.got)[0] = 0x2058 = 8280 +// (.got)[1] = 0x205C = 8284 +// (.got)[2] = 0x2060 = 8288 +// (.got)[3] = 0x2064 = 8292 +// DISASMSHARED-NEXT: 1000: 8b 0d 58 20 00 00 movl 8280, %ecx +// DISASMSHARED-NEXT: 1006: 65 8b 01 movl %gs:(%ecx), %eax +// DISASMSHARED-NEXT: 1009: a1 58 20 00 00 movl 8280, %eax +// DISASMSHARED-NEXT: 100e: 65 8b 00 movl %gs:(%eax), %eax +// DISASMSHARED-NEXT: 1011: 03 0d 58 20 00 00 addl 8280, %ecx +// DISASMSHARED-NEXT: 1017: 65 8b 01 movl %gs:(%ecx), %eax +// DISASMSHARED-NEXT: 101a: 8b 0d 5c 20 00 00 movl 8284, %ecx +// DISASMSHARED-NEXT: 1020: 65 8b 01 movl %gs:(%ecx), %eax +// DISASMSHARED-NEXT: 1023: a1 5c 20 00 00 movl 8284, %eax +// DISASMSHARED-NEXT: 1028: 65 8b 00 movl %gs:(%eax), %eax +// DISASMSHARED-NEXT: 102b: 03 0d 5c 20 00 00 addl 8284, %ecx +// DISASMSHARED-NEXT: 1031: 65 8b 01 movl %gs:(%ecx), %eax +// DISASMSHARED-NEXT: 1034: 8b 0d 60 20 00 00 movl 8288, %ecx +// DISASMSHARED-NEXT: 103a: 65 8b 01 movl %gs:(%ecx), %eax +// DISASMSHARED-NEXT: 103d: 03 0d 64 20 00 00 addl 8292, %ecx +// DISASMSHARED-NEXT: 1043: 65 8b 01 movl %gs:(%ecx), %eax .type tlslocal0,@object .section .tbss,"awT",@nobits diff --git a/test/ELF/linkerscript/arm-lscript.s b/test/ELF/linkerscript/arm-lscript.s new file mode 100644 index 000000000000..c377764e9776 --- /dev/null +++ b/test/ELF/linkerscript/arm-lscript.s @@ -0,0 +1,9 @@ +// REQUIRES: arm +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o +// RUN: echo "SECTIONS { \ +// RUN: .rel.dyn : { } \ +// RUN: .zed : { PROVIDE_HIDDEN (foobar = .); } \ +// RUN: }" > %t.script +// This is a test case for PR33029. Making sure that linker can digest +// the above script without dumping core. +// RUN: ld.lld -emit-relocs -T %t.script %t.o -shared -o %t.so diff --git a/test/ELF/linkerscript/sections-constraint.s b/test/ELF/linkerscript/sections-constraint.s index 796240627170..4d95ec18336c 100644 --- a/test/ELF/linkerscript/sections-constraint.s +++ b/test/ELF/linkerscript/sections-constraint.s @@ -24,8 +24,8 @@ # NO1-NEXT: 0 00000000 # NO1: .writable 00000004 # NO1: .foo.2 00000004 -# NO1: .foo.1 00000004 # NO1: .readable 00000004 +# NO1: .foo.1 00000004 .global _start _start: diff --git a/test/ELF/lto/Inputs/relocation-model-pic.ll b/test/ELF/lto/Inputs/relocation-model-pic.ll new file mode 100644 index 000000000000..e76605435e87 --- /dev/null +++ b/test/ELF/lto/Inputs/relocation-model-pic.ll @@ -0,0 +1,11 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@foo = external global i32 +define i32 @main() { + %t = load i32, i32* @foo + ret i32 %t +} + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"PIC Level", i32 2} diff --git a/test/ELF/lto/relocation-model.ll b/test/ELF/lto/relocation-model.ll new file mode 100644 index 000000000000..78334dd5cd2c --- /dev/null +++ b/test/ELF/lto/relocation-model.ll @@ -0,0 +1,46 @@ +; REQUIRES: x86 + +; RUN: llvm-as %s -o %t.o +; RUN: llvm-as %p/Inputs/relocation-model-pic.ll -o %t.pic.o + +;; Non-PIC source. + +; RUN: ld.lld %t.o -o %t-out -save-temps -shared +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC + +; RUN: ld.lld %t.o -o %t-out -save-temps --export-dynamic --noinhibit-exec -pie +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC + +; RUN: ld.lld %t.o -o %t-out -save-temps --export-dynamic --noinhibit-exec +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=STATIC + +; RUN: ld.lld %t.o -o %t-out -save-temps -r --export-dynamic +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=STATIC + + +;; PIC source. + +; RUN: ld.lld %t.pic.o -o %t-out -save-temps -shared +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC + +; RUN: ld.lld %t.pic.o -o %t-out -save-temps --export-dynamic --noinhibit-exec -pie +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC + +; RUN: ld.lld %t.pic.o -o %t-out -save-temps --export-dynamic --noinhibit-exec +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=STATIC + +; RUN: ld.lld %t.pic.o -o %t-out -save-temps -r --export-dynamic +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC + + +; PIC: R_X86_64_REX_GOTPCRELX foo +; STATIC: R_X86_64_PC32 foo + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@foo = external global i32 +define i32 @main() { + %t = load i32, i32* @foo + ret i32 %t +} diff --git a/test/ELF/relocatable-comdat.s b/test/ELF/relocatable-comdat.s new file mode 100644 index 000000000000..24504d23884f --- /dev/null +++ b/test/ELF/relocatable-comdat.s @@ -0,0 +1,45 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld -r %t.o %t.o -o %t +# RUN: llvm-readobj -elf-section-groups -sections %t | FileCheck %s + +# CHECK: Name: .text.bar +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_EXECINSTR +# CHECK-NEXT: SHF_GROUP +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 8 +# CHECK: Section { +# CHECK-NEXT: Index: 4 +# CHECK-NEXT: Name: .text.foo +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_EXECINSTR +# CHECK-NEXT: SHF_GROUP +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 4 + +# CHECK: Groups { +# CHECK-NEXT: Group { +# CHECK-NEXT: Name: .group +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Type: COMDAT +# CHECK-NEXT: Signature: abc +# CHECK-NEXT: Section(s) in group [ +# CHECK-NEXT: .text.bar +# CHECK-NEXT: .text.foo +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: } + +.section .text.bar,"axG",@progbits,abc,comdat +.quad 42 +.section .text.foo,"axG",@progbits,abc,comdat +.long 42 diff --git a/test/ELF/relocation-size-shared.s b/test/ELF/relocation-size-shared.s index 7b700ad74401..cea9e64d58ed 100644 --- a/test/ELF/relocation-size-shared.s +++ b/test/ELF/relocation-size-shared.s @@ -7,48 +7,48 @@ // RELOCSHARED: Relocations [ // RELOCSHARED-NEXT: Section ({{.*}}) .rela.dyn { -// RELOCSHARED-NEXT: 0x203018 R_X86_64_SIZE64 fooshared 0xFFFFFFFFFFFFFFFF -// RELOCSHARED-NEXT: 0x203020 R_X86_64_SIZE64 fooshared 0x0 -// RELOCSHARED-NEXT: 0x203028 R_X86_64_SIZE64 fooshared 0x1 -// RELOCSHARED-NEXT: 0x203048 R_X86_64_SIZE32 fooshared 0xFFFFFFFFFFFFFFFF -// RELOCSHARED-NEXT: 0x20304F R_X86_64_SIZE32 fooshared 0x0 -// RELOCSHARED-NEXT: 0x203056 R_X86_64_SIZE32 fooshared 0x1 +// RELOCSHARED-NEXT: 0x201018 R_X86_64_SIZE64 fooshared 0xFFFFFFFFFFFFFFFF +// RELOCSHARED-NEXT: 0x201020 R_X86_64_SIZE64 fooshared 0x0 +// RELOCSHARED-NEXT: 0x201028 R_X86_64_SIZE64 fooshared 0x1 +// RELOCSHARED-NEXT: 0x201048 R_X86_64_SIZE32 fooshared 0xFFFFFFFFFFFFFFFF +// RELOCSHARED-NEXT: 0x20104F R_X86_64_SIZE32 fooshared 0x0 +// RELOCSHARED-NEXT: 0x201056 R_X86_64_SIZE32 fooshared 0x1 // RELOCSHARED-NEXT: } // RELOCSHARED-NEXT:] // DISASM: Disassembly of section test // DISASM: _data: -// DISASM-NEXT: 203000: 19 00 -// DISASM-NEXT: 203002: 00 00 -// DISASM-NEXT: 203004: 00 00 -// DISASM-NEXT: 203006: 00 00 -// DISASM-NEXT: 203008: 1a 00 -// DISASM-NEXT: 20300a: 00 00 -// DISASM-NEXT: 20300c: 00 00 -// DISASM-NEXT: 20300e: 00 00 -// DISASM-NEXT: 203010: 1b 00 -// DISASM-NEXT: 203012: 00 00 -// DISASM-NEXT: 203014: 00 00 -// DISASM-NEXT: 203016: 00 00 -// DISASM-NEXT: 203018: 00 00 -// DISASM-NEXT: 20301a: 00 00 -// DISASM-NEXT: 20301c: 00 00 -// DISASM-NEXT: 20301e: 00 00 -// DISASM-NEXT: 203020: 00 00 -// DISASM-NEXT: 203022: 00 00 -// DISASM-NEXT: 203024: 00 00 -// DISASM-NEXT: 203026: 00 00 -// DISASM-NEXT: 203028: 00 00 -// DISASM-NEXT: 20302a: 00 00 -// DISASM-NEXT: 20302c: 00 00 -// DISASM-NEXT: 20302e: 00 00 +// DISASM-NEXT: 201000: 19 00 +// DISASM-NEXT: 201002: 00 00 +// DISASM-NEXT: 201004: 00 00 +// DISASM-NEXT: 201006: 00 00 +// DISASM-NEXT: 201008: 1a 00 +// DISASM-NEXT: 20100a: 00 00 +// DISASM-NEXT: 20100c: 00 00 +// DISASM-NEXT: 20100e: 00 00 +// DISASM-NEXT: 201010: 1b 00 +// DISASM-NEXT: 201012: 00 00 +// DISASM-NEXT: 201014: 00 00 +// DISASM-NEXT: 201016: 00 00 +// DISASM-NEXT: 201018: 00 00 +// DISASM-NEXT: 20101a: 00 00 +// DISASM-NEXT: 20101c: 00 00 +// DISASM-NEXT: 20101e: 00 00 +// DISASM-NEXT: 201020: 00 00 +// DISASM-NEXT: 201022: 00 00 +// DISASM-NEXT: 201024: 00 00 +// DISASM-NEXT: 201026: 00 00 +// DISASM-NEXT: 201028: 00 00 +// DISASM-NEXT: 20102a: 00 00 +// DISASM-NEXT: 20102c: 00 00 +// DISASM-NEXT: 20102e: 00 00 // DISASM: _start: -// DISASM-NEXT: 203030: 8b 04 25 19 00 00 00 movl 25, %eax -// DISASM-NEXT: 203037: 8b 04 25 1a 00 00 00 movl 26, %eax -// DISASM-NEXT: 20303e: 8b 04 25 1b 00 00 00 movl 27, %eax -// DISASM-NEXT: 203045: 8b 04 25 00 00 00 00 movl 0, %eax -// DISASM-NEXT: 20304c: 8b 04 25 00 00 00 00 movl 0, %eax -// DISASM-NEXT: 203053: 8b 04 25 00 00 00 00 movl 0, %eax +// DISASM-NEXT: 201030: 8b 04 25 19 00 00 00 movl 25, %eax +// DISASM-NEXT: 201037: 8b 04 25 1a 00 00 00 movl 26, %eax +// DISASM-NEXT: 20103e: 8b 04 25 1b 00 00 00 movl 27, %eax +// DISASM-NEXT: 201045: 8b 04 25 00 00 00 00 movl 0, %eax +// DISASM-NEXT: 20104c: 8b 04 25 00 00 00 00 movl 0, %eax +// DISASM-NEXT: 201053: 8b 04 25 00 00 00 00 movl 0, %eax .data .global foo diff --git a/test/ELF/relocation-size.s b/test/ELF/relocation-size.s index 2256be67df06..419b8a17fad9 100644 --- a/test/ELF/relocation-size.s +++ b/test/ELF/relocation-size.s @@ -11,82 +11,82 @@ // DISASM: Disassembly of section test: // DISASM-NEXT: _data: -// DISASM-NEXT: 202000: 19 00 -// DISASM-NEXT: 202002: 00 00 -// DISASM-NEXT: 202004: 00 00 -// DISASM-NEXT: 202006: 00 00 -// DISASM-NEXT: 202008: 1a 00 -// DISASM-NEXT: 20200a: 00 00 -// DISASM-NEXT: 20200c: 00 00 -// DISASM-NEXT: 20200e: 00 00 -// DISASM-NEXT: 202010: 1b 00 -// DISASM-NEXT: 202012: 00 00 -// DISASM-NEXT: 202014: 00 00 -// DISASM-NEXT: 202016: 00 00 -// DISASM-NEXT: 202018: 19 00 -// DISASM-NEXT: 20201a: 00 00 -// DISASM-NEXT: 20201c: 00 00 -// DISASM-NEXT: 20201e: 00 00 -// DISASM-NEXT: 202020: 1a 00 -// DISASM-NEXT: 202022: 00 00 -// DISASM-NEXT: 202024: 00 00 -// DISASM-NEXT: 202026: 00 00 -// DISASM-NEXT: 202028: 1b 00 -// DISASM-NEXT: 20202a: 00 00 -// DISASM-NEXT: 20202c: 00 00 -// DISASM-NEXT: 20202e: 00 00 +// DISASM-NEXT: 201000: 19 00 +// DISASM-NEXT: 201002: 00 00 +// DISASM-NEXT: 201004: 00 00 +// DISASM-NEXT: 201006: 00 00 +// DISASM-NEXT: 201008: 1a 00 +// DISASM-NEXT: 20100a: 00 00 +// DISASM-NEXT: 20100c: 00 00 +// DISASM-NEXT: 20100e: 00 00 +// DISASM-NEXT: 201010: 1b 00 +// DISASM-NEXT: 201012: 00 00 +// DISASM-NEXT: 201014: 00 00 +// DISASM-NEXT: 201016: 00 00 +// DISASM-NEXT: 201018: 19 00 +// DISASM-NEXT: 20101a: 00 00 +// DISASM-NEXT: 20101c: 00 00 +// DISASM-NEXT: 20101e: 00 00 +// DISASM-NEXT: 201020: 1a 00 +// DISASM-NEXT: 201022: 00 00 +// DISASM-NEXT: 201024: 00 00 +// DISASM-NEXT: 201026: 00 00 +// DISASM-NEXT: 201028: 1b 00 +// DISASM-NEXT: 20102a: 00 00 +// DISASM-NEXT: 20102c: 00 00 +// DISASM-NEXT: 20102e: 00 00 // DISASM: _start: -// DISASM-NEXT: 202030: 8b 04 25 19 00 00 00 movl 25, %eax -// DISASM-NEXT: 202037: 8b 04 25 1a 00 00 00 movl 26, %eax -// DISASM-NEXT: 20203e: 8b 04 25 1b 00 00 00 movl 27, %eax -// DISASM-NEXT: 202045: 8b 04 25 19 00 00 00 movl 25, %eax -// DISASM-NEXT: 20204c: 8b 04 25 1a 00 00 00 movl 26, %eax -// DISASM-NEXT: 202053: 8b 04 25 1b 00 00 00 movl 27, %eax +// DISASM-NEXT: 201030: 8b 04 25 19 00 00 00 movl 25, %eax +// DISASM-NEXT: 201037: 8b 04 25 1a 00 00 00 movl 26, %eax +// DISASM-NEXT: 20103e: 8b 04 25 1b 00 00 00 movl 27, %eax +// DISASM-NEXT: 201045: 8b 04 25 19 00 00 00 movl 25, %eax +// DISASM-NEXT: 20104c: 8b 04 25 1a 00 00 00 movl 26, %eax +// DISASM-NEXT: 201053: 8b 04 25 1b 00 00 00 movl 27, %eax // RELOCSHARED: Relocations [ // RELOCSHARED-NEXT: Section ({{.*}}) .rela.dyn { -// RELOCSHARED-NEXT: 0x3000 R_X86_64_SIZE64 foo 0xFFFFFFFFFFFFFFFF -// RELOCSHARED-NEXT: 0x3008 R_X86_64_SIZE64 foo 0x0 -// RELOCSHARED-NEXT: 0x3010 R_X86_64_SIZE64 foo 0x1 -// RELOCSHARED-NEXT: 0x3033 R_X86_64_SIZE32 foo 0xFFFFFFFFFFFFFFFF -// RELOCSHARED-NEXT: 0x303A R_X86_64_SIZE32 foo 0x0 -// RELOCSHARED-NEXT: 0x3041 R_X86_64_SIZE32 foo 0x1 +// RELOCSHARED-NEXT: 0x1000 R_X86_64_SIZE64 foo 0xFFFFFFFFFFFFFFFF +// RELOCSHARED-NEXT: 0x1008 R_X86_64_SIZE64 foo 0x0 +// RELOCSHARED-NEXT: 0x1010 R_X86_64_SIZE64 foo 0x1 +// RELOCSHARED-NEXT: 0x1033 R_X86_64_SIZE32 foo 0xFFFFFFFFFFFFFFFF +// RELOCSHARED-NEXT: 0x103A R_X86_64_SIZE32 foo 0x0 +// RELOCSHARED-NEXT: 0x1041 R_X86_64_SIZE32 foo 0x1 // RELOCSHARED-NEXT: } // RELOCSHARED-NEXT: ] // DISASMSHARED: Disassembly of section test: // DISASMSHARED-NEXT: _data: -// DISASMSHARED-NEXT: 3000: 00 00 -// DISASMSHARED-NEXT: 3002: 00 00 -// DISASMSHARED-NEXT: 3004: 00 00 -// DISASMSHARED-NEXT: 3006: 00 00 -// DISASMSHARED-NEXT: 3008: 00 00 -// DISASMSHARED-NEXT: 300a: 00 00 -// DISASMSHARED-NEXT: 300c: 00 00 -// DISASMSHARED-NEXT: 300e: 00 00 -// DISASMSHARED-NEXT: 3010: 00 00 -// DISASMSHARED-NEXT: 3012: 00 00 -// DISASMSHARED-NEXT: 3014: 00 00 -// DISASMSHARED-NEXT: 3016: 00 00 -// DISASMSHARED-NEXT: 3018: 19 00 -// DISASMSHARED-NEXT: 301a: 00 00 -// DISASMSHARED-NEXT: 301c: 00 00 -// DISASMSHARED-NEXT: 301e: 00 00 -// DISASMSHARED-NEXT: 3020: 1a 00 -// DISASMSHARED-NEXT: 3022: 00 00 -// DISASMSHARED-NEXT: 3024: 00 00 -// DISASMSHARED-NEXT: 3026: 00 00 -// DISASMSHARED-NEXT: 3028: 1b 00 -// DISASMSHARED-NEXT: 302a: 00 00 -// DISASMSHARED-NEXT: 302c: 00 00 -// DISASMSHARED-NEXT: 302e: 00 00 +// DISASMSHARED-NEXT: 1000: 00 00 +// DISASMSHARED-NEXT: 1002: 00 00 +// DISASMSHARED-NEXT: 1004: 00 00 +// DISASMSHARED-NEXT: 1006: 00 00 +// DISASMSHARED-NEXT: 1008: 00 00 +// DISASMSHARED-NEXT: 100a: 00 00 +// DISASMSHARED-NEXT: 100c: 00 00 +// DISASMSHARED-NEXT: 100e: 00 00 +// DISASMSHARED-NEXT: 1010: 00 00 +// DISASMSHARED-NEXT: 1012: 00 00 +// DISASMSHARED-NEXT: 1014: 00 00 +// DISASMSHARED-NEXT: 1016: 00 00 +// DISASMSHARED-NEXT: 1018: 19 00 +// DISASMSHARED-NEXT: 101a: 00 00 +// DISASMSHARED-NEXT: 101c: 00 00 +// DISASMSHARED-NEXT: 101e: 00 00 +// DISASMSHARED-NEXT: 1020: 1a 00 +// DISASMSHARED-NEXT: 1022: 00 00 +// DISASMSHARED-NEXT: 1024: 00 00 +// DISASMSHARED-NEXT: 1026: 00 00 +// DISASMSHARED-NEXT: 1028: 1b 00 +// DISASMSHARED-NEXT: 102a: 00 00 +// DISASMSHARED-NEXT: 102c: 00 00 +// DISASMSHARED-NEXT: 102e: 00 00 // DISASMSHARED: _start: -// DISASMSHARED-NEXT: 3030: 8b 04 25 00 00 00 00 movl 0, %eax -// DISASMSHARED-NEXT: 3037: 8b 04 25 00 00 00 00 movl 0, %eax -// DISASMSHARED-NEXT: 303e: 8b 04 25 00 00 00 00 movl 0, %eax -// DISASMSHARED-NEXT: 3045: 8b 04 25 19 00 00 00 movl 25, %eax -// DISASMSHARED-NEXT: 304c: 8b 04 25 1a 00 00 00 movl 26, %eax -// DISASMSHARED-NEXT: 3053: 8b 04 25 1b 00 00 00 movl 27, %eax +// DISASMSHARED-NEXT: 1030: 8b 04 25 00 00 00 00 movl 0, %eax +// DISASMSHARED-NEXT: 1037: 8b 04 25 00 00 00 00 movl 0, %eax +// DISASMSHARED-NEXT: 103e: 8b 04 25 00 00 00 00 movl 0, %eax +// DISASMSHARED-NEXT: 1045: 8b 04 25 19 00 00 00 movl 25, %eax +// DISASMSHARED-NEXT: 104c: 8b 04 25 1a 00 00 00 movl 26, %eax +// DISASMSHARED-NEXT: 1053: 8b 04 25 1b 00 00 00 movl 27, %eax .data .global foo diff --git a/test/ELF/reproduce.s b/test/ELF/reproduce.s index 94823d6d377f..0a93be08d040 100644 --- a/test/ELF/reproduce.s +++ b/test/ELF/reproduce.s @@ -63,7 +63,7 @@ ## Check that directory path is stripped from -o <file-path> # RUN: mkdir -p %t.dir/build3/a/b/c # RUN: cd %t.dir -# RUN: ld.lld build1/foo.o -o build3/a/b/c/bar -shared --as-needed --reproduce repro3.tar +# RUN: ld.lld build1/foo.o -o build3/a/b/c/bar -shared --as-needed --reproduce=repro3.tar # RUN: tar xf repro3.tar # RUN: FileCheck %s --check-prefix=RSP3 < repro3/response.txt # RSP3: -o bar diff --git a/test/ELF/rodynamic.s b/test/ELF/rodynamic.s new file mode 100644 index 000000000000..441e5c395e7c --- /dev/null +++ b/test/ELF/rodynamic.s @@ -0,0 +1,35 @@ +# RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux +# RUN: llvm-mc %p/Inputs/rodynamic.s -o %t.so.o -filetype=obj -triple=x86_64-pc-linux + +# RUN: ld.lld -shared %t.so.o -o %t.so +# RUN: ld.lld %t.o %t.so -o %t.exe +# RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=DEFDEBUG %s +# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=DEFSEC %s + +# RUN: ld.lld -shared -z rodynamic %t.so.o -o %t.so +# RUN: ld.lld -z rodynamic %t.o %t.so -o %t.exe +# RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=RODEBUG %s +# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=ROSEC %s + +.globl _start +_start: + call foo + +# DEFDEBUG: DEBUG + +# DEFSEC: Section { +# DEFSEC: Name: .dynamic +# DEFSEC-NEXT: Type: SHT_DYNAMIC +# DEFSEC-NEXT: Flags [ +# DEFSEC-NEXT: SHF_ALLOC +# DEFSEC-NEXT: SHF_WRITE +# DEFSEC-NEXT: ] + +# RODEBUG-NOT: DEBUG + +# ROSEC: Section { +# ROSEC: Name: .dynamic +# ROSEC-NEXT: Type: SHT_DYNAMIC +# ROSEC-NEXT: Flags [ +# ROSEC-NEXT: SHF_ALLOC +# ROSEC-NEXT: ] diff --git a/test/ELF/section-layout.s b/test/ELF/section-layout.s index f63066e0d926..7febec85a629 100644 --- a/test/ELF/section-layout.s +++ b/test/ELF/section-layout.s @@ -34,6 +34,11 @@ _start: // CHECK: Name: c // CHECK: Name: d +// Sections that are both writable and executable appear before +// sections that are only writable. +// CHECK: Name: k +// CHECK: Name: l + // Writable sections appear before TLS and other relro sections. // CHECK: Name: i @@ -42,8 +47,6 @@ _start: // CHECK: Name: g // CHECK: Name: j -// CHECK: Name: k -// CHECK: Name: l // Non allocated sections are in input order. // CHECK: Name: t diff --git a/test/ELF/tls-i686.s b/test/ELF/tls-i686.s index 2a04a555865a..7f2dd605cacd 100644 --- a/test/ELF/tls-i686.s +++ b/test/ELF/tls-i686.s @@ -32,38 +32,38 @@ _start: // DIS: Disassembly of section test: // DIS-NEXT: _start: -// DIS-NEXT: 12000: ba 08 00 00 00 movl $8, %edx -// DIS-NEXT: 12005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DIS-NEXT: 1200c: 29 d0 subl %edx, %eax -// DIS-NEXT: 1200e: ba 04 00 00 00 movl $4, %edx -// DIS-NEXT: 12013: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DIS-NEXT: 1201a: 29 d0 subl %edx, %eax -// DIS-NEXT: 1201c: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DIS-NEXT: 12023: 8d 81 f8 ff ff ff leal -8(%ecx), %eax -// DIS-NEXT: 12029: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DIS-NEXT: 12030: 8d 81 77 00 00 00 leal 119(%ecx), %eax +// DIS-NEXT: 11000: ba 08 00 00 00 movl $8, %edx +// DIS-NEXT: 11005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DIS-NEXT: 1100c: 29 d0 subl %edx, %eax +// DIS-NEXT: 1100e: ba 04 00 00 00 movl $4, %edx +// DIS-NEXT: 11013: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DIS-NEXT: 1101a: 29 d0 subl %edx, %eax +// DIS-NEXT: 1101c: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DIS-NEXT: 11023: 8d 81 f8 ff ff ff leal -8(%ecx), %eax +// DIS-NEXT: 11029: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DIS-NEXT: 11030: 8d 81 77 00 00 00 leal 119(%ecx), %eax // RELOC: Relocations [ // RELOC-NEXT: ] // DISSHARED: Disassembly of section test: // DISSHARED-NEXT: _start: -// DISSHARED-NEXT: 2000: ba 00 00 00 00 movl $0, %edx -// DISSHARED-NEXT: 2005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DISSHARED-NEXT: 200c: 29 d0 subl %edx, %eax -// DISSHARED-NEXT: 200e: ba 00 00 00 00 movl $0, %edx -// DISSHARED-NEXT: 2013: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DISSHARED-NEXT: 201a: 29 d0 subl %edx, %eax -// DISSHARED-NEXT: 201c: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DISSHARED-NEXT: 2023: 8d 81 00 00 00 00 leal (%ecx), %eax -// DISSHARED-NEXT: 2029: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DISSHARED-NEXT: 2030: 8d 81 7b 00 00 00 leal 123(%ecx), %eax +// DISSHARED-NEXT: 1000: ba 00 00 00 00 movl $0, %edx +// DISSHARED-NEXT: 1005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DISSHARED-NEXT: 100c: 29 d0 subl %edx, %eax +// DISSHARED-NEXT: 100e: ba 00 00 00 00 movl $0, %edx +// DISSHARED-NEXT: 1013: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DISSHARED-NEXT: 101a: 29 d0 subl %edx, %eax +// DISSHARED-NEXT: 101c: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DISSHARED-NEXT: 1023: 8d 81 00 00 00 00 leal (%ecx), %eax +// DISSHARED-NEXT: 1029: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DISSHARED-NEXT: 1030: 8d 81 7b 00 00 00 leal 123(%ecx), %eax // RELOCSHARED: Relocations [ // RELOCSHARED-NEXT: Section (4) .rel.dyn { -// RELOCSHARED-NEXT: 0x2001 R_386_TLS_TPOFF32 var 0x0 -// RELOCSHARED-NEXT: 0x2025 R_386_TLS_TPOFF var 0x0 -// RELOCSHARED-NEXT: 0x200F R_386_TLS_TPOFF32 var1 0x0 -// RELOCSHARED-NEXT: 0x2032 R_386_TLS_TPOFF var1 0x0 +// RELOCSHARED-NEXT: 0x1001 R_386_TLS_TPOFF32 var 0x0 +// RELOCSHARED-NEXT: 0x1025 R_386_TLS_TPOFF var 0x0 +// RELOCSHARED-NEXT: 0x100F R_386_TLS_TPOFF32 var1 0x0 +// RELOCSHARED-NEXT: 0x1032 R_386_TLS_TPOFF var1 0x0 // RELOCSHARED-NEXT: } // RELOCSHARED-NEXT: ] |