diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-04-26 19:24:42 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-04-26 19:24:42 +0000 |
commit | e06a19b85dfce9ea18be97247d4ca315963edc5c (patch) | |
tree | ea315682e394f1c39a30049e4497e1a723f18e3c | |
parent | be08ec96063be8c1a1a8621eccd05a4ebeecfb42 (diff) |
Vendor import of lld trunk r301441:vendor/lld/lld-trunk-r301441
Notes
Notes:
svn path=/vendor/lld/dist/; revision=317453
svn path=/vendor/lld/lld-trunk-r301441/; revision=317454; tag=vendor/lld/lld-trunk-r301441
39 files changed, 489 insertions, 154 deletions
diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp index 10eeedd88e55..2e49f417a206 100644 --- a/COFF/Chunks.cpp +++ b/COFF/Chunks.cpp @@ -319,8 +319,48 @@ void SEHTableChunk::writeTo(uint8_t *Buf) const { std::sort(Begin, Begin + Cnt); } -// Windows-specific. -// This class represents a block in .reloc section. +// Windows-specific. This class represents a block in .reloc section. +// The format is described here. +// +// On Windows, each DLL is linked against a fixed base address and +// usually loaded to that address. However, if there's already another +// DLL that overlaps, the loader has to relocate it. To do that, DLLs +// contain .reloc sections which contain offsets that need to be fixed +// up at runtime. If the loader find that a DLL cannot be loaded to its +// desired base address, it loads it to somewhere else, and add <actual +// base address> - <desired base address> to each offset that is +// specified by .reloc section. +// +// In ELF terms, .reloc sections contain arrays of relocation offsets. +// All these offsets in the section are implicitly R_*_RELATIVE, and +// addends are read from section contents (so it is REL as opposed to +// RELA). +// +// This already reduce the size of relocations to 1/3 compared to ELF +// .dynrel, but Windows does more to reduce it (probably because it was +// invented for PCs in the late '80s or early '90s.) Offsets in .reloc +// are grouped by page where page size is 16 bits, and offsets sharing +// the same page address are stored consecutively to represent them with +// less space. This is a very similar to the page table which is grouped +// by (multiple stages of) pages. +// +// For example, let's say we have 0x00030, 0x00500, 0x01000, 0x01100, +// 0x20004, and 0x20008 in a .reloc section. In the section, they are +// represented like this: +// +// 0x00000 -- page address (4 bytes) +// 16 -- size of this block (4 bytes) +// 0x0030 -- entries (2 bytes each) +// 0x0500 +// 0x1000 +// 0x1100 +// 0x20000 -- page address (4 bytes) +// 12 -- size of this block (4 bytes) +// 0x0004 -- entries (2 bytes each) +// 0x0008 +// +// Usually we have a lot of relocatinos for each page, so the number of +// bytes for one .reloc entry is close to 2 bytes. BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) { // Block header consists of 4 byte page RVA and 4 byte block size. // Each entry is 2 byte. Last entry may be padding. diff --git a/COFF/Config.h b/COFF/Config.h index 31534aeb3971..fafd3bcde2e3 100644 --- a/COFF/Config.h +++ b/COFF/Config.h @@ -43,6 +43,7 @@ struct Export { bool Noname = false; bool Data = false; bool Private = false; + bool Constant = false; // If an export is a form of /export:foo=dllname.bar, that means // that foo should be exported as an alias to bar in the DLL. diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp index daddfb86d4cf..5a15b5b11507 100644 --- a/COFF/Driver.cpp +++ b/COFF/Driver.cpp @@ -512,6 +512,23 @@ void LinkerDriver::invokeMSVC(opt::InputArgList &Args) { std::string Rsp = "/nologo\n"; std::vector<std::string> Temps; + // Write out archive members that we used in symbol resolution and pass these + // to MSVC before any archives, so that MSVC uses the same objects to satisfy + // references. + for (const auto *O : Symtab.ObjectFiles) { + if (O->ParentName.empty()) + continue; + SmallString<128> S; + int Fd; + if (auto EC = sys::fs::createTemporaryFile( + "lld-" + sys::path::filename(O->ParentName), ".obj", Fd, S)) + fatal(EC, "cannot create a temporary file"); + raw_fd_ostream OS(Fd, /*shouldClose*/ true); + OS << O->MB.getBuffer(); + Temps.push_back(S.str()); + Rsp += quote(S) + "\n"; + } + for (auto *Arg : Args) { switch (Arg->getOption().getID()) { case OPT_linkrepro: diff --git a/COFF/Driver.h b/COFF/Driver.h index 4566f73eef31..ad725625e030 100644 --- a/COFF/Driver.h +++ b/COFF/Driver.h @@ -48,7 +48,7 @@ public: llvm::opt::InputArgList parse(llvm::ArrayRef<const char *> Args); // Concatenate LINK environment varirable and given arguments and parse them. - llvm::opt::InputArgList parseLINK(llvm::ArrayRef<const char *> Args); + llvm::opt::InputArgList parseLINK(std::vector<const char *> Args); // Tokenizes a given string and then parses as command line options. llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); } diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp index 2c9ba797f73b..252590c7d870 100644 --- a/COFF/DriverUtils.cpp +++ b/COFF/DriverUtils.cpp @@ -479,6 +479,10 @@ Export parseExport(StringRef Arg) { E.Data = true; continue; } + if (Tok.equals_lower("constant")) { + E.Constant = true; + continue; + } if (Tok.equals_lower("private")) { E.Private = true; continue; @@ -695,17 +699,20 @@ opt::InputArgList ArgParser::parse(ArrayRef<const char *> ArgsArr) { return Args; } -// link.exe has an interesting feature. If LINK environment exists, -// its contents are handled as a command line string. So you can pass -// extra arguments using the environment variable. -opt::InputArgList ArgParser::parseLINK(ArrayRef<const char *> Args) { +// link.exe has an interesting feature. If LINK or _LINK_ environment +// variables exist, their contents are handled as command line strings. +// So you can pass extra arguments using them. +opt::InputArgList ArgParser::parseLINK(std::vector<const char *> Args) { // Concatenate LINK env and command line arguments, and then parse them. - Optional<std::string> Env = Process::GetEnv("LINK"); - if (!Env) - return parse(Args); - std::vector<const char *> V = tokenize(*Env); - V.insert(V.end(), Args.begin(), Args.end()); - return parse(V); + if (Optional<std::string> S = Process::GetEnv("LINK")) { + std::vector<const char *> V = tokenize(*S); + Args.insert(Args.begin(), V.begin(), V.end()); + } + if (Optional<std::string> S = Process::GetEnv("_LINK_")) { + std::vector<const char *> V = tokenize(*S); + Args.insert(Args.begin(), V.begin(), V.end()); + } + return parse(Args); } std::vector<const char *> ArgParser::tokenize(StringRef S) { diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h index 9e02b2fc68bb..3078de687525 100644 --- a/COFF/InputFiles.h +++ b/COFF/InputFiles.h @@ -58,6 +58,8 @@ public: // Returns the CPU type this file was compiled to. virtual MachineTypes getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; } + MemoryBufferRef MB; + // An archive file name if this file is created from an archive. StringRef ParentName; @@ -67,7 +69,6 @@ public: protected: InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} - MemoryBufferRef MB; std::string Directives; private: diff --git a/COFF/Librarian.cpp b/COFF/Librarian.cpp index 3ce72822180b..91316ee6b0c9 100644 --- a/COFF/Librarian.cpp +++ b/COFF/Librarian.cpp @@ -162,7 +162,7 @@ public: // Create a short import file which is described in PE/COFF spec 7. Import // Library Format. NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal, - ImportNameType NameType, bool isData); + ImportType Type, ImportNameType NameType); }; } @@ -440,8 +440,8 @@ NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) { NewArchiveMember ObjectFactory::createShortImport(StringRef Sym, uint16_t Ordinal, - ImportNameType NameType, - bool isData) { + ImportType ImportType, + ImportNameType NameType) { size_t ImpSize = DLLName.size() + Sym.size() + 2; // +2 for NULs size_t Size = sizeof(coff_import_header) + ImpSize; char *Buf = Alloc.Allocate<char>(Size); @@ -456,8 +456,7 @@ NewArchiveMember ObjectFactory::createShortImport(StringRef Sym, Imp->SizeOfData = ImpSize; if (Ordinal > 0) Imp->OrdinalHint = Ordinal; - Imp->TypeInfo = (isData ? IMPORT_DATA : IMPORT_CODE); - Imp->TypeInfo |= NameType << 2; + Imp->TypeInfo = (NameType << 2) | ImportType; // Write symbol name and DLL name. memcpy(P, Sym.data(), Sym.size()); @@ -490,11 +489,18 @@ void lld::coff::writeImportLibrary() { if (E.Private) continue; - ImportNameType Type = getNameType(E.SymbolName, E.Name); + ImportType ImportType = IMPORT_CODE; + if (E.Data) + ImportType = IMPORT_DATA; + if (E.Constant) + ImportType = IMPORT_CONST; + + ImportNameType NameType = getNameType(E.SymbolName, E.Name); std::string Name = E.ExtName.empty() ? std::string(E.SymbolName) : replace(E.SymbolName, E.Name, E.ExtName); - Members.push_back(OF.createShortImport(Name, E.Ordinal, Type, E.Data)); + Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType, + NameType)); } std::pair<StringRef, std::error_code> Result = diff --git a/COFF/ModuleDef.cpp b/COFF/ModuleDef.cpp index c9a40ac5ab8c..740ce867a7c4 100644 --- a/COFF/ModuleDef.cpp +++ b/COFF/ModuleDef.cpp @@ -38,6 +38,7 @@ enum Kind { Comma, Equal, KwBase, + KwConstant, KwData, KwExports, KwHeapsize, @@ -92,6 +93,7 @@ public: StringRef Word = Buf.substr(0, End); Kind K = llvm::StringSwitch<Kind>(Word) .Case("BASE", KwBase) + .Case("CONSTANT", KwConstant) .Case("DATA", KwData) .Case("EXPORTS", KwExports) .Case("HEAPSIZE", KwHeapsize) @@ -227,6 +229,11 @@ private: E.Data = true; continue; } + if (Tok.K == KwConstant) { + warn("CONSTANT keyword is obsolete; use DATA"); + E.Constant = true; + continue; + } if (Tok.K == KwPrivate) { E.Private = true; continue; diff --git a/COFF/SymbolTable.h b/COFF/SymbolTable.h index 764dd5318775..bf8d6618d964 100644 --- a/COFF/SymbolTable.h +++ b/COFF/SymbolTable.h @@ -108,14 +108,9 @@ public: std::vector<Chunk *> LocalImportChunks; private: - void readArchive(); - void readObjects(); - std::pair<Symbol *, bool> insert(StringRef Name); StringRef findByPrefix(StringRef Prefix); - void addCombinedLTOObject(ObjectFile *Obj); - llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> Symtab; std::vector<BitcodeFile *> BitcodeFiles; diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index 93924e4554c9..68eb5616a5c6 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -184,8 +184,6 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) { error("attempted static link of dynamic object " + Path); return; } - Files.push_back(createSharedFile(MBRef)); - // DSOs usually have DT_SONAME tags in their ELF headers, and the // sonames are used to identify DSOs. But if they are missing, // they are identified by filenames. We don't know whether the new @@ -196,8 +194,8 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) { // If a file was specified by -lfoo, the directory part is not // significant, as a user did not specify it. This behavior is // compatible with GNU. - Files.back()->DefaultSoName = - WithLOption ? sys::path::filename(Path) : Path; + Files.push_back(createSharedFile( + MBRef, WithLOption ? sys::path::filename(Path) : Path)); return; default: if (InLib) @@ -708,10 +706,6 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { if (!Config->Shared && !Config->AuxiliaryList.empty()) error("-f may not be used without -shared"); - for (auto *Arg : Args.filtered(OPT_dynamic_list)) - if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) - readDynamicList(*Buffer); - if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file)) if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) Config->SymbolOrderingFile = getLines(*Buffer); @@ -726,21 +720,31 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { {S, /*IsExternCpp*/ false, /*HasWildcard*/ false}); } - for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol)) - Config->VersionScriptGlobals.push_back( - {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false}); - - // Dynamic lists are a simplified linker script that doesn't need the - // "global:" and implicitly ends with a "local:*". Set the variables needed to - // simulate that. - if (Args.hasArg(OPT_dynamic_list) || Args.hasArg(OPT_export_dynamic_symbol)) { - Config->ExportDynamic = true; - if (!Config->Shared) - Config->DefaultSymbolVersion = VER_NDX_LOCAL; - } + bool HasExportDynamic = + getArg(Args, OPT_export_dynamic, OPT_no_export_dynamic, false); - if (getArg(Args, OPT_export_dynamic, OPT_no_export_dynamic, false)) - Config->DefaultSymbolVersion = VER_NDX_GLOBAL; + // Parses -dynamic-list and -export-dynamic-symbol. They make some + // symbols private. Note that -export-dynamic takes precedence over them + // as it says all symbols should be exported. + if (!HasExportDynamic) { + for (auto *Arg : Args.filtered(OPT_dynamic_list)) + if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) + readDynamicList(*Buffer); + + for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol)) + Config->VersionScriptGlobals.push_back( + {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false}); + + // Dynamic lists are a simplified linker script that doesn't need the + // "global:" and implicitly ends with a "local:*". Set the variables + // needed to simulate that. + if (Args.hasArg(OPT_dynamic_list) || + Args.hasArg(OPT_export_dynamic_symbol)) { + Config->ExportDynamic = true; + if (!Config->Shared) + Config->DefaultSymbolVersion = VER_NDX_LOCAL; + } + } if (auto *Arg = Args.getLastArg(OPT_version_script)) if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) @@ -876,6 +880,21 @@ static uint64_t getImageBase(opt::InputArgList &Args) { return V; } +// Parses --defsym=alias option. +static std::vector<std::pair<StringRef, StringRef>> +getDefsym(opt::InputArgList &Args) { + std::vector<std::pair<StringRef, StringRef>> Ret; + for (auto *Arg : Args.filtered(OPT_defsym)) { + StringRef From; + StringRef To; + std::tie(From, To) = StringRef(Arg->getValue()).split('='); + if (!isValidCIdentifier(To)) + error("--defsym: symbol name expected, but got " + To); + Ret.push_back({From, To}); + } + return Ret; +} + // Do actual linking. Note that when this function is called, // all linker scripts have already been parsed. template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { @@ -893,9 +912,11 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { // Fail early if the output file or map file is not writable. If a user has a // long link, e.g. due to a large LTO link, they do not wish to run it and // find that it failed because there was a mistake in their command-line. - if (!isFileWritable(Config->OutputFile, "output file")) - return; - if (!isFileWritable(Config->MapFile, "map file")) + if (auto E = tryCreateFile(Config->OutputFile)) + error("cannot open output file " + Config->OutputFile + ": " + E.message()); + if (auto E = tryCreateFile(Config->MapFile)) + error("cannot open map file " + Config->MapFile + ": " + E.message()); + if (ErrorCount) return; // Use default entry point name if no name was given via the command @@ -941,6 +962,10 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { 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); + // Now that we have a complete list of input files. // Beyond this point, no new files are added. // Aggregate all input sections into one place. diff --git a/ELF/Filesystem.cpp b/ELF/Filesystem.cpp index 75f7bda75a23..b63d521a83b0 100644 --- a/ELF/Filesystem.cpp +++ b/ELF/Filesystem.cpp @@ -13,7 +13,6 @@ #include "Filesystem.h" #include "Config.h" -#include "Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileOutputBuffer.h" #include <thread> @@ -58,22 +57,20 @@ void elf::unlinkAsync(StringRef Path) { std::thread([=] { ::remove(TempPath.str().str().c_str()); }).detach(); } -// Returns true if a given file seems to be writable. +// Simulate file creation to see if Path is writable. // // Determining whether a file is writable or not is amazingly hard, // and after all the only reliable way of doing that is to actually // create a file. But we don't want to do that in this function // because LLD shouldn't update any file if it will end in a failure. -// We also don't want to reimplement heuristics. So we'll let -// FileOutputBuffer do the work. +// We also don't want to reimplement heuristics to determine if a +// file is writable. So we'll let FileOutputBuffer do the work. // // FileOutputBuffer doesn't touch a desitnation file until commit() // is called. We use that class without calling commit() to predict // if the given file is writable. -bool elf::isFileWritable(StringRef Path, StringRef Desc) { - if (auto EC = FileOutputBuffer::create(Path, 1).getError()) { - error("cannot open " + Desc + " " + Path + ": " + EC.message()); - return false; - } - return true; +std::error_code elf::tryCreateFile(StringRef Path) { + if (Path.empty()) + return std::error_code(); + return FileOutputBuffer::create(Path, 1).getError(); } diff --git a/ELF/Filesystem.h b/ELF/Filesystem.h index a33dc3651a4a..d56d067f7378 100644 --- a/ELF/Filesystem.h +++ b/ELF/Filesystem.h @@ -15,7 +15,7 @@ namespace lld { namespace elf { void unlinkAsync(StringRef Path); -bool isFileWritable(StringRef Path, StringRef FileDescription); +std::error_code tryCreateFile(StringRef Path); } } diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index d651fbcad253..d99f71eb4aae 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -608,8 +608,9 @@ ArchiveFile::getMember(const Archive::Symbol *Sym) { } template <class ELFT> -SharedFile<ELFT>::SharedFile(MemoryBufferRef M) - : ELFFileBase<ELFT>(Base::SharedKind, M), AsNeeded(Config->AsNeeded) {} +SharedFile<ELFT>::SharedFile(MemoryBufferRef M, StringRef DefaultSoName) + : ELFFileBase<ELFT>(Base::SharedKind, M), SoName(DefaultSoName), + AsNeeded(Config->AsNeeded) {} template <class ELFT> const typename ELFT::Shdr * @@ -619,12 +620,6 @@ SharedFile<ELFT>::getSection(const Elf_Sym &Sym) const { toString(this)); } -template <class ELFT> StringRef SharedFile<ELFT>::getSoName() const { - if (SoName.empty()) - return this->DefaultSoName; - return SoName; -} - // Partially parse the shared object file so that we can call // getSoName on this object. template <class ELFT> void SharedFile<ELFT>::parseSoName() { @@ -867,8 +862,23 @@ void BitcodeFile::parse(DenseSet<CachedHashStringRef> &ComdatGroups) { Symbols.push_back(createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, this)); } +// Small bit of template meta programming to handle the SharedFile constructor +// being the only one with a DefaultSoName parameter. +template <template <class> class T, class E> +typename std::enable_if<std::is_same<T<E>, SharedFile<E>>::value, + InputFile *>::type +createELFAux(MemoryBufferRef MB, StringRef DefaultSoName) { + return make<T<E>>(MB, DefaultSoName); +} +template <template <class> class T, class E> +typename std::enable_if<!std::is_same<T<E>, SharedFile<E>>::value, + InputFile *>::type +createELFAux(MemoryBufferRef MB, StringRef DefaultSoName) { + return make<T<E>>(MB); +} + template <template <class> class T> -static InputFile *createELFFile(MemoryBufferRef MB) { +static InputFile *createELFFile(MemoryBufferRef MB, StringRef DefaultSoName) { unsigned char Size; unsigned char Endian; std::tie(Size, Endian) = getElfArchType(MB.getBuffer()); @@ -882,13 +892,13 @@ static InputFile *createELFFile(MemoryBufferRef MB) { InputFile *Obj; if (Size == ELFCLASS32 && Endian == ELFDATA2LSB) - Obj = make<T<ELF32LE>>(MB); + Obj = createELFAux<T, ELF32LE>(MB, DefaultSoName); else if (Size == ELFCLASS32 && Endian == ELFDATA2MSB) - Obj = make<T<ELF32BE>>(MB); + Obj = createELFAux<T, ELF32BE>(MB, DefaultSoName); else if (Size == ELFCLASS64 && Endian == ELFDATA2LSB) - Obj = make<T<ELF64LE>>(MB); + Obj = createELFAux<T, ELF64LE>(MB, DefaultSoName); else if (Size == ELFCLASS64 && Endian == ELFDATA2MSB) - Obj = make<T<ELF64BE>>(MB); + Obj = createELFAux<T, ELF64BE>(MB, DefaultSoName); else fatal(MB.getBufferIdentifier() + ": invalid file class"); @@ -933,13 +943,13 @@ InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName, uint64_t OffsetInArchive) { InputFile *F = isBitcode(MB) ? make<BitcodeFile>(MB, ArchiveName, OffsetInArchive) - : createELFFile<ObjectFile>(MB); + : createELFFile<ObjectFile>(MB, ""); F->ArchiveName = ArchiveName; return F; } -InputFile *elf::createSharedFile(MemoryBufferRef MB) { - return createELFFile<SharedFile>(MB); +InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) { + return createELFFile<SharedFile>(MB, DefaultSoName); } MemoryBufferRef LazyObjectFile::getBuffer() { diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h index 40a8b23c5ef4..4552270316d9 100644 --- a/ELF/InputFiles.h +++ b/ELF/InputFiles.h @@ -93,10 +93,6 @@ public: uint16_t EMachine = llvm::ELF::EM_NONE; uint8_t OSABI = 0; - // For SharedKind inputs, the string to use in DT_NEEDED when the library - // has no soname. - std::string DefaultSoName; - // Cache for toString(). Only toString() should use this member. mutable std::string ToStringCache; @@ -283,12 +279,12 @@ template <class ELFT> class SharedFile : public ELFFileBase<ELFT> { typedef typename ELFT::Versym Elf_Versym; std::vector<StringRef> Undefs; - StringRef SoName; const Elf_Shdr *VersymSec = nullptr; const Elf_Shdr *VerdefSec = nullptr; public: - StringRef getSoName() const; + std::string SoName; + const Elf_Shdr *getSection(const Elf_Sym &Sym) const; llvm::ArrayRef<StringRef> getUndefinedSymbols() { return Undefs; } @@ -296,7 +292,7 @@ public: return F->kind() == Base::SharedKind; } - explicit SharedFile(MemoryBufferRef M); + SharedFile(MemoryBufferRef M, StringRef DefaultSoName); void parseSoName(); void parseRest(); @@ -329,7 +325,7 @@ public: InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "", uint64_t OffsetInArchive = 0); -InputFile *createSharedFile(MemoryBufferRef MB); +InputFile *createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName); } // namespace elf } // namespace lld diff --git a/ELF/Options.td b/ELF/Options.td index 4cf14c9011c3..fda675449956 100644 --- a/ELF/Options.td +++ b/ELF/Options.td @@ -25,6 +25,8 @@ def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">; def compress_debug_sections : J<"compress-debug-sections=">, HelpText<"Compress DWARF debug sections">; +def defsym: J<"defsym=">, HelpText<"Define a symbol alias">; + def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">, HelpText<"Add a directory to the library search path">; diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index a40818d2d301..71fc00ac35e7 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -405,8 +405,10 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS, OutputSection *&Sec = Map[Key]; if (Sec) { if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags)) - error("Section has flags incompatible with others with the same name " + - toString(IS)); + error("incompatible section flags for " + Sec->Name + + "\n>>> " + toString(IS) + ": 0x" + utohexstr(IS->Flags) + + "\n>>> output section " + Sec->Name + ": 0x" + + utohexstr(Sec->Flags)); if (Sec->Type != IS->Type) { if (canMergeToProgbits(Sec->Type) && canMergeToProgbits(IS->Type)) Sec->Type = SHT_PROGBITS; diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp index 42b4fdc26faf..e55b8bf52c10 100644 --- a/ELF/SymbolTable.cpp +++ b/ELF/SymbolTable.cpp @@ -81,7 +81,7 @@ template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) { if (auto *F = dyn_cast<SharedFile<ELFT>>(File)) { // DSOs are uniquified not by filename but by soname. F->parseSoName(); - if (ErrorCount || !SoNames.insert(F->getSoName()).second) + if (ErrorCount || !SoNames.insert(F->SoName).second) return; SharedFiles.push_back(F); F->parseRest(); @@ -168,6 +168,19 @@ template <class ELFT> void SymbolTable<ELFT>::wrap(StringRef Name) { memcpy(Sym->Body.buffer, Wrap->Body.buffer, sizeof(Wrap->Body)); } +// Creates alias for symbol. Used to implement --defsym=ALIAS=SYM. +template <class ELFT> +void SymbolTable<ELFT>::alias(StringRef Alias, StringRef Name) { + SymbolBody *B = find(Name); + if (!B) { + error("-defsym: undefined symbol: " + Name); + return; + } + Symbol *Sym = B->symbol(); + Symbol *AliasSym = addUndefined(Alias); + memcpy(AliasSym->Body.buffer, Sym->Body.buffer, sizeof(AliasSym->Body)); +} + static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { if (VA == STV_DEFAULT) return VB; @@ -548,11 +561,20 @@ template <class ELFT> void SymbolTable<ELFT>::scanUndefinedFlags() { // shared libraries can find them. // Except this, we ignore undefined symbols in DSOs. template <class ELFT> void SymbolTable<ELFT>::scanShlibUndefined() { - for (SharedFile<ELFT> *File : SharedFiles) - for (StringRef U : File->getUndefinedSymbols()) - if (SymbolBody *Sym = find(U)) - if (Sym->isDefined()) - Sym->symbol()->ExportDynamic = true; + for (SharedFile<ELFT> *File : SharedFiles) { + for (StringRef U : File->getUndefinedSymbols()) { + SymbolBody *Sym = find(U); + if (!Sym || !Sym->isDefined()) + continue; + Sym->symbol()->ExportDynamic = true; + + // If -dynamic-list is given, the default version is set to + // VER_NDX_LOCAL, which prevents a symbol to be exported via .dynsym. + // Set to VER_NDX_GLOBAL so the symbol will be handled as if it were + // specified by -dynamic-list. + Sym->symbol()->VersionId = VER_NDX_GLOBAL; + } + } } // Initialize DemangledSyms with a map from demangled symbols to symbol diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h index a5395f5beaa1..1a745f9deea5 100644 --- a/ELF/SymbolTable.h +++ b/ELF/SymbolTable.h @@ -86,6 +86,7 @@ public: 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 86f3162cae29..01caa6daa5ac 100644 --- a/ELF/Symbols.cpp +++ b/ELF/Symbols.cpp @@ -339,8 +339,7 @@ uint8_t Symbol::computeBinding() const { return Binding; if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) return STB_LOCAL; - const SymbolBody *Body = body(); - if (VersionId == VER_NDX_LOCAL && Body->isInCurrentDSO()) + if (VersionId == VER_NDX_LOCAL && body()->isInCurrentDSO()) return STB_LOCAL; if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE) return STB_GLOBAL; diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index 7009d3d34f66..e1f81940bb59 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -1027,7 +1027,7 @@ template <class ELFT> void DynamicSection<ELFT>::addEntries() { In<ELFT>::DynStrTab->addString(Config->RPath)}); for (SharedFile<ELFT> *F : Symtab<ELFT>::X->getSharedFiles()) if (F->isNeeded()) - add({DT_NEEDED, In<ELFT>::DynStrTab->addString(F->getSoName())}); + add({DT_NEEDED, In<ELFT>::DynStrTab->addString(F->SoName)}); if (!Config->SoName.empty()) add({DT_SONAME, In<ELFT>::DynStrTab->addString(Config->SoName)}); @@ -2042,7 +2042,7 @@ void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) { // to create one by adding it to our needed list and creating a dynstr entry // for the soname. if (File->VerdefMap.empty()) - Needed.push_back({File, In<ELFT>::DynStrTab->addString(File->getSoName())}); + Needed.push_back({File, In<ELFT>::DynStrTab->addString(File->SoName)}); typename SharedFile<ELFT>::NeededVer &NV = File->VerdefMap[Ver]; // If we don't already know that we need an Elf_Vernaux for this Elf_Verdef, // prepare to create one by allocating a version identifier and creating a diff --git a/ELF/Target.cpp b/ELF/Target.cpp index 664dcd1ed44e..7bc29e3d3de2 100644 --- a/ELF/Target.cpp +++ b/ELF/Target.cpp @@ -223,8 +223,6 @@ public: bool isPicRel(uint32_t Type) const override; uint32_t getDynRel(uint32_t Type) const override; int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; - bool isTlsLocalDynamicRel(uint32_t Type) const override; - bool isTlsInitialExecRel(uint32_t Type) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writePltHeader(uint8_t *Buf) const override; @@ -245,7 +243,6 @@ public: int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; bool isPicRel(uint32_t Type) const override; uint32_t getDynRel(uint32_t Type) const override; - bool isTlsLocalDynamicRel(uint32_t Type) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, @@ -532,6 +529,7 @@ int64_t X86TargetInfo::getImplicitAddend(const uint8_t *Buf, case R_386_GOTPC: case R_386_PC32: case R_386_PLT32: + case R_386_TLS_LDO_32: case R_386_TLS_LE: return SignExtend64<32>(read32le(Buf)); } @@ -2065,14 +2063,6 @@ int64_t ARMTargetInfo::getImplicitAddend(const uint8_t *Buf, } } -bool ARMTargetInfo::isTlsLocalDynamicRel(uint32_t Type) const { - return Type == R_ARM_TLS_LDO32 || Type == R_ARM_TLS_LDM32; -} - -bool ARMTargetInfo::isTlsInitialExecRel(uint32_t Type) const { - return Type == R_ARM_TLS_IE32; -} - template <class ELFT> MipsTargetInfo<ELFT>::MipsTargetInfo() { GotPltHeaderEntriesNum = 2; DefaultMaxPageSize = 65536; @@ -2165,11 +2155,6 @@ uint32_t MipsTargetInfo<ELFT>::getDynRel(uint32_t Type) const { } template <class ELFT> -bool MipsTargetInfo<ELFT>::isTlsLocalDynamicRel(uint32_t Type) const { - return Type == R_MIPS_TLS_LDM; -} - -template <class ELFT> void MipsTargetInfo<ELFT>::writeGotPlt(uint8_t *Buf, const SymbolBody &) const { write32<ELFT::TargetEndianness>(Buf, In<ELFT>::Plt->getVA()); } diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index e8718c258c77..989a55af1675 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -858,11 +858,8 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() { // __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For // static linking the linker is required to optimize away any references to // __tls_get_addr, so it's not defined anywhere. Create a hidden definition - // to avoid the undefined symbol error. As usual special cases are ARM and - // MIPS - the libc for these targets defines __tls_get_addr itself because - // there are no TLS optimizations for these targets. - if (!In<ELFT>::DynSymTab && - (Config->EMachine != EM_MIPS && Config->EMachine != EM_ARM)) + // to avoid the undefined symbol error. + if (!In<ELFT>::DynSymTab) Symtab<ELFT>::X->addIgnored("__tls_get_addr"); // If linker script do layout we do not need to create any standart symbols. diff --git a/test/COFF/Inputs/constant-export.ll b/test/COFF/Inputs/constant-export.ll new file mode 100644 index 000000000000..2b57e8d083fa --- /dev/null +++ b/test/COFF/Inputs/constant-export.ll @@ -0,0 +1,10 @@ +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i686-unknown-windows-msvc18.0.0" + +@__CFConstantStringClassReference = common global [32 x i32] zeroinitializer, align 4 + +!llvm.module.flags = !{!0} + +!0 = !{i32 6, !"Linker Options", !1} +!1 = !{!2} +!2 = !{!" -export:___CFConstantStringClassReference,CONSTANT"} diff --git a/test/COFF/Inputs/msvclto-order-a.ll b/test/COFF/Inputs/msvclto-order-a.ll new file mode 100644 index 000000000000..804e201ff99a --- /dev/null +++ b/test/COFF/Inputs/msvclto-order-a.ll @@ -0,0 +1,7 @@ +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc" + +define void @foo() { + ret void +} + diff --git a/test/COFF/Inputs/msvclto-order-b.ll b/test/COFF/Inputs/msvclto-order-b.ll new file mode 100644 index 000000000000..57f23898e6aa --- /dev/null +++ b/test/COFF/Inputs/msvclto-order-b.ll @@ -0,0 +1,10 @@ +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc" + +declare void @doesntexist() + +define void @foo() { + call void @doesntexist() + ret void +} + diff --git a/test/COFF/constant-export.test b/test/COFF/constant-export.test new file mode 100644 index 000000000000..18b1f5e30d29 --- /dev/null +++ b/test/COFF/constant-export.test @@ -0,0 +1,9 @@ +# RUN: mkdir -p %t +# RUN: yaml2obj -o %t/constant-export.obj %S/constant-export.yaml +# RUN: lld-link /machine:x86 /dll /entry:__CFConstantStringClassReference -out:%t/constant-export.dll %t/constant-export.obj +# RUN: llvm-readobj -coff-exports %t/constant-export.lib | FileCheck %s + +# CHECK: Type: const +# CHECK: Name type: noprefix +# CHECK: Symbol: __imp____CFConstantStringClassReference + diff --git a/test/COFF/constant-export.yaml b/test/COFF/constant-export.yaml new file mode 100644 index 000000000000..7e44bb70c9d7 --- /dev/null +++ b/test/COFF/constant-export.yaml @@ -0,0 +1,83 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '' + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: .bss + Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 20202D6578706F72743A5F5F5F4346436F6E7374616E74537472696E67436C6173735265666572656E63652C434F4E5354414E54 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 1 + - Name: .data + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 2 + - Name: .bss + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 3 + - Name: .drectve + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 52 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 1983959296 + Number: 4 + - Name: '@feat.00' + Value: 1 + SectionNumber: -1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: ___CFConstantStringClassReference + Value: 128 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/linkenv.test b/test/COFF/linkenv.test index 5dfb875a7daf..6033094d6dbe 100644 --- a/test/COFF/linkenv.test +++ b/test/COFF/linkenv.test @@ -1,4 +1,4 @@ -# RUN: env LINK=-help lld-link > %t.log -# RUN: FileCheck %s < %t.log +# RUN: env LINK=-help lld-link | FileCheck %s +# RUN: env _LINK_=-help lld-link | FileCheck %s CHECK: OVERVIEW: LLVM Linker diff --git a/test/COFF/msvclto-order.ll b/test/COFF/msvclto-order.ll new file mode 100644 index 000000000000..8991dce4a8d5 --- /dev/null +++ b/test/COFF/msvclto-order.ll @@ -0,0 +1,24 @@ +; RUN: opt -thinlto-bc %s -o %t.obj +; RUN: llc -filetype=obj %S/Inputs/msvclto-order-a.ll -o %T/msvclto-order-a.obj +; RUN: llvm-ar crs %T/msvclto-order-a.lib %T/msvclto-order-a.obj +; RUN: llc -filetype=obj %S/Inputs/msvclto-order-b.ll -o %T/msvclto-order-b.obj +; RUN: llvm-ar crs %T/msvclto-order-b.lib %T/msvclto-order-b.obj +; RUN: lld-link /verbose /msvclto /out:%t.exe /entry:main %t.obj \ +; RUN: %T/msvclto-order-a.lib %T/msvclto-order-b.lib > %t.log || true +; RUN: FileCheck %s < %t.log + +; CHECK: : link.exe +; CHECK-NOT: .lib{{$}} +; CHECK: lld-msvclto-order-a{{.*}}.obj +; CHECK-NOT: lld-msvclto-order-b{{.*}}.obj +; CHECK: .lib{{$}} + +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc" + +declare void @foo() + +define i32 @main() { + call void @foo() + ret i32 0 +} diff --git a/test/ELF/Inputs/progname-ver.s b/test/ELF/Inputs/progname-ver.s new file mode 100644 index 000000000000..06fc294a0980 --- /dev/null +++ b/test/ELF/Inputs/progname-ver.s @@ -0,0 +1,3 @@ +.global bar +bar: +.quad __progname@GOT diff --git a/test/ELF/Inputs/progname-ver.so b/test/ELF/Inputs/progname-ver.so Binary files differdeleted file mode 100755 index e6bb3228f6c6..000000000000 --- a/test/ELF/Inputs/progname-ver.so +++ /dev/null diff --git a/test/ELF/defsym.s b/test/ELF/defsym.s new file mode 100644 index 000000000000..cafc5142d1a9 --- /dev/null +++ b/test/ELF/defsym.s @@ -0,0 +1,44 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld -o %t %t.o --defsym=foo2=foo1 +# RUN: llvm-readobj -t -s %t | FileCheck %s +# RUN: llvm-objdump -d -print-imm-hex %t | FileCheck %s --check-prefix=USE + +## In compare with GNU linkers, symbol defined with --defsym does +## not get aliased name in symbol table: +# CHECK: Symbol { +# CHECK: Name: foo1 +# CHECK-NEXT: Value: 0x123 +# CHECK-NEXT: Size: +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: +# CHECK-NEXT: Other: +# CHECK-NEXT: Section: Absolute +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: foo1 +# CHECK-NEXT: Value: 0x123 +# CHECK-NEXT: Size: +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: +# CHECK-NEXT: Other: +# CHECK-NEXT: Section: Absolute +# CHECK-NEXT: } + +## Check we can use foo2 and it that it is an alias for foo1. +# USE: Disassembly of section .text: +# USE-NEXT: _start: +# USE-NEXT: movl $0x123, %edx + +# RUN: not ld.lld -o %t %t.o --defsym=foo2=1 2>&1 | FileCheck %s -check-prefix=ERR1 +# ERR1: error: --defsym: symbol name expected, but got 1 + +# RUN: not ld.lld -o %t %t.o --defsym=foo2=und 2>&1 | FileCheck %s -check-prefix=ERR2 +# ERR2: error: -defsym: undefined symbol: und + +.globl foo1 + foo1 = 0x123 + +.global _start +_start: + movl $foo2, %edx diff --git a/test/ELF/driver-access.test b/test/ELF/driver-access.test new file mode 100644 index 000000000000..3c976a66d0f4 --- /dev/null +++ b/test/ELF/driver-access.test @@ -0,0 +1,14 @@ +# REQUIRES: x86, shell +# Make sure that LLD works even if the current directory is not writable. + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t.exe + +# RUN: mkdir -p %t.dir +# RUN: chmod 100 %t.dir +# RUN: cd %t.dir +# RUN: ld.lld %t.o -o %t.exe + +.globl _start +_start: + nop diff --git a/test/ELF/icf-i386.s b/test/ELF/icf-i386.s new file mode 100644 index 000000000000..292883e16fe5 --- /dev/null +++ b/test/ELF/icf-i386.s @@ -0,0 +1,25 @@ +# REQUIRES: x86 +# This test is to make sure that we can handle implicit addends properly. + +# RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %s -o %t +# RUN: ld.lld %t -o %t2 --icf=all --verbose | FileCheck %s + +# CHECK: selected .text.f1 +# CHECK: removed .text.f2 +# CHECK-NOT: removed .text.f3 + +.globl _start, f1, f2, f3 +_start: + ret + +.section .text.f1, "ax" +f1: + movl $42, 4(%edi) + +.section .text.f2, "ax" +f2: + movl $42, 4(%edi) + +.section .text.f3, "ax" +f3: + movl $42, 8(%edi) diff --git a/test/ELF/incompatible-section-flags.s b/test/ELF/incompatible-section-flags.s index efca31bb9a80..25d99945e009 100644 --- a/test/ELF/incompatible-section-flags.s +++ b/test/ELF/incompatible-section-flags.s @@ -1,8 +1,13 @@ // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: not ld.lld -shared %t.o -o %t 2>&1 | FileCheck %s -// CHECK: error: Section has flags incompatible with others with the same name {{.*}}incompatible-section-flags.s.tmp.o:(.foo) -// CHECK: error: Section has flags incompatible with others with the same name {{.*}}incompatible-section-flags.s.tmp.o:(.bar) +// CHECK: error: incompatible section flags for .foo +// CHECK-NEXT: >>> {{.*}}incompatible-section-flags.s.tmp.o:(.foo): 0x3 +// CHECK-NEXT: >>> output section .foo: 0x403 + +// CHECK: error: incompatible section flags for .bar +// CHECK-NEXT: >>> {{.*}}incompatible-section-flags.s.tmp.o:(.bar): 0x403 +// CHECK-NEXT: >>> output section .bar: 0x3 .section .foo, "awT", @progbits, unique, 1 .quad 0 diff --git a/test/ELF/linkerscript/sections.s b/test/ELF/linkerscript/sections.s index 1a2323c001dc..b7d396fdec9f 100644 --- a/test/ELF/linkerscript/sections.s +++ b/test/ELF/linkerscript/sections.s @@ -85,13 +85,13 @@ # RUN: FileCheck -check-prefix=SEC-MULTI %s # Idx Name Size -# SEC-MULTI: 1 .text 0000000e {{[0-9a-f]*}} TEXT DATA -# SEC-MULTI: 2 .data 00000023 {{[0-9a-f]*}} DATA -# SEC-MULTI: 3 .bss 00000002 {{[0-9a-f]*}} BSS -# SEC-MULTI: 4 .comment 00000008 {{[0-9a-f]*}} -# SEC-MULTI: 5 .symtab 00000030 {{[0-9a-f]*}} -# SEC-MULTI: 6 .shstrtab 00000035 {{[0-9a-f]*}} -# SEC-MULTI: 7 .strtab 00000008 {{[0-9a-f]*}} +# SEC-MULTI: 1 .text 0000000e {{[0-9a-f]*}} TEXT DATA +# SEC-MULTI-NEXT: .data 00000023 {{[0-9a-f]*}} DATA +# SEC-MULTI-NEXT: .bss 00000002 {{[0-9a-f]*}} BSS +# SEC-MULTI-NEXT: .comment 00000008 {{[0-9a-f]*}} +# SEC-MULTI-NEXT: .symtab 00000030 {{[0-9a-f]*}} +# SEC-MULTI-NEXT: .shstrtab 00000035 {{[0-9a-f]*}} +# SEC-MULTI-NEXT: .strtab 00000008 {{[0-9a-f]*}} # Input section pattern contains additional semicolon. # Case found in linux kernel script. Check we are able to parse it. diff --git a/test/ELF/lto/asmundef.ll b/test/ELF/lto/asmundef.ll index 1c87cd01fad8..d03a5e387213 100644 --- a/test/ELF/lto/asmundef.ll +++ b/test/ELF/lto/asmundef.ll @@ -20,6 +20,5 @@ define void @_start() { ret void } -; CHECK: @llvm.compiler.used = appending global [1 x i8*] [i8* bitcast (void ()* @foo to i8*)], section "llvm.metadata" -; CHECK: define internal void @foo +; CHECK: define void @foo diff --git a/test/ELF/progname.s b/test/ELF/progname.s index 10cbf177c69b..6d91823c9481 100644 --- a/test/ELF/progname.s +++ b/test/ELF/progname.s @@ -1,31 +1,23 @@ -// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: echo .global __progname > %t2.s -// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %t2.s -o %t2.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t2.s -o %t2.o // RUN: ld.lld -shared %t2.o -o %t2.so // RUN: ld.lld -o %t %t.o %t2.so // RUN: llvm-readobj -dyn-symbols %t | FileCheck %s +// RUN: echo "VER_1 { global: bar; };" > %t.script +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux \ +// RUN: %p/Inputs/progname-ver.s -o %t-ver.o +// RUN: ld.lld -shared -o %t.so -version-script %t.script %t-ver.o +// RUN: ld.lld -o %t %t.o %t.so +// RUN: llvm-readobj -dyn-symbols %t | FileCheck %s -// Inputs/progname-ver.so consists of the assembly file -// -// .global bar -// bar: -// .quad __progname -// -// linked into a library with the version script -// -// VER_1 { -// global: -// bar; -// }; -// -// We should create it with lld itself once we it supports that. - -// RUN: ld.lld -o %t %t.o %p/Inputs/progname-ver.so +// RUN: echo "{ _start; };" > %t.dynlist +// RUN: ld.lld -dynamic-list %t.dynlist -o %t %t.o %t.so // RUN: llvm-readobj -dyn-symbols %t | FileCheck %s // CHECK: Name: __progname@ -// CHECK-NEXT: Value: 0x11000 +// CHECK-NEXT: Value: 0x201000 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Global (0x1) // CHECK-NEXT: Type: None (0x0) diff --git a/test/ELF/tls-dynamic-i686.s b/test/ELF/tls-dynamic-i686.s index 6732483e9e1d..ac88e6eaed31 100644 --- a/test/ELF/tls-dynamic-i686.s +++ b/test/ELF/tls-dynamic-i686.s @@ -25,7 +25,7 @@ tls1: .align 4 tls2: .long 0 - .size tls2, 4 + .size tls2, 8 .section .text .globl _start @@ -42,7 +42,7 @@ leal tls2@dtpoff(%eax),%edx leal tls2@tlsldm(%ebx),%eax call __tls_get_addr@plt -leal tls2@dtpoff(%eax),%edx +leal tls2@dtpoff+4(%eax),%edx movl %gs:0,%eax addl tls0@gotntpoff(%ebx),%eax @@ -91,7 +91,7 @@ addl tls1@gotntpoff(%ebx),%eax // DIS-NEXT: 1023: 8d 90 08 00 00 00 leal 8(%eax), %edx // DIS-NEXT: 1029: 8d 83 f0 ff ff ff leal -16(%ebx), %eax // DIS-NEXT: 102f: e8 3c 00 00 00 calll 60 -// DIS-NEXT: 1034: 8d 90 08 00 00 00 leal 8(%eax), %edx +// DIS-NEXT: 1034: 8d 90 0c 00 00 00 leal 12(%eax), %edx // Initial exec model: // DIS-NEXT: 103a: 65 a1 00 00 00 00 movl %gs:0, %eax // DIS-NEXT: 1040: 03 83 f8 ff ff ff addl -8(%ebx), %eax |