aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-04-26 19:24:42 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-04-26 19:24:42 +0000
commite06a19b85dfce9ea18be97247d4ca315963edc5c (patch)
treeea315682e394f1c39a30049e4497e1a723f18e3c
parentbe08ec96063be8c1a1a8621eccd05a4ebeecfb42 (diff)
downloadsrc-e06a19b85dfce9ea18be97247d4ca315963edc5c.tar.gz
src-e06a19b85dfce9ea18be97247d4ca315963edc5c.zip
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
-rw-r--r--COFF/Chunks.cpp44
-rw-r--r--COFF/Config.h1
-rw-r--r--COFF/Driver.cpp17
-rw-r--r--COFF/Driver.h2
-rw-r--r--COFF/DriverUtils.cpp27
-rw-r--r--COFF/InputFiles.h3
-rw-r--r--COFF/Librarian.cpp20
-rw-r--r--COFF/ModuleDef.cpp7
-rw-r--r--COFF/SymbolTable.h5
-rw-r--r--ELF/Driver.cpp75
-rw-r--r--ELF/Filesystem.cpp17
-rw-r--r--ELF/Filesystem.h2
-rw-r--r--ELF/InputFiles.cpp42
-rw-r--r--ELF/InputFiles.h12
-rw-r--r--ELF/Options.td2
-rw-r--r--ELF/OutputSections.cpp6
-rw-r--r--ELF/SymbolTable.cpp34
-rw-r--r--ELF/SymbolTable.h1
-rw-r--r--ELF/Symbols.cpp3
-rw-r--r--ELF/SyntheticSections.cpp4
-rw-r--r--ELF/Target.cpp17
-rw-r--r--ELF/Writer.cpp7
-rw-r--r--test/COFF/Inputs/constant-export.ll10
-rw-r--r--test/COFF/Inputs/msvclto-order-a.ll7
-rw-r--r--test/COFF/Inputs/msvclto-order-b.ll10
-rw-r--r--test/COFF/constant-export.test9
-rw-r--r--test/COFF/constant-export.yaml83
-rw-r--r--test/COFF/linkenv.test4
-rw-r--r--test/COFF/msvclto-order.ll24
-rw-r--r--test/ELF/Inputs/progname-ver.s3
-rwxr-xr-xtest/ELF/Inputs/progname-ver.sobin1680 -> 0 bytes
-rw-r--r--test/ELF/defsym.s44
-rw-r--r--test/ELF/driver-access.test14
-rw-r--r--test/ELF/icf-i386.s25
-rw-r--r--test/ELF/incompatible-section-flags.s9
-rw-r--r--test/ELF/linkerscript/sections.s14
-rw-r--r--test/ELF/lto/asmundef.ll3
-rw-r--r--test/ELF/progname.s30
-rw-r--r--test/ELF/tls-dynamic-i686.s6
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
deleted file mode 100755
index e6bb3228f6c6..000000000000
--- a/test/ELF/Inputs/progname-ver.so
+++ /dev/null
Binary files differ
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