aboutsummaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rw-r--r--contrib/llvm-project/lld/COFF/CMakeLists.txt2
-rw-r--r--contrib/llvm-project/lld/COFF/Config.h4
-rw-r--r--contrib/llvm-project/lld/COFF/DLL.cpp4
-rw-r--r--contrib/llvm-project/lld/COFF/DebugTypes.cpp27
-rw-r--r--contrib/llvm-project/lld/COFF/Driver.cpp235
-rw-r--r--contrib/llvm-project/lld/COFF/Driver.h20
-rw-r--r--contrib/llvm-project/lld/COFF/DriverUtils.cpp59
-rw-r--r--contrib/llvm-project/lld/COFF/ICF.cpp8
-rw-r--r--contrib/llvm-project/lld/COFF/InputFiles.cpp148
-rw-r--r--contrib/llvm-project/lld/COFF/InputFiles.h57
-rw-r--r--contrib/llvm-project/lld/COFF/LTO.cpp17
-rw-r--r--contrib/llvm-project/lld/COFF/MapFile.cpp15
-rw-r--r--contrib/llvm-project/lld/COFF/MinGW.cpp14
-rw-r--r--contrib/llvm-project/lld/COFF/Options.td39
-rw-r--r--contrib/llvm-project/lld/COFF/PDB.cpp59
-rw-r--r--contrib/llvm-project/lld/COFF/PDB.h9
-rw-r--r--contrib/llvm-project/lld/COFF/SymbolTable.cpp356
-rw-r--r--contrib/llvm-project/lld/COFF/SymbolTable.h21
-rw-r--r--contrib/llvm-project/lld/COFF/Symbols.cpp31
-rw-r--r--contrib/llvm-project/lld/COFF/Symbols.h41
-rw-r--r--contrib/llvm-project/lld/COFF/Writer.cpp47
-rw-r--r--contrib/llvm-project/lld/Common/CMakeLists.txt2
-rw-r--r--contrib/llvm-project/lld/Common/DWARF.cpp103
-rw-r--r--contrib/llvm-project/lld/Common/ErrorHandler.cpp139
-rw-r--r--contrib/llvm-project/lld/Common/Strings.cpp34
-rw-r--r--contrib/llvm-project/lld/Common/TargetOptionsCommandFlags.cpp4
-rw-r--r--contrib/llvm-project/lld/ELF/AArch64ErrataFix.cpp72
-rw-r--r--contrib/llvm-project/lld/ELF/ARMErrataFix.cpp528
-rw-r--r--contrib/llvm-project/lld/ELF/ARMErrataFix.h51
-rw-r--r--contrib/llvm-project/lld/ELF/Arch/AArch64.cpp108
-rw-r--r--contrib/llvm-project/lld/ELF/Arch/AMDGPU.cpp10
-rw-r--r--contrib/llvm-project/lld/ELF/Arch/ARM.cpp10
-rw-r--r--contrib/llvm-project/lld/ELF/Arch/AVR.cpp10
-rw-r--r--contrib/llvm-project/lld/ELF/Arch/Hexagon.cpp59
-rw-r--r--contrib/llvm-project/lld/ELF/Arch/MSP430.cpp10
-rw-r--r--contrib/llvm-project/lld/ELF/Arch/Mips.cpp236
-rw-r--r--contrib/llvm-project/lld/ELF/Arch/MipsArchTree.cpp74
-rw-r--r--contrib/llvm-project/lld/ELF/Arch/PPC.cpp12
-rw-r--r--contrib/llvm-project/lld/ELF/Arch/PPC64.cpp26
-rw-r--r--contrib/llvm-project/lld/ELF/Arch/RISCV.cpp10
-rw-r--r--contrib/llvm-project/lld/ELF/Arch/SPARCV9.cpp10
-rw-r--r--contrib/llvm-project/lld/ELF/Arch/X86.cpp10
-rw-r--r--contrib/llvm-project/lld/ELF/Arch/X86_64.cpp10
-rw-r--r--contrib/llvm-project/lld/ELF/CMakeLists.txt1
-rw-r--r--contrib/llvm-project/lld/ELF/CallGraphSort.cpp126
-rw-r--r--contrib/llvm-project/lld/ELF/Config.h18
-rw-r--r--contrib/llvm-project/lld/ELF/DWARF.cpp26
-rw-r--r--contrib/llvm-project/lld/ELF/DWARF.h33
-rw-r--r--contrib/llvm-project/lld/ELF/Driver.cpp147
-rw-r--r--contrib/llvm-project/lld/ELF/DriverUtils.cpp33
-rw-r--r--contrib/llvm-project/lld/ELF/EhFrame.cpp12
-rw-r--r--contrib/llvm-project/lld/ELF/ICF.cpp43
-rw-r--r--contrib/llvm-project/lld/ELF/InputFiles.cpp227
-rw-r--r--contrib/llvm-project/lld/ELF/InputFiles.h20
-rw-r--r--contrib/llvm-project/lld/ELF/InputSection.cpp59
-rw-r--r--contrib/llvm-project/lld/ELF/InputSection.h21
-rw-r--r--contrib/llvm-project/lld/ELF/LTO.cpp19
-rw-r--r--contrib/llvm-project/lld/ELF/LinkerScript.cpp415
-rw-r--r--contrib/llvm-project/lld/ELF/LinkerScript.h15
-rw-r--r--contrib/llvm-project/lld/ELF/MapFile.cpp18
-rw-r--r--contrib/llvm-project/lld/ELF/MarkLive.cpp33
-rw-r--r--contrib/llvm-project/lld/ELF/Options.td35
-rw-r--r--contrib/llvm-project/lld/ELF/OutputSections.cpp114
-rw-r--r--contrib/llvm-project/lld/ELF/OutputSections.h4
-rw-r--r--contrib/llvm-project/lld/ELF/Relocations.cpp299
-rw-r--r--contrib/llvm-project/lld/ELF/Relocations.h1
-rw-r--r--contrib/llvm-project/lld/ELF/ScriptLexer.cpp7
-rw-r--r--contrib/llvm-project/lld/ELF/ScriptParser.cpp51
-rw-r--r--contrib/llvm-project/lld/ELF/SymbolTable.cpp93
-rw-r--r--contrib/llvm-project/lld/ELF/SymbolTable.h2
-rw-r--r--contrib/llvm-project/lld/ELF/Symbols.cpp65
-rw-r--r--contrib/llvm-project/lld/ELF/Symbols.h96
-rw-r--r--contrib/llvm-project/lld/ELF/SyntheticSections.cpp493
-rw-r--r--contrib/llvm-project/lld/ELF/SyntheticSections.h24
-rw-r--r--contrib/llvm-project/lld/ELF/Target.cpp20
-rw-r--r--contrib/llvm-project/lld/ELF/Writer.cpp361
-rw-r--r--contrib/llvm-project/lld/ELF/Writer.h8
-rw-r--r--contrib/llvm-project/lld/docs/ReleaseNotes.rst233
-rw-r--r--contrib/llvm-project/lld/docs/WebAssembly.rst2
-rw-r--r--contrib/llvm-project/lld/docs/conf.py4
-rw-r--r--contrib/llvm-project/lld/docs/ld.lld.1101
-rw-r--r--contrib/llvm-project/lld/include/lld/Common/DWARF.h47
-rw-r--r--contrib/llvm-project/lld/include/lld/Common/ErrorHandler.h7
-rw-r--r--contrib/llvm-project/lld/include/lld/Common/LLVM.h1
-rw-r--r--contrib/llvm-project/lld/include/lld/Common/Strings.h5
-rw-r--r--contrib/llvm-project/lld/include/lld/Common/TargetOptionsCommandFlags.h1
-rw-r--r--contrib/llvm-project/lld/include/lld/Core/File.h1
-rw-r--r--contrib/llvm-project/lld/include/lld/ReaderWriter/MachOLinkingContext.h2
-rw-r--r--contrib/llvm-project/lld/lib/Driver/DarwinLdDriver.cpp10
-rw-r--r--contrib/llvm-project/lld/lib/ReaderWriter/FileArchive.cpp2
-rw-r--r--contrib/llvm-project/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp50
-rw-r--r--contrib/llvm-project/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp2
-rw-r--r--contrib/llvm-project/lld/lib/ReaderWriter/MachO/DebugInfo.h1
-rw-r--r--contrib/llvm-project/lld/lib/ReaderWriter/MachO/GOTPass.cpp2
-rw-r--r--contrib/llvm-project/lld/lib/ReaderWriter/MachO/LayoutPass.cpp2
-rw-r--r--contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp10
-rw-r--r--contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp4
-rw-r--r--contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp14
-rw-r--r--contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp20
-rw-r--r--contrib/llvm-project/lld/lib/ReaderWriter/MachO/ObjCPass.cpp2
-rw-r--r--contrib/llvm-project/lld/lib/ReaderWriter/MachO/ShimPass.cpp2
-rw-r--r--contrib/llvm-project/lld/lib/ReaderWriter/MachO/TLVPass.cpp2
-rw-r--r--contrib/llvm-project/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp2
-rw-r--r--contrib/llvm-project/lld/tools/lld/lld.cpp1
104 files changed, 3941 insertions, 2269 deletions
diff --git a/contrib/llvm-project/lld/COFF/CMakeLists.txt b/contrib/llvm-project/lld/COFF/CMakeLists.txt
index c7ef7c47fea1..7c5e8b79b7fe 100644
--- a/contrib/llvm-project/lld/COFF/CMakeLists.txt
+++ b/contrib/llvm-project/lld/COFF/CMakeLists.txt
@@ -28,8 +28,10 @@ add_lld_library(lldCOFF
BinaryFormat
Core
DebugInfoCodeView
+ DebugInfoDWARF
DebugInfoMSF
DebugInfoPDB
+ Demangle
LibDriver
LTO
MC
diff --git a/contrib/llvm-project/lld/COFF/Config.h b/contrib/llvm-project/lld/COFF/Config.h
index 4b62cd05f4fc..309e1fbf99e3 100644
--- a/contrib/llvm-project/lld/COFF/Config.h
+++ b/contrib/llvm-project/lld/COFF/Config.h
@@ -122,6 +122,7 @@ struct Configuration {
bool dll = false;
StringRef implib;
std::vector<Export> exports;
+ bool hadExplicitExports;
std::set<std::string> delayLoads;
std::map<std::string, int> dllOrder;
Symbol *delayLoadHelper = nullptr;
@@ -189,6 +190,9 @@ struct Configuration {
// Used for /thinlto-object-suffix-replace:
std::pair<llvm::StringRef, llvm::StringRef> thinLTOObjectSuffixReplace;
+ // Used for /lto-obj-path:
+ llvm::StringRef ltoObjPath;
+
uint64_t align = 4096;
uint64_t imageBase = -1;
uint64_t fileAlign = 512;
diff --git a/contrib/llvm-project/lld/COFF/DLL.cpp b/contrib/llvm-project/lld/COFF/DLL.cpp
index 40d1f463aa3f..39d9fbab63d5 100644
--- a/contrib/llvm-project/lld/COFF/DLL.cpp
+++ b/contrib/llvm-project/lld/COFF/DLL.cpp
@@ -135,7 +135,7 @@ private:
static std::vector<std::vector<DefinedImportData *>>
binImports(const std::vector<DefinedImportData *> &imports) {
// Group DLL-imported symbols by DLL name because that's how
- // symbols are layed out in the import descriptor table.
+ // symbols are laid out in the import descriptor table.
auto less = [](const std::string &a, const std::string &b) {
return config->dllOrder[a] < config->dllOrder[b];
};
@@ -188,7 +188,7 @@ public:
// Initial contents for delay-loaded functions.
// This code calls __delayLoadHelper2 function to resolve a symbol
-// and then overwrites its jump table slot with the result
+// which then overwrites its jump table slot with the result
// for subsequent function calls.
static const uint8_t thunkX64[] = {
0x48, 0x8D, 0x05, 0, 0, 0, 0, // lea rax, [__imp_<FUNCNAME>]
diff --git a/contrib/llvm-project/lld/COFF/DebugTypes.cpp b/contrib/llvm-project/lld/COFF/DebugTypes.cpp
index 78c1c78b408d..6c7d70ee8dcb 100644
--- a/contrib/llvm-project/lld/COFF/DebugTypes.cpp
+++ b/contrib/llvm-project/lld/COFF/DebugTypes.cpp
@@ -17,11 +17,12 @@
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/Support/Path.h"
-using namespace lld;
-using namespace lld::coff;
using namespace llvm;
using namespace llvm::codeview;
+namespace lld {
+namespace coff {
+
namespace {
// The TypeServerSource class represents a PDB type server, a file referenced by
// OBJ files compiled with MSVC /Zi. A single PDB can be shared by several OBJ
@@ -96,27 +97,25 @@ TpiSource::TpiSource(TpiKind k, const ObjFile *f) : kind(k), file(f) {
GC.push_back(std::unique_ptr<TpiSource>(this));
}
-TpiSource *lld::coff::makeTpiSource(const ObjFile *f) {
+TpiSource *makeTpiSource(const ObjFile *f) {
return new TpiSource(TpiSource::Regular, f);
}
-TpiSource *lld::coff::makeUseTypeServerSource(const ObjFile *f,
+TpiSource *makeUseTypeServerSource(const ObjFile *f,
const TypeServer2Record *ts) {
TypeServerSource::enqueue(f, *ts);
return new UseTypeServerSource(f, ts);
}
-TpiSource *lld::coff::makePrecompSource(const ObjFile *f) {
+TpiSource *makePrecompSource(const ObjFile *f) {
return new PrecompSource(f);
}
-TpiSource *lld::coff::makeUsePrecompSource(const ObjFile *f,
+TpiSource *makeUsePrecompSource(const ObjFile *f,
const PrecompRecord *precomp) {
return new UsePrecompSource(f, precomp);
}
-namespace lld {
-namespace coff {
template <>
const PrecompRecord &retrieveDependencyInfo(const TpiSource *source) {
assert(source->kind == TpiSource::UsingPCH);
@@ -128,8 +127,6 @@ const TypeServer2Record &retrieveDependencyInfo(const TpiSource *source) {
assert(source->kind == TpiSource::UsingPDB);
return ((const UseTypeServerSource *)source)->typeServerDependency;
}
-} // namespace coff
-} // namespace lld
std::map<std::string, std::pair<std::string, TypeServerSource *>>
TypeServerSource::instances;
@@ -210,8 +207,7 @@ TypeServerSource::findFromFile(const ObjFile *dependentFile) {
// FIXME: Temporary interface until PDBLinker::maybeMergeTypeServerPDB() is
// moved here.
-Expected<llvm::pdb::NativeSession *>
-lld::coff::findTypeServerSource(const ObjFile *f) {
+Expected<llvm::pdb::NativeSession *> findTypeServerSource(const ObjFile *f) {
Expected<TypeServerSource *> ts = TypeServerSource::findFromFile(f);
if (!ts)
return ts.takeError();
@@ -231,7 +227,7 @@ void TypeServerSource::enqueue(const ObjFile *dependentFile,
if (!it.second)
return; // another OBJ already scheduled this PDB for load
- driver->enqueuePath(*p, false);
+ driver->enqueuePath(*p, false, false);
}
// Create an instance of TypeServerSource or an error string if the PDB couldn't
@@ -239,7 +235,7 @@ void TypeServerSource::enqueue(const ObjFile *dependentFile,
// will be merged in. NOTE - a PDB load failure is not a link error: some
// debug info will simply be missing from the final PDB - that is the default
// accepted behavior.
-void lld::coff::loadTypeServerSource(llvm::MemoryBufferRef m) {
+void loadTypeServerSource(llvm::MemoryBufferRef m) {
std::string path = normalizePdbPath(m.getBufferIdentifier());
Expected<TypeServerSource *> ts = TypeServerSource::getInstance(m);
@@ -266,3 +262,6 @@ Expected<TypeServerSource *> TypeServerSource::getInstance(MemoryBufferRef m) {
return info.takeError();
return new TypeServerSource(m, session.release());
}
+
+} // namespace coff
+} // namespace lld
diff --git a/contrib/llvm-project/lld/COFF/Driver.cpp b/contrib/llvm-project/lld/COFF/Driver.cpp
index 15d6fb5121a1..30967a39b4ca 100644
--- a/contrib/llvm-project/lld/COFF/Driver.cpp
+++ b/contrib/llvm-project/lld/COFF/Driver.cpp
@@ -27,6 +27,7 @@
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/LTO/LTO.h"
#include "llvm/Object/ArchiveWriter.h"
#include "llvm/Object/COFFImportFile.h"
#include "llvm/Object/COFFModuleDefinition.h"
@@ -63,16 +64,16 @@ LinkerDriver *driver;
bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &diag) {
errorHandler().logName = args::getFilenameWithoutExe(args[0]);
errorHandler().errorOS = &diag;
- errorHandler().colorDiagnostics = diag.has_colors();
errorHandler().errorLimitExceededMsg =
"too many errors emitted, stopping now"
" (use /errorlimit:0 to see all errors)";
errorHandler().exitEarly = canExitEarly;
- config = make<Configuration>();
+ enableColors(diag.has_colors());
+ config = make<Configuration>();
symtab = make<SymbolTable>();
-
driver = make<LinkerDriver>();
+
driver->link(args);
// Call exit() if we can to avoid calling destructors.
@@ -170,7 +171,7 @@ MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> mb) {
}
void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
- bool wholeArchive) {
+ bool wholeArchive, bool lazy) {
StringRef filename = mb->getBufferIdentifier();
MemoryBufferRef mbref = takeBuffer(std::move(mb));
@@ -188,18 +189,25 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
Archive *archive = file.get();
make<std::unique_ptr<Archive>>(std::move(file)); // take ownership
+ int memberIndex = 0;
for (MemoryBufferRef m : getArchiveMembers(archive))
- addArchiveBuffer(m, "<whole-archive>", filename, 0);
+ addArchiveBuffer(m, "<whole-archive>", filename, memberIndex++);
return;
}
symtab->addFile(make<ArchiveFile>(mbref));
break;
case file_magic::bitcode:
- symtab->addFile(make<BitcodeFile>(mbref, "", 0));
+ if (lazy)
+ symtab->addFile(make<LazyObjFile>(mbref));
+ else
+ symtab->addFile(make<BitcodeFile>(mbref, "", 0));
break;
case file_magic::coff_object:
case file_magic::coff_import_library:
- symtab->addFile(make<ObjFile>(mbref));
+ if (lazy)
+ symtab->addFile(make<LazyObjFile>(mbref));
+ else
+ symtab->addFile(make<ObjFile>(mbref));
break;
case file_magic::pdb:
loadTypeServerSource(mbref);
@@ -220,7 +228,7 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
}
}
-void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive) {
+void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {
auto future =
std::make_shared<std::future<MBErrPair>>(createFutureForFile(path));
std::string pathStr = path;
@@ -240,7 +248,7 @@ void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive) {
else
error(msg + "; did you mean '" + nearest + "'");
} else
- driver->addBuffer(std::move(mbOrErr.first), wholeArchive);
+ driver->addBuffer(std::move(mbOrErr.first), wholeArchive, lazy);
});
}
@@ -303,9 +311,10 @@ void LinkerDriver::enqueueArchiveMember(const Archive::Child &c,
auto mbOrErr = future->get();
if (mbOrErr.second)
reportBufferError(errorCodeToError(mbOrErr.second), childName);
+ // Pass empty string as archive name so that the original filename is
+ // used as the buffer identifier.
driver->addArchiveBuffer(takeBuffer(std::move(mbOrErr.first)),
- toCOFFString(sym), parentName,
- /*OffsetInArchive=*/0);
+ toCOFFString(sym), "", /*OffsetInArchive=*/0);
});
}
@@ -359,7 +368,7 @@ void LinkerDriver::parseDirectives(InputFile *file) {
break;
case OPT_defaultlib:
if (Optional<StringRef> path = findLib(arg->getValue()))
- enqueuePath(*path, false);
+ enqueuePath(*path, false, false);
break;
case OPT_entry:
config->entry = addUndefined(mangle(arg->getValue()));
@@ -594,6 +603,7 @@ static std::string createResponseFile(const opt::InputArgList &args,
for (auto *arg : args) {
switch (arg->getOption().getID()) {
case OPT_linkrepro:
+ case OPT_reproduce:
case OPT_INPUT:
case OPT_defaultlib:
case OPT_libpath:
@@ -708,8 +718,7 @@ static std::string getImplibPath() {
return out.str();
}
-//
-// The import name is caculated as the following:
+// The import name is calculated as follows:
//
// | LIBRARY w/ ext | LIBRARY w/o ext | no LIBRARY
// -----+----------------+---------------------+------------------
@@ -991,30 +1000,37 @@ static void parsePDBAltPath(StringRef altPath) {
config->pdbAltPath = buf;
}
-/// Check that at most one resource obj file was used.
+/// Convert resource files and potentially merge input resource object
+/// trees into one resource tree.
/// Call after ObjFile::Instances is complete.
-static void diagnoseMultipleResourceObjFiles() {
- // The .rsrc$01 section in a resource obj file contains a tree description
- // of resources. Merging multiple resource obj files would require merging
- // the trees instead of using usual linker section merging semantics.
- // Since link.exe disallows linking more than one resource obj file with
- // LNK4078, mirror that. The normal use of resource files is to give the
- // linker many .res files, which are then converted to a single resource obj
- // file internally, so this is not a big restriction in practice.
- ObjFile *resourceObjFile = nullptr;
- for (ObjFile *f : ObjFile::instances) {
- if (!f->isResourceObjFile)
- continue;
+void LinkerDriver::convertResources() {
+ std::vector<ObjFile *> resourceObjFiles;
- if (!resourceObjFile) {
- resourceObjFile = f;
- continue;
- }
+ for (ObjFile *f : ObjFile::instances) {
+ if (f->isResourceObjFile())
+ resourceObjFiles.push_back(f);
+ }
- error(toString(f) +
+ if (!config->mingw &&
+ (resourceObjFiles.size() > 1 ||
+ (resourceObjFiles.size() == 1 && !resources.empty()))) {
+ error((!resources.empty() ? "internal .obj file created from .res files"
+ : toString(resourceObjFiles[1])) +
": more than one resource obj file not allowed, already got " +
- toString(resourceObjFile));
+ toString(resourceObjFiles.front()));
+ return;
+ }
+
+ if (resources.empty() && resourceObjFiles.size() <= 1) {
+ // No resources to convert, and max one resource object file in
+ // the input. Keep that preconverted resource section as is.
+ for (ObjFile *f : resourceObjFiles)
+ f->includeResourceChunks();
+ return;
}
+ ObjFile *f = make<ObjFile>(convertResToCOFF(resources, resourceObjFiles));
+ symtab->addFile(f);
+ f->includeResourceChunks();
}
// In MinGW, if no symbols are chosen to be exported, then all symbols are
@@ -1055,11 +1071,25 @@ void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) {
});
}
-static const char *libcallRoutineNames[] = {
-#define HANDLE_LIBCALL(code, name) name,
-#include "llvm/IR/RuntimeLibcalls.def"
-#undef HANDLE_LIBCALL
-};
+// lld has a feature to create a tar file containing all input files as well as
+// all command line options, so that other people can run lld again with exactly
+// the same inputs. This feature is accessible via /linkrepro and /reproduce.
+//
+// /linkrepro and /reproduce are very similar, but /linkrepro takes a directory
+// name while /reproduce takes a full path. We have /linkrepro for compatibility
+// with Microsoft link.exe.
+Optional<std::string> getReproduceFile(const opt::InputArgList &args) {
+ if (auto *arg = args.getLastArg(OPT_reproduce))
+ return std::string(arg->getValue());
+
+ if (auto *arg = args.getLastArg(OPT_linkrepro)) {
+ SmallString<64> path = StringRef(arg->getValue());
+ sys::path::append(path, "repro.tar");
+ return path.str().str();
+ }
+
+ return None;
+}
void LinkerDriver::link(ArrayRef<const char *> argsArr) {
// Needed for LTO.
@@ -1079,7 +1109,7 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
// Parse command line options.
ArgParser parser;
- opt::InputArgList args = parser.parseLINK(argsArr);
+ opt::InputArgList args = parser.parse(argsArr);
// Parse and evaluate -mllvm options.
std::vector<const char *> v;
@@ -1123,22 +1153,20 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
// options are handled.
config->mingw = args.hasArg(OPT_lldmingw);
- if (auto *arg = args.getLastArg(OPT_linkrepro)) {
- SmallString<64> path = StringRef(arg->getValue());
- sys::path::append(path, "repro.tar");
-
+ // Handle /linkrepro and /reproduce.
+ if (Optional<std::string> path = getReproduceFile(args)) {
Expected<std::unique_ptr<TarWriter>> errOrWriter =
- TarWriter::create(path, "repro");
+ TarWriter::create(*path, sys::path::stem(*path));
if (errOrWriter) {
tar = std::move(*errOrWriter);
} else {
- error("/linkrepro: failed to open " + path + ": " +
+ error("/linkrepro: failed to open " + *path + ": " +
toString(errOrWriter.takeError()));
}
}
- if (!args.hasArg(OPT_INPUT, OPT_wholearchive_file)) {
+ if (!args.hasArg(OPT_INPUT)) {
if (args.hasArg(OPT_deffile))
config->noEntry = true;
else
@@ -1149,7 +1177,8 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
searchPaths.push_back("");
for (auto *arg : args.filtered(OPT_libpath))
searchPaths.push_back(arg->getValue());
- addLibSearchPaths();
+ if (!args.hasArg(OPT_lldignoreenv))
+ addLibSearchPaths();
// Handle /ignore
for (auto *arg : args.filtered(OPT_ignore)) {
@@ -1481,6 +1510,7 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
getOldNewOptions(args, OPT_thinlto_prefix_replace);
config->thinLTOObjectSuffixReplace =
getOldNewOptions(args, OPT_thinlto_object_suffix_replace);
+ config->ltoObjPath = args.getLastArgValue(OPT_lto_obj_path);
// Handle miscellaneous boolean flags.
config->allowBind = args.hasFlag(OPT_allowbind, OPT_allowbind_no, true);
config->allowIsolation =
@@ -1545,19 +1575,45 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
return false;
};
- // Create a list of input files. Files can be given as arguments
- // for /defaultlib option.
- for (auto *arg : args.filtered(OPT_INPUT, OPT_wholearchive_file))
- if (Optional<StringRef> path = findFile(arg->getValue()))
- enqueuePath(*path, isWholeArchive(*path));
+ // Create a list of input files. These can be given as OPT_INPUT options
+ // and OPT_wholearchive_file options, and we also need to track OPT_start_lib
+ // and OPT_end_lib.
+ bool inLib = false;
+ for (auto *arg : args) {
+ switch (arg->getOption().getID()) {
+ case OPT_end_lib:
+ if (!inLib)
+ error("stray " + arg->getSpelling());
+ inLib = false;
+ break;
+ case OPT_start_lib:
+ if (inLib)
+ error("nested " + arg->getSpelling());
+ inLib = true;
+ break;
+ case OPT_wholearchive_file:
+ if (Optional<StringRef> path = findFile(arg->getValue()))
+ enqueuePath(*path, true, inLib);
+ break;
+ case OPT_INPUT:
+ if (Optional<StringRef> path = findFile(arg->getValue()))
+ enqueuePath(*path, isWholeArchive(*path), inLib);
+ break;
+ default:
+ // Ignore other options.
+ break;
+ }
+ }
+ // Process files specified as /defaultlib. These should be enequeued after
+ // other files, which is why they are in a separate loop.
for (auto *arg : args.filtered(OPT_defaultlib))
if (Optional<StringRef> path = findLib(arg->getValue()))
- enqueuePath(*path, false);
+ enqueuePath(*path, false, false);
// Windows specific -- Create a resource file containing a manifest file.
if (config->manifest == Configuration::Embed)
- addBuffer(createManifestRes(), false);
+ addBuffer(createManifestRes(), false, false);
// Read all input files given via the command line.
run();
@@ -1582,12 +1638,6 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
for (auto *arg : args.filtered(OPT_functionpadmin, OPT_functionpadmin_opt))
parseFunctionPadMin(arg, config->machine);
- // Input files can be Windows resource files (.res files). We use
- // WindowsResource to convert resource files to a regular COFF file,
- // then link the resulting file normally.
- if (!resources.empty())
- symtab->addFile(make<ObjFile>(convertResToCOFF(resources)));
-
if (tar)
tar->append("response.txt",
createResponseFile(args, filePaths,
@@ -1626,7 +1676,7 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
}
// Handle generation of import library from a def file.
- if (!args.hasArg(OPT_INPUT, OPT_wholearchive_file)) {
+ if (!args.hasArg(OPT_INPUT)) {
fixupExports();
createImportLibrary(/*asLib=*/true);
return;
@@ -1672,8 +1722,8 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
// Set default image name if neither /out or /def set it.
if (config->outputFile.empty()) {
- config->outputFile = getOutputPath(
- (*args.filtered(OPT_INPUT, OPT_wholearchive_file).begin())->getValue());
+ config->outputFile =
+ getOutputPath((*args.filtered(OPT_INPUT).begin())->getValue());
}
// Fail early if an output file is not writable.
@@ -1769,7 +1819,7 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
// bitcode file in an archive member, we need to arrange to use LTO to
// compile those archive members by adding them to the link beforehand.
if (!BitcodeFile::instances.empty())
- for (const char *s : libcallRoutineNames)
+ for (auto *s : lto::LTO::getRuntimeLibcallSymbols())
symtab->addLibcall(s);
// Windows specific -- if __load_config_used can be resolved, resolve it.
@@ -1777,28 +1827,10 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
addUndefined(mangle("_load_config_used"));
} while (run());
- if (errorCount())
- return;
-
- // Do LTO by compiling bitcode input files to a set of native COFF files then
- // link those files (unless -thinlto-index-only was given, in which case we
- // resolve symbols and write indices, but don't generate native code or link).
- symtab->addCombinedLTOObjects();
-
- // If -thinlto-index-only is given, we should create only "index
- // files" and not object files. Index file creation is already done
- // in addCombinedLTOObject, so we are done if that's the case.
- if (config->thinLTOIndexOnly)
- return;
-
- // If we generated native object files from bitcode files, this resolves
- // references to the symbols we use from them.
- run();
-
if (args.hasArg(OPT_include_optional)) {
// Handle /includeoptional
for (auto *arg : args.filtered(OPT_include_optional))
- if (dyn_cast_or_null<Lazy>(symtab->find(arg->getValue())))
+ if (dyn_cast_or_null<LazyArchive>(symtab->find(arg->getValue())))
addUndefined(arg->getValue());
while (run());
}
@@ -1821,11 +1853,36 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
run();
}
- // Make sure we have resolved all symbols.
- symtab->reportRemainingUndefines();
+ // At this point, we should not have any symbols that cannot be resolved.
+ // If we are going to do codegen for link-time optimization, check for
+ // unresolvable symbols first, so we don't spend time generating code that
+ // will fail to link anyway.
+ if (!BitcodeFile::instances.empty() && !config->forceUnresolved)
+ symtab->reportUnresolvable();
+ if (errorCount())
+ return;
+
+ // Do LTO by compiling bitcode input files to a set of native COFF files then
+ // link those files (unless -thinlto-index-only was given, in which case we
+ // resolve symbols and write indices, but don't generate native code or link).
+ symtab->addCombinedLTOObjects();
+
+ // If -thinlto-index-only is given, we should create only "index
+ // files" and not object files. Index file creation is already done
+ // in addCombinedLTOObject, so we are done if that's the case.
+ if (config->thinLTOIndexOnly)
+ return;
+
+ // If we generated native object files from bitcode files, this resolves
+ // references to the symbols we use from them.
+ run();
+
+ // Resolve remaining undefined symbols and warn about imported locals.
+ symtab->resolveRemainingUndefines();
if (errorCount())
return;
+ config->hadExplicitExports = !config->exports.empty();
if (config->mingw) {
// In MinGW, all symbols are automatically exported if no symbols
// are chosen to be exported.
@@ -1849,10 +1906,12 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
}
// Windows specific -- when we are creating a .dll file, we also
- // need to create a .lib file.
+ // need to create a .lib file. In MinGW mode, we only do that when the
+ // -implib option is given explicitly, for compatibility with GNU ld.
if (!config->exports.empty() || config->dll) {
fixupExports();
- createImportLibrary(/*asLib=*/false);
+ if (!config->mingw || !config->implib.empty())
+ createImportLibrary(/*asLib=*/false);
assignExportOrdinals();
}
@@ -1896,7 +1955,7 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
markLive(symtab->getChunks());
// Needs to happen after the last call to addFile().
- diagnoseMultipleResourceObjFiles();
+ convertResources();
// Identify identical COMDAT sections to merge them.
if (config->doICF) {
diff --git a/contrib/llvm-project/lld/COFF/Driver.h b/contrib/llvm-project/lld/COFF/Driver.h
index 01bfb02a5c33..cc2f25a6f95e 100644
--- a/contrib/llvm-project/lld/COFF/Driver.h
+++ b/contrib/llvm-project/lld/COFF/Driver.h
@@ -43,8 +43,8 @@ public:
class ArgParser {
public:
- // Concatenate LINK environment variable and given arguments and parse them.
- llvm::opt::InputArgList parseLINK(std::vector<const char *> args);
+ // Parses command line options.
+ llvm::opt::InputArgList parse(llvm::ArrayRef<const char *> args);
// Tokenizes a given string and then parses as command line options.
llvm::opt::InputArgList parse(StringRef s) { return parse(tokenize(s)); }
@@ -56,8 +56,8 @@ public:
parseDirectives(StringRef s);
private:
- // Parses command line options.
- llvm::opt::InputArgList parse(llvm::ArrayRef<const char *> args);
+ // Concatenate LINK environment variable.
+ void addLINK(SmallVector<const char *, 256> &argv);
std::vector<const char *> tokenize(StringRef s);
@@ -77,7 +77,7 @@ public:
MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> mb);
- void enqueuePath(StringRef path, bool wholeArchive);
+ void enqueuePath(StringRef path, bool wholeArchive, bool lazy);
private:
std::unique_ptr<llvm::TarWriter> tar; // for /linkrepro
@@ -98,6 +98,10 @@ private:
// Library search path. The first element is always "" (current directory).
std::vector<StringRef> searchPaths;
+ // Convert resource files and potentially merge input resource object
+ // trees into one resource tree.
+ void convertResources();
+
void maybeExportMinGWSymbols(const llvm::opt::InputArgList &args);
// We don't want to add the same file more than once.
@@ -120,7 +124,8 @@ private:
StringRef findDefaultEntry();
WindowsSubsystem inferSubsystem();
- void addBuffer(std::unique_ptr<MemoryBuffer> mb, bool wholeArchive);
+ void addBuffer(std::unique_ptr<MemoryBuffer> mb, bool wholeArchive,
+ bool lazy);
void addArchiveBuffer(MemoryBufferRef mbref, StringRef symName,
StringRef parentName, uint64_t offsetInArchive);
@@ -184,7 +189,8 @@ void assignExportOrdinals();
void checkFailIfMismatch(StringRef arg, InputFile *source);
// Convert Windows resource files (.res files) to a .obj file.
-MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> mbs);
+MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> mbs,
+ ArrayRef<ObjFile *> objs);
void runMSVCLinker(std::string rsp, ArrayRef<StringRef> objects);
diff --git a/contrib/llvm-project/lld/COFF/DriverUtils.cpp b/contrib/llvm-project/lld/COFF/DriverUtils.cpp
index 4360ac23b262..e08b855740a4 100644
--- a/contrib/llvm-project/lld/COFF/DriverUtils.cpp
+++ b/contrib/llvm-project/lld/COFF/DriverUtils.cpp
@@ -322,7 +322,7 @@ public:
if (!contents.empty()) {
std::error_code ec;
- raw_fd_ostream os(path, ec, sys::fs::F_None);
+ raw_fd_ostream os(path, ec, sys::fs::OF_None);
if (ec)
fatal("failed to open " + path + ": " + ec.message());
os << contents;
@@ -410,7 +410,7 @@ static std::string createManifestXmlWithExternalMt(StringRef defaultXml) {
// Create the default manifest file as a temporary file.
TemporaryFile Default("defaultxml", "manifest");
std::error_code ec;
- raw_fd_ostream os(Default.path, ec, sys::fs::F_Text);
+ raw_fd_ostream os(Default.path, ec, sys::fs::OF_Text);
if (ec)
fatal("failed to open " + Default.path + ": " + ec.message());
os << defaultXml;
@@ -511,7 +511,7 @@ void createSideBySideManifest() {
if (path == "")
path = config->outputFile + ".manifest";
std::error_code ec;
- raw_fd_ostream out(path, ec, sys::fs::F_Text);
+ raw_fd_ostream out(path, ec, sys::fs::OF_Text);
if (ec)
fatal("failed to create manifest: " + ec.message());
out << createManifestXml();
@@ -700,26 +700,42 @@ void checkFailIfMismatch(StringRef arg, InputFile *source) {
// Convert Windows resource files (.res files) to a .obj file.
// Does what cvtres.exe does, but in-process and cross-platform.
-MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> mbs) {
- object::WindowsResourceParser parser;
+MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> mbs,
+ ArrayRef<ObjFile *> objs) {
+ object::WindowsResourceParser parser(/* MinGW */ config->mingw);
+ std::vector<std::string> duplicates;
for (MemoryBufferRef mb : mbs) {
std::unique_ptr<object::Binary> bin = check(object::createBinary(mb));
object::WindowsResource *rf = dyn_cast<object::WindowsResource>(bin.get());
if (!rf)
fatal("cannot compile non-resource file as resource");
- std::vector<std::string> duplicates;
if (auto ec = parser.parse(rf, duplicates))
fatal(toString(std::move(ec)));
+ }
+
+ // Note: This processes all .res files before all objs. Ideally they'd be
+ // handled in the same order they were linked (to keep the right one, if
+ // there are duplicates that are tolerated due to forceMultipleRes).
+ for (ObjFile *f : objs) {
+ object::ResourceSectionRef rsf;
+ if (auto ec = rsf.load(f->getCOFFObj()))
+ fatal(toString(f) + ": " + toString(std::move(ec)));
- for (const auto &dupeDiag : duplicates)
- if (config->forceMultipleRes)
- warn(dupeDiag);
- else
- error(dupeDiag);
+ if (auto ec = parser.parse(rsf, f->getName(), duplicates))
+ fatal(toString(std::move(ec)));
}
+ if (config->mingw)
+ parser.cleanUpManifests(duplicates);
+
+ for (const auto &dupeDiag : duplicates)
+ if (config->forceMultipleRes)
+ warn(dupeDiag);
+ else
+ error(dupeDiag);
+
Expected<std::unique_ptr<MemoryBuffer>> e =
llvm::object::writeWindowsResourceCOFF(config->machine, parser,
config->timestamp);
@@ -757,15 +773,15 @@ static void handleColorDiagnostics(opt::InputArgList &args) {
if (!arg)
return;
if (arg->getOption().getID() == OPT_color_diagnostics) {
- errorHandler().colorDiagnostics = true;
+ enableColors(true);
} else if (arg->getOption().getID() == OPT_no_color_diagnostics) {
- errorHandler().colorDiagnostics = false;
+ enableColors(false);
} else {
StringRef s = arg->getValue();
if (s == "always")
- errorHandler().colorDiagnostics = true;
+ enableColors(true);
else if (s == "never")
- errorHandler().colorDiagnostics = false;
+ enableColors(false);
else if (s != "auto")
error("unknown option: --color-diagnostics=" + s);
}
@@ -792,13 +808,17 @@ opt::InputArgList ArgParser::parse(ArrayRef<const char *> argv) {
// We need to get the quoting style for response files before parsing all
// options so we parse here before and ignore all the options but
- // --rsp-quoting.
+ // --rsp-quoting and /lldignoreenv.
+ // (This means --rsp-quoting can't be added through %LINK%.)
opt::InputArgList args = table.ParseArgs(argv, missingIndex, missingCount);
- // Expand response files (arguments in the form of @<filename>)
- // and then parse the argument again.
+
+ // Expand response files (arguments in the form of @<filename>) and insert
+ // flags from %LINK% and %_LINK_%, and then parse the argument again.
SmallVector<const char *, 256> expandedArgv(argv.data(),
argv.data() + argv.size());
+ if (!args.hasArg(OPT_lldignoreenv))
+ addLINK(expandedArgv);
cl::ExpandResponseFiles(saver, getQuotingStyle(args), expandedArgv);
args = table.ParseArgs(makeArrayRef(expandedArgv).drop_front(), missingIndex,
missingCount);
@@ -868,7 +888,7 @@ ArgParser::parseDirectives(StringRef s) {
// 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 *> argv) {
+void ArgParser::addLINK(SmallVector<const char *, 256> &argv) {
// Concatenate LINK env and command line arguments, and then parse them.
if (Optional<std::string> s = Process::GetEnv("LINK")) {
std::vector<const char *> v = tokenize(*s);
@@ -878,7 +898,6 @@ opt::InputArgList ArgParser::parseLINK(std::vector<const char *> argv) {
std::vector<const char *> v = tokenize(*s);
argv.insert(std::next(argv.begin()), v.begin(), v.end());
}
- return parse(argv);
}
std::vector<const char *> ArgParser::tokenize(StringRef s) {
diff --git a/contrib/llvm-project/lld/COFF/ICF.cpp b/contrib/llvm-project/lld/COFF/ICF.cpp
index 2b2818de3889..c821569e3457 100644
--- a/contrib/llvm-project/lld/COFF/ICF.cpp
+++ b/contrib/llvm-project/lld/COFF/ICF.cpp
@@ -13,7 +13,7 @@
//
// On Windows, ICF is enabled by default.
//
-// See ELF/ICF.cpp for the details about the algortihm.
+// See ELF/ICF.cpp for the details about the algorithm.
//
//===----------------------------------------------------------------------===//
@@ -77,7 +77,7 @@ private:
// section is insignificant to the user program and the behaviour matches that
// of the Visual C++ linker.
bool ICF::isEligible(SectionChunk *c) {
- // Non-comdat chunks, dead chunks, and writable chunks are not elegible.
+ // Non-comdat chunks, dead chunks, and writable chunks are not eligible.
bool writable = c->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_WRITE;
if (!c->isCOMDAT() || !c->live || writable)
return false;
@@ -274,7 +274,7 @@ void ICF::run(ArrayRef<Chunk *> vec) {
for (Symbol *b : sc->symbols())
if (auto *sym = dyn_cast_or_null<DefinedRegular>(b))
hash += sym->getChunk()->eqClass[cnt % 2];
- // Set MSB to 1 to avoid collisions with non-hash classs.
+ // Set MSB to 1 to avoid collisions with non-hash classes.
sc->eqClass[(cnt + 1) % 2] = hash | (1U << 31);
});
}
@@ -297,7 +297,7 @@ void ICF::run(ArrayRef<Chunk *> vec) {
log("ICF needed " + Twine(cnt) + " iterations");
- // Merge sections in the same classs.
+ // Merge sections in the same classes.
forEachClass([&](size_t begin, size_t end) {
if (end - begin == 1)
return;
diff --git a/contrib/llvm-project/lld/COFF/InputFiles.cpp b/contrib/llvm-project/lld/COFF/InputFiles.cpp
index d02fedfd178b..faec3ba160a5 100644
--- a/contrib/llvm-project/lld/COFF/InputFiles.cpp
+++ b/contrib/llvm-project/lld/COFF/InputFiles.cpp
@@ -47,6 +47,24 @@ using llvm::Triple;
using llvm::support::ulittle32_t;
namespace lld {
+
+// Returns the last element of a path, which is supposed to be a filename.
+static StringRef getBasename(StringRef path) {
+ return sys::path::filename(path, sys::path::Style::windows);
+}
+
+// Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)".
+std::string toString(const coff::InputFile *file) {
+ if (!file)
+ return "<internal>";
+ if (file->parentName.empty() || file->kind() == coff::InputFile::ImportKind)
+ return file->getName();
+
+ return (getBasename(file->parentName) + "(" + getBasename(file->getName()) +
+ ")")
+ .str();
+}
+
namespace coff {
std::vector<ObjFile *> ObjFile::instances;
@@ -73,6 +91,10 @@ static void checkAndSetWeakAlias(SymbolTable *symtab, InputFile *f,
}
}
+static bool ignoredSymbolName(StringRef name) {
+ return name == "@feat.00" || name == "@comp.id";
+}
+
ArchiveFile::ArchiveFile(MemoryBufferRef m) : InputFile(ArchiveKind, m) {}
void ArchiveFile::parse() {
@@ -81,7 +103,7 @@ void ArchiveFile::parse() {
// Read the symbol table to construct Lazy objects.
for (const Archive::Symbol &sym : file->symbols())
- symtab->addLazy(this, sym);
+ symtab->addLazyArchive(this, sym);
}
// Returns a buffer pointing to a member file containing a given symbol.
@@ -116,6 +138,49 @@ std::vector<MemoryBufferRef> getArchiveMembers(Archive *file) {
return v;
}
+void LazyObjFile::fetch() {
+ if (mb.getBuffer().empty())
+ return;
+
+ InputFile *file;
+ if (isBitcode(mb))
+ file = make<BitcodeFile>(mb, "", 0, std::move(symbols));
+ else
+ file = make<ObjFile>(mb, std::move(symbols));
+ mb = {};
+ symtab->addFile(file);
+}
+
+void LazyObjFile::parse() {
+ if (isBitcode(this->mb)) {
+ // Bitcode file.
+ std::unique_ptr<lto::InputFile> obj =
+ CHECK(lto::InputFile::create(this->mb), this);
+ for (const lto::InputFile::Symbol &sym : obj->symbols()) {
+ if (!sym.isUndefined())
+ symtab->addLazyObject(this, sym.getName());
+ }
+ return;
+ }
+
+ // Native object file.
+ std::unique_ptr<Binary> coffObjPtr = CHECK(createBinary(mb), this);
+ COFFObjectFile *coffObj = cast<COFFObjectFile>(coffObjPtr.get());
+ uint32_t numSymbols = coffObj->getNumberOfSymbols();
+ for (uint32_t i = 0; i < numSymbols; ++i) {
+ COFFSymbolRef coffSym = check(coffObj->getSymbol(i));
+ if (coffSym.isUndefined() || !coffSym.isExternal() ||
+ coffSym.isWeakExternal())
+ continue;
+ StringRef name;
+ coffObj->getSymbolName(coffSym, name);
+ if (coffSym.isAbsolute() && ignoredSymbolName(name))
+ continue;
+ symtab->addLazyObject(this, name);
+ i += coffSym.getNumberOfAuxSymbols();
+ }
+}
+
void ObjFile::parse() {
// Parse a memory buffer as a COFF file.
std::unique_ptr<Binary> bin = CHECK(createBinary(mb), this);
@@ -206,10 +271,6 @@ SectionChunk *ObjFile::readSection(uint32_t sectionNumber,
if (def)
c->checksum = def->CheckSum;
- // link.exe uses the presence of .rsrc$01 for LNK4078, so match that.
- if (name == ".rsrc$01")
- isResourceObjFile = true;
-
// CodeView sections are stored to a different vector because they are not
// linked in the regular manner.
if (c->isCodeView())
@@ -226,12 +287,18 @@ SectionChunk *ObjFile::readSection(uint32_t sectionNumber,
// relocations, in .rdata, leader symbol name matches the MSVC name mangling
// for string literals) are subject to string tail merging.
MergeChunk::addSection(c);
+ else if (name == ".rsrc" || name.startswith(".rsrc$"))
+ resourceChunks.push_back(c);
else
chunks.push_back(c);
return c;
}
+void ObjFile::includeResourceChunks() {
+ chunks.insert(chunks.end(), resourceChunks.begin(), resourceChunks.end());
+}
+
void ObjFile::readAssociativeDefinition(
COFFSymbolRef sym, const coff_aux_section_definition *def) {
readAssociativeDefinition(sym, def, def->getNumber(sym.isBigObj()));
@@ -315,7 +382,8 @@ Symbol *ObjFile::createRegular(COFFSymbolRef sym) {
StringRef name;
coffObj->getSymbolName(sym, name);
if (sc)
- return symtab->addRegular(this, name, sym.getGeneric(), sc);
+ return symtab->addRegular(this, name, sym.getGeneric(), sc,
+ sym.getValue());
// For MinGW symbols named .weak.* that point to a discarded section,
// don't create an Undefined symbol. If nothing ever refers to the symbol,
// everything should be fine. If something actually refers to the symbol
@@ -469,7 +537,7 @@ void ObjFile::handleComdatSelection(COFFSymbolRef sym, COMDATType &selection,
// if the two comdat sections have e.g. different alignment.
// Match that.
if (leaderChunk->getContents() != newChunk.getContents())
- symtab->reportDuplicate(leader, this);
+ symtab->reportDuplicate(leader, this, &newChunk, sym.getValue());
break;
}
@@ -524,13 +592,11 @@ Optional<Symbol *> ObjFile::createDefined(
if (sym.isAbsolute()) {
StringRef name = getName();
- // Skip special symbols.
- if (name == "@comp.id")
- return nullptr;
- if (name == "@feat.00") {
+ if (name == "@feat.00")
feat00Flags = sym.getValue();
+ // Skip special symbols.
+ if (ignoredSymbolName(name))
return nullptr;
- }
if (sym.isExternal())
return symtab->addAbsolute(name, sym);
@@ -552,7 +618,7 @@ Optional<Symbol *> ObjFile::createDefined(
// Comdat handling.
// A comdat symbol consists of two symbol table entries.
// The first symbol entry has the name of the section (e.g. .text), fixed
- // values for the other fields, and one auxilliary record.
+ // values for the other fields, and one auxiliary record.
// The second symbol entry has the name of the comdat symbol, called the
// "comdat leader".
// When this function is called for the first symbol entry of a comdat,
@@ -622,7 +688,7 @@ ArrayRef<uint8_t> ObjFile::getDebugSection(StringRef secName) {
return {};
}
-// OBJ files systematically store critical informations in a .debug$S stream,
+// OBJ files systematically store critical information in a .debug$S stream,
// even if the TU was compiled with no debug info. At least two records are
// always there. S_OBJNAME stores a 32-bit signature, which is loaded into the
// PCHSignature member. S_COMPILE3 stores compile-time cmd-line flags. This is
@@ -723,6 +789,37 @@ void ObjFile::initializeDependencies() {
debugTypesObj = makeTpiSource(this);
}
+// Used only for DWARF debug info, which is not common (except in MinGW
+// environments). This returns an optional pair of file name and line
+// number for where the variable was defined.
+Optional<std::pair<StringRef, uint32_t>>
+ObjFile::getVariableLocation(StringRef var) {
+ if (!dwarf) {
+ dwarf = make<DWARFCache>(DWARFContext::create(*getCOFFObj()));
+ if (!dwarf)
+ return None;
+ }
+ if (config->machine == I386)
+ var.consume_front("_");
+ Optional<std::pair<std::string, unsigned>> ret = dwarf->getVariableLoc(var);
+ if (!ret)
+ return None;
+ return std::make_pair(saver.save(ret->first), ret->second);
+}
+
+// Used only for DWARF debug info, which is not common (except in MinGW
+// environments).
+Optional<DILineInfo> ObjFile::getDILineInfo(uint32_t offset,
+ uint32_t sectionIndex) {
+ if (!dwarf) {
+ dwarf = make<DWARFCache>(DWARFContext::create(*getCOFFObj()));
+ if (!dwarf)
+ return None;
+ }
+
+ return dwarf->getDILineInfo(offset, sectionIndex);
+}
+
StringRef ltrim1(StringRef s, const char *chars) {
if (!s.empty() && strchr(chars, s[0]))
return s.substr(1);
@@ -780,8 +877,9 @@ void ImportFile::parse() {
}
BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
- uint64_t offsetInArchive)
- : InputFile(BitcodeKind, mb) {
+ uint64_t offsetInArchive,
+ std::vector<Symbol *> &&symbols)
+ : InputFile(BitcodeKind, mb), symbols(std::move(symbols)) {
std::string path = mb.getBufferIdentifier().str();
if (config->thinLTOIndexOnly)
path = replaceThinLTOSuffix(mb.getBufferIdentifier());
@@ -860,22 +958,6 @@ std::string replaceThinLTOSuffix(StringRef path) {
return (path + repl).str();
return path;
}
+
} // namespace coff
} // namespace lld
-
-// Returns the last element of a path, which is supposed to be a filename.
-static StringRef getBasename(StringRef path) {
- return sys::path::filename(path, sys::path::Style::windows);
-}
-
-// Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)".
-std::string lld::toString(const coff::InputFile *file) {
- if (!file)
- return "<internal>";
- if (file->parentName.empty() || file->kind() == coff::InputFile::ImportKind)
- return file->getName();
-
- return (getBasename(file->parentName) + "(" + getBasename(file->getName()) +
- ")")
- .str();
-}
diff --git a/contrib/llvm-project/lld/COFF/InputFiles.h b/contrib/llvm-project/lld/COFF/InputFiles.h
index 8d3a021a3789..672461cd84ba 100644
--- a/contrib/llvm-project/lld/COFF/InputFiles.h
+++ b/contrib/llvm-project/lld/COFF/InputFiles.h
@@ -10,10 +10,12 @@
#define LLD_COFF_INPUT_FILES_H
#include "Config.h"
+#include "lld/Common/DWARF.h"
#include "lld/Common/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/BinaryFormat/Magic.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/LTO/LTO.h"
#include "llvm/Object/Archive.h"
@@ -24,6 +26,7 @@
#include <vector>
namespace llvm {
+struct DILineInfo;
namespace pdb {
class DbiModuleDescriptorBuilder;
}
@@ -47,7 +50,6 @@ class Defined;
class DefinedImportData;
class DefinedImportThunk;
class DefinedRegular;
-class Lazy;
class SectionChunk;
class Symbol;
class Undefined;
@@ -56,7 +58,13 @@ class TpiSource;
// The root class of input files.
class InputFile {
public:
- enum Kind { ArchiveKind, ObjectKind, ImportKind, BitcodeKind };
+ enum Kind {
+ ArchiveKind,
+ ObjectKind,
+ LazyObjectKind,
+ ImportKind,
+ BitcodeKind
+ };
Kind kind() const { return fileKind; }
virtual ~InputFile() {}
@@ -103,10 +111,28 @@ private:
llvm::DenseSet<uint64_t> seen;
};
+// .obj or .o file between -start-lib and -end-lib.
+class LazyObjFile : public InputFile {
+public:
+ explicit LazyObjFile(MemoryBufferRef m) : InputFile(LazyObjectKind, m) {}
+ static bool classof(const InputFile *f) {
+ return f->kind() == LazyObjectKind;
+ }
+ // Makes this object file part of the link.
+ void fetch();
+ // Adds the symbols in this file to the symbol table as LazyObject symbols.
+ void parse() override;
+
+private:
+ std::vector<Symbol *> symbols;
+};
+
// .obj or .o file. This may be a member of an archive file.
class ObjFile : public InputFile {
public:
explicit ObjFile(MemoryBufferRef m) : InputFile(ObjectKind, m) {}
+ explicit ObjFile(MemoryBufferRef m, std::vector<Symbol *> &&symbols)
+ : InputFile(ObjectKind, m), symbols(std::move(symbols)) {}
static bool classof(const InputFile *f) { return f->kind() == ObjectKind; }
void parse() override;
MachineTypes getMachineType() override;
@@ -135,6 +161,10 @@ public:
return symbols.size() - 1;
}
+ void includeResourceChunks();
+
+ bool isResourceObjFile() const { return !resourceChunks.empty(); }
+
static std::vector<ObjFile *> instances;
// Flags in the absolute @feat.00 symbol if it is present. These usually
@@ -162,9 +192,6 @@ public:
// precompiled object. Any difference indicates out-of-date objects.
llvm::Optional<uint32_t> pchSignature;
- // Whether this is an object file created from .res files.
- bool isResourceObjFile = false;
-
// Whether this file was compiled with /hotpatch.
bool hotPatchable = false;
@@ -177,6 +204,12 @@ public:
// The .debug$T stream if there's one.
llvm::Optional<llvm::codeview::CVTypeArray> debugTypes;
+ llvm::Optional<std::pair<StringRef, uint32_t>>
+ getVariableLocation(StringRef var);
+
+ llvm::Optional<llvm::DILineInfo> getDILineInfo(uint32_t offset,
+ uint32_t sectionIndex);
+
private:
const coff_section* getSection(uint32_t i);
const coff_section *getSection(COFFSymbolRef sym) {
@@ -234,6 +267,8 @@ private:
// chunks and non-section chunks for common symbols.
std::vector<Chunk *> chunks;
+ std::vector<SectionChunk *> resourceChunks;
+
// CodeView debug info sections.
std::vector<SectionChunk *> debugChunks;
@@ -258,6 +293,8 @@ private:
// index. Nonexistent indices (which are occupied by auxiliary
// symbols in the real symbol table) are filled with null pointers.
std::vector<Symbol *> symbols;
+
+ DWARFCache *dwarf = nullptr;
};
// This type represents import library members that contain DLL names
@@ -299,7 +336,11 @@ public:
class BitcodeFile : public InputFile {
public:
BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
- uint64_t offsetInArchive);
+ uint64_t offsetInArchive)
+ : BitcodeFile(mb, archiveName, offsetInArchive, {}) {}
+ explicit BitcodeFile(MemoryBufferRef m, StringRef archiveName,
+ uint64_t offsetInArchive,
+ std::vector<Symbol *> &&symbols);
static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
ArrayRef<Symbol *> getSymbols() { return symbols; }
MachineTypes getMachineType() override;
@@ -312,6 +353,10 @@ private:
std::vector<Symbol *> symbols;
};
+inline bool isBitcode(MemoryBufferRef mb) {
+ return identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode;
+}
+
std::string replaceThinLTOSuffix(StringRef path);
} // namespace coff
diff --git a/contrib/llvm-project/lld/COFF/LTO.cpp b/contrib/llvm-project/lld/COFF/LTO.cpp
index eb3c60d66077..1c21236dce2b 100644
--- a/contrib/llvm-project/lld/COFF/LTO.cpp
+++ b/contrib/llvm-project/lld/COFF/LTO.cpp
@@ -39,14 +39,14 @@
using namespace llvm;
using namespace llvm::object;
-using namespace lld;
-using namespace lld::coff;
+namespace lld {
+namespace coff {
// Creates an empty file to and returns a raw_fd_ostream to write to it.
static std::unique_ptr<raw_fd_ostream> openFile(StringRef file) {
std::error_code ec;
auto ret =
- llvm::make_unique<raw_fd_ostream>(file, ec, sys::fs::OpenFlags::F_None);
+ std::make_unique<raw_fd_ostream>(file, ec, sys::fs::OpenFlags::OF_None);
if (ec) {
error("cannot open " + file + ": " + ec.message());
return nullptr;
@@ -105,7 +105,7 @@ BitcodeCompiler::BitcodeCompiler() {
backend = lto::createInProcessThinBackend(config->thinLTOJobs);
}
- ltoObj = llvm::make_unique<lto::LTO>(createConfig(), backend,
+ ltoObj = std::make_unique<lto::LTO>(createConfig(), backend,
config->ltoPartitions);
}
@@ -160,8 +160,8 @@ std::vector<StringRef> BitcodeCompiler::compile() {
checkError(ltoObj->run(
[&](size_t task) {
- return llvm::make_unique<lto::NativeObjectStream>(
- llvm::make_unique<raw_svector_ostream>(buf[task]));
+ return std::make_unique<lto::NativeObjectStream>(
+ std::make_unique<raw_svector_ostream>(buf[task]));
},
cache));
@@ -177,6 +177,8 @@ std::vector<StringRef> BitcodeCompiler::compile() {
// files. After that, we exit from linker and ThinLTO backend runs in a
// distributed environment.
if (config->thinLTOIndexOnly) {
+ if (!config->ltoObjPath.empty())
+ saveBuffer(buf[0], config->ltoObjPath);
if (indexFile)
indexFile->close();
return {};
@@ -204,3 +206,6 @@ std::vector<StringRef> BitcodeCompiler::compile() {
return ret;
}
+
+} // namespace coff
+} // namespace lld
diff --git a/contrib/llvm-project/lld/COFF/MapFile.cpp b/contrib/llvm-project/lld/COFF/MapFile.cpp
index f98cf8fa6130..0fea60aab99b 100644
--- a/contrib/llvm-project/lld/COFF/MapFile.cpp
+++ b/contrib/llvm-project/lld/COFF/MapFile.cpp
@@ -29,14 +29,14 @@
using namespace llvm;
using namespace llvm::object;
-using namespace lld;
-using namespace lld::coff;
+namespace lld {
+namespace coff {
using SymbolMapTy =
DenseMap<const SectionChunk *, SmallVector<DefinedRegular *, 4>>;
-static const std::string indent8 = " "; // 8 spaces
-static const std::string indent16 = " "; // 16 spaces
+static constexpr char indent8[] = " "; // 8 spaces
+static constexpr char indent16[] = " "; // 16 spaces
// Print out the first three columns of a line.
static void writeHeader(raw_ostream &os, uint64_t addr, uint64_t size,
@@ -87,12 +87,12 @@ getSymbolStrings(ArrayRef<DefinedRegular *> syms) {
return ret;
}
-void coff::writeMapFile(ArrayRef<OutputSection *> outputSections) {
+void writeMapFile(ArrayRef<OutputSection *> outputSections) {
if (config->mapFile.empty())
return;
std::error_code ec;
- raw_fd_ostream os(config->mapFile, ec, sys::fs::F_None);
+ raw_fd_ostream os(config->mapFile, ec, sys::fs::OF_None);
if (ec)
fatal("cannot open " + config->mapFile + ": " + ec.message());
@@ -122,3 +122,6 @@ void coff::writeMapFile(ArrayRef<OutputSection *> outputSections) {
}
}
}
+
+} // namespace coff
+} // namespace lld
diff --git a/contrib/llvm-project/lld/COFF/MinGW.cpp b/contrib/llvm-project/lld/COFF/MinGW.cpp
index 2ca8ca0c058c..270cdaab4d9c 100644
--- a/contrib/llvm-project/lld/COFF/MinGW.cpp
+++ b/contrib/llvm-project/lld/COFF/MinGW.cpp
@@ -13,11 +13,12 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
-using namespace lld;
-using namespace lld::coff;
using namespace llvm;
using namespace llvm::COFF;
+namespace lld {
+namespace coff {
+
AutoExporter::AutoExporter() {
excludeLibs = {
"libgcc",
@@ -55,7 +56,7 @@ AutoExporter::AutoExporter() {
// C++ symbols
"__rtti_",
"__builtin_",
- // Artifical symbols such as .refptr
+ // Artificial symbols such as .refptr
".",
};
@@ -146,9 +147,9 @@ bool AutoExporter::shouldExport(Defined *sym) const {
return !excludeObjects.count(fileName);
}
-void coff::writeDefFile(StringRef name) {
+void writeDefFile(StringRef name) {
std::error_code ec;
- raw_fd_ostream os(name, ec, sys::fs::F_None);
+ raw_fd_ostream os(name, ec, sys::fs::OF_None);
if (ec)
fatal("cannot open " + name + ": " + ec.message());
@@ -164,3 +165,6 @@ void coff::writeDefFile(StringRef name) {
os << "\n";
}
}
+
+} // namespace coff
+} // namespace lld
diff --git a/contrib/llvm-project/lld/COFF/Options.td b/contrib/llvm-project/lld/COFF/Options.td
index 024b7be8f78d..9e58d92e634f 100644
--- a/contrib/llvm-project/lld/COFF/Options.td
+++ b/contrib/llvm-project/lld/COFF/Options.td
@@ -21,9 +21,9 @@ def aligncomm : P<"aligncomm", "Set common symbol alignment">;
def alternatename : P<"alternatename", "Define weak alias">;
def base : P<"base", "Base address of the program">;
def color_diagnostics: Flag<["--"], "color-diagnostics">,
- HelpText<"Use colors in diagnostics">;
+ HelpText<"Use colors in diagnostics">;
def color_diagnostics_eq: Joined<["--"], "color-diagnostics=">,
- HelpText<"Use colors in diagnostics; one of 'always', 'never', 'auto'">;
+ HelpText<"Use colors in diagnostics; one of 'always', 'never', 'auto'">;
def defaultlib : P<"defaultlib", "Add the library to the list of input files">;
def delayload : P<"delayload", "Delay loaded DLL name">;
def entry : P<"entry", "Name of entry point symbol">;
@@ -34,7 +34,8 @@ def export : P<"export", "Export a function">;
def failifmismatch : P<"failifmismatch", "">;
def filealign : P<"filealign", "Section alignment in the output file">;
def functionpadmin : F<"functionpadmin">;
-def functionpadmin_opt : P<"functionpadmin", "Prepares an image for hotpatching">;
+def functionpadmin_opt : P<"functionpadmin",
+ "Prepares an image for hotpatching">;
def guard : P<"guard", "Control flow guard">;
def heap : P<"heap", "Size of the heap">;
def ignore : P<"ignore", "Specify warning codes to ignore">;
@@ -42,9 +43,14 @@ def implib : P<"implib", "Import library name">;
def lib : F<"lib">,
HelpText<"Act like lib.exe; must be first argument if present">;
def libpath : P<"libpath", "Additional library search path">;
-def linkrepro : P<"linkrepro", "Dump linker invocation and input files for debugging">;
-def lldltocache : P<"lldltocache", "Path to ThinLTO cached object file directory">;
-def lldltocachepolicy : P<"lldltocachepolicy", "Pruning policy for the ThinLTO cache">;
+def linkrepro : P<"linkrepro",
+ "Dump linker invocation and input files for debugging">;
+def lldignoreenv : F<"lldignoreenv">,
+ HelpText<"Ignore environment variables like %LIB%">;
+def lldltocache : P<"lldltocache",
+ "Path to ThinLTO cached object file directory">;
+def lldltocachepolicy : P<"lldltocachepolicy",
+ "Pruning policy for the ThinLTO cache">;
def lldsavetemps : F<"lldsavetemps">,
HelpText<"Save temporary files instead of deleting them">;
def machine : P<"machine", "Specify target platform">;
@@ -56,7 +62,7 @@ def order : P<"order", "Put functions in order">;
def out : P<"out", "Path to file to write output">;
def natvis : P<"natvis", "Path to natvis file to embed in the PDB">;
def no_color_diagnostics: F<"no-color-diagnostics">,
- HelpText<"Do not use colors in diagnostics">;
+ HelpText<"Do not use colors in diagnostics">;
def pdb : P<"pdb", "PDB file path">;
def pdbaltpath : P<"pdbaltpath", "PDB file path to embed in the image">;
def section : P<"section", "Specify section attributes">;
@@ -65,7 +71,8 @@ def stub : P<"stub", "Specify DOS stub file">;
def subsystem : P<"subsystem", "Specify subsystem">;
def timestamp : P<"timestamp", "Specify the PE header timestamp">;
def version : P<"version", "Specify a version number in the PE header">;
-def wholearchive_file : P<"wholearchive", "Include all object files from this archive">;
+def wholearchive_file : P<"wholearchive",
+ "Include all object files from this library">;
def disallowlib : Joined<["/", "-", "/?", "-?"], "disallowlib:">,
Alias<nodefaultlib>;
@@ -105,6 +112,8 @@ def noentry : F<"noentry">,
def profile : F<"profile">;
def repro : F<"Brepro">,
HelpText<"Use a hash of the executable as the PE header timestamp">;
+def reproduce : P<"reproduce",
+ "Dump linker invocation and input files for debugging">;
def swaprun : P<"swaprun",
"Comma-separated list of 'cd' or 'net'">;
def swaprun_cd : F<"swaprun:cd">, Alias<swaprun>, AliasArgs<["cd"]>,
@@ -112,10 +121,11 @@ def swaprun_cd : F<"swaprun:cd">, Alias<swaprun>, AliasArgs<["cd"]>,
def swaprun_net : F<"swaprun:net">, Alias<swaprun>, AliasArgs<["net"]>,
HelpText<"Make loader run output binary from swap instead of from network">;
def verbose : F<"verbose">;
-def wholearchive_flag : F<"wholearchive">;
+def wholearchive_flag : F<"wholearchive">,
+ HelpText<"Include all object files from all libraries">;
def force : F<"force">,
- HelpText<"Allow undefined and multiply defined symbols when creating executables">;
+ HelpText<"Allow undefined and multiply defined symbols">;
def force_unresolved : F<"force:unresolved">,
HelpText<"Allow undefined symbols when creating executables">;
def force_multiple : F<"force:multiple">,
@@ -162,6 +172,8 @@ def help : F<"help">;
def help_q : Flag<["/??", "-??", "/?", "-?"], "">, Alias<help>;
// LLD extensions
+def end_lib : F<"end-lib">,
+ HelpText<"Ends group of objects treated as if they were in a library">;
def exclude_all_symbols : F<"exclude-all-symbols">;
def export_all_symbols : F<"export-all-symbols">;
defm demangle : B<"demangle",
@@ -173,9 +185,11 @@ def kill_at : F<"kill-at">;
def lldmingw : F<"lldmingw">;
def output_def : Joined<["/", "-", "/?", "-?"], "output-def:">;
def pdb_source_path : P<"pdbsourcepath",
- "Base path used to make relative source file path absolute in PDB">;
+ "Base path used to make relative source file path absolute in PDB">;
def rsp_quoting : Joined<["--"], "rsp-quoting=">,
HelpText<"Quoting style for response files, 'windows' (default) or 'posix'">;
+def start_lib : F<"start-lib">,
+ HelpText<"Starts group of objects treated as if they were in a library">;
def thinlto_emit_imports_files :
F<"thinlto-emit-imports-files">,
HelpText<"Emit .imports files with -thinlto-index-only">;
@@ -191,6 +205,9 @@ def thinlto_object_suffix_replace : P<
def thinlto_prefix_replace: P<
"thinlto-prefix-replace",
"'old;new' replace old prefix with new prefix in ThinLTO outputs">;
+def lto_obj_path : P<
+ "lto-obj-path",
+ "output native object for merged LTO unit to this path">;
def dash_dash_version : Flag<["--"], "version">,
HelpText<"Print version information">;
defm threads: B<"threads",
diff --git a/contrib/llvm-project/lld/COFF/PDB.cpp b/contrib/llvm-project/lld/COFF/PDB.cpp
index a55e5136e040..ea99583b1d80 100644
--- a/contrib/llvm-project/lld/COFF/PDB.cpp
+++ b/contrib/llvm-project/lld/COFF/PDB.cpp
@@ -51,21 +51,22 @@
#include "llvm/Object/COFF.h"
#include "llvm/Object/CVDebugRecord.h"
#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/CRC.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/FormatVariadic.h"
-#include "llvm/Support/JamCRC.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
#include <memory>
-using namespace lld;
-using namespace lld::coff;
using namespace llvm;
using namespace llvm::codeview;
using llvm::object::coff_section;
+namespace lld {
+namespace coff {
+
static ExitOnError exitOnErr;
static Timer totalPdbLinkTimer("PDB Emission (Cumulative)", Timer::root());
@@ -513,16 +514,15 @@ static bool equals_path(StringRef path1, StringRef path2) {
return path1.equals(path2);
#endif
}
-
// Find by name an OBJ provided on the command line
-static ObjFile *findObjByName(StringRef fileNameOnly) {
- SmallString<128> currentPath;
-
+static ObjFile *findObjWithPrecompSignature(StringRef fileNameOnly,
+ uint32_t precompSignature) {
for (ObjFile *f : ObjFile::instances) {
StringRef currentFileName = sys::path::filename(f->getName());
- // Compare based solely on the file name (link.exe behavior)
- if (equals_path(currentFileName, fileNameOnly))
+ if (f->pchSignature.hasValue() &&
+ f->pchSignature.getValue() == precompSignature &&
+ equals_path(fileNameOnly, currentFileName))
return f;
}
return nullptr;
@@ -559,22 +559,15 @@ Expected<const CVIndexMap &> PDBLinker::aquirePrecompObj(ObjFile *file) {
// link.exe requires that a precompiled headers object must always be provided
// on the command-line, even if that's not necessary.
- auto precompFile = findObjByName(precompFileName);
+ auto precompFile =
+ findObjWithPrecompSignature(precompFileName, precomp.Signature);
if (!precompFile)
return createFileError(
- precompFileName.str(),
- make_error<pdb::PDBError>(pdb::pdb_error_code::external_cmdline_ref));
+ precomp.getPrecompFilePath().str(),
+ make_error<pdb::PDBError>(pdb::pdb_error_code::no_matching_pch));
addObjFile(precompFile, &indexMap);
- if (!precompFile->pchSignature)
- fatal(precompFile->getName() + " is not a precompiled headers object");
-
- if (precomp.getSignature() != precompFile->pchSignature.getValueOr(0))
- return createFileError(
- precomp.getPrecompFilePath().str(),
- make_error<pdb::PDBError>(pdb::pdb_error_code::signature_out_of_date));
-
return indexMap;
}
@@ -965,9 +958,7 @@ static pdb::SectionContrib createSectionContrib(const Chunk *c, uint32_t modi) {
sc.Imod = secChunk->file->moduleDBI->getModuleIndex();
ArrayRef<uint8_t> contents = secChunk->getContents();
JamCRC crc(0);
- ArrayRef<char> charContents = makeArrayRef(
- reinterpret_cast<const char *>(contents.data()), contents.size());
- crc.update(charContents);
+ crc.update(contents);
sc.DataCrc = crc.getCRC();
} else {
sc.Characteristics = os ? os->header.Characteristics : 0;
@@ -1150,7 +1141,7 @@ void DebugSHandler::finish() {
// string table. Generally the string table subsection appears after the
// checksum table, so we have to do this after looping over all the
// subsections.
- auto newChecksums = make_unique<DebugChecksumsSubsection>(linker.pdbStrTab);
+ auto newChecksums = std::make_unique<DebugChecksumsSubsection>(linker.pdbStrTab);
for (FileChecksumEntry &fc : checksums) {
SmallString<128> filename =
exitOnErr(cVStrTab.getString(fc.FileNameOffset));
@@ -1599,7 +1590,7 @@ void PDBLinker::addImportFilesToPDB(ArrayRef<OutputSection *> outputSections) {
}
// Creates a PDB file.
-void coff::createPDB(SymbolTable *symtab,
+void createPDB(SymbolTable *symtab,
ArrayRef<OutputSection *> outputSections,
ArrayRef<uint8_t> sectionTable,
llvm::codeview::DebugInfo *buildId) {
@@ -1693,6 +1684,7 @@ void PDBLinker::addSections(ArrayRef<OutputSection *> outputSections,
}
void PDBLinker::commit(codeview::GUID *guid) {
+ ExitOnError exitOnErr((config->pdbPath + ": ").str());
// Write to a file.
exitOnErr(builder.commit(config->pdbPath, guid));
}
@@ -1797,10 +1789,10 @@ static bool findLineTable(const SectionChunk *c, uint32_t addr,
}
// Use CodeView line tables to resolve a file and line number for the given
-// offset into the given chunk and return them, or {"", 0} if a line table was
+// offset into the given chunk and return them, or None if a line table was
// not found.
-std::pair<StringRef, uint32_t> coff::getFileLine(const SectionChunk *c,
- uint32_t addr) {
+Optional<std::pair<StringRef, uint32_t>>
+getFileLineCodeView(const SectionChunk *c, uint32_t addr) {
ExitOnError exitOnErr;
DebugStringTableSubsectionRef cVStrTab;
@@ -1809,7 +1801,7 @@ std::pair<StringRef, uint32_t> coff::getFileLine(const SectionChunk *c,
uint32_t offsetInLinetable;
if (!findLineTable(c, addr, cVStrTab, checksums, lines, offsetInLinetable))
- return {"", 0};
+ return None;
Optional<uint32_t> nameIndex;
Optional<uint32_t> lineNumber;
@@ -1823,14 +1815,17 @@ std::pair<StringRef, uint32_t> coff::getFileLine(const SectionChunk *c,
}
StringRef filename =
exitOnErr(getFileName(cVStrTab, checksums, *nameIndex));
- return {filename, *lineNumber};
+ return std::make_pair(filename, *lineNumber);
}
nameIndex = entry.NameIndex;
lineNumber = li.getStartLine();
}
}
if (!nameIndex)
- return {"", 0};
+ return None;
StringRef filename = exitOnErr(getFileName(cVStrTab, checksums, *nameIndex));
- return {filename, *lineNumber};
+ return std::make_pair(filename, *lineNumber);
}
+
+} // namespace coff
+} // namespace lld
diff --git a/contrib/llvm-project/lld/COFF/PDB.h b/contrib/llvm-project/lld/COFF/PDB.h
index 3ac1adc85c5d..273609ea788c 100644
--- a/contrib/llvm-project/lld/COFF/PDB.h
+++ b/contrib/llvm-project/lld/COFF/PDB.h
@@ -10,6 +10,7 @@
#define LLD_COFF_PDB_H
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
namespace llvm {
@@ -29,9 +30,9 @@ void createPDB(SymbolTable *symtab,
llvm::ArrayRef<uint8_t> sectionTable,
llvm::codeview::DebugInfo *buildId);
-std::pair<llvm::StringRef, uint32_t> getFileLine(const SectionChunk *c,
- uint32_t addr);
-}
-}
+llvm::Optional<std::pair<llvm::StringRef, uint32_t>>
+getFileLineCodeView(const SectionChunk *c, uint32_t addr);
+} // namespace coff
+} // namespace lld
#endif
diff --git a/contrib/llvm-project/lld/COFF/SymbolTable.cpp b/contrib/llvm-project/lld/COFF/SymbolTable.cpp
index 3f3e6607479c..869dfc7a2ee5 100644
--- a/contrib/llvm-project/lld/COFF/SymbolTable.cpp
+++ b/contrib/llvm-project/lld/COFF/SymbolTable.cpp
@@ -15,6 +15,7 @@
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/Timer.h"
+#include "llvm/DebugInfo/Symbolize/Symbolize.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Object/WindowsMachineFlag.h"
#include "llvm/Support/Debug.h"
@@ -61,6 +62,24 @@ static void errorOrWarn(const Twine &s) {
error(s);
}
+// Causes the file associated with a lazy symbol to be linked in.
+static void forceLazy(Symbol *s) {
+ s->pendingArchiveLoad = true;
+ switch (s->kind()) {
+ case Symbol::Kind::LazyArchiveKind: {
+ auto *l = cast<LazyArchive>(s);
+ l->file->addMember(l->sym);
+ break;
+ }
+ case Symbol::Kind::LazyObjectKind:
+ cast<LazyObject>(s)->file->fetch();
+ break;
+ default:
+ llvm_unreachable(
+ "symbol passed to forceLazy is not a LazyArchive or LazyObject");
+ }
+}
+
// Returns the symbol in SC whose value is <= Addr that is closest to Addr.
// This is generally the global variable or function whose definition contains
// Addr.
@@ -69,7 +88,8 @@ static Symbol *getSymbol(SectionChunk *sc, uint32_t addr) {
for (Symbol *s : sc->file->getSymbols()) {
auto *d = dyn_cast_or_null<DefinedRegular>(s);
- if (!d || !d->data || d->getChunk() != sc || d->getValue() > addr ||
+ if (!d || !d->data || d->file != sc->file || d->getChunk() != sc ||
+ d->getValue() > addr ||
(candidate && d->getValue() < candidate->getValue()))
continue;
@@ -79,6 +99,38 @@ static Symbol *getSymbol(SectionChunk *sc, uint32_t addr) {
return candidate;
}
+static std::vector<std::string> getSymbolLocations(BitcodeFile *file) {
+ std::string res("\n>>> referenced by ");
+ StringRef source = file->obj->getSourceFileName();
+ if (!source.empty())
+ res += source.str() + "\n>>> ";
+ res += toString(file);
+ return {res};
+}
+
+static Optional<std::pair<StringRef, uint32_t>>
+getFileLineDwarf(const SectionChunk *c, uint32_t addr) {
+ Optional<DILineInfo> optionalLineInfo =
+ c->file->getDILineInfo(addr, c->getSectionNumber() - 1);
+ if (!optionalLineInfo)
+ return None;
+ const DILineInfo &lineInfo = *optionalLineInfo;
+ if (lineInfo.FileName == DILineInfo::BadString)
+ return None;
+ return std::make_pair(saver.save(lineInfo.FileName), lineInfo.Line);
+}
+
+static Optional<std::pair<StringRef, uint32_t>>
+getFileLine(const SectionChunk *c, uint32_t addr) {
+ // MinGW can optionally use codeview, even if the default is dwarf.
+ Optional<std::pair<StringRef, uint32_t>> fileLine =
+ getFileLineCodeView(c, addr);
+ // If codeview didn't yield any result, check dwarf in MinGW mode.
+ if (!fileLine && config->mingw)
+ fileLine = getFileLineDwarf(c, addr);
+ return fileLine;
+}
+
// Given a file and the index of a symbol in that file, returns a description
// of all references to that symbol from that file. If no debug information is
// available, returns just the name of the file, else one string per actual
@@ -97,11 +149,13 @@ std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex) {
for (const coff_relocation &r : sc->getRelocs()) {
if (r.SymbolTableIndex != symIndex)
continue;
- std::pair<StringRef, uint32_t> fileLine =
+ Optional<std::pair<StringRef, uint32_t>> fileLine =
getFileLine(sc, r.VirtualAddress);
Symbol *sym = getSymbol(sc, r.VirtualAddress);
- if (!fileLine.first.empty() || sym)
- locations.push_back({sym, fileLine});
+ if (fileLine)
+ locations.push_back({sym, *fileLine});
+ else if (sym)
+ locations.push_back({sym, {"", 0}});
}
}
@@ -123,13 +177,23 @@ std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex) {
return symbolLocations;
}
+std::vector<std::string> getSymbolLocations(InputFile *file,
+ uint32_t symIndex) {
+ if (auto *o = dyn_cast<ObjFile>(file))
+ return getSymbolLocations(o, symIndex);
+ if (auto *b = dyn_cast<BitcodeFile>(file))
+ return getSymbolLocations(b);
+ llvm_unreachable("unsupported file type passed to getSymbolLocations");
+ return {};
+}
+
// For an undefined symbol, stores all files referencing it and the index of
// the undefined symbol in each file.
struct UndefinedDiag {
Symbol *sym;
struct File {
- ObjFile *oFile;
- uint64_t symIndex;
+ InputFile *file;
+ uint32_t symIndex;
};
std::vector<File> files;
};
@@ -143,7 +207,7 @@ static void reportUndefinedSymbol(const UndefinedDiag &undefDiag) {
size_t i = 0, numRefs = 0;
for (const UndefinedDiag::File &ref : undefDiag.files) {
std::vector<std::string> symbolLocations =
- getSymbolLocations(ref.oFile, ref.symIndex);
+ getSymbolLocations(ref.file, ref.symIndex);
numRefs += symbolLocations.size();
for (const std::string &s : symbolLocations) {
if (i >= maxUndefReferences)
@@ -165,28 +229,33 @@ void SymbolTable::loadMinGWAutomaticImports() {
continue;
if (!sym->isUsedInRegularObj)
continue;
+ if (undef->getWeakAlias())
+ continue;
StringRef name = undef->getName();
if (name.startswith("__imp_"))
continue;
- // If we have an undefined symbol, but we have a Lazy representing a
- // symbol we could load from file, make sure to load that.
- Lazy *l = dyn_cast_or_null<Lazy>(find(("__imp_" + name).str()));
- if (!l || l->pendingArchiveLoad)
+ // If we have an undefined symbol, but we have a lazy symbol we could
+ // load, load it.
+ Symbol *l = find(("__imp_" + name).str());
+ if (!l || l->pendingArchiveLoad || !l->isLazy())
continue;
- log("Loading lazy " + l->getName() + " from " + l->file->getName() +
+ log("Loading lazy " + l->getName() + " from " + l->getFile()->getName() +
" for automatic import");
- l->pendingArchiveLoad = true;
- l->file->addMember(l->sym);
+ forceLazy(l);
}
}
-bool SymbolTable::handleMinGWAutomaticImport(Symbol *sym, StringRef name) {
+Defined *SymbolTable::impSymbol(StringRef name) {
if (name.startswith("__imp_"))
- return false;
- Defined *imp = dyn_cast_or_null<Defined>(find(("__imp_" + name).str()));
+ return nullptr;
+ return dyn_cast_or_null<Defined>(find(("__imp_" + name).str()));
+}
+
+bool SymbolTable::handleMinGWAutomaticImport(Symbol *sym, StringRef name) {
+ Defined *imp = impSymbol(name);
if (!imp)
return false;
@@ -232,7 +301,97 @@ bool SymbolTable::handleMinGWAutomaticImport(Symbol *sym, StringRef name) {
return true;
}
-void SymbolTable::reportRemainingUndefines() {
+/// Helper function for reportUnresolvable and resolveRemainingUndefines.
+/// This function emits an "undefined symbol" diagnostic for each symbol in
+/// undefs. If localImports is not nullptr, it also emits a "locally
+/// defined symbol imported" diagnostic for symbols in localImports.
+/// objFiles and bitcodeFiles (if not nullptr) are used to report where
+/// undefined symbols are referenced.
+static void
+reportProblemSymbols(const SmallPtrSetImpl<Symbol *> &undefs,
+ const DenseMap<Symbol *, Symbol *> *localImports,
+ const std::vector<ObjFile *> objFiles,
+ const std::vector<BitcodeFile *> *bitcodeFiles) {
+
+ // Return early if there is nothing to report (which should be
+ // the common case).
+ if (undefs.empty() && (!localImports || localImports->empty()))
+ return;
+
+ for (Symbol *b : config->gcroot) {
+ if (undefs.count(b))
+ errorOrWarn("<root>: undefined symbol: " + toString(*b));
+ if (localImports)
+ if (Symbol *imp = localImports->lookup(b))
+ warn("<root>: locally defined symbol imported: " + toString(*imp) +
+ " (defined in " + toString(imp->getFile()) + ") [LNK4217]");
+ }
+
+ std::vector<UndefinedDiag> undefDiags;
+ DenseMap<Symbol *, int> firstDiag;
+
+ auto processFile = [&](InputFile *file, ArrayRef<Symbol *> symbols) {
+ uint32_t symIndex = (uint32_t)-1;
+ for (Symbol *sym : symbols) {
+ ++symIndex;
+ if (!sym)
+ continue;
+ if (undefs.count(sym)) {
+ auto it = firstDiag.find(sym);
+ if (it == firstDiag.end()) {
+ firstDiag[sym] = undefDiags.size();
+ undefDiags.push_back({sym, {{file, symIndex}}});
+ } else {
+ undefDiags[it->second].files.push_back({file, symIndex});
+ }
+ }
+ if (localImports)
+ if (Symbol *imp = localImports->lookup(sym))
+ warn(toString(file) +
+ ": locally defined symbol imported: " + toString(*imp) +
+ " (defined in " + toString(imp->getFile()) + ") [LNK4217]");
+ }
+ };
+
+ for (ObjFile *file : objFiles)
+ processFile(file, file->getSymbols());
+
+ if (bitcodeFiles)
+ for (BitcodeFile *file : *bitcodeFiles)
+ processFile(file, file->getSymbols());
+
+ for (const UndefinedDiag &undefDiag : undefDiags)
+ reportUndefinedSymbol(undefDiag);
+}
+
+void SymbolTable::reportUnresolvable() {
+ SmallPtrSet<Symbol *, 8> undefs;
+ for (auto &i : symMap) {
+ Symbol *sym = i.second;
+ auto *undef = dyn_cast<Undefined>(sym);
+ if (!undef)
+ continue;
+ if (undef->getWeakAlias())
+ continue;
+ StringRef name = undef->getName();
+ if (name.startswith("__imp_")) {
+ Symbol *imp = find(name.substr(strlen("__imp_")));
+ if (imp && isa<Defined>(imp))
+ continue;
+ }
+ if (name.contains("_PchSym_"))
+ continue;
+ if (config->mingw && impSymbol(name))
+ continue;
+ undefs.insert(sym);
+ }
+
+ reportProblemSymbols(undefs,
+ /* localImports */ nullptr, ObjFile::instances,
+ &BitcodeFile::instances);
+}
+
+void SymbolTable::resolveRemainingUndefines() {
SmallPtrSet<Symbol *, 8> undefs;
DenseMap<Symbol *, Symbol *> localImports;
@@ -290,46 +449,9 @@ void SymbolTable::reportRemainingUndefines() {
undefs.insert(sym);
}
- if (undefs.empty() && localImports.empty())
- return;
-
- for (Symbol *b : config->gcroot) {
- if (undefs.count(b))
- errorOrWarn("<root>: undefined symbol: " + toString(*b));
- if (config->warnLocallyDefinedImported)
- if (Symbol *imp = localImports.lookup(b))
- warn("<root>: locally defined symbol imported: " + toString(*imp) +
- " (defined in " + toString(imp->getFile()) + ") [LNK4217]");
- }
-
- std::vector<UndefinedDiag> undefDiags;
- DenseMap<Symbol *, int> firstDiag;
-
- for (ObjFile *file : ObjFile::instances) {
- size_t symIndex = (size_t)-1;
- for (Symbol *sym : file->getSymbols()) {
- ++symIndex;
- if (!sym)
- continue;
- if (undefs.count(sym)) {
- auto it = firstDiag.find(sym);
- if (it == firstDiag.end()) {
- firstDiag[sym] = undefDiags.size();
- undefDiags.push_back({sym, {{file, symIndex}}});
- } else {
- undefDiags[it->second].files.push_back({file, symIndex});
- }
- }
- if (config->warnLocallyDefinedImported)
- if (Symbol *imp = localImports.lookup(sym))
- warn(toString(file) +
- ": locally defined symbol imported: " + toString(*imp) +
- " (defined in " + toString(imp->getFile()) + ") [LNK4217]");
- }
- }
-
- for (const UndefinedDiag& undefDiag : undefDiags)
- reportUndefinedSymbol(undefDiag);
+ reportProblemSymbols(
+ undefs, config->warnLocallyDefinedImported ? &localImports : nullptr,
+ ObjFile::instances, /* bitcode files no longer needed */ nullptr);
}
std::pair<Symbol *, bool> SymbolTable::insert(StringRef name) {
@@ -356,26 +478,22 @@ Symbol *SymbolTable::addUndefined(StringRef name, InputFile *f,
Symbol *s;
bool wasInserted;
std::tie(s, wasInserted) = insert(name, f);
- if (wasInserted || (isa<Lazy>(s) && isWeakAlias)) {
+ if (wasInserted || (s->isLazy() && isWeakAlias)) {
replaceSymbol<Undefined>(s, name);
return s;
}
- if (auto *l = dyn_cast<Lazy>(s)) {
- if (!s->pendingArchiveLoad) {
- s->pendingArchiveLoad = true;
- l->file->addMember(l->sym);
- }
- }
+ if (s->isLazy())
+ forceLazy(s);
return s;
}
-void SymbolTable::addLazy(ArchiveFile *f, const Archive::Symbol &sym) {
+void SymbolTable::addLazyArchive(ArchiveFile *f, const Archive::Symbol &sym) {
StringRef name = sym.getName();
Symbol *s;
bool wasInserted;
std::tie(s, wasInserted) = insert(name);
if (wasInserted) {
- replaceSymbol<Lazy>(s, f, sym);
+ replaceSymbol<LazyArchive>(s, f, sym);
return;
}
auto *u = dyn_cast<Undefined>(s);
@@ -385,15 +503,84 @@ void SymbolTable::addLazy(ArchiveFile *f, const Archive::Symbol &sym) {
f->addMember(sym);
}
-void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile) {
- std::string msg = "duplicate symbol: " + toString(*existing) + " in " +
- toString(existing->getFile()) + " and in " +
- toString(newFile);
+void SymbolTable::addLazyObject(LazyObjFile *f, StringRef n) {
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(n, f);
+ if (wasInserted) {
+ replaceSymbol<LazyObject>(s, f, n);
+ return;
+ }
+ auto *u = dyn_cast<Undefined>(s);
+ if (!u || u->weakAlias || s->pendingArchiveLoad)
+ return;
+ s->pendingArchiveLoad = true;
+ f->fetch();
+}
+
+static std::string getSourceLocationBitcode(BitcodeFile *file) {
+ std::string res("\n>>> defined at ");
+ StringRef source = file->obj->getSourceFileName();
+ if (!source.empty())
+ res += source.str() + "\n>>> ";
+ res += toString(file);
+ return res;
+}
+
+static std::string getSourceLocationObj(ObjFile *file, SectionChunk *sc,
+ uint32_t offset, StringRef name) {
+ Optional<std::pair<StringRef, uint32_t>> fileLine;
+ if (sc)
+ fileLine = getFileLine(sc, offset);
+ if (!fileLine)
+ fileLine = file->getVariableLocation(name);
+
+ std::string res;
+ llvm::raw_string_ostream os(res);
+ os << "\n>>> defined at ";
+ if (fileLine)
+ os << fileLine->first << ":" << fileLine->second << "\n>>> ";
+ os << toString(file);
+ return os.str();
+}
+
+static std::string getSourceLocation(InputFile *file, SectionChunk *sc,
+ uint32_t offset, StringRef name) {
+ if (auto *o = dyn_cast<ObjFile>(file))
+ return getSourceLocationObj(o, sc, offset, name);
+ if (auto *b = dyn_cast<BitcodeFile>(file))
+ return getSourceLocationBitcode(b);
+ return "\n>>> defined at " + toString(file);
+}
+
+// Construct and print an error message in the form of:
+//
+// lld-link: error: duplicate symbol: foo
+// >>> defined at bar.c:30
+// >>> bar.o
+// >>> defined at baz.c:563
+// >>> baz.o
+void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile,
+ SectionChunk *newSc,
+ uint32_t newSectionOffset) {
+ std::string msg;
+ llvm::raw_string_ostream os(msg);
+ os << "duplicate symbol: " << toString(*existing);
+
+ DefinedRegular *d = cast<DefinedRegular>(existing);
+ if (d && isa<ObjFile>(d->getFile())) {
+ os << getSourceLocation(d->getFile(), d->getChunk(), d->getValue(),
+ existing->getName());
+ } else {
+ os << getSourceLocation(existing->getFile(), nullptr, 0, "");
+ }
+ os << getSourceLocation(newFile, newSc, newSectionOffset,
+ existing->getName());
if (config->forceMultiple)
- warn(msg);
+ warn(os.str());
else
- error(msg);
+ error(os.str());
}
Symbol *SymbolTable::addAbsolute(StringRef n, COFFSymbolRef sym) {
@@ -401,7 +588,7 @@ Symbol *SymbolTable::addAbsolute(StringRef n, COFFSymbolRef sym) {
bool wasInserted;
std::tie(s, wasInserted) = insert(n, nullptr);
s->isUsedInRegularObj = true;
- if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s))
+ if (wasInserted || isa<Undefined>(s) || s->isLazy())
replaceSymbol<DefinedAbsolute>(s, n, sym);
else if (!isa<DefinedCOFF>(s))
reportDuplicate(s, nullptr);
@@ -413,7 +600,7 @@ Symbol *SymbolTable::addAbsolute(StringRef n, uint64_t va) {
bool wasInserted;
std::tie(s, wasInserted) = insert(n, nullptr);
s->isUsedInRegularObj = true;
- if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s))
+ if (wasInserted || isa<Undefined>(s) || s->isLazy())
replaceSymbol<DefinedAbsolute>(s, n, va);
else if (!isa<DefinedCOFF>(s))
reportDuplicate(s, nullptr);
@@ -425,7 +612,7 @@ Symbol *SymbolTable::addSynthetic(StringRef n, Chunk *c) {
bool wasInserted;
std::tie(s, wasInserted) = insert(n, nullptr);
s->isUsedInRegularObj = true;
- if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s))
+ if (wasInserted || isa<Undefined>(s) || s->isLazy())
replaceSymbol<DefinedSynthetic>(s, n, c);
else if (!isa<DefinedCOFF>(s))
reportDuplicate(s, nullptr);
@@ -433,8 +620,8 @@ Symbol *SymbolTable::addSynthetic(StringRef n, Chunk *c) {
}
Symbol *SymbolTable::addRegular(InputFile *f, StringRef n,
- const coff_symbol_generic *sym,
- SectionChunk *c) {
+ const coff_symbol_generic *sym, SectionChunk *c,
+ uint32_t sectionOffset) {
Symbol *s;
bool wasInserted;
std::tie(s, wasInserted) = insert(n, f);
@@ -442,7 +629,7 @@ Symbol *SymbolTable::addRegular(InputFile *f, StringRef n,
replaceSymbol<DefinedRegular>(s, f, n, /*IsCOMDAT*/ false,
/*IsExternal*/ true, sym, c);
else
- reportDuplicate(s, f);
+ reportDuplicate(s, f, c, sectionOffset);
return s;
}
@@ -481,7 +668,7 @@ Symbol *SymbolTable::addImportData(StringRef n, ImportFile *f) {
bool wasInserted;
std::tie(s, wasInserted) = insert(n, nullptr);
s->isUsedInRegularObj = true;
- if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s)) {
+ if (wasInserted || isa<Undefined>(s) || s->isLazy()) {
replaceSymbol<DefinedImportData>(s, n, f);
return s;
}
@@ -496,7 +683,7 @@ Symbol *SymbolTable::addImportThunk(StringRef name, DefinedImportData *id,
bool wasInserted;
std::tie(s, wasInserted) = insert(name, nullptr);
s->isUsedInRegularObj = true;
- if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s)) {
+ if (wasInserted || isa<Undefined>(s) || s->isLazy()) {
replaceSymbol<DefinedImportThunk>(s, name, id, machine);
return s;
}
@@ -510,9 +697,12 @@ void SymbolTable::addLibcall(StringRef name) {
if (!sym)
return;
- if (Lazy *l = dyn_cast<Lazy>(sym)) {
+ if (auto *l = dyn_cast<LazyArchive>(sym)) {
MemoryBufferRef mb = l->getMemberBuffer();
- if (identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode)
+ if (isBitcode(mb))
+ addUndefined(sym->getName());
+ } else if (LazyObject *o = dyn_cast<LazyObject>(sym)) {
+ if (isBitcode(o->file->mb))
addUndefined(sym->getName());
}
}
diff --git a/contrib/llvm-project/lld/COFF/SymbolTable.h b/contrib/llvm-project/lld/COFF/SymbolTable.h
index f0a7aaf35a0e..cd8a53dcecdc 100644
--- a/contrib/llvm-project/lld/COFF/SymbolTable.h
+++ b/contrib/llvm-project/lld/COFF/SymbolTable.h
@@ -29,7 +29,7 @@ class Defined;
class DefinedAbsolute;
class DefinedRegular;
class DefinedRelative;
-class Lazy;
+class LazyArchive;
class SectionChunk;
class Symbol;
@@ -49,10 +49,13 @@ class SymbolTable {
public:
void addFile(InputFile *file);
+ // Emit errors for symbols that cannot be resolved.
+ void reportUnresolvable();
+
// Try to resolve any undefined symbols and update the symbol table
// accordingly, then print an error message for any remaining undefined
- // symbols.
- void reportRemainingUndefines();
+ // symbols and warn about imported local symbols.
+ void resolveRemainingUndefines();
void loadMinGWAutomaticImports();
bool handleMinGWAutomaticImport(Symbol *sym, StringRef name);
@@ -83,11 +86,12 @@ public:
Symbol *addAbsolute(StringRef n, uint64_t va);
Symbol *addUndefined(StringRef name, InputFile *f, bool isWeakAlias);
- void addLazy(ArchiveFile *f, const Archive::Symbol &sym);
+ void addLazyArchive(ArchiveFile *f, const Archive::Symbol &sym);
+ void addLazyObject(LazyObjFile *f, StringRef n);
Symbol *addAbsolute(StringRef n, COFFSymbolRef s);
Symbol *addRegular(InputFile *f, StringRef n,
const llvm::object::coff_symbol_generic *s = nullptr,
- SectionChunk *c = nullptr);
+ SectionChunk *c = nullptr, uint32_t sectionOffset = 0);
std::pair<DefinedRegular *, bool>
addComdat(InputFile *f, StringRef n,
const llvm::object::coff_symbol_generic *s = nullptr);
@@ -99,7 +103,9 @@ public:
uint16_t machine);
void addLibcall(StringRef name);
- void reportDuplicate(Symbol *existing, InputFile *newFile);
+ void reportDuplicate(Symbol *existing, InputFile *newFile,
+ SectionChunk *newSc = nullptr,
+ uint32_t newSectionOffset = 0);
// A list of chunks which to be added to .rdata.
std::vector<Chunk *> localImportChunks;
@@ -111,6 +117,9 @@ public:
}
private:
+ /// Given a name without "__imp_" prefix, returns a defined symbol
+ /// with the "__imp_" prefix, if it exists.
+ Defined *impSymbol(StringRef name);
/// Inserts symbol if not already present.
std::pair<Symbol *, bool> insert(StringRef name);
/// Same as insert(Name), but also sets isUsedInRegularObj.
diff --git a/contrib/llvm-project/lld/COFF/Symbols.cpp b/contrib/llvm-project/lld/COFF/Symbols.cpp
index 1af11820a7e6..938c9c527ffa 100644
--- a/contrib/llvm-project/lld/COFF/Symbols.cpp
+++ b/contrib/llvm-project/lld/COFF/Symbols.cpp
@@ -12,6 +12,7 @@
#include "lld/Common/Memory.h"
#include "lld/Common/Strings.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Demangle/Demangle.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@@ -26,15 +27,27 @@ static_assert(sizeof(SymbolUnion) <= 48,
"symbols should be optimized for memory usage");
// Returns a symbol name for an error message.
-static std::string demangle(StringRef symName) {
- if (config->demangle)
- if (Optional<std::string> s = demangleMSVC(symName))
- return *s;
+static std::string maybeDemangleSymbol(StringRef symName) {
+ if (config->demangle) {
+ std::string prefix;
+ StringRef prefixless = symName;
+ if (prefixless.consume_front("__imp_"))
+ prefix = "__declspec(dllimport) ";
+ StringRef demangleInput = prefixless;
+ if (config->machine == I386)
+ demangleInput.consume_front("_");
+ std::string demangled = demangle(demangleInput);
+ if (demangled != demangleInput)
+ return prefix + demangle(demangleInput);
+ return (prefix + prefixless).str();
+ }
return symName;
}
-std::string toString(coff::Symbol &b) { return demangle(b.getName()); }
+std::string toString(coff::Symbol &b) {
+ return maybeDemangleSymbol(b.getName());
+}
std::string toCOFFString(const Archive::Symbol &b) {
- return demangle(b.getName());
+ return maybeDemangleSymbol(b.getName());
}
namespace coff {
@@ -61,7 +74,9 @@ StringRef Symbol::getName() {
InputFile *Symbol::getFile() {
if (auto *sym = dyn_cast<DefinedCOFF>(this))
return sym->file;
- if (auto *sym = dyn_cast<Lazy>(this))
+ if (auto *sym = dyn_cast<LazyArchive>(this))
+ return sym->file;
+ if (auto *sym = dyn_cast<LazyObject>(this))
return sym->file;
return nullptr;
}
@@ -119,7 +134,7 @@ Defined *Undefined::getWeakAlias() {
return nullptr;
}
-MemoryBufferRef Lazy::getMemberBuffer() {
+MemoryBufferRef LazyArchive::getMemberBuffer() {
Archive::Child c =
CHECK(sym.getMember(),
"could not get the member for symbol " + toCOFFString(sym));
diff --git a/contrib/llvm-project/lld/COFF/Symbols.h b/contrib/llvm-project/lld/COFF/Symbols.h
index 78c357aa2a58..fd79bd5065b1 100644
--- a/contrib/llvm-project/lld/COFF/Symbols.h
+++ b/contrib/llvm-project/lld/COFF/Symbols.h
@@ -59,7 +59,8 @@ public:
DefinedSyntheticKind,
UndefinedKind,
- LazyKind,
+ LazyArchiveKind,
+ LazyObjectKind,
LastDefinedCOFFKind = DefinedCommonKind,
LastDefinedKind = DefinedSyntheticKind,
@@ -79,6 +80,10 @@ public:
// after calling markLive.
bool isLive() const;
+ bool isLazy() const {
+ return symbolKind == LazyArchiveKind || symbolKind == LazyObjectKind;
+ }
+
protected:
friend SymbolTable;
explicit Symbol(Kind k, StringRef n = "")
@@ -256,26 +261,29 @@ private:
// This class represents a symbol defined in an archive file. It is
// created from an archive file header, and it knows how to load an
// object file from an archive to replace itself with a defined
-// symbol. If the resolver finds both Undefined and Lazy for
-// the same name, it will ask the Lazy to load a file.
-class Lazy : public Symbol {
+// symbol. If the resolver finds both Undefined and LazyArchive for
+// the same name, it will ask the LazyArchive to load a file.
+class LazyArchive : public Symbol {
public:
- Lazy(ArchiveFile *f, const Archive::Symbol s)
- : Symbol(LazyKind, s.getName()), file(f), sym(s) {}
+ LazyArchive(ArchiveFile *f, const Archive::Symbol s)
+ : Symbol(LazyArchiveKind, s.getName()), file(f), sym(s) {}
- static bool classof(const Symbol *s) { return s->kind() == LazyKind; }
+ static bool classof(const Symbol *s) { return s->kind() == LazyArchiveKind; }
MemoryBufferRef getMemberBuffer();
ArchiveFile *file;
-
-private:
- friend SymbolTable;
-
-private:
const Archive::Symbol sym;
};
+class LazyObject : public Symbol {
+public:
+ LazyObject(LazyObjFile *f, StringRef n)
+ : Symbol(LazyObjectKind, n), file(f) {}
+ static bool classof(const Symbol *s) { return s->kind() == LazyObjectKind; }
+ LazyObjFile *file;
+};
+
// Undefined symbols.
class Undefined : public Symbol {
public:
@@ -381,7 +389,8 @@ inline uint64_t Defined::getRVA() {
return cast<DefinedCommon>(this)->getRVA();
case DefinedRegularKind:
return cast<DefinedRegular>(this)->getRVA();
- case LazyKind:
+ case LazyArchiveKind:
+ case LazyObjectKind:
case UndefinedKind:
llvm_unreachable("Cannot get the address for an undefined symbol.");
}
@@ -404,7 +413,8 @@ inline Chunk *Defined::getChunk() {
return cast<DefinedLocalImport>(this)->getChunk();
case DefinedCommonKind:
return cast<DefinedCommon>(this)->getChunk();
- case LazyKind:
+ case LazyArchiveKind:
+ case LazyObjectKind:
case UndefinedKind:
llvm_unreachable("Cannot get the chunk of an undefined symbol.");
}
@@ -419,11 +429,12 @@ union SymbolUnion {
alignas(DefinedCommon) char b[sizeof(DefinedCommon)];
alignas(DefinedAbsolute) char c[sizeof(DefinedAbsolute)];
alignas(DefinedSynthetic) char d[sizeof(DefinedSynthetic)];
- alignas(Lazy) char e[sizeof(Lazy)];
+ alignas(LazyArchive) char e[sizeof(LazyArchive)];
alignas(Undefined) char f[sizeof(Undefined)];
alignas(DefinedImportData) char g[sizeof(DefinedImportData)];
alignas(DefinedImportThunk) char h[sizeof(DefinedImportThunk)];
alignas(DefinedLocalImport) char i[sizeof(DefinedLocalImport)];
+ alignas(LazyObject) char j[sizeof(LazyObject)];
};
template <typename T, typename... ArgT>
diff --git a/contrib/llvm-project/lld/COFF/Writer.cpp b/contrib/llvm-project/lld/COFF/Writer.cpp
index 5736281958fa..9729c6938ec8 100644
--- a/contrib/llvm-project/lld/COFF/Writer.cpp
+++ b/contrib/llvm-project/lld/COFF/Writer.cpp
@@ -40,8 +40,9 @@ using namespace llvm::COFF;
using namespace llvm::object;
using namespace llvm::support;
using namespace llvm::support::endian;
-using namespace lld;
-using namespace lld::coff;
+
+namespace lld {
+namespace coff {
/* To re-generate DOSProgram:
$ cat > /tmp/DOSProgram.asm
@@ -240,6 +241,8 @@ private:
IdataContents idata;
Chunk *importTableStart = nullptr;
uint64_t importTableSize = 0;
+ Chunk *edataStart = nullptr;
+ Chunk *edataEnd = nullptr;
Chunk *iatStart = nullptr;
uint64_t iatSize = 0;
DelayLoadContents delayIdata;
@@ -283,9 +286,6 @@ private:
};
} // anonymous namespace
-namespace lld {
-namespace coff {
-
static Timer codeLayoutTimer("Code Layout", Timer::root());
static Timer diskCommitTimer("Commit Output File", Timer::root());
@@ -331,9 +331,6 @@ void OutputSection::addContributingPartialSection(PartialSection *sec) {
contribSections.push_back(sec);
}
-} // namespace coff
-} // namespace lld
-
// Check whether the target address S is in range from a relocation
// of type relType at address P.
static bool isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin) {
@@ -741,7 +738,8 @@ void Writer::addSyntheticIdata() {
add(".idata$2", idata.dirs);
add(".idata$4", idata.lookups);
add(".idata$5", idata.addresses);
- add(".idata$6", idata.hints);
+ if (!idata.hints.empty())
+ add(".idata$6", idata.hints);
add(".idata$7", idata.dllNames);
}
@@ -840,6 +838,7 @@ void Writer::createSections() {
}
fixPartialSectionChars(".rsrc", data | r);
+ fixPartialSectionChars(".edata", data | r);
// Even in non MinGW cases, we might need to link against GNU import
// libraries.
bool hasIdata = fixGnuImportChunks();
@@ -1014,10 +1013,19 @@ void Writer::appendImportThunks() {
}
void Writer::createExportTable() {
- if (config->exports.empty())
- return;
- for (Chunk *c : edata.chunks)
- edataSec->addChunk(c);
+ if (!edataSec->chunks.empty()) {
+ // Allow using a custom built export table from input object files, instead
+ // of having the linker synthesize the tables.
+ if (config->hadExplicitExports)
+ warn("literal .edata sections override exports");
+ } else if (!config->exports.empty()) {
+ for (Chunk *c : edata.chunks)
+ edataSec->addChunk(c);
+ }
+ if (!edataSec->chunks.empty()) {
+ edataStart = edataSec->chunks.front();
+ edataEnd = edataSec->chunks.back();
+ }
}
void Writer::removeUnusedSections() {
@@ -1366,9 +1374,10 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
// Write data directory
auto *dir = reinterpret_cast<data_directory *>(buf);
buf += sizeof(*dir) * numberOfDataDirectory;
- if (!config->exports.empty()) {
- dir[EXPORT_TABLE].RelativeVirtualAddress = edata.getRVA();
- dir[EXPORT_TABLE].Size = edata.getSize();
+ if (edataStart) {
+ dir[EXPORT_TABLE].RelativeVirtualAddress = edataStart->getRVA();
+ dir[EXPORT_TABLE].Size =
+ edataEnd->getRVA() + edataEnd->getSize() - edataStart->getRVA();
}
if (importTableStart) {
dir[IMPORT_TABLE].RelativeVirtualAddress = importTableStart->getRVA();
@@ -1506,7 +1515,8 @@ static void maybeAddAddressTakenFunction(SymbolRVASet &addressTakenSyms,
// Absolute is never code, synthetic generally isn't and usually isn't
// determinable.
break;
- case Symbol::LazyKind:
+ case Symbol::LazyArchiveKind:
+ case Symbol::LazyObjectKind:
case Symbol::UndefinedKind:
// Undefined symbols resolve to zero, so they don't have an RVA. Lazy
// symbols shouldn't have relocations.
@@ -1930,3 +1940,6 @@ PartialSection *Writer::findPartialSection(StringRef name, uint32_t outChars) {
return it->second;
return nullptr;
}
+
+} // namespace coff
+} // namespace lld
diff --git a/contrib/llvm-project/lld/Common/CMakeLists.txt b/contrib/llvm-project/lld/Common/CMakeLists.txt
index 70849cc7b94b..1a04a8074bed 100644
--- a/contrib/llvm-project/lld/Common/CMakeLists.txt
+++ b/contrib/llvm-project/lld/Common/CMakeLists.txt
@@ -29,6 +29,7 @@ set_property(SOURCE Version.cpp APPEND PROPERTY
add_lld_library(lldCommon
Args.cpp
+ DWARF.cpp
ErrorHandler.cpp
Filesystem.cpp
Memory.cpp
@@ -46,6 +47,7 @@ add_lld_library(lldCommon
LINK_COMPONENTS
Codegen
Core
+ DebugInfoDWARF
Demangle
MC
Option
diff --git a/contrib/llvm-project/lld/Common/DWARF.cpp b/contrib/llvm-project/lld/Common/DWARF.cpp
new file mode 100644
index 000000000000..077adbcaf858
--- /dev/null
+++ b/contrib/llvm-project/lld/Common/DWARF.cpp
@@ -0,0 +1,103 @@
+//===- DWARF.cpp ----------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Common/DWARF.h"
+#include "lld/Common/ErrorHandler.h"
+
+using namespace llvm;
+
+namespace lld {
+
+DWARFCache::DWARFCache(std::unique_ptr<llvm::DWARFContext> d)
+ : dwarf(std::move(d)) {
+ for (std::unique_ptr<DWARFUnit> &cu : dwarf->compile_units()) {
+ auto report = [](Error err) {
+ handleAllErrors(std::move(err),
+ [](ErrorInfoBase &info) { warn(info.message()); });
+ };
+ Expected<const DWARFDebugLine::LineTable *> expectedLT =
+ dwarf->getLineTableForUnit(cu.get(), report);
+ const DWARFDebugLine::LineTable *lt = nullptr;
+ if (expectedLT)
+ lt = *expectedLT;
+ else
+ report(expectedLT.takeError());
+ if (!lt)
+ continue;
+ lineTables.push_back(lt);
+
+ // Loop over variable records and insert them to variableLoc.
+ for (const auto &entry : cu->dies()) {
+ DWARFDie die(cu.get(), &entry);
+ // Skip all tags that are not variables.
+ if (die.getTag() != dwarf::DW_TAG_variable)
+ continue;
+
+ // Skip if a local variable because we don't need them for generating
+ // error messages. In general, only non-local symbols can fail to be
+ // linked.
+ if (!dwarf::toUnsigned(die.find(dwarf::DW_AT_external), 0))
+ continue;
+
+ // Get the source filename index for the variable.
+ unsigned file = dwarf::toUnsigned(die.find(dwarf::DW_AT_decl_file), 0);
+ if (!lt->hasFileAtIndex(file))
+ continue;
+
+ // Get the line number on which the variable is declared.
+ unsigned line = dwarf::toUnsigned(die.find(dwarf::DW_AT_decl_line), 0);
+
+ // Here we want to take the variable name to add it into variableLoc.
+ // Variable can have regular and linkage name associated. At first, we try
+ // to get linkage name as it can be different, for example when we have
+ // two variables in different namespaces of the same object. Use common
+ // name otherwise, but handle the case when it also absent in case if the
+ // input object file lacks some debug info.
+ StringRef name =
+ dwarf::toString(die.find(dwarf::DW_AT_linkage_name),
+ dwarf::toString(die.find(dwarf::DW_AT_name), ""));
+ if (!name.empty())
+ variableLoc.insert({name, {lt, file, line}});
+ }
+ }
+}
+
+// Returns the pair of file name and line number describing location of data
+// object (variable, array, etc) definition.
+Optional<std::pair<std::string, unsigned>>
+DWARFCache::getVariableLoc(StringRef name) {
+ // Return if we have no debug information about data object.
+ auto it = variableLoc.find(name);
+ if (it == variableLoc.end())
+ return None;
+
+ // Take file name string from line table.
+ std::string fileName;
+ if (!it->second.lt->getFileNameByIndex(
+ it->second.file, {},
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, fileName))
+ return None;
+
+ return std::make_pair(fileName, it->second.line);
+}
+
+// Returns source line information for a given offset
+// using DWARF debug info.
+Optional<DILineInfo> DWARFCache::getDILineInfo(uint64_t offset,
+ uint64_t sectionIndex) {
+ DILineInfo info;
+ for (const llvm::DWARFDebugLine::LineTable *lt : lineTables) {
+ if (lt->getFileLineInfoForAddress(
+ {offset, sectionIndex}, nullptr,
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, info))
+ return info;
+ }
+ return None;
+}
+
+} // namespace lld
diff --git a/contrib/llvm-project/lld/Common/ErrorHandler.cpp b/contrib/llvm-project/lld/Common/ErrorHandler.cpp
index c87c0609b260..b91854c51cef 100644
--- a/contrib/llvm-project/lld/Common/ErrorHandler.cpp
+++ b/contrib/llvm-project/lld/Common/ErrorHandler.cpp
@@ -29,16 +29,14 @@ using namespace lld;
// but outs() or errs() are not thread-safe. We protect them using a mutex.
static std::mutex mu;
-// Prints "\n" or does nothing, depending on Msg contents of
-// the previous call of this function.
-static void newline(raw_ostream *errorOS, const Twine &msg) {
- // True if the previous error message contained "\n".
- // We want to separate multi-line error messages with a newline.
- static bool flag;
-
- if (flag)
- *errorOS << "\n";
- flag = StringRef(msg.str()).contains('\n');
+// We want to separate multi-line messages with a newline. `sep` is "\n"
+// if the last messages was multi-line. Otherwise "".
+static StringRef sep;
+
+static StringRef getSeparator(const Twine &msg) {
+ if (StringRef(msg.str()).contains('\n'))
+ return "\n";
+ return "";
}
ErrorHandler &lld::errorHandler() {
@@ -46,6 +44,10 @@ ErrorHandler &lld::errorHandler() {
return handler;
}
+void lld::enableColors(bool enable) {
+ errorHandler().errorOS->enable_colors(enable);
+}
+
void lld::exitLld(int val) {
// Delete any temporary file, while keeping the memory mapping open.
if (errorHandler().outputBuffer)
@@ -85,56 +87,69 @@ void lld::checkError(Error e) {
[&](ErrorInfoBase &eib) { error(eib.message()); });
}
-static std::string getLocation(std::string msg, std::string defaultMsg) {
- static std::vector<std::regex> Regexes{
- std::regex(R"(^undefined symbol:.*\n>>> referenced by (\S+):(\d+)\n.*)"),
+// This is for --vs-diagnostics.
+//
+// Normally, lld's error message starts with argv[0]. Therefore, it usually
+// looks like this:
+//
+// ld.lld: error: ...
+//
+// This error message style is unfortunately unfriendly to Visual Studio
+// IDE. VS interprets the first word of the first line as an error location
+// and make it clickable, thus "ld.lld" in the above message would become a
+// clickable text. When you click it, VS opens "ld.lld" executable file with
+// a binary editor.
+//
+// As a workaround, we print out an error location instead of "ld.lld" if
+// lld is running in VS diagnostics mode. As a result, error message will
+// look like this:
+//
+// src/foo.c(35): error: ...
+//
+// This function returns an error location string. An error location is
+// extracted from an error message using regexps.
+std::string ErrorHandler::getLocation(const Twine &msg) {
+ if (!vsDiagnostics)
+ return logName;
+
+ static std::regex regexes[] = {
+ std::regex(
+ R"(^undefined (?:\S+ )?symbol:.*\n)"
+ R"(>>> referenced by .+\((\S+):(\d+)\))"),
+ std::regex(
+ R"(^undefined (?:\S+ )?symbol:.*\n>>> referenced by (\S+):(\d+))"),
std::regex(R"(^undefined symbol:.*\n>>> referenced by (.*):)"),
std::regex(
R"(^duplicate symbol: .*\n>>> defined in (\S+)\n>>> defined in.*)"),
std::regex(
- R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+).*)"),
- std::regex(
- R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"),
+ R"(^duplicate symbol: .*\n>>> defined at .+\((\S+):(\d+)\))"),
+ std::regex(R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+))"),
std::regex(
- R"(^undefined (internal|hidden|protected) symbol: .*\n>>> referenced by (\S+):(\d+)\n.*)"),
+ R"(.*\n>>> defined in .*\n>>> referenced by .+\((\S+):(\d+)\))"),
+ std::regex(R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"),
std::regex(R"((\S+):(\d+): unclosed quote)"),
};
- std::smatch Match;
- for (std::regex &Re : Regexes) {
- if (std::regex_search(msg, Match, Re)) {
- return Match.size() > 2 ? Match.str(1) + "(" + Match.str(2) + ")"
- : Match.str(1);
- }
- }
- return defaultMsg;
-}
-
-void ErrorHandler::printHeader(StringRef s, raw_ostream::Colors c,
- const Twine &msg) {
+ std::string str = msg.str();
+ for (std::regex &re : regexes) {
+ std::smatch m;
+ if (!std::regex_search(str, m, re))
+ continue;
- if (vsDiagnostics) {
- // A Visual Studio-style error message starts with an error location.
- // If a location cannot be extracted then we default to LogName.
- *errorOS << getLocation(msg.str(), logName) << ": ";
- } else {
- *errorOS << logName << ": ";
+ assert(m.size() == 2 || m.size() == 3);
+ if (m.size() == 2)
+ return m.str(1);
+ return m.str(1) + "(" + m.str(2) + ")";
}
- if (colorDiagnostics) {
- errorOS->changeColor(c, true);
- *errorOS << s;
- errorOS->resetColor();
- } else {
- *errorOS << s;
- }
+ return logName;
}
void ErrorHandler::log(const Twine &msg) {
- if (verbose) {
- std::lock_guard<std::mutex> lock(mu);
- *errorOS << logName << ": " << msg << "\n";
- }
+ if (!verbose)
+ return;
+ std::lock_guard<std::mutex> lock(mu);
+ *errorOS << logName << ": " << msg << "\n";
}
void ErrorHandler::message(const Twine &msg) {
@@ -150,25 +165,41 @@ void ErrorHandler::warn(const Twine &msg) {
}
std::lock_guard<std::mutex> lock(mu);
- newline(errorOS, msg);
- printHeader("warning: ", raw_ostream::MAGENTA, msg);
- *errorOS << msg << "\n";
+ *errorOS << sep << getLocation(msg) << ": " << Colors::MAGENTA
+ << "warning: " << Colors::RESET << msg << "\n";
+ sep = getSeparator(msg);
}
void ErrorHandler::error(const Twine &msg) {
+ // If Visual Studio-style error message mode is enabled,
+ // this particular error is printed out as two errors.
+ if (vsDiagnostics) {
+ static std::regex re(R"(^(duplicate symbol: .*))"
+ R"((\n>>> defined at \S+:\d+.*\n>>>.*))"
+ R"((\n>>> defined at \S+:\d+.*\n>>>.*))");
+ std::string str = msg.str();
+ std::smatch m;
+
+ if (std::regex_match(str, m, re)) {
+ error(m.str(1) + m.str(2));
+ error(m.str(1) + m.str(3));
+ return;
+ }
+ }
+
std::lock_guard<std::mutex> lock(mu);
- newline(errorOS, msg);
if (errorLimit == 0 || errorCount < errorLimit) {
- printHeader("error: ", raw_ostream::RED, msg);
- *errorOS << msg << "\n";
+ *errorOS << sep << getLocation(msg) << ": " << Colors::RED
+ << "error: " << Colors::RESET << msg << "\n";
} else if (errorCount == errorLimit) {
- printHeader("error: ", raw_ostream::RED, msg);
- *errorOS << errorLimitExceededMsg << "\n";
+ *errorOS << sep << getLocation(msg) << ": " << Colors::RED
+ << "error: " << Colors::RESET << errorLimitExceededMsg << "\n";
if (exitEarly)
exitLld(1);
}
+ sep = getSeparator(msg);
++errorCount;
}
diff --git a/contrib/llvm-project/lld/Common/Strings.cpp b/contrib/llvm-project/lld/Common/Strings.cpp
index 0bf06626cc7a..627435f141da 100644
--- a/contrib/llvm-project/lld/Common/Strings.cpp
+++ b/contrib/llvm-project/lld/Common/Strings.cpp
@@ -18,39 +18,17 @@
using namespace llvm;
using namespace lld;
-// Returns the demangled C++ symbol name for Name.
-Optional<std::string> lld::demangleItanium(StringRef name) {
+// Returns the demangled C++ symbol name for name.
+std::string lld::demangleItanium(StringRef name) {
// itaniumDemangle can be used to demangle strings other than symbol
// names which do not necessarily start with "_Z". Name can be
- // either a C or C++ symbol. Don't call itaniumDemangle if the name
+ // either a C or C++ symbol. Don't call demangle if the name
// does not look like a C++ symbol name to avoid getting unexpected
// result for a C symbol that happens to match a mangled type name.
if (!name.startswith("_Z"))
- return None;
+ return name;
- char *buf = itaniumDemangle(name.str().c_str(), nullptr, nullptr, nullptr);
- if (!buf)
- return None;
- std::string s(buf);
- free(buf);
- return s;
-}
-
-Optional<std::string> lld::demangleMSVC(StringRef name) {
- std::string prefix;
- if (name.consume_front("__imp_"))
- prefix = "__declspec(dllimport) ";
-
- // Demangle only C++ names.
- if (!name.startswith("?"))
- return None;
-
- char *buf = microsoftDemangle(name.str().c_str(), nullptr, nullptr, nullptr);
- if (!buf)
- return None;
- std::string s(buf);
- free(buf);
- return prefix + s;
+ return demangle(name);
}
StringMatcher::StringMatcher(ArrayRef<StringRef> pat) {
@@ -96,7 +74,7 @@ bool lld::isValidCIdentifier(StringRef s) {
// Write the contents of the a buffer to a file
void lld::saveBuffer(StringRef buffer, const Twine &path) {
std::error_code ec;
- raw_fd_ostream os(path.str(), ec, sys::fs::OpenFlags::F_None);
+ raw_fd_ostream os(path.str(), ec, sys::fs::OpenFlags::OF_None);
if (ec)
error("cannot create " + path + ": " + ec.message());
os << buffer;
diff --git a/contrib/llvm-project/lld/Common/TargetOptionsCommandFlags.cpp b/contrib/llvm-project/lld/Common/TargetOptionsCommandFlags.cpp
index d4c29d7f88b8..0137feb63f37 100644
--- a/contrib/llvm-project/lld/Common/TargetOptionsCommandFlags.cpp
+++ b/contrib/llvm-project/lld/Common/TargetOptionsCommandFlags.cpp
@@ -26,6 +26,10 @@ llvm::TargetOptions lld::initTargetOptionsFromCodeGenFlags() {
return ::InitTargetOptionsFromCodeGenFlags();
}
+llvm::Optional<llvm::Reloc::Model> lld::getRelocModelFromCMModel() {
+ return getRelocModel();
+}
+
llvm::Optional<llvm::CodeModel::Model> lld::getCodeModelFromCMModel() {
return getCodeModel();
}
diff --git a/contrib/llvm-project/lld/ELF/AArch64ErrataFix.cpp b/contrib/llvm-project/lld/ELF/AArch64ErrataFix.cpp
index b2eda4dcbc4e..7fb3e02e7ee4 100644
--- a/contrib/llvm-project/lld/ELF/AArch64ErrataFix.cpp
+++ b/contrib/llvm-project/lld/ELF/AArch64ErrataFix.cpp
@@ -6,7 +6,10 @@
//
//===----------------------------------------------------------------------===//
// This file implements Section Patching for the purpose of working around
-// errata in CPUs. The general principle is that an erratum sequence of one or
+// the AArch64 Cortex-53 errata 843419 that affects r0p0, r0p1, r0p2 and r0p4
+// versions of the core.
+//
+// The general principle is that an erratum sequence of one or
// more instructions is detected in the instruction stream, one of the
// instructions in the sequence is replaced with a branch to a patch sequence
// of replacement instructions. At the end of the replacement sequence the
@@ -20,12 +23,6 @@
// - We can overwrite an instruction in the erratum sequence with a branch to
// the replacement sequence.
// - We can place the replacement sequence within range of the branch.
-
-// FIXME:
-// - The implementation here only supports one patch, the AArch64 Cortex-53
-// errata 843419 that affects r0p0, r0p1, r0p2 and r0p4 versions of the core.
-// To keep the initial version simple there is no support for multiple
-// architectures or selection of different patches.
//===----------------------------------------------------------------------===//
#include "AArch64ErrataFix.h"
@@ -48,8 +45,8 @@ using namespace llvm::object;
using namespace llvm::support;
using namespace llvm::support::endian;
-using namespace lld;
-using namespace lld::elf;
+namespace lld {
+namespace elf {
// Helper functions to identify instructions and conditions needed to trigger
// the Cortex-A53-843419 erratum.
@@ -333,16 +330,16 @@ static bool is843419ErratumSequence(uint32_t instr1, uint32_t instr2,
}
// Scan the instruction sequence starting at Offset Off from the base of
-// InputSection IS. We update Off in this function rather than in the caller as
-// we can skip ahead much further into the section when we know how many
+// InputSection isec. We update Off in this function rather than in the caller
+// as we can skip ahead much further into the section when we know how many
// instructions we've scanned.
-// Return the offset of the load or store instruction in IS that we want to
+// Return the offset of the load or store instruction in isec that we want to
// patch or 0 if no patch required.
static uint64_t scanCortexA53Errata843419(InputSection *isec, uint64_t &off,
uint64_t limit) {
uint64_t isecAddr = isec->getVA(0);
- // Advance Off so that (ISAddr + Off) modulo 0x1000 is at least 0xff8.
+ // Advance Off so that (isecAddr + Off) modulo 0x1000 is at least 0xff8.
uint64_t initialPageOff = (isecAddr + off) & 0xfff;
if (initialPageOff < 0xff8)
off += 0xff8 - initialPageOff;
@@ -374,7 +371,7 @@ static uint64_t scanCortexA53Errata843419(InputSection *isec, uint64_t &off,
return patchOff;
}
-class lld::elf::Patch843419Section : public SyntheticSection {
+class Patch843419Section : public SyntheticSection {
public:
Patch843419Section(InputSection *p, uint64_t off);
@@ -386,13 +383,13 @@ public:
// The Section we are patching.
const InputSection *patchee;
- // The offset of the instruction in the Patchee section we are patching.
+ // The offset of the instruction in the patchee section we are patching.
uint64_t patcheeOffset;
// A label for the start of the Patch that we can use as a relocation target.
Symbol *patchSym;
};
-lld::elf::Patch843419Section::Patch843419Section(InputSection *p, uint64_t off)
+Patch843419Section::Patch843419Section(InputSection *p, uint64_t off)
: SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 4,
".text.patch"),
patchee(p), patcheeOffset(off) {
@@ -403,16 +400,16 @@ lld::elf::Patch843419Section::Patch843419Section(InputSection *p, uint64_t off)
addSyntheticLocal(saver.save("$x"), STT_NOTYPE, 0, 0, *this);
}
-uint64_t lld::elf::Patch843419Section::getLDSTAddr() const {
+uint64_t Patch843419Section::getLDSTAddr() const {
return patchee->getVA(patcheeOffset);
}
-void lld::elf::Patch843419Section::writeTo(uint8_t *buf) {
+void Patch843419Section::writeTo(uint8_t *buf) {
// Copy the instruction that we will be replacing with a branch in the
- // Patchee Section.
+ // patchee Section.
write32le(buf, read32le(patchee->data().begin() + patcheeOffset));
- // Apply any relocation transferred from the original PatcheeSection.
+ // Apply any relocation transferred from the original patchee section.
// For a SyntheticSection Buf already has outSecOff added, but relocateAlloc
// also adds outSecOff so we need to subtract to avoid double counting.
this->relocateAlloc(buf - outSecOff, buf - outSecOff + getSize());
@@ -461,18 +458,18 @@ void AArch64Err843419Patcher::init() {
// $d.0 $d.1 $x.1.
for (auto &kv : sectionMap) {
std::vector<const Defined *> &mapSyms = kv.second;
- if (mapSyms.size() <= 1)
- continue;
llvm::stable_sort(mapSyms, [](const Defined *a, const Defined *b) {
return a->value < b->value;
});
mapSyms.erase(
std::unique(mapSyms.begin(), mapSyms.end(),
[=](const Defined *a, const Defined *b) {
- return (isCodeMapSymbol(a) && isCodeMapSymbol(b)) ||
- (isDataMapSymbol(a) && isDataMapSymbol(b));
+ return isCodeMapSymbol(a) == isCodeMapSymbol(b);
}),
mapSyms.end());
+ // Always start with a Code Mapping Symbol.
+ if (!mapSyms.empty() && !isCodeMapSymbol(mapSyms.front()))
+ mapSyms.erase(mapSyms.begin());
}
initialized = true;
}
@@ -511,19 +508,16 @@ void AArch64Err843419Patcher::insertPatches(
(*patchIt)->outSecOff = isecLimit;
}
- // merge all patch sections. We use the outSecOff assigned above to
+ // Merge all patch sections. We use the outSecOff assigned above to
// determine the insertion point. This is ok as we only merge into an
// InputSectionDescription once per pass, and at the end of the pass
// assignAddresses() will recalculate all the outSecOff values.
std::vector<InputSection *> tmp;
tmp.reserve(isd.sections.size() + patches.size());
auto mergeCmp = [](const InputSection *a, const InputSection *b) {
- if (a->outSecOff < b->outSecOff)
- return true;
- if (a->outSecOff == b->outSecOff && isa<Patch843419Section>(a) &&
- !isa<Patch843419Section>(b))
- return true;
- return false;
+ if (a->outSecOff != b->outSecOff)
+ return a->outSecOff < b->outSecOff;
+ return isa<Patch843419Section>(a) && !isa<Patch843419Section>(b);
};
std::merge(isd.sections.begin(), isd.sections.end(), patches.begin(),
patches.end(), std::back_inserter(tmp), mergeCmp);
@@ -532,7 +526,7 @@ void AArch64Err843419Patcher::insertPatches(
// Given an erratum sequence that starts at address adrpAddr, with an
// instruction that we need to patch at patcheeOffset from the start of
-// InputSection IS, create a Patch843419 Section and add it to the
+// InputSection isec, create a Patch843419 Section and add it to the
// Patches that we need to insert.
static void implementPatch(uint64_t adrpAddr, uint64_t patcheeOffset,
InputSection *isec,
@@ -578,7 +572,7 @@ static void implementPatch(uint64_t adrpAddr, uint64_t patcheeOffset,
// Scan all the instructions in InputSectionDescription, for each instance of
// the erratum sequence create a Patch843419Section. We return the list of
-// Patch843419Sections that need to be applied to ISD.
+// Patch843419Sections that need to be applied to the InputSectionDescription.
std::vector<Patch843419Section *>
AArch64Err843419Patcher::patchInputSectionDescription(
InputSectionDescription &isd) {
@@ -594,10 +588,7 @@ AArch64Err843419Patcher::patchInputSectionDescription(
// section size).
std::vector<const Defined *> &mapSyms = sectionMap[isec];
- auto codeSym = llvm::find_if(mapSyms, [&](const Defined *ms) {
- return ms->getName().startswith("$x");
- });
-
+ auto codeSym = mapSyms.begin();
while (codeSym != mapSyms.end()) {
auto dataSym = std::next(codeSym);
uint64_t off = (*codeSym)->value;
@@ -606,7 +597,8 @@ AArch64Err843419Patcher::patchInputSectionDescription(
while (off < limit) {
uint64_t startAddr = isec->getVA(off);
- if (uint64_t patcheeOffset = scanCortexA53Errata843419(isec, off, limit))
+ if (uint64_t patcheeOffset =
+ scanCortexA53Errata843419(isec, off, limit))
implementPatch(startAddr, patcheeOffset, isec, patches);
}
if (dataSym == mapSyms.end())
@@ -630,7 +622,7 @@ AArch64Err843419Patcher::patchInputSectionDescription(
// Ouptut and Input Sections may have been changed.
// Returns false if no patches were required and no changes were made.
bool AArch64Err843419Patcher::createFixes() {
- if (initialized == false)
+ if (!initialized)
init();
bool addressesChanged = false;
@@ -649,3 +641,5 @@ bool AArch64Err843419Patcher::createFixes() {
}
return addressesChanged;
}
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/ARMErrataFix.cpp b/contrib/llvm-project/lld/ELF/ARMErrataFix.cpp
new file mode 100644
index 000000000000..493fafc6a0b2
--- /dev/null
+++ b/contrib/llvm-project/lld/ELF/ARMErrataFix.cpp
@@ -0,0 +1,528 @@
+//===- ARMErrataFix.cpp ---------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// This file implements Section Patching for the purpose of working around the
+// Cortex-a8 erratum 657417 "A 32bit branch instruction that spans 2 4K regions
+// can result in an incorrect instruction fetch or processor deadlock." The
+// erratum affects all but r1p7, r2p5, r2p6, r3p1 and r3p2 revisions of the
+// Cortex-A8. A high level description of the patching technique is given in
+// the opening comment of AArch64ErrataFix.cpp.
+//===----------------------------------------------------------------------===//
+
+#include "ARMErrataFix.h"
+
+#include "Config.h"
+#include "LinkerScript.h"
+#include "OutputSections.h"
+#include "Relocations.h"
+#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "Target.h"
+#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+using namespace llvm::support;
+using namespace llvm::support::endian;
+
+namespace lld {
+namespace elf {
+
+// The documented title for Erratum 657417 is:
+// "A 32bit branch instruction that spans two 4K regions can result in an
+// incorrect instruction fetch or processor deadlock". Graphically using a
+// 32-bit B.w instruction encoded as a pair of halfwords 0xf7fe 0xbfff
+// xxxxxx000 // Memory region 1 start
+// target:
+// ...
+// xxxxxxffe f7fe // First halfword of branch to target:
+// xxxxxx000 // Memory region 2 start
+// xxxxxx002 bfff // Second halfword of branch to target:
+//
+// The specific trigger conditions that can be detected at link time are:
+// - There is a 32-bit Thumb-2 branch instruction with an address of the form
+// xxxxxxFFE. The first 2 bytes of the instruction are in 4KiB region 1, the
+// second 2 bytes are in region 2.
+// - The branch instruction is one of BLX, BL, B.w BCC.w
+// - The instruction preceding the branch is a 32-bit non-branch instruction.
+// - The target of the branch is in region 1.
+//
+// The linker mitigation for the fix is to redirect any branch that meets the
+// erratum conditions to a patch section containing a branch to the target.
+//
+// As adding patch sections may move branches onto region boundaries the patch
+// must iterate until no more patches are added.
+//
+// Example, before:
+// 00000FFA func: NOP.w // 32-bit Thumb function
+// 00000FFE B.W func // 32-bit branch spanning 2 regions, dest in 1st.
+// Example, after:
+// 00000FFA func: NOP.w // 32-bit Thumb function
+// 00000FFE B.w __CortexA8657417_00000FFE
+// 00001002 2 - bytes padding
+// 00001004 __CortexA8657417_00000FFE: B.w func
+
+class Patch657417Section : public SyntheticSection {
+public:
+ Patch657417Section(InputSection *p, uint64_t off, uint32_t instr, bool isARM);
+
+ void writeTo(uint8_t *buf) override;
+
+ size_t getSize() const override { return 4; }
+
+ // Get the virtual address of the branch instruction at patcheeOffset.
+ uint64_t getBranchAddr() const;
+
+ // The Section we are patching.
+ const InputSection *patchee;
+ // The offset of the instruction in the Patchee section we are patching.
+ uint64_t patcheeOffset;
+ // A label for the start of the Patch that we can use as a relocation target.
+ Symbol *patchSym;
+ // A decoding of the branch instruction at patcheeOffset.
+ uint32_t instr;
+ // True If the patch is to be written in ARM state, otherwise the patch will
+ // be written in Thumb state.
+ bool isARM;
+};
+
+// Return true if the half-word, when taken as the first of a pair of halfwords
+// is the first half of a 32-bit instruction.
+// Reference from ARM Architecure Reference Manual ARMv7-A and ARMv7-R edition
+// section A6.3: 32-bit Thumb instruction encoding
+// | HW1 | HW2 |
+// | 1 1 1 | op1 (2) | op2 (7) | x (4) |op| x (15) |
+// With op1 == 0b00, a 16-bit instruction is encoded.
+//
+// We test only the first halfword, looking for op != 0b00.
+static bool is32bitInstruction(uint16_t hw) {
+ return (hw & 0xe000) == 0xe000 && (hw & 0x1800) != 0x0000;
+}
+
+// Reference from ARM Architecure Reference Manual ARMv7-A and ARMv7-R edition
+// section A6.3.4 Branches and miscellaneous control.
+// | HW1 | HW2 |
+// | 1 1 1 | 1 0 | op (7) | x (4) | 1 | op1 (3) | op2 (4) | imm8 (8) |
+// op1 == 0x0 op != x111xxx | Conditional branch (Bcc.W)
+// op1 == 0x1 | Branch (B.W)
+// op1 == 1x0 | Branch with Link and Exchange (BLX.w)
+// op1 == 1x1 | Branch with Link (BL.W)
+
+static bool isBcc(uint32_t instr) {
+ return (instr & 0xf800d000) == 0xf0008000 &&
+ (instr & 0x03800000) != 0x03800000;
+}
+
+static bool isB(uint32_t instr) { return (instr & 0xf800d000) == 0xf0009000; }
+
+static bool isBLX(uint32_t instr) { return (instr & 0xf800d000) == 0xf000c000; }
+
+static bool isBL(uint32_t instr) { return (instr & 0xf800d000) == 0xf000d000; }
+
+static bool is32bitBranch(uint32_t instr) {
+ return isBcc(instr) || isB(instr) || isBL(instr) || isBLX(instr);
+}
+
+Patch657417Section::Patch657417Section(InputSection *p, uint64_t off,
+ uint32_t instr, bool isARM)
+ : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 4,
+ ".text.patch"),
+ patchee(p), patcheeOffset(off), instr(instr), isARM(isARM) {
+ parent = p->getParent();
+ patchSym = addSyntheticLocal(
+ saver.save("__CortexA8657417_" + utohexstr(getBranchAddr())), STT_FUNC,
+ isARM ? 0 : 1, getSize(), *this);
+ addSyntheticLocal(saver.save(isARM ? "$a" : "$t"), STT_NOTYPE, 0, 0, *this);
+}
+
+uint64_t Patch657417Section::getBranchAddr() const {
+ return patchee->getVA(patcheeOffset);
+}
+
+// Given a branch instruction instr at sourceAddr work out its destination
+// address. This is only used when the branch instruction has no relocation.
+static uint64_t getThumbDestAddr(uint64_t sourceAddr, uint32_t instr) {
+ uint8_t buf[4];
+ write16le(buf, instr >> 16);
+ write16le(buf + 2, instr & 0x0000ffff);
+ int64_t offset;
+ if (isBcc(instr))
+ offset = target->getImplicitAddend(buf, R_ARM_THM_JUMP19);
+ else if (isB(instr))
+ offset = target->getImplicitAddend(buf, R_ARM_THM_JUMP24);
+ else
+ offset = target->getImplicitAddend(buf, R_ARM_THM_CALL);
+ return sourceAddr + offset + 4;
+}
+
+void Patch657417Section::writeTo(uint8_t *buf) {
+ // The base instruction of the patch is always a 32-bit unconditional branch.
+ if (isARM)
+ write32le(buf, 0xea000000);
+ else
+ write32le(buf, 0x9000f000);
+ // If we have a relocation then apply it. For a SyntheticSection buf already
+ // has outSecOff added, but relocateAlloc also adds outSecOff so we need to
+ // subtract to avoid double counting.
+ if (!relocations.empty()) {
+ relocateAlloc(buf - outSecOff, buf - outSecOff + getSize());
+ return;
+ }
+
+ // If we don't have a relocation then we must calculate and write the offset
+ // ourselves.
+ // Get the destination offset from the addend in the branch instruction.
+ // We cannot use the instruction in the patchee section as this will have
+ // been altered to point to us!
+ uint64_t s = getThumbDestAddr(getBranchAddr(), instr);
+ uint64_t p = getVA(4);
+ target->relocateOne(buf, isARM ? R_ARM_JUMP24 : R_ARM_THM_JUMP24, s - p);
+}
+
+// Given a branch instruction spanning two 4KiB regions, at offset off from the
+// start of isec, return true if the destination of the branch is within the
+// first of the two 4Kib regions.
+static bool branchDestInFirstRegion(const InputSection *isec, uint64_t off,
+ uint32_t instr, const Relocation *r) {
+ uint64_t sourceAddr = isec->getVA(0) + off;
+ assert((sourceAddr & 0xfff) == 0xffe);
+ uint64_t destAddr = sourceAddr;
+ // If there is a branch relocation at the same offset we must use this to
+ // find the destination address as the branch could be indirected via a thunk
+ // or the PLT.
+ if (r) {
+ uint64_t dst = (r->expr == R_PLT_PC) ? r->sym->getPltVA() : r->sym->getVA();
+ // Account for Thumb PC bias, usually cancelled to 0 by addend of -4.
+ destAddr = dst + r->addend + 4;
+ } else {
+ // If there is no relocation, we must have an intra-section branch
+ // We must extract the offset from the addend manually.
+ destAddr = getThumbDestAddr(sourceAddr, instr);
+ }
+
+ return (destAddr & 0xfffff000) == (sourceAddr & 0xfffff000);
+}
+
+// Return true if a branch can reach a patch section placed after isec.
+// The Bcc.w instruction has a range of 1 MiB, all others have 16 MiB.
+static bool patchInRange(const InputSection *isec, uint64_t off,
+ uint32_t instr) {
+
+ // We need the branch at source to reach a patch section placed immediately
+ // after isec. As there can be more than one patch in the patch section we
+ // add 0x100 as contingency to account for worst case of 1 branch every 4KiB
+ // for a 1 MiB range.
+ return target->inBranchRange(
+ isBcc(instr) ? R_ARM_THM_JUMP19 : R_ARM_THM_JUMP24, isec->getVA(off),
+ isec->getVA() + isec->getSize() + 0x100);
+}
+
+struct ScanResult {
+ // Offset of branch within its InputSection.
+ uint64_t off;
+ // Cached decoding of the branch instruction.
+ uint32_t instr;
+ // Branch relocation at off. Will be nullptr if no relocation exists.
+ Relocation *rel;
+};
+
+// Detect the erratum sequence, returning the offset of the branch instruction
+// and a decoding of the branch. If the erratum sequence is not found then
+// return an offset of 0 for the branch. 0 is a safe value to use for no patch
+// as there must be at least one 32-bit non-branch instruction before the
+// branch so the minimum offset for a patch is 4.
+static ScanResult scanCortexA8Errata657417(InputSection *isec, uint64_t &off,
+ uint64_t limit) {
+ uint64_t isecAddr = isec->getVA(0);
+ // Advance Off so that (isecAddr + off) modulo 0x1000 is at least 0xffa. We
+ // need to check for a 32-bit instruction immediately before a 32-bit branch
+ // at 0xffe modulo 0x1000.
+ off = alignTo(isecAddr + off, 0x1000, 0xffa) - isecAddr;
+ if (off >= limit || limit - off < 8) {
+ // Need at least 2 4-byte sized instructions to trigger erratum.
+ off = limit;
+ return {0, 0, nullptr};
+ }
+
+ ScanResult scanRes = {0, 0, nullptr};
+ const uint8_t *buf = isec->data().begin();
+ // ARMv7-A Thumb 32-bit instructions are encoded 2 consecutive
+ // little-endian halfwords.
+ const ulittle16_t *instBuf = reinterpret_cast<const ulittle16_t *>(buf + off);
+ uint16_t hw11 = *instBuf++;
+ uint16_t hw12 = *instBuf++;
+ uint16_t hw21 = *instBuf++;
+ uint16_t hw22 = *instBuf++;
+ if (is32bitInstruction(hw11) && is32bitInstruction(hw21)) {
+ uint32_t instr1 = (hw11 << 16) | hw12;
+ uint32_t instr2 = (hw21 << 16) | hw22;
+ if (!is32bitBranch(instr1) && is32bitBranch(instr2)) {
+ // Find a relocation for the branch if it exists. This will be used
+ // to determine the target.
+ uint64_t branchOff = off + 4;
+ auto relIt = llvm::find_if(isec->relocations, [=](const Relocation &r) {
+ return r.offset == branchOff &&
+ (r.type == R_ARM_THM_JUMP19 || r.type == R_ARM_THM_JUMP24 ||
+ r.type == R_ARM_THM_CALL);
+ });
+ if (relIt != isec->relocations.end())
+ scanRes.rel = &(*relIt);
+ if (branchDestInFirstRegion(isec, branchOff, instr2, scanRes.rel)) {
+ if (patchInRange(isec, branchOff, instr2)) {
+ scanRes.off = branchOff;
+ scanRes.instr = instr2;
+ } else {
+ warn(toString(isec->file) +
+ ": skipping cortex-a8 657417 erratum sequence, section " +
+ isec->name + " is too large to patch");
+ }
+ }
+ }
+ }
+ off += 0x1000;
+ return scanRes;
+}
+
+void ARMErr657417Patcher::init() {
+ // The Arm ABI permits a mix of ARM, Thumb and Data in the same
+ // InputSection. We must only scan Thumb instructions to avoid false
+ // matches. We use the mapping symbols in the InputObjects to identify this
+ // data, caching the results in sectionMap so we don't have to recalculate
+ // it each pass.
+
+ // The ABI Section 4.5.5 Mapping symbols; defines local symbols that describe
+ // half open intervals [Symbol Value, Next Symbol Value) of code and data
+ // within sections. If there is no next symbol then the half open interval is
+ // [Symbol Value, End of section). The type, code or data, is determined by
+ // the mapping symbol name, $a for Arm code, $t for Thumb code, $d for data.
+ auto isArmMapSymbol = [](const Symbol *s) {
+ return s->getName() == "$a" || s->getName().startswith("$a.");
+ };
+ auto isThumbMapSymbol = [](const Symbol *s) {
+ return s->getName() == "$t" || s->getName().startswith("$t.");
+ };
+ auto isDataMapSymbol = [](const Symbol *s) {
+ return s->getName() == "$d" || s->getName().startswith("$d.");
+ };
+
+ // Collect mapping symbols for every executable InputSection.
+ for (InputFile *file : objectFiles) {
+ auto *f = cast<ObjFile<ELF32LE>>(file);
+ for (Symbol *s : f->getLocalSymbols()) {
+ auto *def = dyn_cast<Defined>(s);
+ if (!def)
+ continue;
+ if (!isArmMapSymbol(def) && !isThumbMapSymbol(def) &&
+ !isDataMapSymbol(def))
+ continue;
+ if (auto *sec = dyn_cast_or_null<InputSection>(def->section))
+ if (sec->flags & SHF_EXECINSTR)
+ sectionMap[sec].push_back(def);
+ }
+ }
+ // For each InputSection make sure the mapping symbols are in sorted in
+ // ascending order and are in alternating Thumb, non-Thumb order.
+ for (auto &kv : sectionMap) {
+ std::vector<const Defined *> &mapSyms = kv.second;
+ llvm::stable_sort(mapSyms, [](const Defined *a, const Defined *b) {
+ return a->value < b->value;
+ });
+ mapSyms.erase(std::unique(mapSyms.begin(), mapSyms.end(),
+ [=](const Defined *a, const Defined *b) {
+ return (isThumbMapSymbol(a) ==
+ isThumbMapSymbol(b));
+ }),
+ mapSyms.end());
+ // Always start with a Thumb Mapping Symbol
+ if (!mapSyms.empty() && !isThumbMapSymbol(mapSyms.front()))
+ mapSyms.erase(mapSyms.begin());
+ }
+ initialized = true;
+}
+
+void ARMErr657417Patcher::insertPatches(
+ InputSectionDescription &isd, std::vector<Patch657417Section *> &patches) {
+ uint64_t spacing = 0x100000 - 0x7500;
+ uint64_t isecLimit;
+ uint64_t prevIsecLimit = isd.sections.front()->outSecOff;
+ uint64_t patchUpperBound = prevIsecLimit + spacing;
+ uint64_t outSecAddr = isd.sections.front()->getParent()->addr;
+
+ // Set the outSecOff of patches to the place where we want to insert them.
+ // We use a similar strategy to initial thunk placement, using 1 MiB as the
+ // range of the Thumb-2 conditional branch with a contingency accounting for
+ // thunk generation.
+ auto patchIt = patches.begin();
+ auto patchEnd = patches.end();
+ for (const InputSection *isec : isd.sections) {
+ isecLimit = isec->outSecOff + isec->getSize();
+ if (isecLimit > patchUpperBound) {
+ for (; patchIt != patchEnd; ++patchIt) {
+ if ((*patchIt)->getBranchAddr() - outSecAddr >= prevIsecLimit)
+ break;
+ (*patchIt)->outSecOff = prevIsecLimit;
+ }
+ patchUpperBound = prevIsecLimit + spacing;
+ }
+ prevIsecLimit = isecLimit;
+ }
+ for (; patchIt != patchEnd; ++patchIt)
+ (*patchIt)->outSecOff = isecLimit;
+
+ // Merge all patch sections. We use the outSecOff assigned above to
+ // determine the insertion point. This is ok as we only merge into an
+ // InputSectionDescription once per pass, and at the end of the pass
+ // assignAddresses() will recalculate all the outSecOff values.
+ std::vector<InputSection *> tmp;
+ tmp.reserve(isd.sections.size() + patches.size());
+ auto mergeCmp = [](const InputSection *a, const InputSection *b) {
+ if (a->outSecOff != b->outSecOff)
+ return a->outSecOff < b->outSecOff;
+ return isa<Patch657417Section>(a) && !isa<Patch657417Section>(b);
+ };
+ std::merge(isd.sections.begin(), isd.sections.end(), patches.begin(),
+ patches.end(), std::back_inserter(tmp), mergeCmp);
+ isd.sections = std::move(tmp);
+}
+
+// Given a branch instruction described by ScanRes redirect it to a patch
+// section containing an unconditional branch instruction to the target.
+// Ensure that this patch section is 4-byte aligned so that the branch cannot
+// span two 4 KiB regions. Place the patch section so that it is always after
+// isec so the branch we are patching always goes forwards.
+static void implementPatch(ScanResult sr, InputSection *isec,
+ std::vector<Patch657417Section *> &patches) {
+
+ log("detected cortex-a8-657419 erratum sequence starting at " +
+ utohexstr(isec->getVA(sr.off)) + " in unpatched output.");
+ Patch657417Section *psec;
+ // We have two cases to deal with.
+ // Case 1. There is a relocation at patcheeOffset to a symbol. The
+ // unconditional branch in the patch must have a relocation so that any
+ // further redirection via the PLT or a Thunk happens as normal. At
+ // patcheeOffset we redirect the existing relocation to a Symbol defined at
+ // the start of the patch section.
+ //
+ // Case 2. There is no relocation at patcheeOffset. We are unlikely to have
+ // a symbol that we can use as a target for a relocation in the patch section.
+ // Luckily we know that the destination cannot be indirected via the PLT or
+ // a Thunk so we can just write the destination directly.
+ if (sr.rel) {
+ // Case 1. We have an existing relocation to redirect to patch and a
+ // Symbol target.
+
+ // Create a branch relocation for the unconditional branch in the patch.
+ // This can be redirected via the PLT or Thunks.
+ RelType patchRelType = R_ARM_THM_JUMP24;
+ int64_t patchRelAddend = sr.rel->addend;
+ bool destIsARM = false;
+ if (isBL(sr.instr) || isBLX(sr.instr)) {
+ // The final target of the branch may be ARM or Thumb, if the target
+ // is ARM then we write the patch in ARM state to avoid a state change
+ // Thunk from the patch to the target.
+ uint64_t dstSymAddr = (sr.rel->expr == R_PLT_PC) ? sr.rel->sym->getPltVA()
+ : sr.rel->sym->getVA();
+ destIsARM = (dstSymAddr & 1) == 0;
+ }
+ psec = make<Patch657417Section>(isec, sr.off, sr.instr, destIsARM);
+ if (destIsARM) {
+ // The patch will be in ARM state. Use an ARM relocation and account for
+ // the larger ARM PC-bias of 8 rather than Thumb's 4.
+ patchRelType = R_ARM_JUMP24;
+ patchRelAddend -= 4;
+ }
+ psec->relocations.push_back(
+ Relocation{sr.rel->expr, patchRelType, 0, patchRelAddend, sr.rel->sym});
+ // Redirect the existing branch relocation to the patch.
+ sr.rel->expr = R_PC;
+ sr.rel->addend = -4;
+ sr.rel->sym = psec->patchSym;
+ } else {
+ // Case 2. We do not have a relocation to the patch. Add a relocation of the
+ // appropriate type to the patch at patcheeOffset.
+
+ // The destination is ARM if we have a BLX.
+ psec = make<Patch657417Section>(isec, sr.off, sr.instr, isBLX(sr.instr));
+ RelType type;
+ if (isBcc(sr.instr))
+ type = R_ARM_THM_JUMP19;
+ else if (isB(sr.instr))
+ type = R_ARM_THM_JUMP24;
+ else
+ type = R_ARM_THM_CALL;
+ isec->relocations.push_back(
+ Relocation{R_PC, type, sr.off, -4, psec->patchSym});
+ }
+ patches.push_back(psec);
+}
+
+// Scan all the instructions in InputSectionDescription, for each instance of
+// the erratum sequence create a Patch657417Section. We return the list of
+// Patch657417Sections that need to be applied to the InputSectionDescription.
+std::vector<Patch657417Section *>
+ARMErr657417Patcher::patchInputSectionDescription(
+ InputSectionDescription &isd) {
+ std::vector<Patch657417Section *> patches;
+ for (InputSection *isec : isd.sections) {
+ // LLD doesn't use the erratum sequence in SyntheticSections.
+ if (isa<SyntheticSection>(isec))
+ continue;
+ // Use sectionMap to make sure we only scan Thumb code and not Arm or inline
+ // data. We have already sorted mapSyms in ascending order and removed
+ // consecutive mapping symbols of the same type. Our range of executable
+ // instructions to scan is therefore [thumbSym->value, nonThumbSym->value)
+ // or [thumbSym->value, section size).
+ std::vector<const Defined *> &mapSyms = sectionMap[isec];
+
+ auto thumbSym = mapSyms.begin();
+ while (thumbSym != mapSyms.end()) {
+ auto nonThumbSym = std::next(thumbSym);
+ uint64_t off = (*thumbSym)->value;
+ uint64_t limit = (nonThumbSym == mapSyms.end()) ? isec->data().size()
+ : (*nonThumbSym)->value;
+
+ while (off < limit) {
+ ScanResult sr = scanCortexA8Errata657417(isec, off, limit);
+ if (sr.off)
+ implementPatch(sr, isec, patches);
+ }
+ if (nonThumbSym == mapSyms.end())
+ break;
+ thumbSym = std::next(nonThumbSym);
+ }
+ }
+ return patches;
+}
+
+bool ARMErr657417Patcher::createFixes() {
+ if (!initialized)
+ init();
+
+ bool addressesChanged = false;
+ for (OutputSection *os : outputSections) {
+ if (!(os->flags & SHF_ALLOC) || !(os->flags & SHF_EXECINSTR))
+ continue;
+ for (BaseCommand *bc : os->sectionCommands)
+ if (auto *isd = dyn_cast<InputSectionDescription>(bc)) {
+ std::vector<Patch657417Section *> patches =
+ patchInputSectionDescription(*isd);
+ if (!patches.empty()) {
+ insertPatches(*isd, patches);
+ addressesChanged = true;
+ }
+ }
+ }
+ return addressesChanged;
+}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/ARMErrataFix.h b/contrib/llvm-project/lld/ELF/ARMErrataFix.h
new file mode 100644
index 000000000000..5a39bcc75cd3
--- /dev/null
+++ b/contrib/llvm-project/lld/ELF/ARMErrataFix.h
@@ -0,0 +1,51 @@
+//===- ARMErrataFix.h -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_ARMA8ERRATAFIX_H
+#define LLD_ELF_ARMA8ERRATAFIX_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
+#include <map>
+#include <vector>
+
+namespace lld {
+namespace elf {
+
+class Defined;
+class InputSection;
+struct InputSectionDescription;
+class OutputSection;
+class Patch657417Section;
+
+class ARMErr657417Patcher {
+public:
+ // Return true if Patches have been added to the OutputSections.
+ bool createFixes();
+
+private:
+ std::vector<Patch657417Section *>
+ patchInputSectionDescription(InputSectionDescription &isd);
+
+ void insertPatches(InputSectionDescription &isd,
+ std::vector<Patch657417Section *> &patches);
+
+ void init();
+
+ // A cache of the mapping symbols defined by the InputSection sorted in order
+ // of ascending value with redundant symbols removed. These describe
+ // the ranges of code and data in an executable InputSection.
+ llvm::DenseMap<InputSection *, std::vector<const Defined *>> sectionMap;
+
+ bool initialized = false;
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm-project/lld/ELF/Arch/AArch64.cpp b/contrib/llvm-project/lld/ELF/Arch/AArch64.cpp
index 4d4789702f03..5cf07029fa1d 100644
--- a/contrib/llvm-project/lld/ELF/Arch/AArch64.cpp
+++ b/contrib/llvm-project/lld/ELF/Arch/AArch64.cpp
@@ -17,13 +17,14 @@
using namespace llvm;
using namespace llvm::support::endian;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
+
+namespace lld {
+namespace elf {
// Page(Expr) is the page address of the expression Expr, defined
// as (Expr & ~0xFFF). (This applies even if the machine page size
// supported by the platform has a different value.)
-uint64_t elf::getAArch64Page(uint64_t expr) {
+uint64_t getAArch64Page(uint64_t expr) {
return expr & ~static_cast<uint64_t>(0xFFF);
}
@@ -76,6 +77,26 @@ AArch64::AArch64() {
RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
const uint8_t *loc) const {
switch (type) {
+ case R_AARCH64_ABS16:
+ case R_AARCH64_ABS32:
+ case R_AARCH64_ABS64:
+ case R_AARCH64_ADD_ABS_LO12_NC:
+ case R_AARCH64_LDST128_ABS_LO12_NC:
+ case R_AARCH64_LDST16_ABS_LO12_NC:
+ case R_AARCH64_LDST32_ABS_LO12_NC:
+ case R_AARCH64_LDST64_ABS_LO12_NC:
+ case R_AARCH64_LDST8_ABS_LO12_NC:
+ case R_AARCH64_MOVW_SABS_G0:
+ case R_AARCH64_MOVW_SABS_G1:
+ case R_AARCH64_MOVW_SABS_G2:
+ case R_AARCH64_MOVW_UABS_G0:
+ case R_AARCH64_MOVW_UABS_G0_NC:
+ case R_AARCH64_MOVW_UABS_G1:
+ case R_AARCH64_MOVW_UABS_G1_NC:
+ case R_AARCH64_MOVW_UABS_G2:
+ case R_AARCH64_MOVW_UABS_G2_NC:
+ case R_AARCH64_MOVW_UABS_G3:
+ return R_ABS;
case R_AARCH64_TLSDESC_ADR_PAGE21:
return R_AARCH64_TLSDESC_PAGE;
case R_AARCH64_TLSDESC_LD64_LO12:
@@ -90,6 +111,11 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G0:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G1:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G2:
return R_TLS;
case R_AARCH64_CALL26:
case R_AARCH64_CONDBR19:
@@ -101,6 +127,13 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
case R_AARCH64_PREL64:
case R_AARCH64_ADR_PREL_LO21:
case R_AARCH64_LD_PREL_LO19:
+ case R_AARCH64_MOVW_PREL_G0:
+ case R_AARCH64_MOVW_PREL_G0_NC:
+ case R_AARCH64_MOVW_PREL_G1:
+ case R_AARCH64_MOVW_PREL_G1_NC:
+ case R_AARCH64_MOVW_PREL_G2:
+ case R_AARCH64_MOVW_PREL_G2_NC:
+ case R_AARCH64_MOVW_PREL_G3:
return R_PC;
case R_AARCH64_ADR_PREL_PG_HI21:
case R_AARCH64_ADR_PREL_PG_HI21_NC:
@@ -114,7 +147,9 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
case R_AARCH64_NONE:
return R_NONE;
default:
- return R_ABS;
+ error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
+ ") against symbol " + toString(s));
+ return R_NONE;
}
}
@@ -247,6 +282,26 @@ static void or32AArch64Imm(uint8_t *l, uint64_t imm) {
or32le(l, (imm & 0xFFF) << 10);
}
+// Update the immediate field in an AArch64 movk, movn or movz instruction
+// for a signed relocation, and update the opcode of a movn or movz instruction
+// to match the sign of the operand.
+static void writeSMovWImm(uint8_t *loc, uint32_t imm) {
+ uint32_t inst = read32le(loc);
+ // Opcode field is bits 30, 29, with 10 = movz, 00 = movn and 11 = movk.
+ if (!(inst & (1 << 29))) {
+ // movn or movz.
+ if (imm & 0x10000) {
+ // Change opcode to movn, which takes an inverted operand.
+ imm ^= 0xFFFF;
+ inst &= ~(1 << 30);
+ } else {
+ // Change opcode to movz.
+ inst |= 1 << 30;
+ }
+ }
+ write32le(loc, inst | ((imm & 0xFFFF) << 5));
+}
+
void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
switch (type) {
case R_AARCH64_ABS16:
@@ -326,18 +381,56 @@ void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
checkAlignment(loc, val, 16, type);
or32AArch64Imm(loc, getBits(val, 4, 11));
break;
+ case R_AARCH64_MOVW_UABS_G0:
+ checkUInt(loc, val, 16, type);
+ LLVM_FALLTHROUGH;
case R_AARCH64_MOVW_UABS_G0_NC:
or32le(loc, (val & 0xFFFF) << 5);
break;
+ case R_AARCH64_MOVW_UABS_G1:
+ checkUInt(loc, val, 32, type);
+ LLVM_FALLTHROUGH;
case R_AARCH64_MOVW_UABS_G1_NC:
or32le(loc, (val & 0xFFFF0000) >> 11);
break;
+ case R_AARCH64_MOVW_UABS_G2:
+ checkUInt(loc, val, 48, type);
+ LLVM_FALLTHROUGH;
case R_AARCH64_MOVW_UABS_G2_NC:
or32le(loc, (val & 0xFFFF00000000) >> 27);
break;
case R_AARCH64_MOVW_UABS_G3:
or32le(loc, (val & 0xFFFF000000000000) >> 43);
break;
+ case R_AARCH64_MOVW_PREL_G0:
+ case R_AARCH64_MOVW_SABS_G0:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G0:
+ checkInt(loc, val, 17, type);
+ LLVM_FALLTHROUGH;
+ case R_AARCH64_MOVW_PREL_G0_NC:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
+ writeSMovWImm(loc, val);
+ break;
+ case R_AARCH64_MOVW_PREL_G1:
+ case R_AARCH64_MOVW_SABS_G1:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G1:
+ checkInt(loc, val, 33, type);
+ LLVM_FALLTHROUGH;
+ case R_AARCH64_MOVW_PREL_G1_NC:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
+ writeSMovWImm(loc, val >> 16);
+ break;
+ case R_AARCH64_MOVW_PREL_G2:
+ case R_AARCH64_MOVW_SABS_G2:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G2:
+ checkInt(loc, val, 49, type);
+ LLVM_FALLTHROUGH;
+ case R_AARCH64_MOVW_PREL_G2_NC:
+ writeSMovWImm(loc, val >> 32);
+ break;
+ case R_AARCH64_MOVW_PREL_G3:
+ writeSMovWImm(loc, val >> 48);
+ break;
case R_AARCH64_TSTBR14:
checkInt(loc, val, 16, type);
or32le(loc, (val & 0xFFFC) << 3);
@@ -351,7 +444,7 @@ void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
or32AArch64Imm(loc, val);
break;
default:
- error(getErrorLocation(loc) + "unrecognized relocation " + toString(type));
+ llvm_unreachable("unknown relocation");
}
}
@@ -587,4 +680,7 @@ static TargetInfo *getTargetInfo() {
return &t;
}
-TargetInfo *elf::getAArch64TargetInfo() { return getTargetInfo(); }
+TargetInfo *getAArch64TargetInfo() { return getTargetInfo(); }
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/Arch/AMDGPU.cpp b/contrib/llvm-project/lld/ELF/Arch/AMDGPU.cpp
index f2e32ca0996d..b42ca7746742 100644
--- a/contrib/llvm-project/lld/ELF/Arch/AMDGPU.cpp
+++ b/contrib/llvm-project/lld/ELF/Arch/AMDGPU.cpp
@@ -17,8 +17,9 @@ using namespace llvm;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
+
+namespace lld {
+namespace elf {
namespace {
class AMDGPU final : public TargetInfo {
@@ -107,7 +108,10 @@ RelType AMDGPU::getDynRel(RelType type) const {
return R_AMDGPU_NONE;
}
-TargetInfo *elf::getAMDGPUTargetInfo() {
+TargetInfo *getAMDGPUTargetInfo() {
static AMDGPU target;
return &target;
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/Arch/ARM.cpp b/contrib/llvm-project/lld/ELF/Arch/ARM.cpp
index 64adc33c07ae..41baea496d36 100644
--- a/contrib/llvm-project/lld/ELF/Arch/ARM.cpp
+++ b/contrib/llvm-project/lld/ELF/Arch/ARM.cpp
@@ -18,8 +18,9 @@
using namespace llvm;
using namespace llvm::support::endian;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
+
+namespace lld {
+namespace elf {
namespace {
class ARM final : public TargetInfo {
@@ -600,7 +601,10 @@ int64_t ARM::getImplicitAddend(const uint8_t *buf, RelType type) const {
}
}
-TargetInfo *elf::getARMTargetInfo() {
+TargetInfo *getARMTargetInfo() {
static ARM target;
return &target;
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/Arch/AVR.cpp b/contrib/llvm-project/lld/ELF/Arch/AVR.cpp
index 869f0fe0c525..cb33ff448ba4 100644
--- a/contrib/llvm-project/lld/ELF/Arch/AVR.cpp
+++ b/contrib/llvm-project/lld/ELF/Arch/AVR.cpp
@@ -36,8 +36,9 @@ using namespace llvm;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
+
+namespace lld {
+namespace elf {
namespace {
class AVR final : public TargetInfo {
@@ -70,7 +71,10 @@ void AVR::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
}
}
-TargetInfo *elf::getAVRTargetInfo() {
+TargetInfo *getAVRTargetInfo() {
static AVR target;
return &target;
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/Arch/Hexagon.cpp b/contrib/llvm-project/lld/ELF/Arch/Hexagon.cpp
index c497a6df7987..67264a2272dd 100644
--- a/contrib/llvm-project/lld/ELF/Arch/Hexagon.cpp
+++ b/contrib/llvm-project/lld/ELF/Arch/Hexagon.cpp
@@ -19,8 +19,9 @@ using namespace llvm;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
+
+namespace lld {
+namespace elf {
namespace {
class Hexagon final : public TargetInfo {
@@ -29,6 +30,7 @@ public:
uint32_t calcEFlags() const override;
RelExpr getRelExpr(RelType type, const Symbol &s,
const uint8_t *loc) const override;
+ RelType getDynRel(RelType type) const override;
void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override;
void writePltHeader(uint8_t *buf) const override;
void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr,
@@ -86,25 +88,47 @@ static uint32_t applyMask(uint32_t mask, uint32_t data) {
RelExpr Hexagon::getRelExpr(RelType type, const Symbol &s,
const uint8_t *loc) const {
switch (type) {
+ case R_HEX_NONE:
+ return R_NONE;
+ case R_HEX_6_X:
+ case R_HEX_8_X:
+ case R_HEX_9_X:
+ case R_HEX_10_X:
+ case R_HEX_11_X:
+ case R_HEX_12_X:
+ case R_HEX_16_X:
+ case R_HEX_32:
+ case R_HEX_32_6_X:
+ case R_HEX_HI16:
+ case R_HEX_LO16:
+ return R_ABS;
case R_HEX_B9_PCREL:
- case R_HEX_B9_PCREL_X:
case R_HEX_B13_PCREL:
case R_HEX_B15_PCREL:
- case R_HEX_B15_PCREL_X:
case R_HEX_6_PCREL_X:
case R_HEX_32_PCREL:
return R_PC;
+ case R_HEX_B9_PCREL_X:
+ case R_HEX_B15_PCREL_X:
case R_HEX_B22_PCREL:
case R_HEX_PLT_B22_PCREL:
case R_HEX_B22_PCREL_X:
case R_HEX_B32_PCREL_X:
return R_PLT_PC;
+ case R_HEX_GOTREL_11_X:
+ case R_HEX_GOTREL_16_X:
+ case R_HEX_GOTREL_32_6_X:
+ case R_HEX_GOTREL_HI16:
+ case R_HEX_GOTREL_LO16:
+ return R_GOTPLTREL;
case R_HEX_GOT_11_X:
case R_HEX_GOT_16_X:
case R_HEX_GOT_32_6_X:
- return R_HEXAGON_GOT;
+ return R_GOTPLT;
default:
- return R_ABS;
+ error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
+ ") against symbol " + toString(s));
+ return R_NONE;
}
}
@@ -197,6 +221,7 @@ void Hexagon::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
break;
case R_HEX_11_X:
case R_HEX_GOT_11_X:
+ case R_HEX_GOTREL_11_X:
or32le(loc, applyMask(findMaskR11(read32le(loc)), val & 0x3f));
break;
case R_HEX_12_X:
@@ -204,6 +229,7 @@ void Hexagon::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
break;
case R_HEX_16_X: // These relocs only have 6 effective bits.
case R_HEX_GOT_16_X:
+ case R_HEX_GOTREL_16_X:
or32le(loc, applyMask(findMaskR16(read32le(loc)), val & 0x3f));
break;
case R_HEX_32:
@@ -212,18 +238,22 @@ void Hexagon::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
break;
case R_HEX_32_6_X:
case R_HEX_GOT_32_6_X:
+ case R_HEX_GOTREL_32_6_X:
or32le(loc, applyMask(0x0fff3fff, val >> 6));
break;
case R_HEX_B9_PCREL:
+ checkInt(loc, val, 11, type);
or32le(loc, applyMask(0x003000fe, val >> 2));
break;
case R_HEX_B9_PCREL_X:
or32le(loc, applyMask(0x003000fe, val & 0x3f));
break;
case R_HEX_B13_PCREL:
+ checkInt(loc, val, 15, type);
or32le(loc, applyMask(0x00202ffe, val >> 2));
break;
case R_HEX_B15_PCREL:
+ checkInt(loc, val, 17, type);
or32le(loc, applyMask(0x00df20fe, val >> 2));
break;
case R_HEX_B15_PCREL_X:
@@ -231,6 +261,7 @@ void Hexagon::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
break;
case R_HEX_B22_PCREL:
case R_HEX_PLT_B22_PCREL:
+ checkInt(loc, val, 22, type);
or32le(loc, applyMask(0x1ff3ffe, val >> 2));
break;
case R_HEX_B22_PCREL_X:
@@ -239,15 +270,16 @@ void Hexagon::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
case R_HEX_B32_PCREL_X:
or32le(loc, applyMask(0x0fff3fff, val >> 6));
break;
+ case R_HEX_GOTREL_HI16:
case R_HEX_HI16:
or32le(loc, applyMask(0x00c03fff, val >> 16));
break;
+ case R_HEX_GOTREL_LO16:
case R_HEX_LO16:
or32le(loc, applyMask(0x00c03fff, val));
break;
default:
- error(getErrorLocation(loc) + "unrecognized relocation " + toString(type));
- break;
+ llvm_unreachable("unknown relocation");
}
}
@@ -285,7 +317,16 @@ void Hexagon::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr,
relocateOne(buf + 4, R_HEX_6_PCREL_X, gotPltEntryAddr - pltEntryAddr);
}
-TargetInfo *elf::getHexagonTargetInfo() {
+RelType Hexagon::getDynRel(RelType type) const {
+ if (type == R_HEX_32)
+ return type;
+ return R_HEX_NONE;
+}
+
+TargetInfo *getHexagonTargetInfo() {
static Hexagon target;
return &target;
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/Arch/MSP430.cpp b/contrib/llvm-project/lld/ELF/Arch/MSP430.cpp
index 90664396c85e..f03e8181923b 100644
--- a/contrib/llvm-project/lld/ELF/Arch/MSP430.cpp
+++ b/contrib/llvm-project/lld/ELF/Arch/MSP430.cpp
@@ -26,8 +26,9 @@ using namespace llvm;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
+
+namespace lld {
+namespace elf {
namespace {
class MSP430 final : public TargetInfo {
@@ -87,7 +88,10 @@ void MSP430::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
}
}
-TargetInfo *elf::getMSP430TargetInfo() {
+TargetInfo *getMSP430TargetInfo() {
static MSP430 target;
return &target;
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/Arch/Mips.cpp b/contrib/llvm-project/lld/ELF/Arch/Mips.cpp
index 24b3957acd99..d8fa306a6205 100644
--- a/contrib/llvm-project/lld/ELF/Arch/Mips.cpp
+++ b/contrib/llvm-project/lld/ELF/Arch/Mips.cpp
@@ -14,15 +14,13 @@
#include "Thunks.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/Object/ELF.h"
-#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace llvm::object;
-using namespace llvm::support::endian;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
+namespace lld {
+namespace elf {
namespace {
template <class ELFT> class MIPS final : public TargetInfo {
public:
@@ -85,8 +83,14 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType type, const Symbol &s,
switch (type) {
case R_MIPS_JALR:
+ // If the target symbol is not preemptible and is not microMIPS,
+ // it might be possible to replace jalr/jr instruction by bal/b.
+ // It depends on the target symbol's offset.
+ if (!s.isPreemptible && !(s.getVA() & 0x1))
+ return R_PC;
+ return R_NONE;
case R_MICROMIPS_JALR:
- return R_HINT;
+ return R_NONE;
case R_MIPS_GPREL16:
case R_MIPS_GPREL32:
case R_MICROMIPS_GPREL16:
@@ -120,15 +124,16 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType type, const Symbol &s,
case R_MIPS_TLS_DTPREL_LO16:
case R_MIPS_TLS_DTPREL32:
case R_MIPS_TLS_DTPREL64:
+ case R_MICROMIPS_TLS_DTPREL_HI16:
+ case R_MICROMIPS_TLS_DTPREL_LO16:
+ return R_ABS;
case R_MIPS_TLS_TPREL_HI16:
case R_MIPS_TLS_TPREL_LO16:
case R_MIPS_TLS_TPREL32:
case R_MIPS_TLS_TPREL64:
- case R_MICROMIPS_TLS_DTPREL_HI16:
- case R_MICROMIPS_TLS_DTPREL_LO16:
case R_MICROMIPS_TLS_TPREL_HI16:
case R_MICROMIPS_TLS_TPREL_LO16:
- return R_ABS;
+ return R_TLS;
case R_MIPS_PC32:
case R_MIPS_PC16:
case R_MIPS_PC19_S2:
@@ -192,7 +197,7 @@ void MIPS<ELFT>::writeGotPlt(uint8_t *buf, const Symbol &) const {
uint64_t va = in.plt->getVA();
if (isMicroMips())
va |= 1;
- write32<ELFT::TargetEndianness>(buf, va);
+ write32(buf, va);
}
template <endianness E> static uint32_t readShuffle(const uint8_t *loc) {
@@ -202,19 +207,18 @@ template <endianness E> static uint32_t readShuffle(const uint8_t *loc) {
// as early as possible. To do so, little-endian binaries keep 16-bit
// words in a big-endian order. That is why we have to swap these
// words to get a correct value.
- uint32_t v = read32<E>(loc);
+ uint32_t v = read32(loc);
if (E == support::little)
return (v << 16) | (v >> 16);
return v;
}
-template <endianness E>
static void writeValue(uint8_t *loc, uint64_t v, uint8_t bitsSize,
uint8_t shift) {
- uint32_t instr = read32<E>(loc);
+ uint32_t instr = read32(loc);
uint32_t mask = 0xffffffff >> (32 - bitsSize);
uint32_t data = (instr & ~mask) | ((v >> shift) & mask);
- write32<E>(loc, data);
+ write32(loc, data);
}
template <endianness E>
@@ -225,7 +229,7 @@ static void writeShuffleValue(uint8_t *loc, uint64_t v, uint8_t bitsSize,
if (E == support::little)
std::swap(words[0], words[1]);
- writeValue<E>(loc, v, bitsSize, shift);
+ writeValue(loc, v, bitsSize, shift);
if (E == support::little)
std::swap(words[0], words[1]);
@@ -234,94 +238,92 @@ static void writeShuffleValue(uint8_t *loc, uint64_t v, uint8_t bitsSize,
template <endianness E>
static void writeMicroRelocation16(uint8_t *loc, uint64_t v, uint8_t bitsSize,
uint8_t shift) {
- uint16_t instr = read16<E>(loc);
+ uint16_t instr = read16(loc);
uint16_t mask = 0xffff >> (16 - bitsSize);
uint16_t data = (instr & ~mask) | ((v >> shift) & mask);
- write16<E>(loc, data);
+ write16(loc, data);
}
template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *buf) const {
- const endianness e = ELFT::TargetEndianness;
if (isMicroMips()) {
uint64_t gotPlt = in.gotPlt->getVA();
uint64_t plt = in.plt->getVA();
// Overwrite trap instructions written by Writer::writeTrapInstr.
memset(buf, 0, pltHeaderSize);
- write16<e>(buf, isMipsR6() ? 0x7860 : 0x7980); // addiupc v1, (GOTPLT) - .
- write16<e>(buf + 4, 0xff23); // lw $25, 0($3)
- write16<e>(buf + 8, 0x0535); // subu16 $2, $2, $3
- write16<e>(buf + 10, 0x2525); // srl16 $2, $2, 2
- write16<e>(buf + 12, 0x3302); // addiu $24, $2, -2
- write16<e>(buf + 14, 0xfffe);
- write16<e>(buf + 16, 0x0dff); // move $15, $31
+ write16(buf, isMipsR6() ? 0x7860 : 0x7980); // addiupc v1, (GOTPLT) - .
+ write16(buf + 4, 0xff23); // lw $25, 0($3)
+ write16(buf + 8, 0x0535); // subu16 $2, $2, $3
+ write16(buf + 10, 0x2525); // srl16 $2, $2, 2
+ write16(buf + 12, 0x3302); // addiu $24, $2, -2
+ write16(buf + 14, 0xfffe);
+ write16(buf + 16, 0x0dff); // move $15, $31
if (isMipsR6()) {
- write16<e>(buf + 18, 0x0f83); // move $28, $3
- write16<e>(buf + 20, 0x472b); // jalrc $25
- write16<e>(buf + 22, 0x0c00); // nop
+ write16(buf + 18, 0x0f83); // move $28, $3
+ write16(buf + 20, 0x472b); // jalrc $25
+ write16(buf + 22, 0x0c00); // nop
relocateOne(buf, R_MICROMIPS_PC19_S2, gotPlt - plt);
} else {
- write16<e>(buf + 18, 0x45f9); // jalrc $25
- write16<e>(buf + 20, 0x0f83); // move $28, $3
- write16<e>(buf + 22, 0x0c00); // nop
+ write16(buf + 18, 0x45f9); // jalrc $25
+ write16(buf + 20, 0x0f83); // move $28, $3
+ write16(buf + 22, 0x0c00); // nop
relocateOne(buf, R_MICROMIPS_PC23_S2, gotPlt - plt);
}
return;
}
if (config->mipsN32Abi) {
- write32<e>(buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0])
- write32<e>(buf + 4, 0x8dd90000); // lw $25, %lo(&GOTPLT[0])($14)
- write32<e>(buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0])
- write32<e>(buf + 12, 0x030ec023); // subu $24, $24, $14
- write32<e>(buf + 16, 0x03e07825); // move $15, $31
- write32<e>(buf + 20, 0x0018c082); // srl $24, $24, 2
+ write32(buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0])
+ write32(buf + 4, 0x8dd90000); // lw $25, %lo(&GOTPLT[0])($14)
+ write32(buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0])
+ write32(buf + 12, 0x030ec023); // subu $24, $24, $14
+ write32(buf + 16, 0x03e07825); // move $15, $31
+ write32(buf + 20, 0x0018c082); // srl $24, $24, 2
} else if (ELFT::Is64Bits) {
- write32<e>(buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0])
- write32<e>(buf + 4, 0xddd90000); // ld $25, %lo(&GOTPLT[0])($14)
- write32<e>(buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0])
- write32<e>(buf + 12, 0x030ec023); // subu $24, $24, $14
- write32<e>(buf + 16, 0x03e07825); // move $15, $31
- write32<e>(buf + 20, 0x0018c0c2); // srl $24, $24, 3
+ write32(buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0])
+ write32(buf + 4, 0xddd90000); // ld $25, %lo(&GOTPLT[0])($14)
+ write32(buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0])
+ write32(buf + 12, 0x030ec023); // subu $24, $24, $14
+ write32(buf + 16, 0x03e07825); // move $15, $31
+ write32(buf + 20, 0x0018c0c2); // srl $24, $24, 3
} else {
- write32<e>(buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0])
- write32<e>(buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28)
- write32<e>(buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0])
- write32<e>(buf + 12, 0x031cc023); // subu $24, $24, $28
- write32<e>(buf + 16, 0x03e07825); // move $15, $31
- write32<e>(buf + 20, 0x0018c082); // srl $24, $24, 2
+ write32(buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0])
+ write32(buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28)
+ write32(buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0])
+ write32(buf + 12, 0x031cc023); // subu $24, $24, $28
+ write32(buf + 16, 0x03e07825); // move $15, $31
+ write32(buf + 20, 0x0018c082); // srl $24, $24, 2
}
uint32_t jalrInst = config->zHazardplt ? 0x0320fc09 : 0x0320f809;
- write32<e>(buf + 24, jalrInst); // jalr.hb $25 or jalr $25
- write32<e>(buf + 28, 0x2718fffe); // subu $24, $24, 2
+ write32(buf + 24, jalrInst); // jalr.hb $25 or jalr $25
+ write32(buf + 28, 0x2718fffe); // subu $24, $24, 2
uint64_t gotPlt = in.gotPlt->getVA();
- writeValue<e>(buf, gotPlt + 0x8000, 16, 16);
- writeValue<e>(buf + 4, gotPlt, 16, 0);
- writeValue<e>(buf + 8, gotPlt, 16, 0);
+ writeValue(buf, gotPlt + 0x8000, 16, 16);
+ writeValue(buf + 4, gotPlt, 16, 0);
+ writeValue(buf + 8, gotPlt, 16, 0);
}
template <class ELFT>
void MIPS<ELFT>::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr,
uint64_t pltEntryAddr, int32_t index,
unsigned relOff) const {
- const endianness e = ELFT::TargetEndianness;
if (isMicroMips()) {
// Overwrite trap instructions written by Writer::writeTrapInstr.
memset(buf, 0, pltEntrySize);
if (isMipsR6()) {
- write16<e>(buf, 0x7840); // addiupc $2, (GOTPLT) - .
- write16<e>(buf + 4, 0xff22); // lw $25, 0($2)
- write16<e>(buf + 8, 0x0f02); // move $24, $2
- write16<e>(buf + 10, 0x4723); // jrc $25 / jr16 $25
+ write16(buf, 0x7840); // addiupc $2, (GOTPLT) - .
+ write16(buf + 4, 0xff22); // lw $25, 0($2)
+ write16(buf + 8, 0x0f02); // move $24, $2
+ write16(buf + 10, 0x4723); // jrc $25 / jr16 $25
relocateOne(buf, R_MICROMIPS_PC19_S2, gotPltEntryAddr - pltEntryAddr);
} else {
- write16<e>(buf, 0x7900); // addiupc $2, (GOTPLT) - .
- write16<e>(buf + 4, 0xff22); // lw $25, 0($2)
- write16<e>(buf + 8, 0x4599); // jrc $25 / jr16 $25
- write16<e>(buf + 10, 0x0f02); // move $24, $2
+ write16(buf, 0x7900); // addiupc $2, (GOTPLT) - .
+ write16(buf + 4, 0xff22); // lw $25, 0($2)
+ write16(buf + 8, 0x4599); // jrc $25 / jr16 $25
+ write16(buf + 10, 0x0f02); // move $24, $2
relocateOne(buf, R_MICROMIPS_PC23_S2, gotPltEntryAddr - pltEntryAddr);
}
return;
@@ -332,13 +334,13 @@ void MIPS<ELFT>::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr,
: (config->zHazardplt ? 0x03200408 : 0x03200008);
uint32_t addInst = ELFT::Is64Bits ? 0x65f80000 : 0x25f80000;
- write32<e>(buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry)
- write32<e>(buf + 4, loadInst); // l[wd] $25, %lo(.got.plt entry)($15)
- write32<e>(buf + 8, jrInst); // jr $25 / jr.hb $25
- write32<e>(buf + 12, addInst); // [d]addiu $24, $15, %lo(.got.plt entry)
- writeValue<e>(buf, gotPltEntryAddr + 0x8000, 16, 16);
- writeValue<e>(buf + 4, gotPltEntryAddr, 16, 0);
- writeValue<e>(buf + 12, gotPltEntryAddr, 16, 0);
+ write32(buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry)
+ write32(buf + 4, loadInst); // l[wd] $25, %lo(.got.plt entry)($15)
+ write32(buf + 8, jrInst); // jr $25 / jr.hb $25
+ write32(buf + 12, addInst); // [d]addiu $24, $15, %lo(.got.plt entry)
+ writeValue(buf, gotPltEntryAddr + 0x8000, 16, 16);
+ writeValue(buf + 4, gotPltEntryAddr, 16, 0);
+ writeValue(buf + 12, gotPltEntryAddr, 16, 0);
}
template <class ELFT>
@@ -372,16 +374,16 @@ int64_t MIPS<ELFT>::getImplicitAddend(const uint8_t *buf, RelType type) const {
case R_MIPS_GPREL32:
case R_MIPS_TLS_DTPREL32:
case R_MIPS_TLS_TPREL32:
- return SignExtend64<32>(read32<e>(buf));
+ return SignExtend64<32>(read32(buf));
case R_MIPS_26:
// FIXME (simon): If the relocation target symbol is not a PLT entry
// we should use another expression for calculation:
// ((A << 2) | (P & 0xf0000000)) >> 2
- return SignExtend64<28>(read32<e>(buf) << 2);
+ return SignExtend64<28>(read32(buf) << 2);
case R_MIPS_GOT16:
case R_MIPS_HI16:
case R_MIPS_PCHI16:
- return SignExtend64<16>(read32<e>(buf)) << 16;
+ return SignExtend64<16>(read32(buf)) << 16;
case R_MIPS_GPREL16:
case R_MIPS_LO16:
case R_MIPS_PCLO16:
@@ -389,7 +391,7 @@ int64_t MIPS<ELFT>::getImplicitAddend(const uint8_t *buf, RelType type) const {
case R_MIPS_TLS_DTPREL_LO16:
case R_MIPS_TLS_TPREL_HI16:
case R_MIPS_TLS_TPREL_LO16:
- return SignExtend64<16>(read32<e>(buf));
+ return SignExtend64<16>(read32(buf));
case R_MICROMIPS_GOT16:
case R_MICROMIPS_HI16:
return SignExtend64<16>(readShuffle<e>(buf)) << 16;
@@ -403,21 +405,21 @@ int64_t MIPS<ELFT>::getImplicitAddend(const uint8_t *buf, RelType type) const {
case R_MICROMIPS_GPREL7_S2:
return SignExtend64<9>(readShuffle<e>(buf) << 2);
case R_MIPS_PC16:
- return SignExtend64<18>(read32<e>(buf) << 2);
+ return SignExtend64<18>(read32(buf) << 2);
case R_MIPS_PC19_S2:
- return SignExtend64<21>(read32<e>(buf) << 2);
+ return SignExtend64<21>(read32(buf) << 2);
case R_MIPS_PC21_S2:
- return SignExtend64<23>(read32<e>(buf) << 2);
+ return SignExtend64<23>(read32(buf) << 2);
case R_MIPS_PC26_S2:
- return SignExtend64<28>(read32<e>(buf) << 2);
+ return SignExtend64<28>(read32(buf) << 2);
case R_MIPS_PC32:
- return SignExtend64<32>(read32<e>(buf));
+ return SignExtend64<32>(read32(buf));
case R_MICROMIPS_26_S1:
return SignExtend64<27>(readShuffle<e>(buf) << 1);
case R_MICROMIPS_PC7_S1:
- return SignExtend64<8>(read16<e>(buf) << 1);
+ return SignExtend64<8>(read16(buf) << 1);
case R_MICROMIPS_PC10_S1:
- return SignExtend64<11>(read16<e>(buf) << 1);
+ return SignExtend64<11>(read16(buf) << 1);
case R_MICROMIPS_PC16_S1:
return SignExtend64<17>(readShuffle<e>(buf) << 1);
case R_MICROMIPS_PC18_S3:
@@ -487,9 +489,9 @@ static uint64_t fixupCrossModeJump(uint8_t *loc, RelType type, uint64_t val) {
switch (type) {
case R_MIPS_26: {
- uint32_t inst = read32<e>(loc) >> 26;
+ uint32_t inst = read32(loc) >> 26;
if (inst == 0x3 || inst == 0x1d) { // JAL or JALX
- writeValue<e>(loc, 0x1d << 26, 32, 0);
+ writeValue(loc, 0x1d << 26, 32, 0);
return val;
}
break;
@@ -538,11 +540,6 @@ void MIPS<ELFT>::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
type == R_MICROMIPS_TLS_DTPREL_HI16 ||
type == R_MICROMIPS_TLS_DTPREL_LO16) {
val -= 0x8000;
- } else if (type == R_MIPS_TLS_TPREL_HI16 || type == R_MIPS_TLS_TPREL_LO16 ||
- type == R_MIPS_TLS_TPREL32 || type == R_MIPS_TLS_TPREL64 ||
- type == R_MICROMIPS_TLS_TPREL_HI16 ||
- type == R_MICROMIPS_TLS_TPREL_LO16) {
- val -= 0x7000;
}
switch (type) {
@@ -550,25 +547,25 @@ void MIPS<ELFT>::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
case R_MIPS_GPREL32:
case R_MIPS_TLS_DTPREL32:
case R_MIPS_TLS_TPREL32:
- write32<e>(loc, val);
+ write32(loc, val);
break;
case R_MIPS_64:
case R_MIPS_TLS_DTPREL64:
case R_MIPS_TLS_TPREL64:
- write64<e>(loc, val);
+ write64(loc, val);
break;
case R_MIPS_26:
- writeValue<e>(loc, val, 26, 2);
+ writeValue(loc, val, 26, 2);
break;
case R_MIPS_GOT16:
// The R_MIPS_GOT16 relocation's value in "relocatable" linking mode
// is updated addend (not a GOT index). In that case write high 16 bits
// to store a correct addend value.
if (config->relocatable) {
- writeValue<e>(loc, val + 0x8000, 16, 16);
+ writeValue(loc, val + 0x8000, 16, 16);
} else {
checkInt(loc, val, 16, type);
- writeValue<e>(loc, val, 16, 0);
+ writeValue(loc, val, 16, 0);
}
break;
case R_MICROMIPS_GOT16:
@@ -595,7 +592,7 @@ void MIPS<ELFT>::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
case R_MIPS_PCLO16:
case R_MIPS_TLS_DTPREL_LO16:
case R_MIPS_TLS_TPREL_LO16:
- writeValue<e>(loc, val, 16, 0);
+ writeValue(loc, val, 16, 0);
break;
case R_MICROMIPS_GPREL16:
case R_MICROMIPS_TLS_GD:
@@ -621,7 +618,7 @@ void MIPS<ELFT>::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
case R_MIPS_PCHI16:
case R_MIPS_TLS_DTPREL_HI16:
case R_MIPS_TLS_TPREL_HI16:
- writeValue<e>(loc, val + 0x8000, 16, 16);
+ writeValue(loc, val + 0x8000, 16, 16);
break;
case R_MICROMIPS_CALL_HI16:
case R_MICROMIPS_GOT_HI16:
@@ -631,37 +628,51 @@ void MIPS<ELFT>::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
writeShuffleValue<e>(loc, val + 0x8000, 16, 16);
break;
case R_MIPS_HIGHER:
- writeValue<e>(loc, val + 0x80008000, 16, 32);
+ writeValue(loc, val + 0x80008000, 16, 32);
break;
case R_MIPS_HIGHEST:
- writeValue<e>(loc, val + 0x800080008000, 16, 48);
+ writeValue(loc, val + 0x800080008000, 16, 48);
break;
case R_MIPS_JALR:
+ val -= 4;
+ // Replace jalr/jr instructions by bal/b if the target
+ // offset fits into the 18-bit range.
+ if (isInt<18>(val)) {
+ switch (read32(loc)) {
+ case 0x0320f809: // jalr $25 => bal sym
+ write32(loc, 0x04110000 | ((val >> 2) & 0xffff));
+ break;
+ case 0x03200008: // jr $25 => b sym
+ write32(loc, 0x10000000 | ((val >> 2) & 0xffff));
+ break;
+ }
+ }
+ break;
case R_MICROMIPS_JALR:
// Ignore this optimization relocation for now
break;
case R_MIPS_PC16:
checkAlignment(loc, val, 4, type);
checkInt(loc, val, 18, type);
- writeValue<e>(loc, val, 16, 2);
+ writeValue(loc, val, 16, 2);
break;
case R_MIPS_PC19_S2:
checkAlignment(loc, val, 4, type);
checkInt(loc, val, 21, type);
- writeValue<e>(loc, val, 19, 2);
+ writeValue(loc, val, 19, 2);
break;
case R_MIPS_PC21_S2:
checkAlignment(loc, val, 4, type);
checkInt(loc, val, 23, type);
- writeValue<e>(loc, val, 21, 2);
+ writeValue(loc, val, 21, 2);
break;
case R_MIPS_PC26_S2:
checkAlignment(loc, val, 4, type);
checkInt(loc, val, 28, type);
- writeValue<e>(loc, val, 26, 2);
+ writeValue(loc, val, 26, 2);
break;
case R_MIPS_PC32:
- writeValue<e>(loc, val, 32, 0);
+ writeValue(loc, val, 32, 0);
break;
case R_MICROMIPS_26_S1:
case R_MICROMIPS_PC26_S1:
@@ -707,7 +718,7 @@ template <class ELFT> bool MIPS<ELFT>::usesOnlyLowPageBits(RelType type) const {
}
// Return true if the symbol is a PIC function.
-template <class ELFT> bool elf::isMipsPIC(const Defined *sym) {
+template <class ELFT> bool isMipsPIC(const Defined *sym) {
if (!sym->isFunc())
return false;
@@ -725,17 +736,20 @@ template <class ELFT> bool elf::isMipsPIC(const Defined *sym) {
return file->getObj().getHeader()->e_flags & EF_MIPS_PIC;
}
-template <class ELFT> TargetInfo *elf::getMipsTargetInfo() {
+template <class ELFT> TargetInfo *getMipsTargetInfo() {
static MIPS<ELFT> target;
return &target;
}
-template TargetInfo *elf::getMipsTargetInfo<ELF32LE>();
-template TargetInfo *elf::getMipsTargetInfo<ELF32BE>();
-template TargetInfo *elf::getMipsTargetInfo<ELF64LE>();
-template TargetInfo *elf::getMipsTargetInfo<ELF64BE>();
+template TargetInfo *getMipsTargetInfo<ELF32LE>();
+template TargetInfo *getMipsTargetInfo<ELF32BE>();
+template TargetInfo *getMipsTargetInfo<ELF64LE>();
+template TargetInfo *getMipsTargetInfo<ELF64BE>();
+
+template bool isMipsPIC<ELF32LE>(const Defined *);
+template bool isMipsPIC<ELF32BE>(const Defined *);
+template bool isMipsPIC<ELF64LE>(const Defined *);
+template bool isMipsPIC<ELF64BE>(const Defined *);
-template bool elf::isMipsPIC<ELF32LE>(const Defined *);
-template bool elf::isMipsPIC<ELF32BE>(const Defined *);
-template bool elf::isMipsPIC<ELF64LE>(const Defined *);
-template bool elf::isMipsPIC<ELF64BE>(const Defined *);
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/Arch/MipsArchTree.cpp b/contrib/llvm-project/lld/ELF/Arch/MipsArchTree.cpp
index 20e07e1114eb..923458afae0d 100644
--- a/contrib/llvm-project/lld/ELF/Arch/MipsArchTree.cpp
+++ b/contrib/llvm-project/lld/ELF/Arch/MipsArchTree.cpp
@@ -23,8 +23,8 @@ using namespace llvm;
using namespace llvm::object;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
+namespace lld {
+namespace elf {
namespace {
struct ArchTreeEdge {
@@ -166,17 +166,17 @@ static ArchTreeEdge archTree[] = {
{EF_MIPS_ARCH_2, EF_MIPS_ARCH_1},
};
-static bool isArchMatched(uint32_t New, uint32_t res) {
- if (New == res)
+static bool isArchMatched(uint32_t newFlags, uint32_t res) {
+ if (newFlags == res)
return true;
- if (New == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, res))
+ if (newFlags == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, res))
return true;
- if (New == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, res))
+ if (newFlags == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, res))
return true;
for (const auto &edge : archTree) {
if (res == edge.child) {
res = edge.parent;
- if (res == New)
+ if (res == newFlags)
return true;
}
}
@@ -278,46 +278,34 @@ static uint32_t getArchFlags(ArrayRef<FileFlags> files) {
uint32_t ret = files[0].flags & (EF_MIPS_ARCH | EF_MIPS_MACH);
for (const FileFlags &f : files.slice(1)) {
- uint32_t New = f.flags & (EF_MIPS_ARCH | EF_MIPS_MACH);
+ uint32_t newFlags = f.flags & (EF_MIPS_ARCH | EF_MIPS_MACH);
// Check ISA compatibility.
- if (isArchMatched(New, ret))
+ if (isArchMatched(newFlags, ret))
continue;
- if (!isArchMatched(ret, New)) {
+ if (!isArchMatched(ret, newFlags)) {
error("incompatible target ISA:\n>>> " + toString(files[0].file) + ": " +
getFullArchName(ret) + "\n>>> " + toString(f.file) + ": " +
- getFullArchName(New));
+ getFullArchName(newFlags));
return 0;
}
- ret = New;
+ ret = newFlags;
}
return ret;
}
-// If we don't have any input files, we'll have to rely on the information we
-// can derive from emulation information, since this at least gets us ABI.
-static uint32_t getFlagsFromEmulation() {
- uint32_t ret = 0;
-
- if (config->emulation.empty())
- return 0;
-
- if (config->ekind == ELF32BEKind || config->ekind == ELF32LEKind) {
- if (config->mipsN32Abi)
- ret |= EF_MIPS_ABI2;
- else
- ret |= EF_MIPS_ABI_O32;
- }
-
- return ret;
-}
-
-template <class ELFT> uint32_t elf::calcMipsEFlags() {
+template <class ELFT> uint32_t calcMipsEFlags() {
std::vector<FileFlags> v;
for (InputFile *f : objectFiles)
v.push_back({f, cast<ObjFile<ELFT>>(f)->getObj().getHeader()->e_flags});
- if (v.empty())
- return getFlagsFromEmulation();
+ if (v.empty()) {
+ // If we don't have any input files, we'll have to rely on the information
+ // we can derive from emulation information, since this at least gets us
+ // ABI.
+ if (config->emulation.empty() || config->is64)
+ return 0;
+ return config->mipsN32Abi ? EF_MIPS_ABI2 : EF_MIPS_ABI_O32;
+ }
checkFlags(v);
return getMiscFlags(v) | getPicFlags(v) | getArchFlags(v);
}
@@ -362,8 +350,7 @@ static StringRef getMipsFpAbiName(uint8_t fpAbi) {
}
}
-uint8_t elf::getMipsFpAbiFlag(uint8_t oldFlag, uint8_t newFlag,
- StringRef fileName) {
+uint8_t getMipsFpAbiFlag(uint8_t oldFlag, uint8_t newFlag, StringRef fileName) {
if (compareMipsFpAbi(newFlag, oldFlag) >= 0)
return newFlag;
if (compareMipsFpAbi(oldFlag, newFlag) < 0)
@@ -379,7 +366,7 @@ template <class ELFT> static bool isN32Abi(const InputFile *f) {
return false;
}
-bool elf::isMipsN32Abi(const InputFile *f) {
+bool isMipsN32Abi(const InputFile *f) {
switch (config->ekind) {
case ELF32LEKind:
return isN32Abi<ELF32LE>(f);
@@ -394,14 +381,17 @@ bool elf::isMipsN32Abi(const InputFile *f) {
}
}
-bool elf::isMicroMips() { return config->eflags & EF_MIPS_MICROMIPS; }
+bool isMicroMips() { return config->eflags & EF_MIPS_MICROMIPS; }
-bool elf::isMipsR6() {
+bool isMipsR6() {
uint32_t arch = config->eflags & EF_MIPS_ARCH;
return arch == EF_MIPS_ARCH_32R6 || arch == EF_MIPS_ARCH_64R6;
}
-template uint32_t elf::calcMipsEFlags<ELF32LE>();
-template uint32_t elf::calcMipsEFlags<ELF32BE>();
-template uint32_t elf::calcMipsEFlags<ELF64LE>();
-template uint32_t elf::calcMipsEFlags<ELF64BE>();
+template uint32_t calcMipsEFlags<ELF32LE>();
+template uint32_t calcMipsEFlags<ELF32BE>();
+template uint32_t calcMipsEFlags<ELF64LE>();
+template uint32_t calcMipsEFlags<ELF64BE>();
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/Arch/PPC.cpp b/contrib/llvm-project/lld/ELF/Arch/PPC.cpp
index cf4ad4049926..c4eecb9a29c2 100644
--- a/contrib/llvm-project/lld/ELF/Arch/PPC.cpp
+++ b/contrib/llvm-project/lld/ELF/Arch/PPC.cpp
@@ -16,8 +16,9 @@
using namespace llvm;
using namespace llvm::support::endian;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
+
+namespace lld {
+namespace elf {
namespace {
class PPC final : public TargetInfo {
@@ -61,7 +62,7 @@ static void writeFromHalf16(uint8_t *loc, uint32_t insn) {
write32(config->isLE ? loc : loc - 2, insn);
}
-void elf::writePPC32GlinkSection(uint8_t *buf, size_t numEntries) {
+void writePPC32GlinkSection(uint8_t *buf, size_t numEntries) {
// On PPC Secure PLT ABI, bl foo@plt jumps to a call stub, which loads an
// absolute address from a specific .plt slot (usually called .got.plt on
// other targets) and jumps there.
@@ -435,7 +436,10 @@ void PPC::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const {
}
}
-TargetInfo *elf::getPPCTargetInfo() {
+TargetInfo *getPPCTargetInfo() {
static PPC target;
return &target;
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/Arch/PPC64.cpp b/contrib/llvm-project/lld/ELF/Arch/PPC64.cpp
index 0f382dcd6b3c..905903fa4d66 100644
--- a/contrib/llvm-project/lld/ELF/Arch/PPC64.cpp
+++ b/contrib/llvm-project/lld/ELF/Arch/PPC64.cpp
@@ -16,8 +16,9 @@ using namespace llvm;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
+
+namespace lld {
+namespace elf {
static uint64_t ppc64TocOffset = 0x8000;
static uint64_t dynamicThreadPointerOffset = 0x8000;
@@ -59,7 +60,7 @@ enum DFormOpcd {
ADDI = 14
};
-uint64_t elf::getPPC64TocBase() {
+uint64_t getPPC64TocBase() {
// The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The
// TOC starts where the first of these sections starts. We always create a
// .got when we see a relocation that uses it, so for us the start is always
@@ -73,7 +74,7 @@ uint64_t elf::getPPC64TocBase() {
return tocVA + ppc64TocOffset;
}
-unsigned elf::getPPC64GlobalEntryToLocalEntryOffset(uint8_t stOther) {
+unsigned getPPC64GlobalEntryToLocalEntryOffset(uint8_t stOther) {
// The offset is encoded into the 3 most significant bits of the st_other
// field, with some special values described in section 3.4.1 of the ABI:
// 0 --> Zero offset between the GEP and LEP, and the function does NOT use
@@ -98,7 +99,7 @@ unsigned elf::getPPC64GlobalEntryToLocalEntryOffset(uint8_t stOther) {
return 0;
}
-bool elf::isPPC64SmallCodeModelTocReloc(RelType type) {
+bool isPPC64SmallCodeModelTocReloc(RelType type) {
// The only small code model relocations that access the .toc section.
return type == R_PPC64_TOC16 || type == R_PPC64_TOC16_DS;
}
@@ -153,8 +154,8 @@ getRelaTocSymAndAddend(InputSectionBase *tocSec, uint64_t offset) {
// ld/lwa 3, 0(3) # load the value from the address
//
// Returns true if the relaxation is performed.
-bool elf::tryRelaxPPC64TocIndirection(RelType type, const Relocation &rel,
- uint8_t *bufLoc) {
+bool tryRelaxPPC64TocIndirection(RelType type, const Relocation &rel,
+ uint8_t *bufLoc) {
assert(config->tocOptimize);
if (rel.addend < 0)
return false;
@@ -175,6 +176,10 @@ bool elf::tryRelaxPPC64TocIndirection(RelType type, const Relocation &rel,
if (!d || d->isPreemptible)
return false;
+ // R_PPC64_ADDR64 should have created a canonical PLT for the non-preemptable
+ // ifunc and changed its type to STT_FUNC.
+ assert(!d->isGnuIFunc());
+
// Two instructions can materialize a 32-bit signed offset from the toc base.
uint64_t tocRelative = d->getVA(addend) - getPPC64TocBase();
if (!isInt<32>(tocRelative))
@@ -454,7 +459,7 @@ void PPC64::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const {
}
}
-unsigned elf::getPPCDFormOp(unsigned secondaryOp) {
+unsigned getPPCDFormOp(unsigned secondaryOp) {
switch (secondaryOp) {
case LBZX:
return LBZ;
@@ -1089,7 +1094,10 @@ bool PPC64::adjustPrologueForCrossSplitStack(uint8_t *loc, uint8_t *end,
return true;
}
-TargetInfo *elf::getPPC64TargetInfo() {
+TargetInfo *getPPC64TargetInfo() {
static PPC64 target;
return &target;
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/Arch/RISCV.cpp b/contrib/llvm-project/lld/ELF/Arch/RISCV.cpp
index 80c2da48ca30..9a6b7990f2a0 100644
--- a/contrib/llvm-project/lld/ELF/Arch/RISCV.cpp
+++ b/contrib/llvm-project/lld/ELF/Arch/RISCV.cpp
@@ -14,8 +14,9 @@ using namespace llvm;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
+
+namespace lld {
+namespace elf {
namespace {
@@ -439,7 +440,10 @@ void RISCV::relocateOne(uint8_t *loc, const RelType type,
}
}
-TargetInfo *elf::getRISCVTargetInfo() {
+TargetInfo *getRISCVTargetInfo() {
static RISCV target;
return &target;
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/Arch/SPARCV9.cpp b/contrib/llvm-project/lld/ELF/Arch/SPARCV9.cpp
index 5299206dd919..a0afdff08a63 100644
--- a/contrib/llvm-project/lld/ELF/Arch/SPARCV9.cpp
+++ b/contrib/llvm-project/lld/ELF/Arch/SPARCV9.cpp
@@ -16,8 +16,9 @@
using namespace llvm;
using namespace llvm::support::endian;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
+
+namespace lld {
+namespace elf {
namespace {
class SPARCV9 final : public TargetInfo {
@@ -143,7 +144,10 @@ void SPARCV9::writePlt(uint8_t *buf, uint64_t gotEntryAddr,
relocateOne(buf + 4, R_SPARC_WDISP19, -(off + 4 - pltEntrySize));
}
-TargetInfo *elf::getSPARCV9TargetInfo() {
+TargetInfo *getSPARCV9TargetInfo() {
static SPARCV9 target;
return &target;
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/Arch/X86.cpp b/contrib/llvm-project/lld/ELF/Arch/X86.cpp
index e1dd231e8e8d..b27a6e302e78 100644
--- a/contrib/llvm-project/lld/ELF/Arch/X86.cpp
+++ b/contrib/llvm-project/lld/ELF/Arch/X86.cpp
@@ -16,8 +16,9 @@
using namespace llvm;
using namespace llvm::support::endian;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
+
+namespace lld {
+namespace elf {
namespace {
class X86 : public TargetInfo {
@@ -539,7 +540,7 @@ void RetpolineNoPic::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr,
write32le(buf + 22, -off - 26);
}
-TargetInfo *elf::getX86TargetInfo() {
+TargetInfo *getX86TargetInfo() {
if (config->zRetpolineplt) {
if (config->isPic) {
static RetpolinePic t;
@@ -552,3 +553,6 @@ TargetInfo *elf::getX86TargetInfo() {
static X86 t;
return &t;
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/Arch/X86_64.cpp b/contrib/llvm-project/lld/ELF/Arch/X86_64.cpp
index de67aa5c33dc..bb8d92fc61b9 100644
--- a/contrib/llvm-project/lld/ELF/Arch/X86_64.cpp
+++ b/contrib/llvm-project/lld/ELF/Arch/X86_64.cpp
@@ -18,8 +18,9 @@ using namespace llvm;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
+
+namespace lld {
+namespace elf {
namespace {
class X86_64 : public TargetInfo {
@@ -698,4 +699,7 @@ static TargetInfo *getTargetInfo() {
return &t;
}
-TargetInfo *elf::getX86_64TargetInfo() { return getTargetInfo(); }
+TargetInfo *getX86_64TargetInfo() { return getTargetInfo(); }
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/CMakeLists.txt b/contrib/llvm-project/lld/ELF/CMakeLists.txt
index 70578746483d..1ba79bec73df 100644
--- a/contrib/llvm-project/lld/ELF/CMakeLists.txt
+++ b/contrib/llvm-project/lld/ELF/CMakeLists.txt
@@ -22,6 +22,7 @@ add_lld_library(lldELF
Arch/SPARCV9.cpp
Arch/X86.cpp
Arch/X86_64.cpp
+ ARMErrataFix.cpp
CallGraphSort.cpp
DWARF.cpp
Driver.cpp
diff --git a/contrib/llvm-project/lld/ELF/CallGraphSort.cpp b/contrib/llvm-project/lld/ELF/CallGraphSort.cpp
index 9aaadd481833..6f8ef8954af3 100644
--- a/contrib/llvm-project/lld/ELF/CallGraphSort.cpp
+++ b/contrib/llvm-project/lld/ELF/CallGraphSort.cpp
@@ -45,9 +45,12 @@
#include "SymbolTable.h"
#include "Symbols.h"
+#include <numeric>
+
using namespace llvm;
-using namespace lld;
-using namespace lld::elf;
+
+namespace lld {
+namespace elf {
namespace {
struct Edge {
@@ -56,7 +59,7 @@ struct Edge {
};
struct Cluster {
- Cluster(int sec, size_t s) : sections{sec}, size(s) {}
+ Cluster(int sec, size_t s) : next(sec), prev(sec), size(s) {}
double getDensity() const {
if (size == 0)
@@ -64,7 +67,8 @@ struct Cluster {
return double(weight) / double(size);
}
- std::vector<int> sections;
+ int next;
+ int prev;
size_t size = 0;
uint64_t weight = 0;
uint64_t initialWeight = 0;
@@ -80,8 +84,6 @@ public:
private:
std::vector<Cluster> clusters;
std::vector<const InputSectionBase *> sections;
-
- void groupClusters();
};
// Maximum ammount the combined cluster density can be worse than the original
@@ -103,7 +105,7 @@ CallGraphSort::CallGraphSort() {
DenseMap<const InputSectionBase *, int> secToCluster;
auto getOrCreateNode = [&](const InputSectionBase *isec) -> int {
- auto res = secToCluster.insert(std::make_pair(isec, clusters.size()));
+ auto res = secToCluster.try_emplace(isec, clusters.size());
if (res.second) {
sections.push_back(isec);
clusters.emplace_back(clusters.size(), isec->getSize());
@@ -151,83 +153,88 @@ static bool isNewDensityBad(Cluster &a, Cluster &b) {
return newDensity < a.getDensity() / MAX_DENSITY_DEGRADATION;
}
-static void mergeClusters(Cluster &into, Cluster &from) {
- into.sections.insert(into.sections.end(), from.sections.begin(),
- from.sections.end());
+// Find the leader of V's belonged cluster (represented as an equivalence
+// class). We apply union-find path-halving technique (simple to implement) in
+// the meantime as it decreases depths and the time complexity.
+static int getLeader(std::vector<int> &leaders, int v) {
+ while (leaders[v] != v) {
+ leaders[v] = leaders[leaders[v]];
+ v = leaders[v];
+ }
+ return v;
+}
+
+static void mergeClusters(std::vector<Cluster> &cs, Cluster &into, int intoIdx,
+ Cluster &from, int fromIdx) {
+ int tail1 = into.prev, tail2 = from.prev;
+ into.prev = tail2;
+ cs[tail2].next = intoIdx;
+ from.prev = tail1;
+ cs[tail1].next = fromIdx;
into.size += from.size;
into.weight += from.weight;
- from.sections.clear();
from.size = 0;
from.weight = 0;
}
// Group InputSections into clusters using the Call-Chain Clustering heuristic
// then sort the clusters by density.
-void CallGraphSort::groupClusters() {
- std::vector<int> sortedSecs(clusters.size());
- std::vector<Cluster *> secToCluster(clusters.size());
-
- for (size_t i = 0; i < clusters.size(); ++i) {
- sortedSecs[i] = i;
- secToCluster[i] = &clusters[i];
- }
+DenseMap<const InputSectionBase *, int> CallGraphSort::run() {
+ std::vector<int> sorted(clusters.size());
+ std::vector<int> leaders(clusters.size());
- llvm::stable_sort(sortedSecs, [&](int a, int b) {
+ std::iota(leaders.begin(), leaders.end(), 0);
+ std::iota(sorted.begin(), sorted.end(), 0);
+ llvm::stable_sort(sorted, [&](int a, int b) {
return clusters[a].getDensity() > clusters[b].getDensity();
});
- for (int si : sortedSecs) {
- // clusters[si] is the same as secToClusters[si] here because it has not
- // been merged into another cluster yet.
- Cluster &c = clusters[si];
+ for (int l : sorted) {
+ // The cluster index is the same as the index of its leader here because
+ // clusters[L] has not been merged into another cluster yet.
+ Cluster &c = clusters[l];
// Don't consider merging if the edge is unlikely.
if (c.bestPred.from == -1 || c.bestPred.weight * 10 <= c.initialWeight)
continue;
- Cluster *predC = secToCluster[c.bestPred.from];
- if (predC == &c)
+ int predL = getLeader(leaders, c.bestPred.from);
+ if (l == predL)
continue;
+ Cluster *predC = &clusters[predL];
if (c.size + predC->size > MAX_CLUSTER_SIZE)
continue;
if (isNewDensityBad(*predC, c))
continue;
- // NOTE: Consider using a disjoint-set to track section -> cluster mapping
- // if this is ever slow.
- for (int si : c.sections)
- secToCluster[si] = predC;
-
- mergeClusters(*predC, c);
+ leaders[l] = predL;
+ mergeClusters(clusters, *predC, predL, c, l);
}
- // Remove empty or dead nodes. Invalidates all cluster indices.
- llvm::erase_if(clusters, [](const Cluster &c) {
- return c.size == 0 || c.sections.empty();
+ // Sort remaining non-empty clusters by density.
+ sorted.clear();
+ for (int i = 0, e = (int)clusters.size(); i != e; ++i)
+ if (clusters[i].size > 0)
+ sorted.push_back(i);
+ llvm::stable_sort(sorted, [&](int a, int b) {
+ return clusters[a].getDensity() > clusters[b].getDensity();
});
- // Sort by density.
- llvm::stable_sort(clusters, [](const Cluster &a, const Cluster &b) {
- return a.getDensity() > b.getDensity();
- });
-}
-
-DenseMap<const InputSectionBase *, int> CallGraphSort::run() {
- groupClusters();
-
- // Generate order.
DenseMap<const InputSectionBase *, int> orderMap;
- ssize_t curOrder = 1;
-
- for (const Cluster &c : clusters)
- for (int secIndex : c.sections)
- orderMap[sections[secIndex]] = curOrder++;
+ int curOrder = 1;
+ for (int leader : sorted)
+ for (int i = leader;;) {
+ orderMap[sections[i]] = curOrder++;
+ i = clusters[i].next;
+ if (i == leader)
+ break;
+ }
if (!config->printSymbolOrder.empty()) {
std::error_code ec;
- raw_fd_ostream os(config->printSymbolOrder, ec, sys::fs::F_None);
+ raw_fd_ostream os(config->printSymbolOrder, ec, sys::fs::OF_None);
if (ec) {
error("cannot open " + config->printSymbolOrder + ": " + ec.message());
return orderMap;
@@ -235,15 +242,19 @@ DenseMap<const InputSectionBase *, int> CallGraphSort::run() {
// Print the symbols ordered by C3, in the order of increasing curOrder
// Instead of sorting all the orderMap, just repeat the loops above.
- for (const Cluster &c : clusters)
- for (int secIndex : c.sections)
+ for (int leader : sorted)
+ for (int i = leader;;) {
// Search all the symbols in the file of the section
// and find out a Defined symbol with name that is within the section.
- for (Symbol *sym: sections[secIndex]->file->getSymbols())
+ for (Symbol *sym : sections[i]->file->getSymbols())
if (!sym->isSection()) // Filter out section-type symbols here.
if (auto *d = dyn_cast<Defined>(sym))
- if (sections[secIndex] == d->section)
+ if (sections[i] == d->section)
os << sym->getName() << "\n";
+ i = clusters[i].next;
+ if (i == leader)
+ break;
+ }
}
return orderMap;
@@ -254,6 +265,9 @@ DenseMap<const InputSectionBase *, int> CallGraphSort::run() {
// This first builds a call graph based on the profile data then merges sections
// according to the C³ huristic. All clusters are then sorted by a density
// metric to further improve locality.
-DenseMap<const InputSectionBase *, int> elf::computeCallGraphProfileOrder() {
+DenseMap<const InputSectionBase *, int> computeCallGraphProfileOrder() {
return CallGraphSort().run();
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/Config.h b/contrib/llvm-project/lld/ELF/Config.h
index ff9d3dc0933c..0c68a8485fa2 100644
--- a/contrib/llvm-project/lld/ELF/Config.h
+++ b/contrib/llvm-project/lld/ELF/Config.h
@@ -61,6 +61,9 @@ enum class Target2Policy { Abs, Rel, GotRel };
// For tracking ARM Float Argument PCS
enum class ARMVFPArgKind { Default, Base, VFP, ToolChain };
+// For -z noseparate-code, -z separate-code and -z separate-loadable-segments.
+enum class SeparateSegmentKind { None, Code, Loadable };
+
struct SymbolVersion {
llvm::StringRef name;
bool isExternCpp;
@@ -71,8 +74,8 @@ struct SymbolVersion {
// can be found in version script if it is used for link.
struct VersionDefinition {
llvm::StringRef name;
- uint16_t id = 0;
- std::vector<SymbolVersion> globals;
+ uint16_t id;
+ std::vector<SymbolVersion> patterns;
};
// This struct contains the global configuration for the linker.
@@ -117,8 +120,6 @@ struct Configuration {
std::vector<llvm::StringRef> symbolOrderingFile;
std::vector<llvm::StringRef> undefined;
std::vector<SymbolVersion> dynamicList;
- std::vector<SymbolVersion> versionScriptGlobals;
- std::vector<SymbolVersion> versionScriptLocals;
std::vector<uint8_t> buildIdVector;
llvm::MapVector<std::pair<const InputSectionBase *, const InputSectionBase *>,
uint64_t>
@@ -147,6 +148,7 @@ struct Configuration {
bool executeOnly;
bool exportDynamic;
bool fixCortexA53Errata843419;
+ bool fixCortexA8;
bool forceBTI;
bool formatBinary = false;
bool requireCET;
@@ -222,8 +224,8 @@ struct Configuration {
Target2Policy target2;
ARMVFPArgKind armVFPArgs = ARMVFPArgKind::Default;
BuildIdKind buildId = BuildIdKind::None;
+ SeparateSegmentKind zSeparate;
ELFKind ekind = ELFNoneKind;
- uint16_t defaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL;
uint16_t emachine = llvm::ELF::EM_NONE;
llvm::Optional<uint64_t> imageBase;
uint64_t commonPageSize;
@@ -309,6 +311,12 @@ struct Configuration {
// The only instance of Configuration struct.
extern Configuration *config;
+// The first two elements of versionDefinitions represent VER_NDX_LOCAL and
+// VER_NDX_GLOBAL. This helper returns other elements.
+static inline ArrayRef<VersionDefinition> namedVersionDefs() {
+ return llvm::makeArrayRef(config->versionDefinitions).slice(2);
+}
+
static inline void errorOrWarn(const Twine &msg) {
if (!config->noinhibitExec)
error(msg);
diff --git a/contrib/llvm-project/lld/ELF/DWARF.cpp b/contrib/llvm-project/lld/ELF/DWARF.cpp
index 1e4b36f71b54..a00189a0e3a2 100644
--- a/contrib/llvm-project/lld/ELF/DWARF.cpp
+++ b/contrib/llvm-project/lld/ELF/DWARF.cpp
@@ -22,9 +22,9 @@
using namespace llvm;
using namespace llvm::object;
-using namespace lld;
-using namespace lld::elf;
+namespace lld {
+namespace elf {
template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *obj) {
for (InputSectionBase *sec : obj->getSections()) {
if (!sec)
@@ -33,11 +33,12 @@ template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *obj) {
if (LLDDWARFSection *m =
StringSwitch<LLDDWARFSection *>(sec->name)
.Case(".debug_addr", &addrSection)
- .Case(".debug_gnu_pubnames", &gnuPubNamesSection)
- .Case(".debug_gnu_pubtypes", &gnuPubTypesSection)
+ .Case(".debug_gnu_pubnames", &gnuPubnamesSection)
+ .Case(".debug_gnu_pubtypes", &gnuPubtypesSection)
.Case(".debug_info", &infoSection)
- .Case(".debug_ranges", &rangeSection)
- .Case(".debug_rnglists", &rngListsSection)
+ .Case(".debug_ranges", &rangesSection)
+ .Case(".debug_rnglists", &rnglistsSection)
+ .Case(".debug_str_offsets", &strOffsetsSection)
.Case(".debug_line", &lineSection)
.Default(nullptr)) {
m->Data = toStringRef(sec->data());
@@ -50,7 +51,7 @@ template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *obj) {
else if (sec->name == ".debug_str")
strSection = toStringRef(sec->data());
else if (sec->name == ".debug_line_str")
- lineStringSection = toStringRef(sec->data());
+ lineStrSection = toStringRef(sec->data());
}
}
@@ -123,7 +124,10 @@ Optional<RelocAddrEntry> LLDDwarfObj<ELFT>::find(const llvm::DWARFSection &s,
return findAux(*sec.sec, pos, sec.sec->template rels<ELFT>());
}
-template class elf::LLDDwarfObj<ELF32LE>;
-template class elf::LLDDwarfObj<ELF32BE>;
-template class elf::LLDDwarfObj<ELF64LE>;
-template class elf::LLDDwarfObj<ELF64BE>;
+template class LLDDwarfObj<ELF32LE>;
+template class LLDDwarfObj<ELF32BE>;
+template class LLDDwarfObj<ELF64LE>;
+template class LLDDwarfObj<ELF64BE>;
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/DWARF.h b/contrib/llvm-project/lld/ELF/DWARF.h
index 426022945007..51ec9092f172 100644
--- a/contrib/llvm-project/lld/ELF/DWARF.h
+++ b/contrib/llvm-project/lld/ELF/DWARF.h
@@ -32,12 +32,16 @@ public:
f(infoSection);
}
- const llvm::DWARFSection &getRangeSection() const override {
- return rangeSection;
+ const llvm::DWARFSection &getRangesSection() const override {
+ return rangesSection;
}
const llvm::DWARFSection &getRnglistsSection() const override {
- return rngListsSection;
+ return rnglistsSection;
+ }
+
+ const llvm::DWARFSection &getStrOffsetsSection() const override {
+ return strOffsetsSection;
}
const llvm::DWARFSection &getLineSection() const override {
@@ -48,18 +52,18 @@ public:
return addrSection;
}
- const llvm::DWARFSection &getGnuPubNamesSection() const override {
- return gnuPubNamesSection;
+ const llvm::DWARFSection &getGnuPubnamesSection() const override {
+ return gnuPubnamesSection;
}
- const llvm::DWARFSection &getGnuPubTypesSection() const override {
- return gnuPubTypesSection;
+ const llvm::DWARFSection &getGnuPubtypesSection() const override {
+ return gnuPubtypesSection;
}
StringRef getFileName() const override { return ""; }
StringRef getAbbrevSection() const override { return abbrevSection; }
- StringRef getStringSection() const override { return strSection; }
- StringRef getLineStringSection() const override { return lineStringSection; }
+ StringRef getStrSection() const override { return strSection; }
+ StringRef getLineStrSection() const override { return lineStrSection; }
bool isLittleEndian() const override {
return ELFT::TargetEndianness == llvm::support::little;
@@ -74,16 +78,17 @@ private:
uint64_t pos,
ArrayRef<RelTy> rels) const;
- LLDDWARFSection gnuPubNamesSection;
- LLDDWARFSection gnuPubTypesSection;
+ LLDDWARFSection gnuPubnamesSection;
+ LLDDWARFSection gnuPubtypesSection;
LLDDWARFSection infoSection;
- LLDDWARFSection rangeSection;
- LLDDWARFSection rngListsSection;
+ LLDDWARFSection rangesSection;
+ LLDDWARFSection rnglistsSection;
+ LLDDWARFSection strOffsetsSection;
LLDDWARFSection lineSection;
LLDDWARFSection addrSection;
StringRef abbrevSection;
StringRef strSection;
- StringRef lineStringSection;
+ StringRef lineStrSection;
};
} // namespace elf
diff --git a/contrib/llvm-project/lld/ELF/Driver.cpp b/contrib/llvm-project/lld/ELF/Driver.cpp
index 81894e98f395..96257a4c7624 100644
--- a/contrib/llvm-project/lld/ELF/Driver.cpp
+++ b/contrib/llvm-project/lld/ELF/Driver.cpp
@@ -48,6 +48,7 @@
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/LTO/LTO.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/GlobPattern.h"
@@ -65,24 +66,23 @@ using namespace llvm::object;
using namespace llvm::sys;
using namespace llvm::support;
-using namespace lld;
-using namespace lld::elf;
+namespace lld {
+namespace elf {
-Configuration *elf::config;
-LinkerDriver *elf::driver;
+Configuration *config;
+LinkerDriver *driver;
static void setConfigs(opt::InputArgList &args);
static void readConfigs(opt::InputArgList &args);
-bool elf::link(ArrayRef<const char *> args, bool canExitEarly,
- raw_ostream &error) {
+bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &error) {
errorHandler().logName = args::getFilenameWithoutExe(args[0]);
errorHandler().errorLimitExceededMsg =
"too many errors emitted, stopping now (use "
"-error-limit=0 to see all errors)";
errorHandler().errorOS = &error;
errorHandler().exitEarly = canExitEarly;
- errorHandler().colorDiagnostics = error.has_colors();
+ enableColors(error.has_colors());
inputSections.clear();
outputSections.clear();
@@ -299,6 +299,9 @@ static void checkOptions() {
if (config->fixCortexA53Errata843419 && config->emachine != EM_AARCH64)
error("--fix-cortex-a53-843419 is only supported on AArch64 targets");
+ if (config->fixCortexA8 && config->emachine != EM_ARM)
+ error("--fix-cortex-a8 is only supported on ARM targets");
+
if (config->tocOptimize && config->emachine != EM_PPC64)
error("--toc-optimize is only supported on the PowerPC64 target");
@@ -314,6 +317,9 @@ static void checkOptions() {
if (!config->relocatable && !config->defineCommon)
error("-no-define-common not supported in non relocatable output");
+ if (config->strip == StripPolicy::All && config->emitRelocs)
+ error("--strip-all and --emit-relocs may not be used together");
+
if (config->zText && config->zIfuncNoplt)
error("-z text and -z ifunc-noplt may not be used together");
@@ -328,6 +334,8 @@ static void checkOptions() {
error("-r and --icf may not be used together");
if (config->pie)
error("-r and -pie may not be used together");
+ if (config->exportDynamic)
+ error("-r and --export-dynamic may not be used together");
}
if (config->executeOnly) {
@@ -373,17 +381,32 @@ static bool getZFlag(opt::InputArgList &args, StringRef k1, StringRef k2,
return Default;
}
+static SeparateSegmentKind getZSeparate(opt::InputArgList &args) {
+ for (auto *arg : args.filtered_reverse(OPT_z)) {
+ StringRef v = arg->getValue();
+ if (v == "noseparate-code")
+ return SeparateSegmentKind::None;
+ if (v == "separate-code")
+ return SeparateSegmentKind::Code;
+ if (v == "separate-loadable-segments")
+ return SeparateSegmentKind::Loadable;
+ }
+ return SeparateSegmentKind::None;
+}
+
static bool isKnownZFlag(StringRef s) {
return s == "combreloc" || s == "copyreloc" || s == "defs" ||
s == "execstack" || s == "global" || s == "hazardplt" ||
s == "ifunc-noplt" || s == "initfirst" || s == "interpose" ||
s == "keep-text-section-prefix" || s == "lazy" || s == "muldefs" ||
+ s == "separate-code" || s == "separate-loadable-segments" ||
s == "nocombreloc" || s == "nocopyreloc" || s == "nodefaultlib" ||
s == "nodelete" || s == "nodlopen" || s == "noexecstack" ||
- s == "nokeep-text-section-prefix" || s == "norelro" || s == "notext" ||
- s == "now" || s == "origin" || s == "relro" || s == "retpolineplt" ||
- s == "rodynamic" || s == "text" || s == "wxneeded" ||
- s.startswith("common-page-size") || s.startswith("max-page-size=") ||
+ s == "nokeep-text-section-prefix" || s == "norelro" ||
+ s == "noseparate-code" || s == "notext" || s == "now" ||
+ s == "origin" || s == "relro" || s == "retpolineplt" ||
+ s == "rodynamic" || s == "text" || s == "undefs" || s == "wxneeded" ||
+ s.startswith("common-page-size=") || s.startswith("max-page-size=") ||
s.startswith("stack-size=");
}
@@ -513,6 +536,8 @@ static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &args) {
case OPT_z:
if (StringRef(arg->getValue()) == "defs")
return errorOrWarn;
+ if (StringRef(arg->getValue()) == "undefs")
+ return UnresolvedPolicy::Ignore;
continue;
}
}
@@ -747,6 +772,12 @@ static bool getCompressDebugSections(opt::InputArgList &args) {
return true;
}
+static StringRef getAliasSpelling(opt::Arg *arg) {
+ if (const opt::Arg *alias = arg->getAlias())
+ return alias->getSpelling();
+ return arg->getSpelling();
+}
+
static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &args,
unsigned id) {
auto *arg = args.getLastArg(id);
@@ -756,7 +787,7 @@ static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &args,
StringRef s = arg->getValue();
std::pair<StringRef, StringRef> ret = s.split(';');
if (ret.second.empty())
- error(arg->getSpelling() + " expects 'old;new' format, but got " + s);
+ error(getAliasSpelling(arg) + " expects 'old;new' format, but got " + s);
return ret;
}
@@ -829,6 +860,7 @@ static void readConfigs(opt::InputArgList &args) {
config->filterList = args::getStrings(args, OPT_filter);
config->fini = args.getLastArgValue(OPT_fini, "_fini");
config->fixCortexA53Errata843419 = args.hasArg(OPT_fix_cortex_a53_843419);
+ config->fixCortexA8 = args.hasArg(OPT_fix_cortex_a8);
config->forceBTI = args.hasArg(OPT_force_bti);
config->requireCET = args.hasArg(OPT_require_cet);
config->gcSections = args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false);
@@ -847,7 +879,7 @@ static void readConfigs(opt::InputArgList &args) {
config->ltoNewPassManager = args.hasArg(OPT_lto_new_pass_manager);
config->ltoNewPmPasses = args.getLastArgValue(OPT_lto_newpm_passes);
config->ltoo = args::getInteger(args, OPT_lto_O, 2);
- config->ltoObjPath = args.getLastArgValue(OPT_plugin_opt_obj_path_eq);
+ config->ltoObjPath = args.getLastArgValue(OPT_lto_obj_path_eq);
config->ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1);
config->ltoSampleProfile = args.getLastArgValue(OPT_lto_sample_profile);
config->mapFile = args.getLastArgValue(OPT_Map);
@@ -892,17 +924,15 @@ static void readConfigs(opt::InputArgList &args) {
config->thinLTOCachePolicy = CHECK(
parseCachePruningPolicy(args.getLastArgValue(OPT_thinlto_cache_policy)),
"--thinlto-cache-policy: invalid cache policy");
- config->thinLTOEmitImportsFiles =
- args.hasArg(OPT_plugin_opt_thinlto_emit_imports_files);
- config->thinLTOIndexOnly = args.hasArg(OPT_plugin_opt_thinlto_index_only) ||
- args.hasArg(OPT_plugin_opt_thinlto_index_only_eq);
- config->thinLTOIndexOnlyArg =
- args.getLastArgValue(OPT_plugin_opt_thinlto_index_only_eq);
+ config->thinLTOEmitImportsFiles = args.hasArg(OPT_thinlto_emit_imports_files);
+ config->thinLTOIndexOnly = args.hasArg(OPT_thinlto_index_only) ||
+ args.hasArg(OPT_thinlto_index_only_eq);
+ config->thinLTOIndexOnlyArg = args.getLastArgValue(OPT_thinlto_index_only_eq);
config->thinLTOJobs = args::getInteger(args, OPT_thinlto_jobs, -1u);
config->thinLTOObjectSuffixReplace =
- getOldNewOptions(args, OPT_plugin_opt_thinlto_object_suffix_replace_eq);
+ getOldNewOptions(args, OPT_thinlto_object_suffix_replace_eq);
config->thinLTOPrefixReplace =
- getOldNewOptions(args, OPT_plugin_opt_thinlto_prefix_replace_eq);
+ getOldNewOptions(args, OPT_thinlto_prefix_replace_eq);
config->trace = args.hasArg(OPT_trace);
config->undefined = args::getStrings(args, OPT_undefined);
config->undefinedVersion =
@@ -935,6 +965,7 @@ static void readConfigs(opt::InputArgList &args) {
config->zRelro = getZFlag(args, "relro", "norelro", true);
config->zRetpolineplt = hasZOption(args, "retpolineplt");
config->zRodynamic = hasZOption(args, "rodynamic");
+ config->zSeparate = getZSeparate(args);
config->zStackSize = args::getZOptionValue(args, OPT_z, "stack-size", 0);
config->zText = getZFlag(args, "text", "notext", true);
config->zWxneeded = hasZOption(args, "wxneeded");
@@ -1010,30 +1041,33 @@ static void readConfigs(opt::InputArgList &args) {
}
}
+ assert(config->versionDefinitions.empty());
+ config->versionDefinitions.push_back({"local", (uint16_t)VER_NDX_LOCAL, {}});
+ config->versionDefinitions.push_back(
+ {"global", (uint16_t)VER_NDX_GLOBAL, {}});
+
// If --retain-symbol-file is used, we'll keep only the symbols listed in
// the file and discard all others.
if (auto *arg = args.getLastArg(OPT_retain_symbols_file)) {
- config->defaultSymbolVersion = VER_NDX_LOCAL;
+ config->versionDefinitions[VER_NDX_LOCAL].patterns.push_back(
+ {"*", /*isExternCpp=*/false, /*hasWildcard=*/true});
if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue()))
for (StringRef s : args::getLines(*buffer))
- config->versionScriptGlobals.push_back(
- {s, /*IsExternCpp*/ false, /*HasWildcard*/ false});
+ config->versionDefinitions[VER_NDX_GLOBAL].patterns.push_back(
+ {s, /*isExternCpp=*/false, /*hasWildcard=*/false});
}
- bool hasExportDynamic =
- args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false);
-
// 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) {
+ if (!config->exportDynamic) {
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->dynamicList.push_back(
- {arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false});
+ {arg->getValue(), /*isExternCpp=*/false, /*hasWildcard=*/false});
}
// If --export-dynamic-symbol=foo is given and symbol foo is defined in
@@ -1659,12 +1693,6 @@ template <class ELFT> static uint32_t getAndFeatures() {
return ret;
}
-static const char *libcallRoutineNames[] = {
-#define HANDLE_LIBCALL(code, name) name,
-#include "llvm/IR/RuntimeLibcalls.def"
-#undef HANDLE_LIBCALL
-};
-
// 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) {
@@ -1755,7 +1783,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// libcall symbols will be added to the link after LTO when we add the LTO
// object file to the link.
if (!bitcodeFiles.empty())
- for (const char *s : libcallRoutineNames)
+ for (auto *s : lto::LTO::getRuntimeLibcallSymbols())
handleLibcall(s);
// Return if there were name resolution errors.
@@ -1880,20 +1908,54 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
"feature detected");
}
- // This adds a .comment section containing a version string. We have to add it
- // before mergeSections because the .comment section is a mergeable section.
+ // This adds a .comment section containing a version string.
if (!config->relocatable)
inputSections.push_back(createCommentSection());
// Replace common symbols with regular symbols.
replaceCommonSymbols();
- // Do size optimizations: garbage collection, merging of SHF_MERGE sections
- // and identical code folding.
+ // Split SHF_MERGE and .eh_frame sections into pieces in preparation for garbage collection.
splitSections<ELFT>();
+
+ // Garbage collection and removal of shared symbols from unused shared objects.
markLive<ELFT>();
demoteSharedSymbols();
- mergeSections();
+
+ // Make copies of any input sections that need to be copied into each
+ // partition.
+ copySectionsIntoPartitions();
+
+ // Create synthesized sections such as .got and .plt. This is called before
+ // processSectionCommands() so that they can be placed by SECTIONS commands.
+ createSyntheticSections<ELFT>();
+
+ // Some input sections that are used for exception handling need to be moved
+ // into synthetic sections. Do that now so that they aren't assigned to
+ // output sections in the usual way.
+ if (!config->relocatable)
+ combineEhSections();
+
+ // Create output sections described by SECTIONS commands.
+ script->processSectionCommands();
+
+ // Linker scripts control how input sections are assigned to output sections.
+ // Input sections that were not handled by scripts are called "orphans", and
+ // they are assigned to output sections by the default rule. Process that.
+ script->addOrphanSections();
+
+ // Migrate InputSectionDescription::sectionBases to sections. This includes
+ // merging MergeInputSections into a single MergeSyntheticSection. From this
+ // point onwards InputSectionDescription::sections should be used instead of
+ // sectionBases.
+ for (BaseCommand *base : script->sectionCommands)
+ if (auto *sec = dyn_cast<OutputSection>(base))
+ sec->finalizeInputSections();
+ llvm::erase_if(inputSections,
+ [](InputSectionBase *s) { return isa<MergeInputSection>(s); });
+
+ // Two input sections with different output sections should not be folded.
+ // ICF runs after processSectionCommands() so that we know the output sections.
if (config->icf != ICFLevel::None) {
findKeepUniqueSections<ELFT>(args);
doIcf<ELFT>();
@@ -1910,3 +1972,6 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// Write the result to the file.
writeResult<ELFT>();
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/DriverUtils.cpp b/contrib/llvm-project/lld/ELF/DriverUtils.cpp
index 87f0aa2a9827..43987cd5d4d4 100644
--- a/contrib/llvm-project/lld/ELF/DriverUtils.cpp
+++ b/contrib/llvm-project/lld/ELF/DriverUtils.cpp
@@ -30,8 +30,8 @@ using namespace llvm;
using namespace llvm::sys;
using namespace llvm::opt;
-using namespace lld;
-using namespace lld::elf;
+namespace lld {
+namespace elf {
// Create OptTable
@@ -59,15 +59,15 @@ static void handleColorDiagnostics(opt::InputArgList &args) {
if (!arg)
return;
if (arg->getOption().getID() == OPT_color_diagnostics) {
- errorHandler().colorDiagnostics = true;
+ enableColors(true);
} else if (arg->getOption().getID() == OPT_no_color_diagnostics) {
- errorHandler().colorDiagnostics = false;
+ enableColors(false);
} else {
StringRef s = arg->getValue();
if (s == "always")
- errorHandler().colorDiagnostics = true;
+ enableColors(true);
else if (s == "never")
- errorHandler().colorDiagnostics = false;
+ enableColors(false);
else if (s != "auto")
error("unknown option: --color-diagnostics=" + s);
}
@@ -143,7 +143,7 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> argv) {
return args;
}
-void elf::printHelp() {
+void printHelp() {
ELFOptTable().PrintHelp(
outs(), (config->progName + " [options] file...").str().c_str(), "lld",
false /*ShowHidden*/, true /*ShowAllAliases*/);
@@ -165,7 +165,7 @@ static std::string rewritePath(StringRef s) {
// Reconstructs command line arguments so that so that you can re-run
// the same command with the same inputs. This is for --reproduce.
-std::string elf::createResponseFile(const opt::InputArgList &args) {
+std::string createResponseFile(const opt::InputArgList &args) {
SmallString<0> data;
raw_svector_ostream os(data);
os << "--chroot .\n";
@@ -216,7 +216,7 @@ static Optional<std::string> findFile(StringRef path1, const Twine &path2) {
return None;
}
-Optional<std::string> elf::findFromSearchPaths(StringRef path) {
+Optional<std::string> findFromSearchPaths(StringRef path) {
for (StringRef dir : config->searchPaths)
if (Optional<std::string> s = findFile(dir, path))
return s;
@@ -225,7 +225,7 @@ Optional<std::string> elf::findFromSearchPaths(StringRef path) {
// This is for -l<basename>. We'll look for lib<basename>.so or lib<basename>.a from
// search paths.
-Optional<std::string> elf::searchLibraryBaseName(StringRef name) {
+Optional<std::string> searchLibraryBaseName(StringRef name) {
for (StringRef dir : config->searchPaths) {
if (!config->isStatic)
if (Optional<std::string> s = findFile(dir, "lib" + name + ".so"))
@@ -237,17 +237,20 @@ Optional<std::string> elf::searchLibraryBaseName(StringRef name) {
}
// This is for -l<namespec>.
-Optional<std::string> elf::searchLibrary(StringRef name) {
- if (name.startswith(":"))
- return findFromSearchPaths(name.substr(1));
- return searchLibraryBaseName (name);
+Optional<std::string> searchLibrary(StringRef name) {
+ if (name.startswith(":"))
+ return findFromSearchPaths(name.substr(1));
+ return searchLibraryBaseName(name);
}
// If a linker/version script doesn't exist in the current directory, we also
// look for the script in the '-L' search paths. This matches the behaviour of
// '-T', --version-script=, and linker script INPUT() command in ld.bfd.
-Optional<std::string> elf::searchScript(StringRef name) {
+Optional<std::string> searchScript(StringRef name) {
if (fs::exists(name))
return name.str();
return findFromSearchPaths(name);
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/EhFrame.cpp b/contrib/llvm-project/lld/ELF/EhFrame.cpp
index b3245dd01669..a9c66f29446c 100644
--- a/contrib/llvm-project/lld/ELF/EhFrame.cpp
+++ b/contrib/llvm-project/lld/ELF/EhFrame.cpp
@@ -30,9 +30,8 @@ using namespace llvm::ELF;
using namespace llvm::dwarf;
using namespace llvm::object;
-using namespace lld;
-using namespace lld::elf;
-
+namespace lld {
+namespace elf {
namespace {
class EhReader {
public:
@@ -57,7 +56,7 @@ private:
};
}
-size_t elf::readEhRecordSize(InputSectionBase *s, size_t off) {
+size_t readEhRecordSize(InputSectionBase *s, size_t off) {
return EhReader(s, s->data().slice(off)).readEhRecordSize();
}
@@ -149,7 +148,7 @@ void EhReader::skipAugP() {
d = d.slice(size);
}
-uint8_t elf::getFdeEncoding(EhSectionPiece *p) {
+uint8_t getFdeEncoding(EhSectionPiece *p) {
return EhReader(p->sec, p->data()).getFdeEncoding();
}
@@ -195,3 +194,6 @@ uint8_t EhReader::getFdeEncoding() {
}
return DW_EH_PE_absptr;
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/ICF.cpp b/contrib/llvm-project/lld/ELF/ICF.cpp
index 8b01d06b0248..dce76f79c9b3 100644
--- a/contrib/llvm-project/lld/ELF/ICF.cpp
+++ b/contrib/llvm-project/lld/ELF/ICF.cpp
@@ -74,6 +74,8 @@
#include "ICF.h"
#include "Config.h"
+#include "LinkerScript.h"
+#include "OutputSections.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
@@ -86,12 +88,12 @@
#include <algorithm>
#include <atomic>
-using namespace lld;
-using namespace lld::elf;
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
+namespace lld {
+namespace elf {
namespace {
template <class ELFT> class ICF {
public:
@@ -304,10 +306,8 @@ bool ICF<ELFT>::equalsConstant(const InputSection *a, const InputSection *b) {
return false;
// If two sections have different output sections, we cannot merge them.
- // FIXME: This doesn't do the right thing in the case where there is a linker
- // script. We probably need to move output section assignment before ICF to
- // get the correct behaviour here.
- if (getOutputSectionName(a) != getOutputSectionName(b))
+ assert(a->getParent() && b->getParent());
+ if (a->getParent() != b->getParent())
return false;
if (a->areRelocsRela)
@@ -446,10 +446,11 @@ static void print(const Twine &s) {
// The main function of ICF.
template <class ELFT> void ICF<ELFT>::run() {
// Collect sections to merge.
- for (InputSectionBase *sec : inputSections)
- if (auto *s = dyn_cast<InputSection>(sec))
- if (isEligible(s))
- sections.push_back(s);
+ for (InputSectionBase *sec : inputSections) {
+ auto *s = cast<InputSection>(sec);
+ if (isEligible(s))
+ sections.push_back(s);
+ }
// Initially, we use hash values to partition sections.
parallelForEach(sections, [&](InputSection *s) {
@@ -499,12 +500,24 @@ template <class ELFT> void ICF<ELFT>::run() {
isec->markDead();
}
});
+
+ // InputSectionDescription::sections is populated by processSectionCommands().
+ // ICF may fold some input sections assigned to output sections. Remove them.
+ for (BaseCommand *base : script->sectionCommands)
+ if (auto *sec = dyn_cast<OutputSection>(base))
+ for (BaseCommand *sub_base : sec->sectionCommands)
+ if (auto *isd = dyn_cast<InputSectionDescription>(sub_base))
+ llvm::erase_if(isd->sections,
+ [](InputSection *isec) { return !isec->isLive(); });
}
// ICF entry point function.
-template <class ELFT> void elf::doIcf() { ICF<ELFT>().run(); }
+template <class ELFT> void doIcf() { ICF<ELFT>().run(); }
+
+template void doIcf<ELF32LE>();
+template void doIcf<ELF32BE>();
+template void doIcf<ELF64LE>();
+template void doIcf<ELF64BE>();
-template void elf::doIcf<ELF32LE>();
-template void elf::doIcf<ELF32BE>();
-template void elf::doIcf<ELF64LE>();
-template void elf::doIcf<ELF64BE>();
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/InputFiles.cpp b/contrib/llvm-project/lld/ELF/InputFiles.cpp
index f9cbf1569090..fdf935a30856 100644
--- a/contrib/llvm-project/lld/ELF/InputFiles.cpp
+++ b/contrib/llvm-project/lld/ELF/InputFiles.cpp
@@ -17,7 +17,6 @@
#include "lld/Common/Memory.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/Analysis.h"
-#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/LTO/LTO.h"
@@ -37,18 +36,31 @@ using namespace llvm::sys;
using namespace llvm::sys::fs;
using namespace llvm::support::endian;
-using namespace lld;
-using namespace lld::elf;
+namespace lld {
+// Returns "<internal>", "foo.a(bar.o)" or "baz.o".
+std::string toString(const elf::InputFile *f) {
+ if (!f)
+ return "<internal>";
+
+ if (f->toStringCache.empty()) {
+ if (f->archiveName.empty())
+ f->toStringCache = f->getName();
+ else
+ f->toStringCache = (f->archiveName + "(" + f->getName() + ")").str();
+ }
+ return f->toStringCache;
+}
+namespace elf {
bool InputFile::isInGroup;
uint32_t InputFile::nextGroupId;
-std::vector<BinaryFile *> elf::binaryFiles;
-std::vector<BitcodeFile *> elf::bitcodeFiles;
-std::vector<LazyObjFile *> elf::lazyObjFiles;
-std::vector<InputFile *> elf::objectFiles;
-std::vector<SharedFile *> elf::sharedFiles;
+std::vector<BinaryFile *> binaryFiles;
+std::vector<BitcodeFile *> bitcodeFiles;
+std::vector<LazyObjFile *> lazyObjFiles;
+std::vector<InputFile *> objectFiles;
+std::vector<SharedFile *> sharedFiles;
-std::unique_ptr<TarWriter> elf::tar;
+std::unique_ptr<TarWriter> tar;
static ELFKind getELFKind(MemoryBufferRef mb, StringRef archiveName) {
unsigned char size;
@@ -88,7 +100,7 @@ InputFile::InputFile(Kind k, MemoryBufferRef m)
++nextGroupId;
}
-Optional<MemoryBufferRef> elf::readFile(StringRef path) {
+Optional<MemoryBufferRef> readFile(StringRef path) {
// The --chroot option changes our virtual root directory.
// This is useful when you are dealing with files created by --reproduce.
if (!config->chroot.empty() && path.startswith("/"))
@@ -127,18 +139,18 @@ static bool isCompatible(InputFile *file) {
if (!config->emulation.empty()) {
error(toString(file) + " is incompatible with " + config->emulation);
- } else {
- InputFile *existing;
- if (!objectFiles.empty())
- existing = objectFiles[0];
- else if (!sharedFiles.empty())
- existing = sharedFiles[0];
- else
- existing = bitcodeFiles[0];
-
- error(toString(file) + " is incompatible with " + toString(existing));
+ return false;
}
+ InputFile *existing;
+ if (!objectFiles.empty())
+ existing = objectFiles[0];
+ else if (!sharedFiles.empty())
+ existing = sharedFiles[0];
+ else
+ existing = bitcodeFiles[0];
+
+ error(toString(file) + " is incompatible with " + toString(existing));
return false;
}
@@ -188,7 +200,7 @@ template <class ELFT> static void doParseFile(InputFile *file) {
}
// Add symbols in File to the symbol table.
-void elf::parseFile(InputFile *file) {
+void parseFile(InputFile *file) {
switch (config->ekind) {
case ELF32LEKind:
doParseFile<ELF32LE>(file);
@@ -252,57 +264,8 @@ std::string InputFile::getSrcMsg(const Symbol &sym, InputSectionBase &sec,
}
template <class ELFT> void ObjFile<ELFT>::initializeDwarf() {
- dwarf = llvm::make_unique<DWARFContext>(make_unique<LLDDwarfObj<ELFT>>(this));
- for (std::unique_ptr<DWARFUnit> &cu : dwarf->compile_units()) {
- auto report = [](Error err) {
- handleAllErrors(std::move(err),
- [](ErrorInfoBase &info) { warn(info.message()); });
- };
- Expected<const DWARFDebugLine::LineTable *> expectedLT =
- dwarf->getLineTableForUnit(cu.get(), report);
- const DWARFDebugLine::LineTable *lt = nullptr;
- if (expectedLT)
- lt = *expectedLT;
- else
- report(expectedLT.takeError());
- if (!lt)
- continue;
- lineTables.push_back(lt);
-
- // Loop over variable records and insert them to variableLoc.
- for (const auto &entry : cu->dies()) {
- DWARFDie die(cu.get(), &entry);
- // Skip all tags that are not variables.
- if (die.getTag() != dwarf::DW_TAG_variable)
- continue;
-
- // Skip if a local variable because we don't need them for generating
- // error messages. In general, only non-local symbols can fail to be
- // linked.
- if (!dwarf::toUnsigned(die.find(dwarf::DW_AT_external), 0))
- continue;
-
- // Get the source filename index for the variable.
- unsigned file = dwarf::toUnsigned(die.find(dwarf::DW_AT_decl_file), 0);
- if (!lt->hasFileAtIndex(file))
- continue;
-
- // Get the line number on which the variable is declared.
- unsigned line = dwarf::toUnsigned(die.find(dwarf::DW_AT_decl_line), 0);
-
- // Here we want to take the variable name to add it into variableLoc.
- // Variable can have regular and linkage name associated. At first, we try
- // to get linkage name as it can be different, for example when we have
- // two variables in different namespaces of the same object. Use common
- // name otherwise, but handle the case when it also absent in case if the
- // input object file lacks some debug info.
- StringRef name =
- dwarf::toString(die.find(dwarf::DW_AT_linkage_name),
- dwarf::toString(die.find(dwarf::DW_AT_name), ""));
- if (!name.empty())
- variableLoc.insert({name, {lt, file, line}});
- }
- }
+ dwarf = make<DWARFCache>(std::make_unique<DWARFContext>(
+ std::make_unique<LLDDwarfObj<ELFT>>(this)));
}
// Returns the pair of file name and line number describing location of data
@@ -312,19 +275,7 @@ Optional<std::pair<std::string, unsigned>>
ObjFile<ELFT>::getVariableLoc(StringRef name) {
llvm::call_once(initDwarfLine, [this]() { initializeDwarf(); });
- // Return if we have no debug information about data object.
- auto it = variableLoc.find(name);
- if (it == variableLoc.end())
- return None;
-
- // Take file name string from line table.
- std::string fileName;
- if (!it->second.lt->getFileNameByIndex(
- it->second.file, {},
- DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, fileName))
- return None;
-
- return std::make_pair(fileName, it->second.line);
+ return dwarf->getVariableLoc(name);
}
// Returns source line information for a given offset
@@ -346,28 +297,7 @@ Optional<DILineInfo> ObjFile<ELFT>::getDILineInfo(InputSectionBase *s,
// Use fake address calcuated by adding section file offset and offset in
// section. See comments for ObjectInfo class.
- DILineInfo info;
- for (const llvm::DWARFDebugLine::LineTable *lt : lineTables) {
- if (lt->getFileLineInfoForAddress(
- {s->getOffsetInFile() + offset, sectionIndex}, nullptr,
- DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, info))
- return info;
- }
- return None;
-}
-
-// Returns "<internal>", "foo.a(bar.o)" or "baz.o".
-std::string lld::toString(const InputFile *f) {
- if (!f)
- return "<internal>";
-
- if (f->toStringCache.empty()) {
- if (f->archiveName.empty())
- f->toStringCache = f->getName();
- else
- f->toStringCache = (f->archiveName + "(" + f->getName() + ")").str();
- }
- return f->toStringCache;
+ return dwarf->getDILineInfo(s->getOffsetInFile() + offset, sectionIndex);
}
ELFFileBase::ELFFileBase(Kind k, MemoryBufferRef mb) : InputFile(k, mb) {
@@ -484,7 +414,8 @@ StringRef ObjFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> sections,
return signature;
}
-template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &sec) {
+template <class ELFT>
+bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &sec, StringRef name) {
// On a regular link we don't merge sections if -O0 (default is -O1). This
// sometimes makes the linker significantly faster, although the output will
// be bigger.
@@ -516,14 +447,16 @@ template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &sec) {
if (entSize == 0)
return false;
if (sec.sh_size % entSize)
- fatal(toString(this) +
- ": SHF_MERGE section size must be a multiple of sh_entsize");
+ fatal(toString(this) + ":(" + name + "): SHF_MERGE section size (" +
+ Twine(sec.sh_size) + ") must be a multiple of sh_entsize (" +
+ Twine(entSize) + ")");
uint64_t flags = sec.sh_flags;
if (!(flags & SHF_MERGE))
return false;
if (flags & SHF_WRITE)
- fatal(toString(this) + ": writable SHF_MERGE section is not supported");
+ fatal(toString(this) + ":(" + name +
+ "): writable SHF_MERGE section is not supported");
return true;
}
@@ -573,7 +506,7 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats) {
this->sectionStringTable =
CHECK(obj.getSectionStringTable(objSections), this);
- for (size_t i = 0, e = objSections.size(); i < e; 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];
@@ -652,25 +585,29 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats) {
default:
this->sections[i] = createInputSection(sec);
}
+ }
+
+ for (size_t i = 0, e = objSections.size(); i < e; ++i) {
+ if (this->sections[i] == &InputSection::discarded)
+ continue;
+ const Elf_Shdr &sec = objSections[i];
+ if (!(sec.sh_flags & SHF_LINK_ORDER))
+ continue;
// .ARM.exidx sections have a reverse dependency on the InputSection they
// have a SHF_LINK_ORDER dependency, this is identified by the sh_link.
- if (sec.sh_flags & SHF_LINK_ORDER) {
- InputSectionBase *linkSec = nullptr;
- if (sec.sh_link < this->sections.size())
- linkSec = this->sections[sec.sh_link];
- if (!linkSec)
- fatal(toString(this) +
- ": invalid sh_link index: " + Twine(sec.sh_link));
-
- InputSection *isec = cast<InputSection>(this->sections[i]);
- linkSec->dependentSections.push_back(isec);
- if (!isa<InputSection>(linkSec))
- error("a section " + isec->name +
- " with SHF_LINK_ORDER should not refer a non-regular "
- "section: " +
- toString(linkSec));
- }
+ InputSectionBase *linkSec = nullptr;
+ if (sec.sh_link < this->sections.size())
+ linkSec = this->sections[sec.sh_link];
+ if (!linkSec)
+ fatal(toString(this) + ": invalid sh_link index: " + Twine(sec.sh_link));
+
+ InputSection *isec = cast<InputSection>(this->sections[i]);
+ linkSec->dependentSections.push_back(isec);
+ if (!isa<InputSection>(linkSec))
+ error("a section " + isec->name +
+ " with SHF_LINK_ORDER should not refer a non-regular section: " +
+ toString(linkSec));
}
}
@@ -1030,7 +967,7 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &sec) {
if (name == ".eh_frame" && !config->relocatable)
return make<EhInputSection>(*this, sec, name);
- if (shouldMerge(sec))
+ if (shouldMerge(sec, name))
return make<MergeInputSection>(*this, sec, name);
return make<InputSection>(*this, sec, name);
}
@@ -1094,6 +1031,7 @@ template <class ELFT> void ObjFile<ELFT>::initializeSymbols() {
// Handle global undefined symbols.
if (eSym.st_shndx == SHN_UNDEF) {
this->symbols[i]->resolve(Undefined{this, name, binding, stOther, type});
+ this->symbols[i]->referenced = true;
continue;
}
@@ -1470,10 +1408,12 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &keptComdats,
int c = objSym.getComdatIndex();
if (objSym.isUndefined() || (c != -1 && !keptComdats[c])) {
- Undefined New(&f, name, binding, visibility, type);
+ Undefined newSym(&f, name, binding, visibility, type);
if (canOmitFromDynSym)
- New.exportDynamic = false;
- return symtab->addSymbol(New);
+ newSym.exportDynamic = false;
+ Symbol *ret = symtab->addSymbol(newSym);
+ ret->referenced = true;
+ return ret;
}
if (objSym.isCommon())
@@ -1481,10 +1421,10 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &keptComdats,
CommonSymbol{&f, name, binding, visibility, STT_OBJECT,
objSym.getCommonAlignment(), objSym.getCommonSize()});
- Defined New(&f, name, binding, visibility, type, 0, 0, nullptr);
+ Defined newSym(&f, name, binding, visibility, type, 0, 0, nullptr);
if (canOmitFromDynSym)
- New.exportDynamic = false;
- return symtab->addSymbol(New);
+ newSym.exportDynamic = false;
+ return symtab->addSymbol(newSym);
}
template <class ELFT> void BitcodeFile::parse() {
@@ -1523,8 +1463,8 @@ void BinaryFile::parse() {
STV_DEFAULT, STT_OBJECT, data.size(), 0, nullptr});
}
-InputFile *elf::createObjectFile(MemoryBufferRef mb, StringRef archiveName,
- uint64_t offsetInArchive) {
+InputFile *createObjectFile(MemoryBufferRef mb, StringRef archiveName,
+ uint64_t offsetInArchive) {
if (isBitcode(mb))
return make<BitcodeFile>(mb, archiveName, offsetInArchive);
@@ -1615,7 +1555,7 @@ template <class ELFT> void LazyObjFile::parse() {
}
}
-std::string elf::replaceThinLTOSuffix(StringRef path) {
+std::string replaceThinLTOSuffix(StringRef path) {
StringRef suffix = config->thinLTOObjectSuffixReplace.first;
StringRef repl = config->thinLTOObjectSuffixReplace.second;
@@ -1634,12 +1574,15 @@ template void LazyObjFile::parse<ELF32BE>();
template void LazyObjFile::parse<ELF64LE>();
template void LazyObjFile::parse<ELF64BE>();
-template class elf::ObjFile<ELF32LE>;
-template class elf::ObjFile<ELF32BE>;
-template class elf::ObjFile<ELF64LE>;
-template class elf::ObjFile<ELF64BE>;
+template class ObjFile<ELF32LE>;
+template class ObjFile<ELF32BE>;
+template class ObjFile<ELF64LE>;
+template class ObjFile<ELF64BE>;
template void SharedFile::parse<ELF32LE>();
template void SharedFile::parse<ELF32BE>();
template void SharedFile::parse<ELF64LE>();
template void SharedFile::parse<ELF64BE>();
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/InputFiles.h b/contrib/llvm-project/lld/ELF/InputFiles.h
index 5ccc3d402b37..cde6bc617764 100644
--- a/contrib/llvm-project/lld/ELF/InputFiles.h
+++ b/contrib/llvm-project/lld/ELF/InputFiles.h
@@ -10,13 +10,13 @@
#define LLD_ELF_INPUT_FILES_H
#include "Config.h"
+#include "lld/Common/DWARF.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/LLVM.h"
#include "lld/Common/Reproduce.h"
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
#include "llvm/IR/Comdat.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ELF.h"
@@ -26,22 +26,19 @@
namespace llvm {
class TarWriter;
-struct DILineInfo;
namespace lto {
class InputFile;
}
} // namespace llvm
namespace lld {
-namespace elf {
-class InputFile;
-class InputSectionBase;
-}
// Returns "<internal>", "foo.a(bar.o)" or "baz.o".
std::string toString(const elf::InputFile *f);
namespace elf {
+class InputFile;
+class InputSectionBase;
using llvm::object::Archive;
@@ -261,7 +258,7 @@ private:
InputSectionBase *createInputSection(const Elf_Shdr &sec);
StringRef getSectionName(const Elf_Shdr &sec);
- bool shouldMerge(const Elf_Shdr &sec);
+ bool shouldMerge(const Elf_Shdr &sec, StringRef name);
// Each ELF symbol contains a section index which the symbol belongs to.
// However, because the number of bits dedicated for that is limited, a
@@ -284,14 +281,7 @@ private:
// reporting. Linker may find reasonable number of errors in a
// single object file, so we cache debugging information in order to
// parse it only once for each object file we link.
- std::unique_ptr<llvm::DWARFContext> dwarf;
- std::vector<const llvm::DWARFDebugLine::LineTable *> lineTables;
- struct VarLoc {
- const llvm::DWARFDebugLine::LineTable *lt;
- unsigned file;
- unsigned line;
- };
- llvm::DenseMap<StringRef, VarLoc> variableLoc;
+ DWARFCache *dwarf;
llvm::once_flag initDwarfLine;
};
diff --git a/contrib/llvm-project/lld/ELF/InputSection.cpp b/contrib/llvm-project/lld/ELF/InputSection.cpp
index a024ac307b0a..0c93d2e10959 100644
--- a/contrib/llvm-project/lld/ELF/InputSection.cpp
+++ b/contrib/llvm-project/lld/ELF/InputSection.cpp
@@ -37,16 +37,15 @@ using namespace llvm::support;
using namespace llvm::support::endian;
using namespace llvm::sys;
-using namespace lld;
-using namespace lld::elf;
-
-std::vector<InputSectionBase *> elf::inputSections;
-
+namespace lld {
// Returns a string to construct an error message.
-std::string lld::toString(const InputSectionBase *sec) {
+std::string toString(const elf::InputSectionBase *sec) {
return (toString(sec->file) + ":(" + sec->name + ")").str();
}
+namespace elf {
+std::vector<InputSectionBase *> inputSections;
+
template <class ELFT>
static ArrayRef<uint8_t> getSectionContents(ObjFile<ELFT> &file,
const typename ELFT::Shdr &hdr) {
@@ -608,26 +607,39 @@ static int64_t getTlsTpOffset(const Symbol &s) {
if (&s == ElfSym::tlsModuleBase)
return 0;
+ // There are 2 TLS layouts. Among targets we support, x86 uses TLS Variant 2
+ // while most others use Variant 1. At run time TP will be aligned to p_align.
+
+ // Variant 1. TP will be followed by an optional gap (which is the size of 2
+ // pointers on ARM/AArch64, 0 on other targets), followed by alignment
+ // padding, then the static TLS blocks. The alignment padding is added so that
+ // (TP + gap + padding) is congruent to p_vaddr modulo p_align.
+ //
+ // Variant 2. Static TLS blocks, followed by alignment padding are placed
+ // before TP. The alignment padding is added so that (TP - padding -
+ // p_memsz) is congruent to p_vaddr modulo p_align.
+ PhdrEntry *tls = Out::tlsPhdr;
switch (config->emachine) {
+ // Variant 1.
case EM_ARM:
case EM_AARCH64:
- // Variant 1. The thread pointer points to a TCB with a fixed 2-word size,
- // followed by a variable amount of alignment padding, followed by the TLS
- // segment.
- return s.getVA(0) + alignTo(config->wordsize * 2, Out::tlsPhdr->p_align);
- case EM_386:
- case EM_X86_64:
- // Variant 2. The TLS segment is located just before the thread pointer.
- return s.getVA(0) - alignTo(Out::tlsPhdr->p_memsz, Out::tlsPhdr->p_align);
+ return s.getVA(0) + config->wordsize * 2 +
+ ((tls->p_vaddr - config->wordsize * 2) & (tls->p_align - 1));
+ case EM_MIPS:
case EM_PPC:
case EM_PPC64:
- // The thread pointer points to a fixed offset from the start of the
- // executable's TLS segment. An offset of 0x7000 allows a signed 16-bit
- // offset to reach 0x1000 of TCB/thread-library data and 0xf000 of the
- // program's TLS segment.
- return s.getVA(0) - 0x7000;
+ // Adjusted Variant 1. TP is placed with a displacement of 0x7000, which is
+ // to allow a signed 16-bit offset to reach 0x1000 of TCB/thread-library
+ // data and 0xf000 of the program's TLS segment.
+ return s.getVA(0) + (tls->p_vaddr & (tls->p_align - 1)) - 0x7000;
case EM_RISCV:
- return s.getVA(0);
+ return s.getVA(0) + (tls->p_vaddr & (tls->p_align - 1));
+
+ // Variant 2.
+ case EM_386:
+ case EM_X86_64:
+ return s.getVA(0) - tls->p_memsz -
+ ((-tls->p_vaddr - tls->p_memsz) & (tls->p_align - 1));
default:
llvm_unreachable("unhandled Config->EMachine");
}
@@ -671,8 +683,6 @@ static uint64_t getRelocTargetVA(const InputFile *file, RelType type, int64_t a,
case R_GOT_PC:
case R_RELAX_TLS_GD_TO_IE:
return sym.getGotVA() + a - p;
- case R_HEXAGON_GOT:
- return sym.getGotVA() - in.gotPlt->getVA();
case R_MIPS_GOTREL:
return sym.getVA(a) - in.mipsGot->getGp(file);
case R_MIPS_GOT_GP:
@@ -1071,7 +1081,7 @@ void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *buf,
end, f->stOther))
continue;
if (!getFile<ELFT>()->someNoSplitStack)
- error(lld::toString(this) + ": " + f->getName() +
+ error(toString(this) + ": " + f->getName() +
" (with -fsplit-stack) calls " + rel.sym->getName() +
" (without -fsplit-stack), but couldn't adjust its prologue");
}
@@ -1334,3 +1344,6 @@ template void EhInputSection::split<ELF32LE>();
template void EhInputSection::split<ELF32BE>();
template void EhInputSection::split<ELF64LE>();
template void EhInputSection::split<ELF64BE>();
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/InputSection.h b/contrib/llvm-project/lld/ELF/InputSection.h
index 3a974074e0e5..d7c953262a41 100644
--- a/contrib/llvm-project/lld/ELF/InputSection.h
+++ b/contrib/llvm-project/lld/ELF/InputSection.h
@@ -54,22 +54,9 @@ public:
unsigned sectionKind : 3;
- // The next three bit fields are only used by InputSectionBase, but we
+ // The next two bit fields are only used by InputSectionBase, but we
// put them here so the struct packs better.
- // True if this section has already been placed to a linker script
- // output section. This is needed because, in a linker script, you
- // can refer to the same section more than once. For example, in
- // the following linker script,
- //
- // .foo : { *(.text) }
- // .bar : { *(.text) }
- //
- // .foo takes all .text sections, and .bar becomes empty. To achieve
- // this, we need to memorize whether a section has been placed or
- // not for each input section.
- unsigned assigned : 1;
-
unsigned bss : 1;
// Set for sections that should not be folded by ICF.
@@ -108,9 +95,9 @@ protected:
SectionBase(Kind sectionKind, StringRef name, uint64_t flags,
uint64_t entsize, uint64_t alignment, uint32_t type,
uint32_t info, uint32_t link)
- : name(name), repl(this), sectionKind(sectionKind), assigned(false),
- bss(false), keepUnique(false), partition(0), alignment(alignment),
- flags(flags), entsize(entsize), type(type), link(link), info(info) {}
+ : name(name), repl(this), sectionKind(sectionKind), bss(false),
+ keepUnique(false), partition(0), alignment(alignment), flags(flags),
+ entsize(entsize), type(type), link(link), info(info) {}
};
// This corresponds to a section of an input file.
diff --git a/contrib/llvm-project/lld/ELF/LTO.cpp b/contrib/llvm-project/lld/ELF/LTO.cpp
index 28d4bfe77c5d..6da409568c8b 100644
--- a/contrib/llvm-project/lld/ELF/LTO.cpp
+++ b/contrib/llvm-project/lld/ELF/LTO.cpp
@@ -42,15 +42,15 @@ using namespace llvm;
using namespace llvm::object;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
+namespace lld {
+namespace elf {
// Creates an empty file to store a list of object files for final
// linking of distributed ThinLTO.
static std::unique_ptr<raw_fd_ostream> openFile(StringRef file) {
std::error_code ec;
auto ret =
- llvm::make_unique<raw_fd_ostream>(file, ec, sys::fs::OpenFlags::F_None);
+ std::make_unique<raw_fd_ostream>(file, ec, sys::fs::OpenFlags::OF_None);
if (ec) {
error("cannot open " + file + ": " + ec.message());
return nullptr;
@@ -76,7 +76,9 @@ static lto::Config createConfig() {
c.Options.FunctionSections = true;
c.Options.DataSections = true;
- if (config->relocatable)
+ if (auto relocModel = getRelocModelFromCMModel())
+ c.RelocModel = *relocModel;
+ else if (config->relocatable)
c.RelocModel = None;
else if (config->isPic)
c.RelocModel = Reloc::PIC_;
@@ -139,7 +141,7 @@ BitcodeCompiler::BitcodeCompiler() {
backend = lto::createInProcessThinBackend(config->thinLTOJobs);
}
- ltoObj = llvm::make_unique<lto::LTO>(createConfig(), backend,
+ ltoObj = std::make_unique<lto::LTO>(createConfig(), backend,
config->ltoPartitions);
// Initialize usedStartStop.
@@ -249,8 +251,8 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
if (!bitcodeFiles.empty())
checkError(ltoObj->run(
[&](size_t task) {
- return llvm::make_unique<lto::NativeObjectStream>(
- llvm::make_unique<raw_svector_ostream>(buf[task]));
+ return std::make_unique<lto::NativeObjectStream>(
+ std::make_unique<raw_svector_ostream>(buf[task]));
},
cache));
@@ -301,3 +303,6 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
ret.push_back(createObjectFile(*file));
return ret;
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/LinkerScript.cpp b/contrib/llvm-project/lld/ELF/LinkerScript.cpp
index 49e44d780476..cebbd89168be 100644
--- a/contrib/llvm-project/lld/ELF/LinkerScript.cpp
+++ b/contrib/llvm-project/lld/ELF/LinkerScript.cpp
@@ -43,29 +43,27 @@ using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::support::endian;
-using namespace lld;
-using namespace lld::elf;
-LinkerScript *elf::script;
+namespace lld {
+namespace elf {
+LinkerScript *script;
-static uint64_t getOutputSectionVA(SectionBase *inputSec, StringRef loc) {
- if (OutputSection *os = inputSec->getOutputSection())
- return os->addr;
- error(loc + ": unable to evaluate expression: input section " +
- inputSec->name + " has no output section assigned");
- return 0;
+static uint64_t getOutputSectionVA(SectionBase *sec) {
+ OutputSection *os = sec->getOutputSection();
+ assert(os && "input section has no output section assigned");
+ return os ? os->addr : 0;
}
uint64_t ExprValue::getValue() const {
if (sec)
- return alignTo(sec->getOffset(val) + getOutputSectionVA(sec, loc),
+ return alignTo(sec->getOffset(val) + getOutputSectionVA(sec),
alignment);
return alignTo(val, alignment);
}
uint64_t ExprValue::getSecAddr() const {
if (sec)
- return sec->getOffset(0) + getOutputSectionVA(sec, loc);
+ return sec->getOffset(0) + getOutputSectionVA(sec);
return 0;
}
@@ -73,7 +71,7 @@ uint64_t ExprValue::getSectionOffset() const {
// If the alignment is trivial, we don't have to compute the full
// value to know the offset. This allows this function to succeed in
// cases where the output section is not yet known.
- if (alignment == 1 && (!sec || !sec->getOutputSection()))
+ if (alignment == 1 && !sec)
return val;
return getValue() - getSecAddr();
}
@@ -157,8 +155,8 @@ static bool shouldDefineSym(SymbolAssignment *cmd) {
return false;
}
-// This function is called from processSectionCommands,
-// while we are fixing the output section layout.
+// Called by processSymbolAssignments() to assign definitions to
+// linker-script-defined symbols.
void LinkerScript::addSymbol(SymbolAssignment *cmd) {
if (!shouldDefineSym(cmd))
return;
@@ -181,12 +179,12 @@ void LinkerScript::addSymbol(SymbolAssignment *cmd) {
// write expressions like this: `alignment = 16; . = ALIGN(., alignment)`.
uint64_t symValue = value.sec ? 0 : value.getValue();
- Defined New(nullptr, cmd->name, STB_GLOBAL, visibility, STT_NOTYPE, symValue,
- 0, sec);
+ Defined newSym(nullptr, cmd->name, STB_GLOBAL, visibility, STT_NOTYPE,
+ symValue, 0, sec);
Symbol *sym = symtab->insert(cmd->name);
- sym->mergeProperties(New);
- sym->replace(New);
+ sym->mergeProperties(newSym);
+ sym->replace(newSym);
cmd->sym = cast<Defined>(sym);
}
@@ -197,19 +195,57 @@ static void declareSymbol(SymbolAssignment *cmd) {
return;
uint8_t visibility = cmd->hidden ? STV_HIDDEN : STV_DEFAULT;
- Defined New(nullptr, cmd->name, STB_GLOBAL, visibility, STT_NOTYPE, 0, 0,
- nullptr);
+ Defined newSym(nullptr, cmd->name, STB_GLOBAL, visibility, STT_NOTYPE, 0, 0,
+ nullptr);
// We can't calculate final value right now.
Symbol *sym = symtab->insert(cmd->name);
- sym->mergeProperties(New);
- sym->replace(New);
+ sym->mergeProperties(newSym);
+ sym->replace(newSym);
cmd->sym = cast<Defined>(sym);
cmd->provide = false;
sym->scriptDefined = true;
}
+using SymbolAssignmentMap =
+ DenseMap<const Defined *, std::pair<SectionBase *, uint64_t>>;
+
+// Collect section/value pairs of linker-script-defined symbols. This is used to
+// check whether symbol values converge.
+static SymbolAssignmentMap
+getSymbolAssignmentValues(const std::vector<BaseCommand *> &sectionCommands) {
+ SymbolAssignmentMap ret;
+ for (BaseCommand *base : sectionCommands) {
+ if (auto *cmd = dyn_cast<SymbolAssignment>(base)) {
+ if (cmd->sym) // sym is nullptr for dot.
+ ret.try_emplace(cmd->sym,
+ std::make_pair(cmd->sym->section, cmd->sym->value));
+ continue;
+ }
+ for (BaseCommand *sub_base : cast<OutputSection>(base)->sectionCommands)
+ if (auto *cmd = dyn_cast<SymbolAssignment>(sub_base))
+ if (cmd->sym)
+ ret.try_emplace(cmd->sym,
+ std::make_pair(cmd->sym->section, cmd->sym->value));
+ }
+ return ret;
+}
+
+// Returns the lexicographical smallest (for determinism) Defined whose
+// section/value has changed.
+static const Defined *
+getChangedSymbolAssignment(const SymbolAssignmentMap &oldValues) {
+ const Defined *changed = nullptr;
+ for (auto &it : oldValues) {
+ const Defined *sym = it.first;
+ if (std::make_pair(sym->section, sym->value) != it.second &&
+ (!changed || sym->getName() < changed->getName()))
+ changed = sym;
+ }
+ return changed;
+}
+
// This method is used to handle INSERT AFTER statement. Here we rebuild
// the list of script commands to mix sections inserted into.
void LinkerScript::processInsertCommands() {
@@ -305,46 +341,44 @@ bool LinkerScript::shouldKeep(InputSectionBase *s) {
}
// A helper function for the SORT() command.
-static std::function<bool(InputSectionBase *, InputSectionBase *)>
-getComparator(SortSectionPolicy k) {
- switch (k) {
- case SortSectionPolicy::Alignment:
- return [](InputSectionBase *a, InputSectionBase *b) {
- // ">" is not a mistake. Sections with larger alignments are placed
- // before sections with smaller alignments in order to reduce the
- // amount of padding necessary. This is compatible with GNU.
- return a->alignment > b->alignment;
- };
- case SortSectionPolicy::Name:
- return [](InputSectionBase *a, InputSectionBase *b) {
- return a->name < b->name;
- };
- case SortSectionPolicy::Priority:
- return [](InputSectionBase *a, InputSectionBase *b) {
- return getPriority(a->name) < getPriority(b->name);
- };
- default:
- llvm_unreachable("unknown sort policy");
- }
-}
-
-// A helper function for the SORT() command.
-static bool matchConstraints(ArrayRef<InputSection *> sections,
+static bool matchConstraints(ArrayRef<InputSectionBase *> sections,
ConstraintKind kind) {
if (kind == ConstraintKind::NoConstraint)
return true;
bool isRW = llvm::any_of(
- sections, [](InputSection *sec) { return sec->flags & SHF_WRITE; });
+ sections, [](InputSectionBase *sec) { return sec->flags & SHF_WRITE; });
return (isRW && kind == ConstraintKind::ReadWrite) ||
(!isRW && kind == ConstraintKind::ReadOnly);
}
-static void sortSections(MutableArrayRef<InputSection *> vec,
+static void sortSections(MutableArrayRef<InputSectionBase *> vec,
SortSectionPolicy k) {
- if (k != SortSectionPolicy::Default && k != SortSectionPolicy::None)
- llvm::stable_sort(vec, getComparator(k));
+ auto alignmentComparator = [](InputSectionBase *a, InputSectionBase *b) {
+ // ">" is not a mistake. Sections with larger alignments are placed
+ // before sections with smaller alignments in order to reduce the
+ // amount of padding necessary. This is compatible with GNU.
+ return a->alignment > b->alignment;
+ };
+ auto nameComparator = [](InputSectionBase *a, InputSectionBase *b) {
+ return a->name < b->name;
+ };
+ auto priorityComparator = [](InputSectionBase *a, InputSectionBase *b) {
+ return getPriority(a->name) < getPriority(b->name);
+ };
+
+ switch (k) {
+ case SortSectionPolicy::Default:
+ case SortSectionPolicy::None:
+ return;
+ case SortSectionPolicy::Alignment:
+ return llvm::stable_sort(vec, alignmentComparator);
+ case SortSectionPolicy::Name:
+ return llvm::stable_sort(vec, nameComparator);
+ case SortSectionPolicy::Priority:
+ return llvm::stable_sort(vec, priorityComparator);
+ }
}
// Sort sections as instructed by SORT-family commands and --sort-section
@@ -358,7 +392,7 @@ static void sortSections(MutableArrayRef<InputSection *> vec,
// --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.
-static void sortInputSections(MutableArrayRef<InputSection *> vec,
+static void sortInputSections(MutableArrayRef<InputSectionBase *> vec,
const SectionPattern &pat) {
if (pat.sortOuter == SortSectionPolicy::None)
return;
@@ -371,16 +405,16 @@ static void sortInputSections(MutableArrayRef<InputSection *> vec,
}
// Compute and remember which sections the InputSectionDescription matches.
-std::vector<InputSection *>
+std::vector<InputSectionBase *>
LinkerScript::computeInputSections(const InputSectionDescription *cmd) {
- std::vector<InputSection *> ret;
+ std::vector<InputSectionBase *> ret;
// Collects all sections that satisfy constraints of Cmd.
for (const SectionPattern &pat : cmd->sectionPatterns) {
size_t sizeBefore = ret.size();
for (InputSectionBase *sec : inputSections) {
- if (!sec->isLive() || sec->assigned)
+ if (!sec->isLive() || sec->parent)
continue;
// For -emit-relocs we have to ignore entries like
@@ -388,9 +422,9 @@ LinkerScript::computeInputSections(const InputSectionDescription *cmd) {
// which are common because they are in the default bfd script.
// We do not ignore SHT_REL[A] linker-synthesized sections here because
// want to support scripts that do custom layout for them.
- if (auto *isec = dyn_cast<InputSection>(sec))
- if (isec->getRelocatedSection())
- continue;
+ if (isa<InputSection>(sec) &&
+ cast<InputSection>(sec)->getRelocatedSection())
+ continue;
std::string filename = getFilename(sec->file);
if (!cmd->filePat.match(filename) ||
@@ -398,88 +432,60 @@ LinkerScript::computeInputSections(const InputSectionDescription *cmd) {
!pat.sectionPat.match(sec->name))
continue;
- // It is safe to assume that Sec is an InputSection
- // because mergeable or EH input sections have already been
- // handled and eliminated.
- ret.push_back(cast<InputSection>(sec));
- sec->assigned = true;
+ ret.push_back(sec);
}
- sortInputSections(MutableArrayRef<InputSection *>(ret).slice(sizeBefore),
- pat);
+ sortInputSections(
+ MutableArrayRef<InputSectionBase *>(ret).slice(sizeBefore), pat);
}
return ret;
}
-void LinkerScript::discard(ArrayRef<InputSection *> v) {
- for (InputSection *s : v) {
- if (s == in.shStrTab || s == mainPart->relaDyn || s == mainPart->relrDyn)
- error("discarding " + s->name + " section is not allowed");
-
- // You can discard .hash and .gnu.hash sections by linker scripts. Since
- // they are synthesized sections, we need to handle them differently than
- // other regular sections.
- if (s == mainPart->gnuHashTab)
- mainPart->gnuHashTab = nullptr;
- if (s == mainPart->hashTab)
- mainPart->hashTab = nullptr;
-
- s->assigned = false;
- s->markDead();
- discard(s->dependentSections);
- }
+void LinkerScript::discard(InputSectionBase *s) {
+ if (s == in.shStrTab || s == mainPart->relaDyn || s == mainPart->relrDyn)
+ error("discarding " + s->name + " section is not allowed");
+
+ // You can discard .hash and .gnu.hash sections by linker scripts. Since
+ // they are synthesized sections, we need to handle them differently than
+ // other regular sections.
+ if (s == mainPart->gnuHashTab)
+ mainPart->gnuHashTab = nullptr;
+ if (s == mainPart->hashTab)
+ mainPart->hashTab = nullptr;
+
+ s->markDead();
+ s->parent = nullptr;
+ for (InputSection *ds : s->dependentSections)
+ discard(ds);
}
-std::vector<InputSection *>
+std::vector<InputSectionBase *>
LinkerScript::createInputSectionList(OutputSection &outCmd) {
- std::vector<InputSection *> ret;
+ std::vector<InputSectionBase *> ret;
for (BaseCommand *base : outCmd.sectionCommands) {
if (auto *cmd = dyn_cast<InputSectionDescription>(base)) {
- cmd->sections = computeInputSections(cmd);
- ret.insert(ret.end(), cmd->sections.begin(), cmd->sections.end());
+ cmd->sectionBases = computeInputSections(cmd);
+ for (InputSectionBase *s : cmd->sectionBases)
+ s->parent = &outCmd;
+ ret.insert(ret.end(), cmd->sectionBases.begin(), cmd->sectionBases.end());
}
}
return ret;
}
+// Create output sections described by SECTIONS commands.
void LinkerScript::processSectionCommands() {
- // A symbol can be assigned before any section is mentioned in the linker
- // script. In an DSO, the symbol values are addresses, so the only important
- // section values are:
- // * SHN_UNDEF
- // * SHN_ABS
- // * Any value meaning a regular section.
- // To handle that, create a dummy aether section that fills the void before
- // the linker scripts switches to another section. It has an index of one
- // which will map to whatever the first actual section is.
- aether = make<OutputSection>("", 0, SHF_ALLOC);
- aether->sectionIndex = 1;
-
- // Ctx captures the local AddressState and makes it accessible deliberately.
- // This is needed as there are some cases where we cannot just
- // thread the current state through to a lambda function created by the
- // script parser.
- auto deleter = make_unique<AddressState>();
- ctx = deleter.get();
- ctx->outSec = aether;
-
size_t i = 0;
- // Add input sections to output sections.
for (BaseCommand *base : sectionCommands) {
- // Handle symbol assignments outside of any output section.
- if (auto *cmd = dyn_cast<SymbolAssignment>(base)) {
- addSymbol(cmd);
- continue;
- }
-
if (auto *sec = dyn_cast<OutputSection>(base)) {
- std::vector<InputSection *> v = createInputSectionList(*sec);
+ std::vector<InputSectionBase *> v = createInputSectionList(*sec);
// The output section name `/DISCARD/' is special.
// Any input section assigned to it is discarded.
if (sec->name == "/DISCARD/") {
- discard(v);
+ for (InputSectionBase *s : v)
+ discard(s);
sec->sectionCommands.clear();
continue;
}
@@ -493,17 +499,11 @@ void LinkerScript::processSectionCommands() {
// way to "make it as if it wasn't present" is to make it empty.
if (!matchConstraints(v, sec->constraint)) {
for (InputSectionBase *s : v)
- s->assigned = false;
+ s->parent = nullptr;
sec->sectionCommands.clear();
continue;
}
- // A directive may contain symbol definitions like this:
- // ".foo : { ...; bar = .; }". Handle them.
- for (BaseCommand *base : sec->sectionCommands)
- if (auto *outCmd = dyn_cast<SymbolAssignment>(base))
- addSymbol(outCmd);
-
// Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign
// is given, input sections are aligned to that value, whether the
// given value is larger or smaller than the original section alignment.
@@ -513,17 +513,40 @@ void LinkerScript::processSectionCommands() {
s->alignment = subalign;
}
- // Add input sections to an output section.
- for (InputSection *s : v)
- sec->addSection(s);
+ // Set the partition field the same way OutputSection::recordSection()
+ // does. Partitions cannot be used with the SECTIONS command, so this is
+ // always 1.
+ sec->partition = 1;
sec->sectionIndex = i++;
- if (sec->noload)
- sec->type = SHT_NOBITS;
- if (sec->nonAlloc)
- sec->flags &= ~(uint64_t)SHF_ALLOC;
}
}
+}
+
+void LinkerScript::processSymbolAssignments() {
+ // Dot outside an output section still represents a relative address, whose
+ // sh_shndx should not be SHN_UNDEF or SHN_ABS. Create a dummy aether section
+ // that fills the void outside a section. It has an index of one, which is
+ // indistinguishable from any other regular section index.
+ aether = make<OutputSection>("", 0, SHF_ALLOC);
+ aether->sectionIndex = 1;
+
+ // ctx captures the local AddressState and makes it accessible deliberately.
+ // This is needed as there are some cases where we cannot just thread the
+ // current state through to a lambda function created by the script parser.
+ AddressState state;
+ ctx = &state;
+ ctx->outSec = aether;
+
+ for (BaseCommand *base : sectionCommands) {
+ if (auto *cmd = dyn_cast<SymbolAssignment>(base))
+ addSymbol(cmd);
+ else
+ for (BaseCommand *sub_base : cast<OutputSection>(base)->sectionCommands)
+ if (auto *cmd = dyn_cast<SymbolAssignment>(sub_base))
+ addSymbol(cmd);
+ }
+
ctx = nullptr;
}
@@ -539,7 +562,7 @@ static OutputSection *findByName(ArrayRef<BaseCommand *> vec,
static OutputSection *createSection(InputSectionBase *isec,
StringRef outsecName) {
OutputSection *sec = script->createOutputSection(outsecName, "<internal>");
- sec->addSection(cast<InputSection>(isec));
+ sec->recordSection(isec);
return sec;
}
@@ -568,7 +591,7 @@ addInputSec(StringMap<TinyPtrVector<OutputSection *>> &map,
OutputSection *out = sec->getRelocatedSection()->getOutputSection();
if (out->relocationSection) {
- out->relocationSection->addSection(sec);
+ out->relocationSection->recordSection(sec);
return nullptr;
}
@@ -576,12 +599,6 @@ addInputSec(StringMap<TinyPtrVector<OutputSection *>> &map,
return out->relocationSection;
}
- // When control reaches here, mergeable sections have already been merged into
- // synthetic sections. For relocatable case we want to create one output
- // section per syntetic section so that they have a valid sh_entsize.
- if (config->relocatable && (isec->flags & SHF_MERGE))
- return createSection(isec, outsecName);
-
// The ELF spec just says
// ----------------------------------------------------------------
// In the first phase, input sections that match in name, type and
@@ -628,7 +645,21 @@ addInputSec(StringMap<TinyPtrVector<OutputSection *>> &map,
for (OutputSection *sec : v) {
if (sec->partition != isec->partition)
continue;
- sec->addSection(cast<InputSection>(isec));
+
+ if (config->relocatable && (isec->flags & SHF_LINK_ORDER)) {
+ // Merging two SHF_LINK_ORDER sections with different sh_link fields will
+ // change their semantics, so we only merge them in -r links if they will
+ // end up being linked to the same output section. The casts are fine
+ // because everything in the map was created by the orphan placement code.
+ auto *firstIsec = cast<InputSectionBase>(
+ cast<InputSectionDescription>(sec->sectionCommands[0])
+ ->sectionBases[0]);
+ if (firstIsec->getLinkOrderDep()->getOutputSection() !=
+ isec->getLinkOrderDep()->getOutputSection())
+ continue;
+ }
+
+ sec->recordSection(isec);
return nullptr;
}
@@ -642,25 +673,30 @@ void LinkerScript::addOrphanSections() {
StringMap<TinyPtrVector<OutputSection *>> map;
std::vector<OutputSection *> v;
- auto add = [&](InputSectionBase *s) {
- if (!s->isLive() || s->parent)
- return;
-
- StringRef name = getOutputSectionName(s);
-
- if (config->orphanHandling == OrphanHandlingPolicy::Error)
- error(toString(s) + " is being placed in '" + name + "'");
- else if (config->orphanHandling == OrphanHandlingPolicy::Warn)
- warn(toString(s) + " is being placed in '" + name + "'");
-
- if (OutputSection *sec = findByName(sectionCommands, name)) {
- sec->addSection(cast<InputSection>(s));
- return;
+ std::function<void(InputSectionBase *)> add;
+ add = [&](InputSectionBase *s) {
+ if (s->isLive() && !s->parent) {
+ StringRef name = getOutputSectionName(s);
+
+ if (config->orphanHandling == OrphanHandlingPolicy::Error)
+ error(toString(s) + " is being placed in '" + name + "'");
+ else if (config->orphanHandling == OrphanHandlingPolicy::Warn)
+ warn(toString(s) + " is being placed in '" + name + "'");
+
+ if (OutputSection *sec = findByName(sectionCommands, name)) {
+ sec->recordSection(s);
+ } else {
+ if (OutputSection *os = addInputSec(map, s, name))
+ v.push_back(os);
+ assert(isa<MergeInputSection>(s) ||
+ s->getOutputSection()->sectionIndex == UINT32_MAX);
+ }
}
- if (OutputSection *os = addInputSec(map, s, name))
- v.push_back(os);
- assert(s->getOutputSection()->sectionIndex == UINT32_MAX);
+ if (config->relocatable)
+ for (InputSectionBase *depSec : s->dependentSections)
+ if (depSec->flags & SHF_LINK_ORDER)
+ add(depSec);
};
// For futher --emit-reloc handling code we need target output section
@@ -668,6 +704,12 @@ void LinkerScript::addOrphanSections() {
// to create target sections first. We do not want priority handling
// for synthetic sections because them are special.
for (InputSectionBase *isec : inputSections) {
+ // In -r links, SHF_LINK_ORDER sections are added while adding their parent
+ // sections because we need to know the parent's output section before we
+ // can select an output section for the SHF_LINK_ORDER section.
+ if (config->relocatable && (isec->flags & SHF_LINK_ORDER))
+ continue;
+
if (auto *sec = dyn_cast<InputSection>(isec))
if (InputSectionBase *rel = sec->getRelocatedSection())
if (auto *relIS = dyn_cast_or_null<InputSectionBase>(rel->parent))
@@ -772,6 +814,14 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
if ((sec->flags & SHF_ALLOC) && sec->addrExpr)
setDot(sec->addrExpr, sec->location, false);
+ // If the address of the section has been moved forward by an explicit
+ // expression so that it now starts past the current curPos of the enclosing
+ // region, we need to expand the current region to account for the space
+ // between the previous section, if any, and the start of this section.
+ if (ctx->memRegion && ctx->memRegion->curPos < dot)
+ expandMemoryRegion(ctx->memRegion, dot - ctx->memRegion->curPos,
+ ctx->memRegion->name, sec->name);
+
switchTo(sec);
if (sec->lmaExpr)
@@ -972,17 +1022,13 @@ static uint64_t computeBase(uint64_t min, bool allocateHeaders) {
return alignDown(min, config->maxPageSize);
}
-// Try to find an address for the file and program headers output sections,
-// which were unconditionally added to the first PT_LOAD segment earlier.
-//
-// When using the default layout, we check if the headers fit below the first
-// allocated section. When using a linker script, we also check if the headers
-// are covered by the output section. This allows omitting the headers by not
-// leaving enough space for them in the linker script; this pattern is common
-// in embedded systems.
+// When the SECTIONS command is used, try to find an address for the file and
+// program headers output sections, which can be added to the first PT_LOAD
+// segment when program headers are created.
//
-// If there isn't enough space for these sections, we'll remove them from the
-// PT_LOAD segment, and we'll also remove the PT_PHDR segment.
+// We check if the headers fit below the first allocated section. If there isn't
+// enough space for these sections, we'll remove them from the PT_LOAD segment,
+// and we'll also remove the PT_PHDR segment.
void LinkerScript::allocateHeaders(std::vector<PhdrEntry *> &phdrs) {
uint64_t min = std::numeric_limits<uint64_t>::max();
for (OutputSection *sec : outputSections)
@@ -1028,32 +1074,30 @@ LinkerScript::AddressState::AddressState() {
}
}
-static uint64_t getInitialDot() {
- // By default linker scripts use an initial value of 0 for '.',
- // but prefer -image-base if set.
- if (script->hasSectionsCommand)
- return config->imageBase ? *config->imageBase : 0;
-
- uint64_t startAddr = UINT64_MAX;
- // The sections with -T<section> have been sorted in order of ascending
- // address. We must lower startAddr if the lowest -T<section address> as
- // calls to setDot() must be monotonically increasing.
- for (auto &kv : config->sectionStartMap)
- startAddr = std::min(startAddr, kv.second);
- return std::min(startAddr, target->getImageBase() + elf::getHeaderSize());
-}
-
// Here we assign addresses as instructed by linker script SECTIONS
// sub-commands. Doing that allows us to use final VA values, so here
// we also handle rest commands like symbol assignments and ASSERTs.
-void LinkerScript::assignAddresses() {
- dot = getInitialDot();
+// Returns a symbol that has changed its section or value, or nullptr if no
+// symbol has changed.
+const Defined *LinkerScript::assignAddresses() {
+ if (script->hasSectionsCommand) {
+ // With a linker script, assignment of addresses to headers is covered by
+ // allocateHeaders().
+ dot = config->imageBase.getValueOr(0);
+ } else {
+ // Assign addresses to headers right now.
+ dot = target->getImageBase();
+ Out::elfHeader->addr = dot;
+ Out::programHeaders->addr = dot + Out::elfHeader->size;
+ dot += getHeaderSize();
+ }
- auto deleter = make_unique<AddressState>();
+ auto deleter = std::make_unique<AddressState>();
ctx = deleter.get();
errorOnMissingSection = true;
switchTo(aether);
+ SymbolAssignmentMap oldValues = getSymbolAssignmentValues(sectionCommands);
for (BaseCommand *base : sectionCommands) {
if (auto *cmd = dyn_cast<SymbolAssignment>(base)) {
cmd->addr = dot;
@@ -1063,7 +1107,9 @@ void LinkerScript::assignAddresses() {
}
assignOffsets(cast<OutputSection>(base));
}
+
ctx = nullptr;
+ return getChangedSymbolAssignment(oldValues);
}
// Creates program headers as instructed by PHDRS linker script command.
@@ -1156,3 +1202,6 @@ std::vector<size_t> LinkerScript::getPhdrIndices(OutputSection *cmd) {
}
return ret;
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/LinkerScript.h b/contrib/llvm-project/lld/ELF/LinkerScript.h
index 9e9c08ef10ba..621b8baeaae6 100644
--- a/contrib/llvm-project/lld/ELF/LinkerScript.h
+++ b/contrib/llvm-project/lld/ELF/LinkerScript.h
@@ -168,6 +168,12 @@ struct InputSectionDescription : BaseCommand {
// will be associated with this InputSectionDescription.
std::vector<SectionPattern> sectionPatterns;
+ // Includes InputSections and MergeInputSections. Used temporarily during
+ // assignment of input sections to output sections.
+ std::vector<InputSectionBase *> sectionBases;
+
+ // Used after the finalizeInputSections() pass. MergeInputSections have been
+ // merged into MergeSyntheticSections.
std::vector<InputSection *> sections;
// Temporary record of synthetic ThunkSection instances and the pass that
@@ -226,10 +232,10 @@ class LinkerScript final {
void expandOutputSection(uint64_t size);
void expandMemoryRegions(uint64_t size);
- std::vector<InputSection *>
+ std::vector<InputSectionBase *>
computeInputSections(const InputSectionDescription *);
- std::vector<InputSection *> createInputSectionList(OutputSection &cmd);
+ std::vector<InputSectionBase *> createInputSectionList(OutputSection &cmd);
std::vector<size_t> getPhdrIndices(OutputSection *sec);
@@ -259,7 +265,7 @@ public:
bool hasPhdrsCommands() { return !phdrsCommands.empty(); }
uint64_t getDot() { return dot; }
- void discard(ArrayRef<InputSection *> v);
+ void discard(InputSectionBase *s);
ExprValue getSymbolValue(StringRef name, const Twine &loc);
@@ -271,9 +277,10 @@ public:
bool needsInterpSection();
bool shouldKeep(InputSectionBase *s);
- void assignAddresses();
+ const Defined *assignAddresses();
void allocateHeaders(std::vector<PhdrEntry *> &phdrs);
void processSectionCommands();
+ void processSymbolAssignments();
void declareSymbols();
// Used to handle INSERT AFTER statements.
diff --git a/contrib/llvm-project/lld/ELF/MapFile.cpp b/contrib/llvm-project/lld/ELF/MapFile.cpp
index a4a6238fc655..4d76e22f37f5 100644
--- a/contrib/llvm-project/lld/ELF/MapFile.cpp
+++ b/contrib/llvm-project/lld/ELF/MapFile.cpp
@@ -34,13 +34,12 @@
using namespace llvm;
using namespace llvm::object;
-using namespace lld;
-using namespace lld::elf;
-
+namespace lld {
+namespace elf {
using SymbolMapTy = DenseMap<const SectionBase *, SmallVector<Defined *, 4>>;
-static const std::string indent8 = " "; // 8 spaces
-static const std::string indent16 = " "; // 16 spaces
+static constexpr char indent8[] = " "; // 8 spaces
+static constexpr char indent16[] = " "; // 16 spaces
// Print out the first three columns of a line.
static void writeHeader(raw_ostream &os, uint64_t vma, uint64_t lma,
@@ -139,13 +138,13 @@ static void printEhFrame(raw_ostream &os, const EhFrameSection *sec) {
}
}
-void elf::writeMapFile() {
+void writeMapFile() {
if (config->mapFile.empty())
return;
// Open a map file for writing.
std::error_code ec;
- raw_fd_ostream os(config->mapFile, ec, sys::fs::F_None);
+ raw_fd_ostream os(config->mapFile, ec, sys::fs::OF_None);
if (ec) {
error("cannot open " + config->mapFile + ": " + ec.message());
return;
@@ -228,7 +227,7 @@ static void print(StringRef a, StringRef b) {
//
// In this case, strlen is defined by libc.so.6 and used by other two
// files.
-void elf::writeCrossReferenceTable() {
+void writeCrossReferenceTable() {
if (!config->cref)
return;
@@ -259,3 +258,6 @@ void elf::writeCrossReferenceTable() {
print("", toString(file));
}
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/MarkLive.cpp b/contrib/llvm-project/lld/ELF/MarkLive.cpp
index 36b847f725b8..02ab6d18e537 100644
--- a/contrib/llvm-project/lld/ELF/MarkLive.cpp
+++ b/contrib/llvm-project/lld/ELF/MarkLive.cpp
@@ -37,11 +37,11 @@
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
-using namespace llvm::support::endian;
-using namespace lld;
-using namespace lld::elf;
+namespace endian = llvm::support::endian;
+namespace lld {
+namespace elf {
namespace {
template <class ELFT> class MarkLive {
public:
@@ -141,7 +141,7 @@ void MarkLive<ELFT>::scanEhFrameSection(EhInputSection &eh,
if (firstRelI == (unsigned)-1)
continue;
- if (read32<ELFT::TargetEndianness>(piece.data().data() + 4) == 0) {
+ if (endian::read32<ELFT::TargetEndianness>(piece.data().data() + 4) == 0) {
// This is a CIE, we only need to worry about the first relocation. It is
// known to point to the personality function.
resolveReloc(eh, rels[firstRelI], false);
@@ -291,6 +291,10 @@ template <class ELFT> void MarkLive<ELFT>::mark() {
// GOT, which means that the ifunc must be available when the main partition is
// loaded) and TLS symbols (because we only know how to correctly process TLS
// relocations for the main partition).
+//
+// We also need to move sections whose names are C identifiers that are referred
+// to from __start_/__stop_ symbols because there will only be one set of
+// symbols for the whole program.
template <class ELFT> void MarkLive<ELFT>::moveToMain() {
for (InputFile *file : objectFiles)
for (Symbol *s : file->getSymbols())
@@ -299,13 +303,21 @@ template <class ELFT> void MarkLive<ELFT>::moveToMain() {
d->section->isLive())
markSymbol(s);
+ for (InputSectionBase *sec : inputSections) {
+ if (!sec->isLive() || !isValidCIdentifier(sec->name))
+ continue;
+ if (symtab->find(("__start_" + sec->name).str()) ||
+ symtab->find(("__stop_" + sec->name).str()))
+ enqueue(sec, 0);
+ }
+
mark();
}
// Before calling this function, Live bits are off for all
// input sections. This function make some or all of them on
// so that they are emitted to the output file.
-template <class ELFT> void elf::markLive() {
+template <class ELFT> void markLive() {
// If -gc-sections is not given, no sections are removed.
if (!config->gcSections) {
for (InputSectionBase *sec : inputSections)
@@ -367,7 +379,10 @@ template <class ELFT> void elf::markLive() {
message("removing unused section " + toString(sec));
}
-template void elf::markLive<ELF32LE>();
-template void elf::markLive<ELF32BE>();
-template void elf::markLive<ELF64LE>();
-template void elf::markLive<ELF64BE>();
+template void markLive<ELF32LE>();
+template void markLive<ELF32BE>();
+template void markLive<ELF64LE>();
+template void markLive<ELF64BE>();
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/Options.td b/contrib/llvm-project/lld/ELF/Options.td
index 3ebb46f2e1b2..c540efb25e90 100644
--- a/contrib/llvm-project/lld/ELF/Options.td
+++ b/contrib/llvm-project/lld/ELF/Options.td
@@ -171,6 +171,9 @@ defm fini: Eq<"fini", "Specify a finalizer function">, MetaVarName<"<symbol>">;
def fix_cortex_a53_843419: F<"fix-cortex-a53-843419">,
HelpText<"Apply fixes for AArch64 Cortex-A53 erratum 843419">;
+def fix_cortex_a8: F<"fix-cortex-a8">,
+ HelpText<"Apply fixes for ARM Cortex-A8 erratum 657417">;
+
// This option is intentionally hidden from the user as the implementation
// is not complete.
def require_cet: F<"require-cet">;
@@ -306,7 +309,7 @@ def push_state: F<"push-state">,
def print_map: F<"print-map">,
HelpText<"Print a link map to the standard output">;
-defm reproduce: Eq<"reproduce", "Dump linker invocation and input files for debugging">;
+defm reproduce: Eq<"reproduce", "Write a tar file containing input files and command line options to reproduce link">;
defm rpath: Eq<"rpath", "Add a DT_RUNPATH to the output">;
@@ -478,6 +481,7 @@ def lto_cs_profile_generate: F<"lto-cs-profile-generate">,
HelpText<"Perform context senstive PGO instrumentation">;
def lto_cs_profile_file: J<"lto-cs-profile-file=">,
HelpText<"Context sensitive profile file path">;
+def lto_obj_path_eq: J<"lto-obj-path=">;
def lto_sample_profile: J<"lto-sample-profile=">,
HelpText<"Sample profile file path">;
def disable_verify: F<"disable-verify">;
@@ -495,7 +499,12 @@ def save_temps: F<"save-temps">;
def thinlto_cache_dir: J<"thinlto-cache-dir=">,
HelpText<"Path to ThinLTO cached object file directory">;
defm thinlto_cache_policy: Eq<"thinlto-cache-policy", "Pruning policy for the ThinLTO cache">;
+def thinlto_emit_imports_files: F<"thinlto-emit-imports-files">;
+def thinlto_index_only: F<"thinlto-index-only">;
+def thinlto_index_only_eq: J<"thinlto-index-only=">;
def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
+def thinlto_object_suffix_replace_eq: J<"thinlto-object-suffix-replace=">;
+def thinlto_prefix_replace_eq: J<"thinlto-prefix-replace=">;
def: J<"plugin-opt=O">, Alias<lto_O>, HelpText<"Alias for -lto-O">;
def: F<"plugin-opt=debug-pass-manager">,
@@ -509,19 +518,31 @@ def: J<"plugin-opt=lto-partitions=">, Alias<lto_partitions>, HelpText<"Alias for
def plugin_opt_mcpu_eq: J<"plugin-opt=mcpu=">;
def: F<"plugin-opt=new-pass-manager">,
Alias<lto_new_pass_manager>, HelpText<"Alias for -lto-new-pass-manager">;
-def plugin_opt_obj_path_eq: J<"plugin-opt=obj-path=">;
def: F<"plugin-opt=cs-profile-generate">,
Alias<lto_cs_profile_generate>, HelpText<"Alias for -lto-cs-profile-generate">;
def: J<"plugin-opt=cs-profile-path=">,
Alias<lto_cs_profile_file>, HelpText<"Alias for -lto-cs-profile-file">;
+def: J<"plugin-opt=obj-path=">,
+ Alias<lto_obj_path_eq>,
+ HelpText<"Alias for -lto-obj-path=">;
def: J<"plugin-opt=sample-profile=">,
Alias<lto_sample_profile>, HelpText<"Alias for -lto-sample-profile">;
def: F<"plugin-opt=save-temps">, Alias<save_temps>, HelpText<"Alias for -save-temps">;
-def plugin_opt_thinlto_emit_imports_files: F<"plugin-opt=thinlto-emit-imports-files">;
-def plugin_opt_thinlto_index_only: F<"plugin-opt=thinlto-index-only">;
-def plugin_opt_thinlto_index_only_eq: J<"plugin-opt=thinlto-index-only=">;
-def plugin_opt_thinlto_object_suffix_replace_eq: J<"plugin-opt=thinlto-object-suffix-replace=">;
-def plugin_opt_thinlto_prefix_replace_eq: J<"plugin-opt=thinlto-prefix-replace=">;
+def: F<"plugin-opt=thinlto-emit-imports-files">,
+ Alias<thinlto_emit_imports_files>,
+ HelpText<"Alias for -thinlto-emit-imports-files">;
+def: F<"plugin-opt=thinlto-index-only">,
+ Alias<thinlto_index_only>,
+ HelpText<"Alias for -thinlto-index-only">;
+def: J<"plugin-opt=thinlto-index-only=">,
+ Alias<thinlto_index_only_eq>,
+ HelpText<"Alias for -thinlto-index-only=">;
+def: J<"plugin-opt=thinlto-object-suffix-replace=">,
+ Alias<thinlto_object_suffix_replace_eq>,
+ HelpText<"Alias for -thinlto-object-suffix-replace=">;
+def: J<"plugin-opt=thinlto-prefix-replace=">,
+ Alias<thinlto_prefix_replace_eq>,
+ HelpText<"Alias for -thinlto-prefix-replace=">;
// Ignore LTO plugin-related options.
// clang -flto passes -plugin and -plugin-opt to the linker. This is required
diff --git a/contrib/llvm-project/lld/ELF/OutputSections.cpp b/contrib/llvm-project/lld/ELF/OutputSections.cpp
index a89bd509bc96..ea7c96eb676a 100644
--- a/contrib/llvm-project/lld/ELF/OutputSections.cpp
+++ b/contrib/llvm-project/lld/ELF/OutputSections.cpp
@@ -27,9 +27,8 @@ using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
-
+namespace lld {
+namespace elf {
uint8_t *Out::bufferStart;
uint8_t Out::first;
PhdrEntry *Out::tlsPhdr;
@@ -39,7 +38,7 @@ OutputSection *Out::preinitArray;
OutputSection *Out::initArray;
OutputSection *Out::finiArray;
-std::vector<OutputSection *> elf::outputSections;
+std::vector<OutputSection *> outputSections;
uint32_t OutputSection::getPhdrFlags() const {
uint32_t ret = 0;
@@ -83,12 +82,32 @@ static bool canMergeToProgbits(unsigned type) {
type == SHT_NOTE;
}
-void OutputSection::addSection(InputSection *isec) {
+// Record that isec will be placed in the OutputSection. isec does not become
+// permanent until finalizeInputSections() is called. The function should not be
+// used after finalizeInputSections() is called. If you need to add an
+// InputSection post finalizeInputSections(), then you must do the following:
+//
+// 1. Find or create an InputSectionDescription to hold InputSection.
+// 2. Add the InputSection to the InputSectionDesciption::sections.
+// 3. Call commitSection(isec).
+void OutputSection::recordSection(InputSectionBase *isec) {
+ partition = isec->partition;
+ isec->parent = this;
+ if (sectionCommands.empty() ||
+ !isa<InputSectionDescription>(sectionCommands.back()))
+ sectionCommands.push_back(make<InputSectionDescription>(""));
+ auto *isd = cast<InputSectionDescription>(sectionCommands.back());
+ isd->sectionBases.push_back(isec);
+}
+
+// Update fields (type, flags, alignment, etc) according to the InputSection
+// isec. Also check whether the InputSection flags and type are consistent with
+// other InputSections.
+void OutputSection::commitSection(InputSection *isec) {
if (!hasInputSections) {
// If IS is the first section to be added to this section,
- // initialize Partition, Type, Entsize and flags from IS.
+ // initialize type, entsize and flags from isec.
hasInputSections = true;
- partition = isec->partition;
type = isec->type;
entsize = isec->entsize;
flags = isec->flags;
@@ -110,6 +129,8 @@ void OutputSection::addSection(InputSection *isec) {
type = SHT_PROGBITS;
}
}
+ if (noload)
+ type = SHT_NOBITS;
isec->parent = this;
uint64_t andMask =
@@ -118,6 +139,8 @@ void OutputSection::addSection(InputSection *isec) {
uint64_t andFlags = (flags & isec->flags) & andMask;
uint64_t orFlags = (flags | isec->flags) & orMask;
flags = andFlags | orFlags;
+ if (nonAlloc)
+ flags &= ~(uint64_t)SHF_ALLOC;
alignment = std::max(alignment, isec->alignment);
@@ -126,15 +149,69 @@ void OutputSection::addSection(InputSection *isec) {
// set sh_entsize to 0.
if (entsize != isec->entsize)
entsize = 0;
+}
- if (!isec->assigned) {
- isec->assigned = true;
- if (sectionCommands.empty() ||
- !isa<InputSectionDescription>(sectionCommands.back()))
- sectionCommands.push_back(make<InputSectionDescription>(""));
- auto *isd = cast<InputSectionDescription>(sectionCommands.back());
- isd->sections.push_back(isec);
+// This function scans over the InputSectionBase list sectionBases to create
+// InputSectionDescription::sections.
+//
+// It removes MergeInputSections from the input section array and adds
+// new synthetic sections at the location of the first input section
+// that it replaces. It then finalizes each synthetic section in order
+// to compute an output offset for each piece of each input section.
+void OutputSection::finalizeInputSections() {
+ std::vector<MergeSyntheticSection *> mergeSections;
+ for (BaseCommand *base : sectionCommands) {
+ auto *cmd = dyn_cast<InputSectionDescription>(base);
+ if (!cmd)
+ continue;
+ cmd->sections.reserve(cmd->sectionBases.size());
+ for (InputSectionBase *s : cmd->sectionBases) {
+ MergeInputSection *ms = dyn_cast<MergeInputSection>(s);
+ if (!ms) {
+ cmd->sections.push_back(cast<InputSection>(s));
+ continue;
+ }
+
+ // We do not want to handle sections that are not alive, so just remove
+ // them instead of trying to merge.
+ if (!ms->isLive())
+ continue;
+
+ auto i = llvm::find_if(mergeSections, [=](MergeSyntheticSection *sec) {
+ // While we could create a single synthetic section for two different
+ // values of Entsize, it is better to take Entsize into consideration.
+ //
+ // With a single synthetic section no two pieces with different Entsize
+ // could be equal, so we may as well have two sections.
+ //
+ // Using Entsize in here also allows us to propagate it to the synthetic
+ // section.
+ //
+ // SHF_STRINGS section with different alignments should not be merged.
+ return sec->flags == ms->flags && sec->entsize == ms->entsize &&
+ (sec->alignment == ms->alignment || !(sec->flags & SHF_STRINGS));
+ });
+ if (i == mergeSections.end()) {
+ MergeSyntheticSection *syn =
+ createMergeSynthetic(name, ms->type, ms->flags, ms->alignment);
+ mergeSections.push_back(syn);
+ i = std::prev(mergeSections.end());
+ syn->entsize = ms->entsize;
+ cmd->sections.push_back(syn);
+ }
+ (*i)->addSection(ms);
+ }
+
+ // sectionBases should not be used from this point onwards. Clear it to
+ // catch misuses.
+ cmd->sectionBases.clear();
+
+ // Some input sections may be removed from the list after ICF.
+ for (InputSection *s : cmd->sections)
+ commitSection(s);
}
+ for (auto *ms : mergeSections)
+ ms->finalizeContents();
}
static void sortByOrder(MutableArrayRef<InputSection *> in,
@@ -148,7 +225,7 @@ static void sortByOrder(MutableArrayRef<InputSection *> in,
in[i] = v[i].second;
}
-uint64_t elf::getHeaderSize() {
+uint64_t getHeaderSize() {
if (config->oFormatBinary)
return 0;
return Out::elfHeader->size + Out::programHeaders->size;
@@ -368,7 +445,7 @@ void OutputSection::sortCtorsDtors() {
// If an input string is in the form of "foo.N" where N is a number,
// return N. Otherwise, returns 65536, which is one greater than the
// lowest priority.
-int elf::getPriority(StringRef s) {
+int getPriority(StringRef s) {
size_t pos = s.rfind('.');
if (pos == StringRef::npos)
return 65536;
@@ -378,7 +455,7 @@ int elf::getPriority(StringRef s) {
return v;
}
-std::vector<InputSection *> elf::getInputSections(OutputSection *os) {
+std::vector<InputSection *> getInputSections(OutputSection *os) {
std::vector<InputSection *> ret;
for (BaseCommand *base : os->sectionCommands)
if (auto *isd = dyn_cast<InputSectionDescription>(base))
@@ -419,3 +496,6 @@ template void OutputSection::maybeCompress<ELF32LE>();
template void OutputSection::maybeCompress<ELF32BE>();
template void OutputSection::maybeCompress<ELF64LE>();
template void OutputSection::maybeCompress<ELF64BE>();
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/OutputSections.h b/contrib/llvm-project/lld/ELF/OutputSections.h
index fff8327ea376..a24294eedf35 100644
--- a/contrib/llvm-project/lld/ELF/OutputSections.h
+++ b/contrib/llvm-project/lld/ELF/OutputSections.h
@@ -71,7 +71,9 @@ public:
uint64_t addr = 0;
uint32_t shName = 0;
- void addSection(InputSection *isec);
+ void recordSection(InputSectionBase *isec);
+ void commitSection(InputSection *isec);
+ void finalizeInputSections();
// The following members are normally only used in linker scripts.
MemoryRegion *memRegion = nullptr;
diff --git a/contrib/llvm-project/lld/ELF/Relocations.cpp b/contrib/llvm-project/lld/ELF/Relocations.cpp
index ee48f4808136..ab3030d91017 100644
--- a/contrib/llvm-project/lld/ELF/Relocations.cpp
+++ b/contrib/llvm-project/lld/ELF/Relocations.cpp
@@ -62,9 +62,8 @@ using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::support::endian;
-using namespace lld;
-using namespace lld::elf;
-
+namespace lld {
+namespace elf {
static Optional<std::string> getLinkerScriptLocation(const Symbol &sym) {
for (BaseCommand *base : script->sectionCommands)
if (auto *cmd = dyn_cast<SymbolAssignment>(base))
@@ -344,9 +343,9 @@ static bool needsPlt(RelExpr expr) {
// returns false for TLS variables even though they need GOT, because
// TLS variables uses GOT differently than the regular variables.
static bool needsGot(RelExpr expr) {
- return oneof<R_GOT, R_GOT_OFF, R_HEXAGON_GOT, R_MIPS_GOT_LOCAL_PAGE,
- R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC,
- R_GOT_PC, R_GOTPLT>(expr);
+ return oneof<R_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF,
+ R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT>(
+ expr);
}
// True if this expression is of the form Sym - X, where X is a position in the
@@ -369,7 +368,7 @@ static bool isRelExpr(RelExpr expr) {
static bool isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym,
InputSectionBase &s, uint64_t relOff) {
// These expressions always compute a constant
- if (oneof<R_DTPREL, R_GOTPLT, R_GOT_OFF, R_HEXAGON_GOT, R_TLSLD_GOT_OFF,
+ if (oneof<R_DTPREL, R_GOTPLT, R_GOT_OFF, R_TLSLD_GOT_OFF,
R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOTREL, R_MIPS_GOT_OFF,
R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, R_MIPS_TLSGD,
R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC,
@@ -510,10 +509,8 @@ static void replaceWithDefined(Symbol &sym, SectionBase *sec, uint64_t value,
sym.gotIndex = old.gotIndex;
sym.verdefIndex = old.verdefIndex;
sym.ppc64BranchltIndex = old.ppc64BranchltIndex;
- sym.isPreemptible = true;
sym.exportDynamic = true;
sym.isUsedInRegularObj = true;
- sym.used = true;
}
// Reserve space in .bss or .bss.rel.ro for copy relocation.
@@ -569,10 +566,16 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol &ss) {
bool isRO = isReadOnly<ELFT>(ss);
BssSection *sec =
make<BssSection>(isRO ? ".bss.rel.ro" : ".bss", symSize, ss.alignment);
- if (isRO)
- in.bssRelRo->getParent()->addSection(sec);
- else
- in.bss->getParent()->addSection(sec);
+ OutputSection *osec = (isRO ? in.bssRelRo : in.bss)->getParent();
+
+ // At this point, sectionBases has been migrated to sections. Append sec to
+ // sections.
+ if (osec->sectionCommands.empty() ||
+ !isa<InputSectionDescription>(osec->sectionCommands.back()))
+ osec->sectionCommands.push_back(make<InputSectionDescription>(""));
+ auto *isd = cast<InputSectionDescription>(osec->sectionCommands.back());
+ isd->sections.push_back(sec);
+ osec->commitSection(sec);
// Look through the DSO's dynamic symbol table for aliases and create a
// dynamic symbol for each one. This causes the copy relocation to correctly
@@ -693,8 +696,75 @@ struct UndefinedDiag {
static std::vector<UndefinedDiag> undefs;
+// Suggest an alternative spelling of an "undefined symbol" diagnostic. Returns
+// the suggested symbol, which is either in the symbol table, or in the same
+// file of sym.
+static const Symbol *getAlternativeSpelling(const Undefined &sym) {
+ // Build a map of local defined symbols.
+ DenseMap<StringRef, const Symbol *> map;
+ if (sym.file && !isa<SharedFile>(sym.file)) {
+ for (const Symbol *s : sym.file->getSymbols())
+ if (s->isLocal() && s->isDefined())
+ map.try_emplace(s->getName(), s);
+ }
+
+ auto suggest = [&](StringRef newName) -> const Symbol * {
+ // If defined locally.
+ if (const Symbol *s = map.lookup(newName))
+ return s;
+
+ // If in the symbol table and not undefined.
+ if (const Symbol *s = symtab->find(newName))
+ if (!s->isUndefined())
+ return s;
+
+ return nullptr;
+ };
+
+ // This loop enumerates all strings of Levenshtein distance 1 as typo
+ // correction candidates and suggests the one that exists as a non-undefined
+ // symbol.
+ StringRef name = sym.getName();
+ for (size_t i = 0, e = name.size(); i != e + 1; ++i) {
+ // Insert a character before name[i].
+ std::string newName = (name.substr(0, i) + "0" + name.substr(i)).str();
+ for (char c = '0'; c <= 'z'; ++c) {
+ newName[i] = c;
+ if (const Symbol *s = suggest(newName))
+ return s;
+ }
+ if (i == e)
+ break;
+
+ // Substitute name[i].
+ newName = name;
+ for (char c = '0'; c <= 'z'; ++c) {
+ newName[i] = c;
+ if (const Symbol *s = suggest(newName))
+ return s;
+ }
+
+ // Transpose name[i] and name[i+1]. This is of edit distance 2 but it is
+ // common.
+ if (i + 1 < e) {
+ newName[i] = name[i + 1];
+ newName[i + 1] = name[i];
+ if (const Symbol *s = suggest(newName))
+ return s;
+ }
+
+ // Delete name[i].
+ newName = (name.substr(0, i) + name.substr(i + 1)).str();
+ if (const Symbol *s = suggest(newName))
+ return s;
+ }
+
+ return nullptr;
+}
+
template <class ELFT>
-static void reportUndefinedSymbol(const UndefinedDiag &undef) {
+static void reportUndefinedSymbol(const UndefinedDiag &undef,
+ bool correctSpelling) {
Symbol &sym = *undef.sym;
auto visibility = [&]() -> std::string {
@@ -734,6 +804,14 @@ static void reportUndefinedSymbol(const UndefinedDiag &undef) {
msg += ("\n>>> referenced " + Twine(undef.locs.size() - i) + " more times")
.str();
+ if (correctSpelling)
+ if (const Symbol *corrected =
+ getAlternativeSpelling(cast<Undefined>(sym))) {
+ msg += "\n>>> did you mean: " + toString(*corrected);
+ if (corrected->file)
+ msg += "\n>>> defined in: " + toString(corrected->file);
+ }
+
if (sym.getName().startswith("_ZTV"))
msg += "\nthe vtable symbol may be undefined because the class is missing "
"its key function (see https://lld.llvm.org/missingkeyfunction)";
@@ -744,7 +822,7 @@ static void reportUndefinedSymbol(const UndefinedDiag &undef) {
error(msg);
}
-template <class ELFT> void elf::reportUndefinedSymbols() {
+template <class ELFT> void reportUndefinedSymbols() {
// Find the first "undefined symbol" diagnostic for each diagnostic, and
// collect all "referenced from" lines at the first diagnostic.
DenseMap<Symbol *, UndefinedDiag *> firstRef;
@@ -757,23 +835,21 @@ template <class ELFT> void elf::reportUndefinedSymbols() {
firstRef[undef.sym] = &undef;
}
- for (const UndefinedDiag &undef : undefs) {
- if (!undef.locs.empty())
- reportUndefinedSymbol<ELFT>(undef);
- }
+ // Enable spell corrector for the first 2 diagnostics.
+ for (auto it : enumerate(undefs))
+ if (!it.value().locs.empty())
+ reportUndefinedSymbol<ELFT>(it.value(), it.index() < 2);
undefs.clear();
}
// Report an undefined symbol if necessary.
// Returns true if the undefined symbol will produce an error message.
-template <class ELFT>
static bool maybeReportUndefined(Symbol &sym, InputSectionBase &sec,
uint64_t offset) {
if (!sym.isUndefined() || sym.isWeak())
return false;
- bool canBeExternal = !sym.isLocal() && sym.computeBinding() != STB_LOCAL &&
- sym.visibility == STV_DEFAULT;
+ bool canBeExternal = !sym.isLocal() && sym.visibility == STV_DEFAULT;
if (config->unresolvedSymbols == UnresolvedPolicy::Ignore && canBeExternal)
return false;
@@ -997,56 +1073,29 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
}
}
- if (!canWrite && (config->isPic && !isRelExpr(expr))) {
- error(
- "can't create dynamic relocation " + toString(type) + " against " +
- (sym.getName().empty() ? "local symbol" : "symbol: " + toString(sym)) +
- " in readonly segment; recompile object files with -fPIC "
- "or pass '-Wl,-z,notext' to allow text relocations in the output" +
- getLocation(sec, sym, offset));
- return;
- }
-
- // Copy relocations (for STT_OBJECT) and canonical PLT (for STT_FUNC) are only
- // possible in an executable.
- //
- // Among R_ABS relocatoin types, symbolicRel has the same size as the word
- // size. Others have fewer bits and may cause runtime overflow in -pie/-shared
- // mode. Disallow them.
- if (config->shared ||
- (config->pie && expr == R_ABS && type != target->symbolicRel)) {
- errorOrWarn(
- "relocation " + toString(type) + " cannot be used against " +
- (sym.getName().empty() ? "local symbol" : "symbol " + toString(sym)) +
- "; recompile with -fPIC" + getLocation(sec, sym, offset));
- return;
- }
-
- // If the symbol is undefined we already reported any relevant errors.
- if (sym.isUndefined())
- return;
-
- if (!canDefineSymbolInExecutable(sym)) {
- error("cannot preempt symbol: " + toString(sym) +
- getLocation(sec, sym, offset));
- return;
- }
+ // When producing an executable, we can perform copy relocations (for
+ // STT_OBJECT) and canonical PLT (for STT_FUNC).
+ if (!config->shared) {
+ if (!canDefineSymbolInExecutable(sym)) {
+ errorOrWarn("cannot preempt symbol: " + toString(sym) +
+ getLocation(sec, sym, offset));
+ return;
+ }
- if (sym.isObject()) {
- // Produce a copy relocation.
- if (auto *ss = dyn_cast<SharedSymbol>(&sym)) {
- if (!config->zCopyreloc)
- error("unresolvable relocation " + toString(type) +
- " against symbol '" + toString(*ss) +
- "'; recompile with -fPIC or remove '-z nocopyreloc'" +
- getLocation(sec, sym, offset));
- addCopyRelSymbol<ELFT>(*ss);
+ if (sym.isObject()) {
+ // Produce a copy relocation.
+ if (auto *ss = dyn_cast<SharedSymbol>(&sym)) {
+ if (!config->zCopyreloc)
+ error("unresolvable relocation " + toString(type) +
+ " against symbol '" + toString(*ss) +
+ "'; recompile with -fPIC or remove '-z nocopyreloc'" +
+ getLocation(sec, sym, offset));
+ addCopyRelSymbol<ELFT>(*ss);
+ }
+ sec.relocations.push_back({expr, type, offset, addend, &sym});
+ return;
}
- sec.relocations.push_back({expr, type, offset, addend, &sym});
- return;
- }
- if (sym.isFunc()) {
// This handles a non PIC program call to function in a shared library. In
// an ideal world, we could just report an error saying the relocation can
// overflow at runtime. In the real world with glibc, crt1.o has a
@@ -1074,18 +1123,37 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
// compiled without -fPIE/-fPIC and doesn't maintain ebx.
// * If a library definition gets preempted to the executable, it will have
// the wrong ebx value.
- if (config->pie && config->emachine == EM_386)
- errorOrWarn("symbol '" + toString(sym) +
- "' cannot be preempted; recompile with -fPIE" +
- getLocation(sec, sym, offset));
- if (!sym.isInPlt())
- addPltEntry<ELFT>(in.plt, in.gotPlt, in.relaPlt, target->pltRel, sym);
- if (!sym.isDefined())
- replaceWithDefined(
- sym, in.plt,
- target->pltHeaderSize + target->pltEntrySize * sym.pltIndex, 0);
- sym.needsPltAddr = true;
- sec.relocations.push_back({expr, type, offset, addend, &sym});
+ if (sym.isFunc()) {
+ if (config->pie && config->emachine == EM_386)
+ errorOrWarn("symbol '" + toString(sym) +
+ "' cannot be preempted; recompile with -fPIE" +
+ getLocation(sec, sym, offset));
+ if (!sym.isInPlt())
+ addPltEntry<ELFT>(in.plt, in.gotPlt, in.relaPlt, target->pltRel, sym);
+ if (!sym.isDefined())
+ replaceWithDefined(
+ sym, in.plt,
+ target->pltHeaderSize + target->pltEntrySize * sym.pltIndex, 0);
+ sym.needsPltAddr = true;
+ sec.relocations.push_back({expr, type, offset, addend, &sym});
+ return;
+ }
+ }
+
+ if (config->isPic) {
+ if (!canWrite && !isRelExpr(expr))
+ errorOrWarn(
+ "can't create dynamic relocation " + toString(type) + " against " +
+ (sym.getName().empty() ? "local symbol"
+ : "symbol: " + toString(sym)) +
+ " in readonly segment; recompile object files with -fPIC "
+ "or pass '-Wl,-z,notext' to allow text relocations in the output" +
+ getLocation(sec, sym, offset));
+ else
+ errorOrWarn(
+ "relocation " + toString(type) + " cannot be used against " +
+ (sym.getName().empty() ? "local symbol" : "symbol " + toString(sym)) +
+ "; recompile with -fPIC" + getLocation(sec, sym, offset));
return;
}
@@ -1093,15 +1161,6 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
getLocation(sec, sym, offset));
}
-struct IRelativeReloc {
- RelType type;
- InputSectionBase *sec;
- uint64_t offset;
- Symbol *sym;
-};
-
-static std::vector<IRelativeReloc> iRelativeRelocs;
-
template <class ELFT, class RelTy>
static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
RelTy *end) {
@@ -1125,7 +1184,7 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
// Error if the target symbol is undefined. Symbol index 0 may be used by
// marker relocations, e.g. R_*_NONE and R_ARM_V4BX. Don't error on them.
- if (symIndex != 0 && maybeReportUndefined<ELFT>(sym, sec, rel.r_offset))
+ if (symIndex != 0 && maybeReportUndefined(sym, sec, rel.r_offset))
return;
const uint8_t *relocatedAddr = sec.data().begin() + rel.r_offset;
@@ -1269,12 +1328,6 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
// correctly, the IRELATIVE relocations are stored in an array which a
// statically linked executable's startup code must enumerate using the
// linker-defined symbols __rela?_iplt_{start,end}.
- //
- // - An absolute relocation to a non-preemptible ifunc (such as a global
- // variable containing a pointer to the ifunc) needs to be relocated in
- // the exact same way as a GOT entry, so we can avoid needing to make the
- // PLT entry canonical by translating such relocations into IRELATIVE
- // relocations in the relaIplt.
if (!sym.isInPlt()) {
// Create PLT and GOTPLT slots for the symbol.
sym.isInIplt = true;
@@ -1291,17 +1344,6 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
*directSym);
sym.pltIndex = directSym->pltIndex;
}
- if (expr == R_ABS && addend == 0 && (sec.flags & SHF_WRITE)) {
- // We might be able to represent this as an IRELATIVE. But we don't know
- // yet whether some later relocation will make the symbol point to a
- // canonical PLT, which would make this either a dynamic RELATIVE (PIC) or
- // static (non-PIC) relocation. So we keep a record of the information
- // required to process the relocation, and after scanRelocs() has been
- // called on all relocations, the relocation is resolved by
- // addIRelativeRelocs().
- iRelativeRelocs.push_back({type, &sec, offset, &sym});
- return;
- }
if (needsGot(expr)) {
// Redirect GOT accesses to point to the Igot.
//
@@ -1362,28 +1404,13 @@ static void scanRelocs(InputSectionBase &sec, ArrayRef<RelTy> rels) {
});
}
-template <class ELFT> void elf::scanRelocations(InputSectionBase &s) {
+template <class ELFT> void scanRelocations(InputSectionBase &s) {
if (s.areRelocsRela)
scanRelocs<ELFT>(s, s.relas<ELFT>());
else
scanRelocs<ELFT>(s, s.rels<ELFT>());
}
-// Figure out which representation to use for any absolute relocs to
-// non-preemptible ifuncs that we visited during scanRelocs().
-void elf::addIRelativeRelocs() {
- for (IRelativeReloc &r : iRelativeRelocs) {
- if (r.sym->type == STT_GNU_IFUNC)
- in.relaIplt->addReloc(
- {target->iRelativeRel, r.sec, r.offset, true, r.sym, 0});
- else if (config->isPic)
- addRelativeReloc(r.sec, r.offset, r.sym, 0, R_ABS, r.type);
- else
- r.sec->relocations.push_back({R_ABS, r.type, r.offset, 0, r.sym});
- }
- iRelativeRelocs.clear();
-}
-
static bool mergeCmp(const InputSection *a, const InputSection *b) {
// std::merge requires a strict weak ordering.
if (a->outSecOff < b->outSecOff)
@@ -1745,11 +1772,6 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> outputSections) {
if (pass == 0 && target->getThunkSectionSpacing())
createInitialThunkSections(outputSections);
- // With Thunk Size much smaller than branch range we expect to
- // converge quickly; if we get to 10 something has gone wrong.
- if (pass == 10)
- fatal("thunk creation not converged");
-
// Create all the Thunks and insert them into synthetic ThunkSections. The
// ThunkSections are later inserted back into InputSectionDescriptions.
// We separate the creation of ThunkSections from the insertion of the
@@ -1809,11 +1831,14 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> outputSections) {
return addressesChanged;
}
-template void elf::scanRelocations<ELF32LE>(InputSectionBase &);
-template void elf::scanRelocations<ELF32BE>(InputSectionBase &);
-template void elf::scanRelocations<ELF64LE>(InputSectionBase &);
-template void elf::scanRelocations<ELF64BE>(InputSectionBase &);
-template void elf::reportUndefinedSymbols<ELF32LE>();
-template void elf::reportUndefinedSymbols<ELF32BE>();
-template void elf::reportUndefinedSymbols<ELF64LE>();
-template void elf::reportUndefinedSymbols<ELF64BE>();
+template void scanRelocations<ELF32LE>(InputSectionBase &);
+template void scanRelocations<ELF32BE>(InputSectionBase &);
+template void scanRelocations<ELF64LE>(InputSectionBase &);
+template void scanRelocations<ELF64BE>(InputSectionBase &);
+template void reportUndefinedSymbols<ELF32LE>();
+template void reportUndefinedSymbols<ELF32BE>();
+template void reportUndefinedSymbols<ELF64LE>();
+template void reportUndefinedSymbols<ELF64BE>();
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/Relocations.h b/contrib/llvm-project/lld/ELF/Relocations.h
index d74d7b9b458e..befe15b8f3b9 100644
--- a/contrib/llvm-project/lld/ELF/Relocations.h
+++ b/contrib/llvm-project/lld/ELF/Relocations.h
@@ -82,7 +82,6 @@ enum RelExpr {
R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
R_AARCH64_TLSDESC_PAGE,
R_ARM_SBREL,
- R_HEXAGON_GOT,
R_MIPS_GOTREL,
R_MIPS_GOT_GP,
R_MIPS_GOT_GP_PC,
diff --git a/contrib/llvm-project/lld/ELF/ScriptLexer.cpp b/contrib/llvm-project/lld/ELF/ScriptLexer.cpp
index 953a3df8a31c..e0ff56fec3f3 100644
--- a/contrib/llvm-project/lld/ELF/ScriptLexer.cpp
+++ b/contrib/llvm-project/lld/ELF/ScriptLexer.cpp
@@ -36,9 +36,9 @@
#include "llvm/ADT/Twine.h"
using namespace llvm;
-using namespace lld;
-using namespace lld::elf;
+namespace lld {
+namespace elf {
// Returns a whole line containing the current token.
StringRef ScriptLexer::getLine() {
StringRef s = getCurrentMB().getBuffer();
@@ -298,3 +298,6 @@ MemoryBufferRef ScriptLexer::getCurrentMB() {
return mb;
llvm_unreachable("getCurrentMB: failed to find a token");
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/ScriptParser.cpp b/contrib/llvm-project/lld/ELF/ScriptParser.cpp
index 8f0aa660145a..fd8de3b54bd7 100644
--- a/contrib/llvm-project/lld/ELF/ScriptParser.cpp
+++ b/contrib/llvm-project/lld/ELF/ScriptParser.cpp
@@ -37,9 +37,9 @@
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::support::endian;
-using namespace lld;
-using namespace lld::elf;
+namespace lld {
+namespace elf {
namespace {
class ScriptParser final : ScriptLexer {
public:
@@ -720,7 +720,7 @@ Expr ScriptParser::readAssert() {
return [=] {
if (!e().getValue())
- error(msg);
+ errorOrWarn(msg);
return script->getDot();
};
}
@@ -1268,7 +1268,7 @@ Expr ScriptParser::readPrimary() {
return [=] { return cmd->size; };
}
if (tok == "SIZEOF_HEADERS")
- return [=] { return elf::getHeaderSize(); };
+ return [=] { return getHeaderSize(); };
// Tok is the dot.
if (tok == ".")
@@ -1344,16 +1344,10 @@ void ScriptParser::readAnonymousDeclaration() {
std::vector<SymbolVersion> locals;
std::vector<SymbolVersion> globals;
std::tie(locals, globals) = readSymbols();
-
- for (SymbolVersion v : locals) {
- if (v.name == "*")
- config->defaultSymbolVersion = VER_NDX_LOCAL;
- else
- config->versionScriptLocals.push_back(v);
- }
-
- for (SymbolVersion v : globals)
- config->versionScriptGlobals.push_back(v);
+ for (const SymbolVersion &pat : locals)
+ config->versionDefinitions[VER_NDX_LOCAL].patterns.push_back(pat);
+ for (const SymbolVersion &pat : globals)
+ config->versionDefinitions[VER_NDX_GLOBAL].patterns.push_back(pat);
expect(";");
}
@@ -1365,22 +1359,14 @@ void ScriptParser::readVersionDeclaration(StringRef verStr) {
std::vector<SymbolVersion> locals;
std::vector<SymbolVersion> globals;
std::tie(locals, globals) = readSymbols();
-
- for (SymbolVersion v : locals) {
- if (v.name == "*")
- config->defaultSymbolVersion = VER_NDX_LOCAL;
- else
- config->versionScriptLocals.push_back(v);
- }
+ for (const SymbolVersion &pat : locals)
+ config->versionDefinitions[VER_NDX_LOCAL].patterns.push_back(pat);
// Create a new version definition and add that to the global symbols.
VersionDefinition ver;
ver.name = verStr;
- ver.globals = globals;
-
- // User-defined version number starts from 2 because 0 and 1 are
- // reserved for VER_NDX_LOCAL and VER_NDX_GLOBAL, respectively.
- ver.id = config->versionDefinitions.size() + 2;
+ ver.patterns = globals;
+ ver.id = config->versionDefinitions.size();
config->versionDefinitions.push_back(ver);
// Each version may have a parent version. For example, "Ver2"
@@ -1525,18 +1511,19 @@ std::pair<uint32_t, uint32_t> ScriptParser::readMemoryAttributes() {
return {flags, negFlags};
}
-void elf::readLinkerScript(MemoryBufferRef mb) {
+void readLinkerScript(MemoryBufferRef mb) {
ScriptParser(mb).readLinkerScript();
}
-void elf::readVersionScript(MemoryBufferRef mb) {
+void readVersionScript(MemoryBufferRef mb) {
ScriptParser(mb).readVersionScript();
}
-void elf::readDynamicList(MemoryBufferRef mb) {
- ScriptParser(mb).readDynamicList();
-}
+void readDynamicList(MemoryBufferRef mb) { ScriptParser(mb).readDynamicList(); }
-void elf::readDefsym(StringRef name, MemoryBufferRef mb) {
+void readDefsym(StringRef name, MemoryBufferRef mb) {
ScriptParser(mb).readDefsym(name);
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/SymbolTable.cpp b/contrib/llvm-project/lld/ELF/SymbolTable.cpp
index 3faeed8c2bdc..5f6008ef908b 100644
--- a/contrib/llvm-project/lld/ELF/SymbolTable.cpp
+++ b/contrib/llvm-project/lld/ELF/SymbolTable.cpp
@@ -27,10 +27,9 @@ using namespace llvm;
using namespace llvm::object;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
-
-SymbolTable *elf::symtab;
+namespace lld {
+namespace elf {
+SymbolTable *symtab;
void SymbolTable::wrap(Symbol *sym, Symbol *real, Symbol *wrap) {
// Swap symbols as instructed by -wrap.
@@ -71,21 +70,26 @@ Symbol *SymbolTable::insert(StringRef name) {
Symbol *sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
symVector.push_back(sym);
+ // *sym was not initialized by a constructor. Fields that may get referenced
+ // when it is a placeholder must be initialized here.
sym->setName(name);
sym->symbolKind = Symbol::PlaceholderKind;
- sym->versionId = config->defaultSymbolVersion;
+ sym->versionId = VER_NDX_GLOBAL;
sym->visibility = STV_DEFAULT;
sym->isUsedInRegularObj = false;
sym->exportDynamic = false;
+ sym->inDynamicList = false;
sym->canInline = true;
+ sym->referenced = false;
+ sym->traced = false;
sym->scriptDefined = false;
sym->partition = 1;
return sym;
}
-Symbol *SymbolTable::addSymbol(const Symbol &New) {
- Symbol *sym = symtab->insert(New.getName());
- sym->resolve(New);
+Symbol *SymbolTable::addSymbol(const Symbol &newSym) {
+ Symbol *sym = symtab->insert(newSym.getName());
+ sym->resolve(newSym);
return sym;
}
@@ -118,10 +122,7 @@ StringMap<std::vector<Symbol *>> &SymbolTable::getDemangledSyms() {
for (Symbol *sym : symVector) {
if (!sym->isDefined() && !sym->isCommon())
continue;
- if (Optional<std::string> s = demangleItanium(sym->getName()))
- (*demangledSyms)[*s].push_back(sym);
- else
- (*demangledSyms)[sym->getName()].push_back(sym);
+ (*demangledSyms)[demangleItanium(sym->getName())].push_back(sym);
}
}
return *demangledSyms;
@@ -162,12 +163,8 @@ void SymbolTable::handleDynamicList() {
else
syms = findByVersion(ver);
- for (Symbol *b : syms) {
- if (!config->shared)
- b->exportDynamic = true;
- else if (b->includeInDynsym())
- b->isPreemptible = true;
- }
+ for (Symbol *sym : syms)
+ sym->inDynamicList = true;
}
}
@@ -192,7 +189,7 @@ void SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId,
return "VER_NDX_LOCAL";
if (ver == VER_NDX_GLOBAL)
return "VER_NDX_GLOBAL";
- return ("version '" + config->versionDefinitions[ver - 2].name + "'").str();
+ return ("version '" + config->versionDefinitions[ver].name + "'").str();
};
// Assign the version.
@@ -203,8 +200,12 @@ void SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId,
if (sym->getName().contains('@'))
continue;
- if (sym->versionId == config->defaultSymbolVersion)
+ // If the version has not been assigned, verdefIndex is -1. Use an arbitrary
+ // number (0) to indicate the version has been assigned.
+ if (sym->verdefIndex == UINT32_C(-1)) {
+ sym->verdefIndex = 0;
sym->versionId = versionId;
+ }
if (sym->versionId == versionId)
continue;
@@ -214,15 +215,14 @@ void SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId,
}
void SymbolTable::assignWildcardVersion(SymbolVersion ver, uint16_t versionId) {
- if (!ver.hasWildcard)
- return;
-
// Exact matching takes precendence over fuzzy matching,
// so we set a version to a symbol only if no version has been assigned
// to the symbol. This behavior is compatible with GNU.
- for (Symbol *b : findAllByVersion(ver))
- if (b->versionId == config->defaultSymbolVersion)
- b->versionId = versionId;
+ for (Symbol *sym : findAllByVersion(ver))
+ if (sym->verdefIndex == UINT32_C(-1)) {
+ sym->verdefIndex = 0;
+ sym->versionId = versionId;
+ }
}
// This function processes version scripts by updating the versionId
@@ -233,26 +233,24 @@ void SymbolTable::assignWildcardVersion(SymbolVersion ver, uint16_t versionId) {
void SymbolTable::scanVersionScript() {
// First, we assign versions to exact matching symbols,
// i.e. version definitions not containing any glob meta-characters.
- for (SymbolVersion &ver : config->versionScriptGlobals)
- assignExactVersion(ver, VER_NDX_GLOBAL, "global");
- for (SymbolVersion &ver : config->versionScriptLocals)
- assignExactVersion(ver, VER_NDX_LOCAL, "local");
for (VersionDefinition &v : config->versionDefinitions)
- for (SymbolVersion &ver : v.globals)
- assignExactVersion(ver, v.id, v.name);
-
- // Next, we assign versions to fuzzy matching symbols,
- // i.e. version definitions containing glob meta-characters.
- for (SymbolVersion &ver : config->versionScriptGlobals)
- assignWildcardVersion(ver, VER_NDX_GLOBAL);
- for (SymbolVersion &ver : config->versionScriptLocals)
- assignWildcardVersion(ver, VER_NDX_LOCAL);
-
- // Note that because the last match takes precedence over previous matches,
- // we iterate over the definitions in the reverse order.
+ for (SymbolVersion &pat : v.patterns)
+ assignExactVersion(pat, v.id, v.name);
+
+ // Next, assign versions to wildcards that are not "*". Note that because the
+ // last match takes precedence over previous matches, we iterate over the
+ // definitions in the reverse order.
for (VersionDefinition &v : llvm::reverse(config->versionDefinitions))
- for (SymbolVersion &ver : v.globals)
- assignWildcardVersion(ver, v.id);
+ for (SymbolVersion &pat : v.patterns)
+ if (pat.hasWildcard && pat.name != "*")
+ assignWildcardVersion(pat, v.id);
+
+ // Then, assign versions to "*". In GNU linkers they have lower priority than
+ // other wildcards.
+ for (VersionDefinition &v : config->versionDefinitions)
+ for (SymbolVersion &pat : v.patterns)
+ if (pat.hasWildcard && pat.name == "*")
+ assignWildcardVersion(pat, v.id);
// Symbol themselves might know their versions because symbols
// can contain versions in the form of <name>@<version>.
@@ -262,7 +260,10 @@ void SymbolTable::scanVersionScript() {
// isPreemptible is false at this point. To correctly compute the binding of a
// Defined (which is used by includeInDynsym()), we need to know if it is
- // VER_NDX_LOCAL or not. If defaultSymbolVersion is VER_NDX_LOCAL, we should
- // compute symbol versions before handling --dynamic-list.
+ // VER_NDX_LOCAL or not. Compute symbol versions before handling
+ // --dynamic-list.
handleDynamicList();
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/SymbolTable.h b/contrib/llvm-project/lld/ELF/SymbolTable.h
index b64707f4ab02..d3be0cb6450f 100644
--- a/contrib/llvm-project/lld/ELF/SymbolTable.h
+++ b/contrib/llvm-project/lld/ELF/SymbolTable.h
@@ -43,7 +43,7 @@ public:
Symbol *insert(StringRef name);
- Symbol *addSymbol(const Symbol &New);
+ Symbol *addSymbol(const Symbol &newSym);
void scanVersionScript();
diff --git a/contrib/llvm-project/lld/ELF/Symbols.cpp b/contrib/llvm-project/lld/ELF/Symbols.cpp
index 22677303c322..c0cba21cfe8d 100644
--- a/contrib/llvm-project/lld/ELF/Symbols.cpp
+++ b/contrib/llvm-project/lld/ELF/Symbols.cpp
@@ -23,9 +23,20 @@ using namespace llvm;
using namespace llvm::object;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
+namespace lld {
+// Returns a symbol for an error message.
+static std::string demangle(StringRef symName) {
+ if (elf::config->demangle)
+ return demangleItanium(symName);
+ return symName;
+}
+
+std::string toString(const elf::Symbol &b) { return demangle(b.getName()); }
+std::string toELFString(const Archive::Symbol &b) {
+ return demangle(b.getName());
+}
+namespace elf {
Defined *ElfSym::bss;
Defined *ElfSym::etext1;
Defined *ElfSym::etext2;
@@ -42,20 +53,6 @@ Defined *ElfSym::relaIpltEnd;
Defined *ElfSym::riscvGlobalPointer;
Defined *ElfSym::tlsModuleBase;
-// Returns a symbol for an error message.
-static std::string demangle(StringRef symName) {
- if (config->demangle)
- if (Optional<std::string> s = demangleItanium(symName))
- return *s;
- return symName;
-}
-namespace lld {
-std::string toString(const Symbol &b) { return demangle(b.getName()); }
-std::string toELFString(const Archive::Symbol &b) {
- return demangle(b.getName());
-}
-} // namespace lld
-
static uint64_t getSymVA(const Symbol &sym, int64_t &addend) {
switch (sym.kind()) {
case Symbol::DefinedKind: {
@@ -227,7 +224,7 @@ void Symbol::parseSymbolVersion() {
if (isDefault)
verstr = verstr.substr(1);
- for (VersionDefinition &ver : config->versionDefinitions) {
+ for (const VersionDefinition &ver : namedVersionDefs()) {
if (ver.name != verstr)
continue;
@@ -276,9 +273,8 @@ MemoryBufferRef LazyArchive::getMemberBuffer() {
uint8_t Symbol::computeBinding() const {
if (config->relocatable)
return binding;
- if (visibility != STV_DEFAULT && visibility != STV_PROTECTED)
- return STB_LOCAL;
- if (versionId == VER_NDX_LOCAL && isDefined() && !isPreemptible)
+ if ((visibility != STV_DEFAULT && visibility != STV_PROTECTED) ||
+ versionId == VER_NDX_LOCAL)
return STB_LOCAL;
if (!config->gnuUnique && binding == STB_GNU_UNIQUE)
return STB_GLOBAL;
@@ -296,11 +292,11 @@ bool Symbol::includeInDynsym() const {
if (isUndefWeak() && config->pie && sharedFiles.empty())
return false;
- return isUndefined() || isShared() || exportDynamic;
+ return isUndefined() || isShared() || exportDynamic || inDynamicList;
}
// Print out a log message for --trace-symbol.
-void elf::printTraceSymbol(const Symbol *sym) {
+void printTraceSymbol(const Symbol *sym) {
std::string s;
if (sym->isUndefined())
s = ": reference to ";
@@ -316,7 +312,7 @@ void elf::printTraceSymbol(const Symbol *sym) {
message(toString(sym->file) + s + sym->getName());
}
-void elf::maybeWarnUnorderableSymbol(const Symbol *sym) {
+void maybeWarnUnorderableSymbol(const Symbol *sym) {
if (!config->warnSymbolOrdering)
return;
@@ -492,17 +488,13 @@ void Symbol::resolveUndefined(const Undefined &other) {
if (dyn_cast_or_null<SharedFile>(other.file))
return;
- if (isUndefined()) {
- // The binding may "upgrade" from weak to non-weak.
- if (other.binding != STB_WEAK)
- binding = other.binding;
- } else if (auto *s = dyn_cast<SharedSymbol>(this)) {
- // The binding of a SharedSymbol will be weak if there is at least one
- // reference and all are weak. The binding has one opportunity to change to
- // weak: if the first reference is weak.
- if (other.binding != STB_WEAK || !s->referenced)
+ if (isUndefined() || isShared()) {
+ // The binding will be weak if there is at least one reference and all are
+ // weak. The binding has one opportunity to change to weak: if the first
+ // reference is weak.
+ if (other.binding != STB_WEAK || !referenced)
binding = other.binding;
- s->referenced = true;
+ referenced = true;
}
}
@@ -560,7 +552,7 @@ int Symbol::compare(const Symbol *other) const {
auto *oldSym = cast<Defined>(this);
auto *newSym = cast<Defined>(other);
- if (other->file && isa<BitcodeFile>(other->file))
+ if (dyn_cast_or_null<BitcodeFile>(other->file))
return 0;
if (!oldSym->section && !newSym->section && oldSym->value == newSym->value &&
@@ -658,6 +650,9 @@ void Symbol::resolveShared(const SharedSymbol &other) {
uint8_t bind = binding;
replace(other);
binding = bind;
- cast<SharedSymbol>(this)->referenced = true;
+ referenced = true;
}
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/Symbols.h b/contrib/llvm-project/lld/ELF/Symbols.h
index d20d06eec4ce..d43568fe295c 100644
--- a/contrib/llvm-project/lld/ELF/Symbols.h
+++ b/contrib/llvm-project/lld/ELF/Symbols.h
@@ -21,6 +21,13 @@
#include "llvm/Object/ELF.h"
namespace lld {
+std::string toString(const elf::Symbol &);
+
+// There are two different ways to convert an Archive::Symbol to a string:
+// One for Microsoft name mangling and one for Itanium name mangling.
+// Call the functions toCOFFString and toELFString, not just toString.
+std::string toELFString(const llvm::object::Archive::Symbol &);
+
namespace elf {
class CommonSymbol;
class Defined;
@@ -30,16 +37,6 @@ class LazyObject;
class SharedSymbol;
class Symbol;
class Undefined;
-} // namespace elf
-
-std::string toString(const elf::Symbol &);
-
-// There are two different ways to convert an Archive::Symbol to a string:
-// One for Microsoft name mangling and one for Itanium name mangling.
-// Call the functions toCOFFString and toELFString, not just toString.
-std::string toELFString(const elf::Archive::Symbol &);
-
-namespace elf {
// This is a StringRef-like container that doesn't run strlen().
//
@@ -108,29 +105,43 @@ public:
// Symbol visibility. This is the computed minimum visibility of all
// observed non-DSO symbols.
- uint8_t visibility : 2;
+ unsigned visibility : 2;
// True if the symbol was used for linking and thus need to be added to the
// output file's symbol table. This is true for all symbols except for
// unreferenced DSO symbols, lazy (archive) symbols, and bitcode symbols that
// are unreferenced except by other bitcode objects.
- uint8_t isUsedInRegularObj : 1;
+ unsigned isUsedInRegularObj : 1;
- // If this flag is true and the symbol has protected or default visibility, it
- // will appear in .dynsym. This flag is set by interposable DSO symbols in
- // executables, by most symbols in DSOs and executables built with
- // --export-dynamic, and by dynamic lists.
- uint8_t exportDynamic : 1;
+ // Used by a Defined symbol with protected or default visibility, to record
+ // whether it is required to be exported into .dynsym. This is set when any of
+ // the following conditions hold:
+ //
+ // - If there is an interposable symbol from a DSO.
+ // - If -shared or --export-dynamic is specified, any symbol in an object
+ // file/bitcode sets this property, unless suppressed by LTO
+ // canBeOmittedFromSymbolTable().
+ unsigned exportDynamic : 1;
+
+ // True if the symbol is in the --dynamic-list file. A Defined symbol with
+ // protected or default visibility with this property is required to be
+ // exported into .dynsym.
+ unsigned inDynamicList : 1;
// False if LTO shouldn't inline whatever this symbol points to. If a symbol
// is overwritten after LTO, LTO shouldn't inline the symbol because it
// doesn't know the final contents of the symbol.
- uint8_t canInline : 1;
+ unsigned canInline : 1;
+
+ // Used by Undefined and SharedSymbol to track if there has been at least one
+ // undefined reference to the symbol. The binding may change to STB_WEAK if
+ // the first undefined reference from a non-shared object is weak.
+ unsigned referenced : 1;
// True if this symbol is specified by --trace-symbol option.
- uint8_t traced : 1;
+ unsigned traced : 1;
- inline void replace(const Symbol &New);
+ inline void replace(const Symbol &newSym);
bool includeInDynsym() const;
uint8_t computeBinding() const;
@@ -228,36 +239,37 @@ protected:
: file(file), nameData(name.data), nameSize(name.size), binding(binding),
type(type), stOther(stOther), symbolKind(k), visibility(stOther & 3),
isUsedInRegularObj(!file || file->kind() == InputFile::ObjKind),
- exportDynamic(isExportDynamic(k, visibility)), canInline(false),
- traced(false), needsPltAddr(false), isInIplt(false), gotInIgot(false),
- isPreemptible(false), used(!config->gcSections), needsTocRestore(false),
+ exportDynamic(isExportDynamic(k, visibility)), inDynamicList(false),
+ canInline(false), referenced(false), traced(false), needsPltAddr(false),
+ isInIplt(false), gotInIgot(false), isPreemptible(false),
+ used(!config->gcSections), needsTocRestore(false),
scriptDefined(false) {}
public:
// True the symbol should point to its PLT entry.
// For SharedSymbol only.
- uint8_t needsPltAddr : 1;
+ unsigned needsPltAddr : 1;
// True if this symbol is in the Iplt sub-section of the Plt and the Igot
// sub-section of the .got.plt or .got.
- uint8_t isInIplt : 1;
+ unsigned isInIplt : 1;
// True if this symbol needs a GOT entry and its GOT entry is actually in
// Igot. This will be true only for certain non-preemptible ifuncs.
- uint8_t gotInIgot : 1;
+ unsigned gotInIgot : 1;
// True if this symbol is preemptible at load time.
- uint8_t isPreemptible : 1;
+ unsigned isPreemptible : 1;
// True if an undefined or shared symbol is used from a live section.
- uint8_t used : 1;
+ unsigned used : 1;
// True if a call to this symbol needs to be followed by a restore of the
// PPC64 toc pointer.
- uint8_t needsTocRestore : 1;
+ unsigned needsTocRestore : 1;
// True if this symbol is defined by a linker script.
- uint8_t scriptDefined : 1;
+ unsigned scriptDefined : 1;
// The partition whose dynamic symbol table contains this symbol's definition.
uint8_t partition = 1;
@@ -367,11 +379,6 @@ public:
uint64_t value; // st_value
uint64_t size; // st_size
uint32_t alignment;
-
- // This is true if there has been at least one undefined reference to the
- // symbol. The binding may change to STB_WEAK if the first undefined reference
- // is weak.
- bool referenced = false;
};
// LazyArchive and LazyObject represent a symbols that is not yet in the link,
@@ -511,7 +518,7 @@ size_t Symbol::getSymbolSize() const {
// replace() replaces "this" object with a given symbol by memcpy'ing
// it over to "this". This function is called as a result of name
// resolution, e.g. to replace an undefind symbol with a defined symbol.
-void Symbol::replace(const Symbol &New) {
+void Symbol::replace(const Symbol &newSym) {
using llvm::ELF::STT_TLS;
// Symbols representing thread-local variables must be referenced by
@@ -519,22 +526,23 @@ void Symbol::replace(const Symbol &New) {
// non-TLS relocations, so there's a clear distinction between TLS
// and non-TLS symbols. It is an error if the same symbol is defined
// as a TLS symbol in one file and as a non-TLS symbol in other file.
- if (symbolKind != PlaceholderKind && !isLazy() && !New.isLazy()) {
- bool tlsMismatch = (type == STT_TLS && New.type != STT_TLS) ||
- (type != STT_TLS && New.type == STT_TLS);
- if (tlsMismatch)
- error("TLS attribute mismatch: " + toString(*this) + "\n>>> defined in " +
- toString(New.file) + "\n>>> defined in " + toString(file));
- }
+ if (symbolKind != PlaceholderKind && !isLazy() && !newSym.isLazy() &&
+ (type == STT_TLS) != (newSym.type == STT_TLS))
+ error("TLS attribute mismatch: " + toString(*this) + "\n>>> defined in " +
+ toString(newSym.file) + "\n>>> defined in " + toString(file));
Symbol old = *this;
- memcpy(this, &New, New.getSymbolSize());
+ memcpy(this, &newSym, newSym.getSymbolSize());
+ // old may be a placeholder. The referenced fields must be initialized in
+ // SymbolTable::insert.
versionId = old.versionId;
visibility = old.visibility;
isUsedInRegularObj = old.isUsedInRegularObj;
exportDynamic = old.exportDynamic;
+ inDynamicList = old.inDynamicList;
canInline = old.canInline;
+ referenced = old.referenced;
traced = old.traced;
isPreemptible = old.isPreemptible;
scriptDefined = old.scriptDefined;
diff --git a/contrib/llvm-project/lld/ELF/SyntheticSections.cpp b/contrib/llvm-project/lld/ELF/SyntheticSections.cpp
index 35b9b8928c9f..ff35bb7bd10c 100644
--- a/contrib/llvm-project/lld/ELF/SyntheticSections.cpp
+++ b/contrib/llvm-project/lld/ELF/SyntheticSections.cpp
@@ -45,13 +45,12 @@ using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::support;
-using namespace lld;
-using namespace lld::elf;
-
using llvm::support::endian::read32le;
using llvm::support::endian::write32le;
using llvm::support::endian::write64le;
+namespace lld {
+namespace elf {
constexpr size_t MergeNoTailSection::numShards;
static uint64_t readUint(uint8_t *buf) {
@@ -82,7 +81,7 @@ static ArrayRef<uint8_t> getVersion() {
// With this feature, you can identify LLD-generated binaries easily
// by "readelf --string-dump .comment <file>".
// The returned object is a mergeable string section.
-MergeInputSection *elf::createCommentSection() {
+MergeInputSection *createCommentSection() {
return make<MergeInputSection>(SHF_MERGE | SHF_STRINGS, SHT_PROGBITS, 1,
getVersion(), ".comment");
}
@@ -138,7 +137,7 @@ MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() {
flags.ases |= s->ases;
flags.flags1 |= s->flags1;
flags.flags2 |= s->flags2;
- flags.fp_abi = elf::getMipsFpAbiFlag(flags.fp_abi, s->fp_abi, filename);
+ flags.fp_abi = getMipsFpAbiFlag(flags.fp_abi, s->fp_abi, filename);
};
if (create)
@@ -252,19 +251,17 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() {
return make<MipsReginfoSection<ELFT>>(reginfo);
}
-InputSection *elf::createInterpSection() {
+InputSection *createInterpSection() {
// StringSaver guarantees that the returned string ends with '\0'.
StringRef s = saver.save(config->dynamicLinker);
ArrayRef<uint8_t> contents = {(const uint8_t *)s.data(), s.size() + 1};
- auto *sec = make<InputSection>(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, contents,
- ".interp");
- sec->markLive();
- return sec;
+ return make<InputSection>(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, contents,
+ ".interp");
}
-Defined *elf::addSyntheticLocal(StringRef name, uint8_t type, uint64_t value,
- uint64_t size, InputSectionBase &section) {
+Defined *addSyntheticLocal(StringRef name, uint8_t type, uint64_t value,
+ uint64_t size, InputSectionBase &section) {
auto *s = make<Defined>(section.file, name, STB_LOCAL, STV_DEFAULT, type,
value, size, &section);
if (in.symTab)
@@ -402,7 +399,7 @@ bool EhFrameSection::isFdeLive(EhSectionPiece &fde, ArrayRef<RelTy> rels) {
// a list of FDEs. This function searches an existing CIE or create a new
// one and associates FDEs to the CIE.
template <class ELFT, class RelTy>
-void EhFrameSection::addSectionAux(EhInputSection *sec, ArrayRef<RelTy> rels) {
+void EhFrameSection::addRecords(EhInputSection *sec, ArrayRef<RelTy> rels) {
offsetToCie.clear();
for (EhSectionPiece &piece : sec->pieces) {
// The empty record is the end marker.
@@ -428,8 +425,17 @@ void EhFrameSection::addSectionAux(EhInputSection *sec, ArrayRef<RelTy> rels) {
}
}
-template <class ELFT> void EhFrameSection::addSection(InputSectionBase *c) {
- auto *sec = cast<EhInputSection>(c);
+template <class ELFT>
+void EhFrameSection::addSectionAux(EhInputSection *sec) {
+ if (!sec->isLive())
+ return;
+ if (sec->areRelocsRela)
+ addRecords<ELFT>(sec, sec->template relas<ELFT>());
+ else
+ addRecords<ELFT>(sec, sec->template rels<ELFT>());
+}
+
+void EhFrameSection::addSection(EhInputSection *sec) {
sec->parent = this;
alignment = std::max(alignment, sec->alignment);
@@ -437,14 +443,6 @@ template <class ELFT> void EhFrameSection::addSection(InputSectionBase *c) {
for (auto *ds : sec->dependentSections)
dependentSections.push_back(ds);
-
- if (sec->pieces.empty())
- return;
-
- if (sec->areRelocsRela)
- addSectionAux<ELFT>(sec, sec->template relas<ELFT>());
- else
- addSectionAux<ELFT>(sec, sec->template rels<ELFT>());
}
static void writeCieFde(uint8_t *buf, ArrayRef<uint8_t> d) {
@@ -461,6 +459,28 @@ static void writeCieFde(uint8_t *buf, ArrayRef<uint8_t> d) {
void EhFrameSection::finalizeContents() {
assert(!this->size); // Not finalized.
+
+ switch (config->ekind) {
+ case ELFNoneKind:
+ llvm_unreachable("invalid ekind");
+ case ELF32LEKind:
+ for (EhInputSection *sec : sections)
+ addSectionAux<ELF32LE>(sec);
+ break;
+ case ELF32BEKind:
+ for (EhInputSection *sec : sections)
+ addSectionAux<ELF32BE>(sec);
+ break;
+ case ELF64LEKind:
+ for (EhInputSection *sec : sections)
+ addSectionAux<ELF64LE>(sec);
+ break;
+ case ELF64BEKind:
+ for (EhInputSection *sec : sections)
+ addSectionAux<ELF64BE>(sec);
+ break;
+ }
+
size_t off = 0;
for (CieRecord *rec : cieRecords) {
rec->cie->outputOff = off;
@@ -1162,10 +1182,12 @@ void StringTableSection::writeTo(uint8_t *buf) {
}
}
-// Returns the number of version definition entries. Because the first entry
-// is for the version definition itself, it is the number of versioned symbols
-// plus one. Note that we don't support multiple versions yet.
-static unsigned getVerDefNum() { return config->versionDefinitions.size() + 1; }
+// Returns the number of entries in .gnu.version_d: the number of
+// non-VER_NDX_LOCAL-non-VER_NDX_GLOBAL definitions, plus 1.
+// Note that we don't support vd_cnt > 1 yet.
+static unsigned getVerDefNum() {
+ return namedVersionDefs().size() + 1;
+}
template <class ELFT>
DynamicSection<ELFT>::DynamicSection()
@@ -1218,6 +1240,25 @@ void DynamicSection<ELFT>::addSym(int32_t tag, Symbol *sym) {
entries.push_back({tag, [=] { return sym->getVA(); }});
}
+// The output section .rela.dyn may include these synthetic sections:
+//
+// - part.relaDyn
+// - in.relaIplt: this is included if in.relaIplt is named .rela.dyn
+// - in.relaPlt: this is included if a linker script places .rela.plt inside
+// .rela.dyn
+//
+// DT_RELASZ is the total size of the included sections.
+static std::function<uint64_t()> addRelaSz(RelocationBaseSection *relaDyn) {
+ return [=]() {
+ size_t size = relaDyn->getSize();
+ if (in.relaIplt->getParent() == relaDyn->getParent())
+ size += in.relaIplt->getSize();
+ if (in.relaPlt->getParent() == relaDyn->getParent())
+ size += in.relaPlt->getSize();
+ return size;
+ };
+}
+
// A Linker script may assign the RELA relocation sections to the same
// output section. When this occurs we cannot just use the OutputSection
// Size. Moreover the [DT_JMPREL, DT_JMPREL + DT_PLTRELSZ) is permitted to
@@ -1232,7 +1273,7 @@ static uint64_t addPltRelSz() {
// Add remaining entries to complete .dynamic contents.
template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
- elf::Partition &part = getPartition();
+ Partition &part = getPartition();
bool isMain = part.name.empty();
for (StringRef s : config->filterList)
@@ -1306,9 +1347,11 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
if (OutputSection *sec = part.dynStrTab->getParent())
this->link = sec->sectionIndex;
- if (part.relaDyn->isNeeded()) {
+ if (part.relaDyn->isNeeded() ||
+ (in.relaIplt->isNeeded() &&
+ part.relaDyn->getParent() == in.relaIplt->getParent())) {
addInSec(part.relaDyn->dynamicTag, part.relaDyn);
- addSize(part.relaDyn->sizeDynamicTag, part.relaDyn->getParent());
+ entries.push_back({part.relaDyn->sizeDynamicTag, addRelaSz(part.relaDyn)});
bool isRela = config->isRela;
addInt(isRela ? DT_RELAENT : DT_RELENT,
@@ -1679,6 +1722,56 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
relativeGroups.emplace_back(std::move(group));
}
+ // For non-relative relocations, we would like to:
+ // 1. Have relocations with the same symbol offset to be consecutive, so
+ // that the runtime linker can speed-up symbol lookup by implementing an
+ // 1-entry cache.
+ // 2. Group relocations by r_info to reduce the size of the relocation
+ // section.
+ // Since the symbol offset is the high bits in r_info, sorting by r_info
+ // allows us to do both.
+ //
+ // For Rela, we also want to sort by r_addend when r_info is the same. This
+ // enables us to group by r_addend as well.
+ llvm::stable_sort(nonRelatives, [](const Elf_Rela &a, const Elf_Rela &b) {
+ if (a.r_info != b.r_info)
+ return a.r_info < b.r_info;
+ if (config->isRela)
+ return a.r_addend < b.r_addend;
+ return false;
+ });
+
+ // Group relocations with the same r_info. Note that each group emits a group
+ // header and that may make the relocation section larger. It is hard to
+ // estimate the size of a group header as the encoded size of that varies
+ // based on r_info. However, we can approximate this trade-off by the number
+ // of values encoded. Each group header contains 3 values, and each relocation
+ // in a group encodes one less value, as compared to when it is not grouped.
+ // Therefore, we only group relocations if there are 3 or more of them with
+ // the same r_info.
+ //
+ // For Rela, the addend for most non-relative relocations is zero, and thus we
+ // can usually get a smaller relocation section if we group relocations with 0
+ // addend as well.
+ std::vector<Elf_Rela> ungroupedNonRelatives;
+ std::vector<std::vector<Elf_Rela>> nonRelativeGroups;
+ for (auto i = nonRelatives.begin(), e = nonRelatives.end(); i != e;) {
+ auto j = i + 1;
+ while (j != e && i->r_info == j->r_info &&
+ (!config->isRela || i->r_addend == j->r_addend))
+ ++j;
+ if (j - i < 3 || (config->isRela && i->r_addend != 0))
+ ungroupedNonRelatives.insert(ungroupedNonRelatives.end(), i, j);
+ else
+ nonRelativeGroups.emplace_back(i, j);
+ i = j;
+ }
+
+ // Sort ungrouped relocations by offset to minimize the encoded length.
+ llvm::sort(ungroupedNonRelatives, [](const Elf_Rela &a, const Elf_Rela &b) {
+ return a.r_offset < b.r_offset;
+ });
+
unsigned hasAddendIfRela =
config->isRela ? RELOCATION_GROUP_HAS_ADDEND_FLAG : 0;
@@ -1733,14 +1826,23 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
}
}
- // Finally the non-relative relocations.
- llvm::sort(nonRelatives, [](const Elf_Rela &a, const Elf_Rela &b) {
- return a.r_offset < b.r_offset;
- });
- if (!nonRelatives.empty()) {
- add(nonRelatives.size());
+ // Grouped non-relatives.
+ for (ArrayRef<Elf_Rela> g : nonRelativeGroups) {
+ add(g.size());
+ add(RELOCATION_GROUPED_BY_INFO_FLAG);
+ add(g[0].r_info);
+ for (const Elf_Rela &r : g) {
+ add(r.r_offset - offset);
+ offset = r.r_offset;
+ }
+ addend = 0;
+ }
+
+ // Finally the ungrouped non-relative relocations.
+ if (!ungroupedNonRelatives.empty()) {
+ add(ungroupedNonRelatives.size());
add(hasAddendIfRela);
- for (Elf_Rela &r : nonRelatives) {
+ for (Elf_Rela &r : ungroupedNonRelatives) {
add(r.r_offset - offset);
offset = r.r_offset;
add(r.r_info);
@@ -1852,6 +1954,14 @@ template <class ELFT> bool RelrSection<ELFT>::updateAllocSize() {
}
}
+ // Don't allow the section to shrink; otherwise the size of the section can
+ // oscillate infinitely. Trailing 1s do not decode to more relocations.
+ if (relrRelocs.size() < oldSize) {
+ log(".relr.dyn needs " + Twine(oldSize - relrRelocs.size()) +
+ " padding word(s)");
+ relrRelocs.resize(oldSize, Elf_Relr(1));
+ }
+
return relrRelocs.size() != oldSize;
}
@@ -2452,6 +2562,10 @@ readAddressAreas(DWARFContext &dwarf, InputSection *sec) {
uint32_t cuIdx = 0;
for (std::unique_ptr<DWARFUnit> &cu : dwarf.compile_units()) {
+ if (Error e = cu->tryExtractDIEsIfNeeded(false)) {
+ error(toString(sec) + ": " + toString(std::move(e)));
+ return {};
+ }
Expected<DWARFAddressRangesVector> ranges = cu->collectAddressRanges();
if (!ranges) {
error(toString(sec) + ": " + toString(ranges.takeError()));
@@ -2481,9 +2595,9 @@ readAddressAreas(DWARFContext &dwarf, InputSection *sec) {
template <class ELFT>
static std::vector<GdbIndexSection::NameAttrEntry>
readPubNamesAndTypes(const LLDDwarfObj<ELFT> &obj,
- const std::vector<GdbIndexSection::CuEntry> &cUs) {
- const DWARFSection &pubNames = obj.getGnuPubNamesSection();
- const DWARFSection &pubTypes = obj.getGnuPubTypesSection();
+ const std::vector<GdbIndexSection::CuEntry> &cus) {
+ const DWARFSection &pubNames = obj.getGnuPubnamesSection();
+ const DWARFSection &pubTypes = obj.getGnuPubtypesSection();
std::vector<GdbIndexSection::NameAttrEntry> ret;
for (const DWARFSection *pub : {&pubNames, &pubTypes}) {
@@ -2493,12 +2607,11 @@ readPubNamesAndTypes(const LLDDwarfObj<ELFT> &obj,
// don't know how many compilation units precede this object to compute
// cuIndex, we compute (kind << 24 | cuIndexInThisObject) instead, and add
// the number of preceding compilation units later.
- uint32_t i =
- lower_bound(cUs, set.Offset,
- [](GdbIndexSection::CuEntry cu, uint32_t offset) {
- return cu.cuOffset < offset;
- }) -
- cUs.begin();
+ uint32_t i = llvm::partition_point(cus,
+ [&](GdbIndexSection::CuEntry cu) {
+ return cu.cuOffset < set.Offset;
+ }) -
+ cus.begin();
for (const DWARFDebugPubTable::Entry &ent : set.Entries)
ret.push_back({{ent.Name, computeGdbHash(ent.Name)},
(ent.Descriptor.toBits() << 24) | i});
@@ -2603,7 +2716,7 @@ template <class ELFT> GdbIndexSection *GdbIndexSection::create() {
parallelForEachN(0, sections.size(), [&](size_t i) {
ObjFile<ELFT> *file = sections[i]->getFile<ELFT>();
- DWARFContext dwarf(make_unique<LLDDwarfObj<ELFT>>(file));
+ DWARFContext dwarf(std::make_unique<LLDDwarfObj<ELFT>>(file));
chunks[i].sec = sections[i];
chunks[i].compilationUnits = readCuList(dwarf);
@@ -2750,7 +2863,7 @@ StringRef VersionDefinitionSection::getFileDefName() {
void VersionDefinitionSection::finalizeContents() {
fileDefNameOff = getPartition().dynStrTab->addString(getFileDefName());
- for (VersionDefinition &v : config->versionDefinitions)
+ for (const VersionDefinition &v : namedVersionDefs())
verDefNameOffs.push_back(getPartition().dynStrTab->addString(v.name));
if (OutputSection *sec = getPartition().dynStrTab->getParent())
@@ -2784,7 +2897,7 @@ void VersionDefinitionSection::writeTo(uint8_t *buf) {
writeOne(buf, 1, getFileDefName(), fileDefNameOff);
auto nameOffIt = verDefNameOffs.begin();
- for (VersionDefinition &v : config->versionDefinitions) {
+ for (const VersionDefinition &v : namedVersionDefs()) {
buf += EntrySize;
writeOne(buf, v.id, v.name, *nameOffIt++);
}
@@ -2826,7 +2939,7 @@ bool VersionTableSection::isNeeded() const {
return getPartition().verDef || getPartition().verNeed->isNeeded();
}
-void elf::addVerneed(Symbol *ss) {
+void addVerneed(Symbol *ss) {
auto &file = cast<SharedFile>(*ss->file);
if (ss->verdefIndex == VER_NDX_GLOBAL) {
ss->versionId = VER_NDX_GLOBAL;
@@ -3009,17 +3122,16 @@ void MergeNoTailSection::finalizeContents() {
});
}
-static MergeSyntheticSection *createMergeSynthetic(StringRef name,
- uint32_t type,
- uint64_t flags,
- uint32_t alignment) {
+MergeSyntheticSection *createMergeSynthetic(StringRef name, uint32_t type,
+ uint64_t flags,
+ uint32_t alignment) {
bool shouldTailMerge = (flags & SHF_STRINGS) && config->optimize >= 2;
if (shouldTailMerge)
return make<MergeTailSection>(name, type, flags, alignment);
return make<MergeNoTailSection>(name, type, flags, alignment);
}
-template <class ELFT> void elf::splitSections() {
+template <class ELFT> void splitSections() {
// splitIntoPieces needs to be called on each MergeInputSection
// before calling finalizeContents().
parallelForEach(inputSections, [](InputSectionBase *sec) {
@@ -3030,63 +3142,6 @@ template <class ELFT> void elf::splitSections() {
});
}
-// This function scans over the inputsections to create mergeable
-// synthetic sections.
-//
-// It removes MergeInputSections from the input section array and adds
-// new synthetic sections at the location of the first input section
-// that it replaces. It then finalizes each synthetic section in order
-// to compute an output offset for each piece of each input section.
-void elf::mergeSections() {
- std::vector<MergeSyntheticSection *> mergeSections;
- for (InputSectionBase *&s : inputSections) {
- MergeInputSection *ms = dyn_cast<MergeInputSection>(s);
- if (!ms)
- continue;
-
- // We do not want to handle sections that are not alive, so just remove
- // them instead of trying to merge.
- if (!ms->isLive()) {
- s = nullptr;
- continue;
- }
-
- StringRef outsecName = getOutputSectionName(ms);
-
- auto i = llvm::find_if(mergeSections, [=](MergeSyntheticSection *sec) {
- // While we could create a single synthetic section for two different
- // values of Entsize, it is better to take Entsize into consideration.
- //
- // With a single synthetic section no two pieces with different Entsize
- // could be equal, so we may as well have two sections.
- //
- // Using Entsize in here also allows us to propagate it to the synthetic
- // section.
- //
- // SHF_STRINGS section with different alignments should not be merged.
- return sec->name == outsecName && sec->flags == ms->flags &&
- sec->entsize == ms->entsize &&
- (sec->alignment == ms->alignment || !(sec->flags & SHF_STRINGS));
- });
- if (i == mergeSections.end()) {
- MergeSyntheticSection *syn =
- createMergeSynthetic(outsecName, ms->type, ms->flags, ms->alignment);
- mergeSections.push_back(syn);
- i = std::prev(mergeSections.end());
- s = syn;
- syn->entsize = ms->entsize;
- } else {
- s = nullptr;
- }
- (*i)->addSection(ms);
- }
- for (auto *ms : mergeSections)
- ms->finalizeContents();
-
- std::vector<InputSectionBase *> &v = inputSections;
- v.erase(std::remove(v.begin(), v.end(), nullptr), v.end());
-}
-
MipsRldMapSection::MipsRldMapSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, config->wordsize,
".rld_map") {}
@@ -3102,17 +3157,23 @@ static InputSection *findExidxSection(InputSection *isec) {
return nullptr;
}
+static bool isValidExidxSectionDep(InputSection *isec) {
+ return (isec->flags & SHF_ALLOC) && (isec->flags & SHF_EXECINSTR) &&
+ isec->getSize() > 0;
+}
+
bool ARMExidxSyntheticSection::addSection(InputSection *isec) {
if (isec->type == SHT_ARM_EXIDX) {
- exidxSections.push_back(isec);
- return true;
+ if (InputSection* dep = isec->getLinkOrderDep())
+ if (isValidExidxSectionDep(dep)) {
+ exidxSections.push_back(isec);
+ return true;
+ }
+ return false;
}
- if ((isec->flags & SHF_ALLOC) && (isec->flags & SHF_EXECINSTR) &&
- isec->getSize() > 0) {
+ if (isValidExidxSectionDep(isec)) {
executableSections.push_back(isec);
- if (empty && findExidxSection(isec))
- empty = false;
return false;
}
@@ -3182,17 +3243,14 @@ static bool isDuplicateArmExidxSec(InputSection *prev, InputSection *cur) {
// with the highest address and any InputSections that have mergeable
// .ARM.exidx table entries are removed from it.
void ARMExidxSyntheticSection::finalizeContents() {
- if (script->hasSectionsCommand) {
- // The executableSections and exidxSections that we use to derive the
- // final contents of this SyntheticSection are populated before the
- // linker script assigns InputSections to OutputSections. The linker script
- // SECTIONS command may have a /DISCARD/ entry that removes executable
- // InputSections and their dependent .ARM.exidx section that we recorded
- // earlier.
- auto isDiscarded = [](const InputSection *isec) { return !isec->isLive(); };
- llvm::erase_if(executableSections, isDiscarded);
- llvm::erase_if(exidxSections, isDiscarded);
- }
+ // The executableSections and exidxSections that we use to derive the final
+ // contents of this SyntheticSection are populated before
+ // processSectionCommands() and ICF. A /DISCARD/ entry in SECTIONS command or
+ // ICF may remove executable InputSections and their dependent .ARM.exidx
+ // section that we recorded earlier.
+ auto isDiscarded = [](const InputSection *isec) { return !isec->isLive(); };
+ llvm::erase_if(executableSections, isDiscarded);
+ llvm::erase_if(exidxSections, isDiscarded);
// Sort the executable sections that may or may not have associated
// .ARM.exidx sections by order of ascending address. This requires the
@@ -3282,6 +3340,12 @@ void ARMExidxSyntheticSection::writeTo(uint8_t *buf) {
assert(size == offset + 8);
}
+bool ARMExidxSyntheticSection::isNeeded() const {
+ return llvm::find_if(exidxSections, [](InputSection *isec) {
+ return isec->isLive();
+ }) != exidxSections.end();
+}
+
bool ARMExidxSyntheticSection::classof(const SectionBase *d) {
return d->kind() == InputSectionBase::Synthetic && d->type == SHT_ARM_EXIDX;
}
@@ -3401,23 +3465,6 @@ bool PPC64LongBranchTargetSection::isNeeded() const {
return !finalized || !entries.empty();
}
-RISCVSdataSection::RISCVSdataSection()
- : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 1, ".sdata") {}
-
-bool RISCVSdataSection::isNeeded() const {
- if (!ElfSym::riscvGlobalPointer)
- return false;
-
- // __global_pointer$ is defined relative to .sdata . If the section does not
- // exist, create a dummy one.
- for (BaseCommand *base : getParent()->sectionCommands)
- if (auto *isd = dyn_cast<InputSectionDescription>(base))
- for (InputSection *isec : isd->sections)
- if (isec != this)
- return false;
- return true;
-}
-
static uint8_t getAbiVersion() {
// MIPS non-PIC executable gets ABI version 1.
if (config->emachine == EM_MIPS) {
@@ -3438,7 +3485,7 @@ static uint8_t getAbiVersion() {
return 0;
}
-template <typename ELFT> void elf::writeEhdr(uint8_t *buf, Partition &part) {
+template <typename ELFT> void writeEhdr(uint8_t *buf, Partition &part) {
// For executable segments, the trap instructions are written before writing
// the header. Setting Elf header bytes to zero ensures that any unused bytes
// in header are zero-cleared, instead of having trap instructions.
@@ -3464,7 +3511,7 @@ template <typename ELFT> void elf::writeEhdr(uint8_t *buf, Partition &part) {
}
}
-template <typename ELFT> void elf::writePhdrs(uint8_t *buf, Partition &part) {
+template <typename ELFT> void writePhdrs(uint8_t *buf, Partition &part) {
// Write the program header table.
auto *hBuf = reinterpret_cast<typename ELFT::Phdr *>(buf);
for (PhdrEntry *p : part.phdrs) {
@@ -3539,92 +3586,90 @@ void PartitionIndexSection::writeTo(uint8_t *buf) {
}
}
-InStruct elf::in;
+InStruct in;
-std::vector<Partition> elf::partitions;
-Partition *elf::mainPart;
+std::vector<Partition> partitions;
+Partition *mainPart;
template GdbIndexSection *GdbIndexSection::create<ELF32LE>();
template GdbIndexSection *GdbIndexSection::create<ELF32BE>();
template GdbIndexSection *GdbIndexSection::create<ELF64LE>();
template GdbIndexSection *GdbIndexSection::create<ELF64BE>();
-template void elf::splitSections<ELF32LE>();
-template void elf::splitSections<ELF32BE>();
-template void elf::splitSections<ELF64LE>();
-template void elf::splitSections<ELF64BE>();
-
-template void EhFrameSection::addSection<ELF32LE>(InputSectionBase *);
-template void EhFrameSection::addSection<ELF32BE>(InputSectionBase *);
-template void EhFrameSection::addSection<ELF64LE>(InputSectionBase *);
-template void EhFrameSection::addSection<ELF64BE>(InputSectionBase *);
+template void splitSections<ELF32LE>();
+template void splitSections<ELF32BE>();
+template void splitSections<ELF64LE>();
+template void splitSections<ELF64BE>();
template void PltSection::addEntry<ELF32LE>(Symbol &Sym);
template void PltSection::addEntry<ELF32BE>(Symbol &Sym);
template void PltSection::addEntry<ELF64LE>(Symbol &Sym);
template void PltSection::addEntry<ELF64BE>(Symbol &Sym);
-template class elf::MipsAbiFlagsSection<ELF32LE>;
-template class elf::MipsAbiFlagsSection<ELF32BE>;
-template class elf::MipsAbiFlagsSection<ELF64LE>;
-template class elf::MipsAbiFlagsSection<ELF64BE>;
-
-template class elf::MipsOptionsSection<ELF32LE>;
-template class elf::MipsOptionsSection<ELF32BE>;
-template class elf::MipsOptionsSection<ELF64LE>;
-template class elf::MipsOptionsSection<ELF64BE>;
-
-template class elf::MipsReginfoSection<ELF32LE>;
-template class elf::MipsReginfoSection<ELF32BE>;
-template class elf::MipsReginfoSection<ELF64LE>;
-template class elf::MipsReginfoSection<ELF64BE>;
-
-template class elf::DynamicSection<ELF32LE>;
-template class elf::DynamicSection<ELF32BE>;
-template class elf::DynamicSection<ELF64LE>;
-template class elf::DynamicSection<ELF64BE>;
-
-template class elf::RelocationSection<ELF32LE>;
-template class elf::RelocationSection<ELF32BE>;
-template class elf::RelocationSection<ELF64LE>;
-template class elf::RelocationSection<ELF64BE>;
-
-template class elf::AndroidPackedRelocationSection<ELF32LE>;
-template class elf::AndroidPackedRelocationSection<ELF32BE>;
-template class elf::AndroidPackedRelocationSection<ELF64LE>;
-template class elf::AndroidPackedRelocationSection<ELF64BE>;
-
-template class elf::RelrSection<ELF32LE>;
-template class elf::RelrSection<ELF32BE>;
-template class elf::RelrSection<ELF64LE>;
-template class elf::RelrSection<ELF64BE>;
-
-template class elf::SymbolTableSection<ELF32LE>;
-template class elf::SymbolTableSection<ELF32BE>;
-template class elf::SymbolTableSection<ELF64LE>;
-template class elf::SymbolTableSection<ELF64BE>;
-
-template class elf::VersionNeedSection<ELF32LE>;
-template class elf::VersionNeedSection<ELF32BE>;
-template class elf::VersionNeedSection<ELF64LE>;
-template class elf::VersionNeedSection<ELF64BE>;
-
-template void elf::writeEhdr<ELF32LE>(uint8_t *Buf, Partition &Part);
-template void elf::writeEhdr<ELF32BE>(uint8_t *Buf, Partition &Part);
-template void elf::writeEhdr<ELF64LE>(uint8_t *Buf, Partition &Part);
-template void elf::writeEhdr<ELF64BE>(uint8_t *Buf, Partition &Part);
-
-template void elf::writePhdrs<ELF32LE>(uint8_t *Buf, Partition &Part);
-template void elf::writePhdrs<ELF32BE>(uint8_t *Buf, Partition &Part);
-template void elf::writePhdrs<ELF64LE>(uint8_t *Buf, Partition &Part);
-template void elf::writePhdrs<ELF64BE>(uint8_t *Buf, Partition &Part);
-
-template class elf::PartitionElfHeaderSection<ELF32LE>;
-template class elf::PartitionElfHeaderSection<ELF32BE>;
-template class elf::PartitionElfHeaderSection<ELF64LE>;
-template class elf::PartitionElfHeaderSection<ELF64BE>;
-
-template class elf::PartitionProgramHeadersSection<ELF32LE>;
-template class elf::PartitionProgramHeadersSection<ELF32BE>;
-template class elf::PartitionProgramHeadersSection<ELF64LE>;
-template class elf::PartitionProgramHeadersSection<ELF64BE>;
+template class MipsAbiFlagsSection<ELF32LE>;
+template class MipsAbiFlagsSection<ELF32BE>;
+template class MipsAbiFlagsSection<ELF64LE>;
+template class MipsAbiFlagsSection<ELF64BE>;
+
+template class MipsOptionsSection<ELF32LE>;
+template class MipsOptionsSection<ELF32BE>;
+template class MipsOptionsSection<ELF64LE>;
+template class MipsOptionsSection<ELF64BE>;
+
+template class MipsReginfoSection<ELF32LE>;
+template class MipsReginfoSection<ELF32BE>;
+template class MipsReginfoSection<ELF64LE>;
+template class MipsReginfoSection<ELF64BE>;
+
+template class DynamicSection<ELF32LE>;
+template class DynamicSection<ELF32BE>;
+template class DynamicSection<ELF64LE>;
+template class DynamicSection<ELF64BE>;
+
+template class RelocationSection<ELF32LE>;
+template class RelocationSection<ELF32BE>;
+template class RelocationSection<ELF64LE>;
+template class RelocationSection<ELF64BE>;
+
+template class AndroidPackedRelocationSection<ELF32LE>;
+template class AndroidPackedRelocationSection<ELF32BE>;
+template class AndroidPackedRelocationSection<ELF64LE>;
+template class AndroidPackedRelocationSection<ELF64BE>;
+
+template class RelrSection<ELF32LE>;
+template class RelrSection<ELF32BE>;
+template class RelrSection<ELF64LE>;
+template class RelrSection<ELF64BE>;
+
+template class SymbolTableSection<ELF32LE>;
+template class SymbolTableSection<ELF32BE>;
+template class SymbolTableSection<ELF64LE>;
+template class SymbolTableSection<ELF64BE>;
+
+template class VersionNeedSection<ELF32LE>;
+template class VersionNeedSection<ELF32BE>;
+template class VersionNeedSection<ELF64LE>;
+template class VersionNeedSection<ELF64BE>;
+
+template void writeEhdr<ELF32LE>(uint8_t *Buf, Partition &Part);
+template void writeEhdr<ELF32BE>(uint8_t *Buf, Partition &Part);
+template void writeEhdr<ELF64LE>(uint8_t *Buf, Partition &Part);
+template void writeEhdr<ELF64BE>(uint8_t *Buf, Partition &Part);
+
+template void writePhdrs<ELF32LE>(uint8_t *Buf, Partition &Part);
+template void writePhdrs<ELF32BE>(uint8_t *Buf, Partition &Part);
+template void writePhdrs<ELF64LE>(uint8_t *Buf, Partition &Part);
+template void writePhdrs<ELF64BE>(uint8_t *Buf, Partition &Part);
+
+template class PartitionElfHeaderSection<ELF32LE>;
+template class PartitionElfHeaderSection<ELF32BE>;
+template class PartitionElfHeaderSection<ELF64LE>;
+template class PartitionElfHeaderSection<ELF64BE>;
+
+template class PartitionProgramHeadersSection<ELF32LE>;
+template class PartitionProgramHeadersSection<ELF32BE>;
+template class PartitionProgramHeadersSection<ELF64LE>;
+template class PartitionProgramHeadersSection<ELF64BE>;
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/SyntheticSections.h b/contrib/llvm-project/lld/ELF/SyntheticSections.h
index 1c4dd06e0277..d592dcb84e12 100644
--- a/contrib/llvm-project/lld/ELF/SyntheticSections.h
+++ b/contrib/llvm-project/lld/ELF/SyntheticSections.h
@@ -76,7 +76,7 @@ public:
return SyntheticSection::classof(d) && d->name == ".eh_frame";
}
- template <class ELFT> void addSection(InputSectionBase *s);
+ void addSection(EhInputSection *sec);
std::vector<EhInputSection *> sections;
size_t numFdes = 0;
@@ -97,7 +97,9 @@ private:
uint64_t size = 0;
template <class ELFT, class RelTy>
- void addSectionAux(EhInputSection *s, llvm::ArrayRef<RelTy> rels);
+ void addRecords(EhInputSection *s, llvm::ArrayRef<RelTy> rels);
+ template <class ELFT>
+ void addSectionAux(EhInputSection *s);
template <class ELFT, class RelTy>
CieRecord *addCie(EhSectionPiece &piece, ArrayRef<RelTy> rels);
@@ -992,7 +994,7 @@ public:
size_t getSize() const override { return size; }
void writeTo(uint8_t *buf) override;
- bool isNeeded() const override { return !empty; }
+ bool isNeeded() const override;
// Sort and remove duplicate entries.
void finalizeContents() override;
InputSection *getLinkOrderDep() const;
@@ -1006,9 +1008,6 @@ public:
private:
size_t size;
- // Empty if ExecutableSections contains no dependent .ARM.exidx sections.
- bool empty = true;
-
// Instead of storing pointers to the .ARM.exidx InputSections from
// InputObjects, we store pointers to the executable sections that need
// .ARM.exidx sections. We can then use the dependentSections of these to
@@ -1098,19 +1097,11 @@ public:
void writeTo(uint8_t *buf) override;
};
-// Create a dummy .sdata for __global_pointer$ if .sdata does not exist.
-class RISCVSdataSection final : public SyntheticSection {
-public:
- RISCVSdataSection();
- size_t getSize() const override { return 0; }
- bool isNeeded() const override;
- void writeTo(uint8_t *buf) override {}
-};
-
InputSection *createInterpSection();
MergeInputSection *createCommentSection();
+MergeSyntheticSection *createMergeSynthetic(StringRef name, uint32_t type,
+ uint64_t flags, uint32_t alignment);
template <class ELFT> void splitSections();
-void mergeSections();
template <typename ELFT> void writeEhdr(uint8_t *buf, Partition &part);
template <typename ELFT> void writePhdrs(uint8_t *buf, Partition &part);
@@ -1171,7 +1162,6 @@ struct InStruct {
PltSection *plt;
PltSection *iplt;
PPC32Got2Section *ppc32Got2;
- RISCVSdataSection *riscvSdata;
RelocationBaseSection *relaPlt;
RelocationBaseSection *relaIplt;
StringTableSection *shStrTab;
diff --git a/contrib/llvm-project/lld/ELF/Target.cpp b/contrib/llvm-project/lld/ELF/Target.cpp
index d07478a5178c..024e0cfec27b 100644
--- a/contrib/llvm-project/lld/ELF/Target.cpp
+++ b/contrib/llvm-project/lld/ELF/Target.cpp
@@ -34,19 +34,19 @@
using namespace llvm;
using namespace llvm::object;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
-const TargetInfo *elf::target;
-
-std::string lld::toString(RelType type) {
+namespace lld {
+std::string toString(elf::RelType type) {
StringRef s = getELFRelocationTypeName(elf::config->emachine, type);
if (s == "Unknown")
return ("Unknown (" + Twine(type) + ")").str();
return s;
}
-TargetInfo *elf::getTarget() {
+namespace elf {
+const TargetInfo *target;
+
+TargetInfo *getTarget() {
switch (config->emachine) {
case EM_386:
case EM_IAMCU:
@@ -91,6 +91,9 @@ TargetInfo *elf::getTarget() {
}
template <class ELFT> static ErrorPlace getErrPlace(const uint8_t *loc) {
+ if (!Out::bufferStart)
+ return {};
+
for (InputSectionBase *d : inputSections) {
auto *isec = cast<InputSection>(d);
if (!isec->getParent())
@@ -103,7 +106,7 @@ template <class ELFT> static ErrorPlace getErrPlace(const uint8_t *loc) {
return {};
}
-ErrorPlace elf::getErrorPlace(const uint8_t *loc) {
+ErrorPlace getErrorPlace(const uint8_t *loc) {
switch (config->ekind) {
case ELF32LEKind:
return getErrPlace<ELF32LE>(loc);
@@ -179,3 +182,6 @@ uint64_t TargetInfo::getImageBase() const {
return *config->imageBase;
return config->isPic ? 0 : defaultImageBase;
}
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/Writer.cpp b/contrib/llvm-project/lld/ELF/Writer.cpp
index 10b171e8c0d7..dc0f9254596a 100644
--- a/contrib/llvm-project/lld/ELF/Writer.cpp
+++ b/contrib/llvm-project/lld/ELF/Writer.cpp
@@ -8,6 +8,7 @@
#include "Writer.h"
#include "AArch64ErrataFix.h"
+#include "ARMErrataFix.h"
#include "CallGraphSort.h"
#include "Config.h"
#include "LinkerScript.h"
@@ -35,9 +36,8 @@ using namespace llvm::object;
using namespace llvm::support;
using namespace llvm::support::endian;
-using namespace lld;
-using namespace lld::elf;
-
+namespace lld {
+namespace elf {
namespace {
// The writer writes a SymbolTable result to a file.
template <class ELFT> class Writer {
@@ -62,7 +62,6 @@ private:
void setReservedSymbolSections();
std::vector<PhdrEntry *> createPhdrs(Partition &part);
- void removeEmptyPTLoad(std::vector<PhdrEntry *> &phdrEntry);
void addPhdrForSection(Partition &part, unsigned shType, unsigned pType,
unsigned pFlags);
void assignFileOffsets();
@@ -92,7 +91,7 @@ static bool isSectionPrefix(StringRef prefix, StringRef name) {
return name.startswith(prefix) || name == prefix.drop_back();
}
-StringRef elf::getOutputSectionName(const InputSectionBase *s) {
+StringRef getOutputSectionName(const InputSectionBase *s) {
if (config->relocatable)
return s->name;
@@ -140,10 +139,9 @@ static bool needsInterpSection() {
script->needsInterpSection();
}
-template <class ELFT> void elf::writeResult() { Writer<ELFT>().run(); }
+template <class ELFT> void writeResult() { Writer<ELFT>().run(); }
-template <class ELFT>
-void Writer<ELFT>::removeEmptyPTLoad(std::vector<PhdrEntry *> &phdrs) {
+static void removeEmptyPTLoad(std::vector<PhdrEntry *> &phdrs) {
llvm::erase_if(phdrs, [&](const PhdrEntry *p) {
if (p->p_type != PT_LOAD)
return false;
@@ -154,7 +152,7 @@ void Writer<ELFT>::removeEmptyPTLoad(std::vector<PhdrEntry *> &phdrs) {
});
}
-template <class ELFT> static void copySectionsIntoPartitions() {
+void copySectionsIntoPartitions() {
std::vector<InputSectionBase *> newSections;
for (unsigned part = 2; part != partitions.size() + 1; ++part) {
for (InputSectionBase *s : inputSections) {
@@ -176,7 +174,7 @@ template <class ELFT> static void copySectionsIntoPartitions() {
newSections.end());
}
-template <class ELFT> static void combineEhSections() {
+void combineEhSections() {
for (InputSectionBase *&s : inputSections) {
// Ignore dead sections and the partition end marker (.part.end),
// whose partition number is out of bounds.
@@ -185,7 +183,7 @@ template <class ELFT> static void combineEhSections() {
Partition &part = s->getPartition();
if (auto *es = dyn_cast<EhInputSection>(s)) {
- part.ehFrame->addSection<ELFT>(es);
+ part.ehFrame->addSection(es);
s = nullptr;
} else if (s->kind() == SectionBase::Regular && part.armExidx &&
part.armExidx->addSection(cast<InputSection>(s))) {
@@ -217,7 +215,7 @@ static Defined *addAbsolute(StringRef name) {
// The linker is expected to define some symbols depending on
// the linking result. This function defines such symbols.
-void elf::addReservedSymbols() {
+void addReservedSymbols() {
if (config->emachine == EM_MIPS) {
// Define _gp for MIPS. st_value of _gp symbol will be updated by Writer
// so that it points to an absolute address which by default is relative
@@ -310,13 +308,23 @@ static OutputSection *findSection(StringRef name, unsigned partition = 1) {
return nullptr;
}
-// Initialize Out members.
-template <class ELFT> static void createSyntheticSections() {
+template <class ELFT> void createSyntheticSections() {
// Initialize all pointers with NULL. This is needed because
// you can call lld::elf::main more than once as a library.
memset(&Out::first, 0, sizeof(Out));
- auto add = [](InputSectionBase *sec) { inputSections.push_back(sec); };
+ // Add the .interp section first because it is not a SyntheticSection.
+ // The removeUnusedSyntheticSections() function relies on the
+ // SyntheticSections coming last.
+ if (needsInterpSection()) {
+ for (size_t i = 1; i <= partitions.size(); ++i) {
+ InputSection *sec = createInterpSection();
+ sec->partition = i;
+ inputSections.push_back(sec);
+ }
+ }
+
+ auto add = [](SyntheticSection *sec) { inputSections.push_back(sec); };
in.shStrTab = make<StringTableSection>(".shstrtab", false);
@@ -355,8 +363,10 @@ template <class ELFT> static void createSyntheticSections() {
add(sec);
}
+ StringRef relaDynName = config->isRela ? ".rela.dyn" : ".rel.dyn";
+
for (Partition &part : partitions) {
- auto add = [&](InputSectionBase *sec) {
+ auto add = [&](SyntheticSection *sec) {
sec->partition = part.getNumber();
inputSections.push_back(sec);
};
@@ -378,16 +388,11 @@ template <class ELFT> static void createSyntheticSections() {
part.dynStrTab = make<StringTableSection>(".dynstr", true);
part.dynSymTab = make<SymbolTableSection<ELFT>>(*part.dynStrTab);
part.dynamic = make<DynamicSection<ELFT>>();
- if (config->androidPackDynRelocs) {
- part.relaDyn = make<AndroidPackedRelocationSection<ELFT>>(
- config->isRela ? ".rela.dyn" : ".rel.dyn");
- } else {
- part.relaDyn = make<RelocationSection<ELFT>>(
- config->isRela ? ".rela.dyn" : ".rel.dyn", config->zCombreloc);
- }
-
- if (needsInterpSection())
- add(createInterpSection());
+ if (config->androidPackDynRelocs)
+ part.relaDyn = make<AndroidPackedRelocationSection<ELFT>>(relaDynName);
+ else
+ part.relaDyn =
+ make<RelocationSection<ELFT>>(relaDynName, config->zCombreloc);
if (config->hasDynSymTab) {
part.dynSymTab = make<SymbolTableSection<ELFT>>(*part.dynStrTab);
@@ -396,7 +401,7 @@ template <class ELFT> static void createSyntheticSections() {
part.verSym = make<VersionTableSection>();
add(part.verSym);
- if (!config->versionDefinitions.empty()) {
+ if (!namedVersionDefs().empty()) {
part.verDef = make<VersionDefinitionSection>();
add(part.verDef);
}
@@ -476,11 +481,6 @@ template <class ELFT> static void createSyntheticSections() {
add(in.ppc64LongBranchTarget);
}
- if (config->emachine == EM_RISCV) {
- in.riscvSdata = make<RISCVSdataSection>();
- add(in.riscvSdata);
- }
-
in.gotPlt = make<GotPltSection>();
add(in.gotPlt);
in.igotPlt = make<IgotPltSection>();
@@ -504,16 +504,14 @@ template <class ELFT> static void createSyntheticSections() {
config->isRela ? ".rela.plt" : ".rel.plt", /*sort=*/false);
add(in.relaPlt);
- // The relaIplt immediately follows .rel.plt (.rel.dyn for ARM) to ensure
- // that the IRelative relocations are processed last by the dynamic loader.
- // We cannot place the iplt section in .rel.dyn when Android relocation
- // packing is enabled because that would cause a section type mismatch.
- // However, because the Android dynamic loader reads .rel.plt after .rel.dyn,
- // we can get the desired behaviour by placing the iplt section in .rel.plt.
+ // The relaIplt immediately follows .rel[a].dyn to ensure that the IRelative
+ // relocations are processed last by the dynamic loader. We cannot place the
+ // iplt section in .rel.dyn when Android relocation packing is enabled because
+ // that would cause a section type mismatch. However, because the Android
+ // dynamic loader reads .rel.plt after .rel.dyn, we can get the desired
+ // behaviour by placing the iplt section in .rel.plt.
in.relaIplt = make<RelocationSection<ELFT>>(
- (config->emachine == EM_ARM && !config->androidPackDynRelocs)
- ? ".rel.dyn"
- : in.relaPlt->name,
+ config->androidPackDynRelocs ? in.relaPlt->name : relaDynName,
/*sort=*/false);
add(in.relaIplt);
@@ -544,29 +542,6 @@ template <class ELFT> static void createSyntheticSections() {
// The main function of the writer.
template <class ELFT> void Writer<ELFT>::run() {
- // Make copies of any input sections that need to be copied into each
- // partition.
- copySectionsIntoPartitions<ELFT>();
-
- // Create linker-synthesized sections such as .got or .plt.
- // Such sections are of type input section.
- createSyntheticSections<ELFT>();
-
- // Some input sections that are used for exception handling need to be moved
- // into synthetic sections. Do that now so that they aren't assigned to
- // output sections in the usual way.
- if (!config->relocatable)
- combineEhSections<ELFT>();
-
- // We want to process linker script commands. When SECTIONS command
- // is given we let it create sections.
- script->processSectionCommands();
-
- // Linker scripts controls how input sections are assigned to output sections.
- // Input sections that were not handled by scripts are called "orphans", and
- // they are assigned to output sections by the default rule. Process that.
- script->addOrphanSections();
-
if (config->discard != DiscardPolicy::All)
copyLocalSymbols();
@@ -582,15 +557,14 @@ template <class ELFT> void Writer<ELFT>::run() {
if (errorCount())
return;
- script->assignAddresses();
-
// If -compressed-debug-sections is specified, we need to compress
// .debug_* sections. Do it right now because it changes the size of
// output sections.
for (OutputSection *sec : outputSections)
sec->maybeCompress<ELFT>();
- script->allocateHeaders(mainPart->phdrs);
+ if (script->hasSectionsCommand)
+ script->allocateHeaders(mainPart->phdrs);
// Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
// 0 sized region. This has to be done late since only after assignAddresses
@@ -622,7 +596,8 @@ template <class ELFT> void Writer<ELFT>::run() {
return;
if (!config->oFormatBinary) {
- writeTrapInstr();
+ if (config->zSeparate != SeparateSegmentKind::None)
+ writeTrapInstr();
writeHeader();
writeSections();
} else {
@@ -738,7 +713,7 @@ template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
});
if (i == sec->sectionCommands.end())
continue;
- InputSection *isec = cast<InputSectionDescription>(*i)->sections[0];
+ InputSectionBase *isec = cast<InputSectionDescription>(*i)->sections[0];
// Relocations are not using REL[A] section symbols.
if (isec->type == SHT_REL || isec->type == SHT_RELA)
@@ -1070,7 +1045,7 @@ template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() {
ElfSym::globalOffsetTable->section = gotSection;
}
- // .rela_iplt_{start,end} mark the start and the end of .rela.plt section.
+ // .rela_iplt_{start,end} mark the start and the end of in.relaIplt.
if (ElfSym::relaIpltStart && in.relaIplt->isNeeded()) {
ElfSym::relaIpltStart->section = in.relaIplt;
ElfSym::relaIpltEnd->section = in.relaIplt;
@@ -1298,10 +1273,7 @@ sortISDBySectionOrder(InputSectionDescription *isd,
}
orderedSections.push_back({isec, i->second});
}
- llvm::sort(orderedSections, [&](std::pair<InputSection *, int> a,
- std::pair<InputSection *, int> b) {
- return a.second < b.second;
- });
+ llvm::sort(orderedSections, llvm::less_second());
// Find an insertion point for the ordered section list in the unordered
// section list. On targets with limited-range branches, this is the mid-point
@@ -1536,6 +1508,12 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
if (!(sec->flags & SHF_LINK_ORDER))
continue;
+ // The ARM.exidx section use SHF_LINK_ORDER, but we have consolidated
+ // this processing inside the ARMExidxsyntheticsection::finalizeContents().
+ if (!config->relocatable && config->emachine == EM_ARM &&
+ sec->type == SHT_ARM_EXIDX)
+ continue;
+
// Link order may be distributed across several InputSectionDescriptions
// but sort must consider them all at once.
std::vector<InputSection **> scriptSections;
@@ -1545,14 +1523,16 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
for (InputSection *&isec : isd->sections) {
scriptSections.push_back(&isec);
sections.push_back(isec);
+
+ InputSection *link = isec->getLinkOrderDep();
+ if (!link->getParent())
+ error(toString(isec) + ": sh_link points to discarded section " +
+ toString(link));
}
}
}
- // The ARM.exidx section use SHF_LINK_ORDER, but we have consolidated
- // this processing inside the ARMExidxsyntheticsection::finalizeContents().
- if (!config->relocatable && config->emachine == EM_ARM &&
- sec->type == SHT_ARM_EXIDX)
+ if (errorCount())
continue;
llvm::stable_sort(sections, compareByFilePosition);
@@ -1569,21 +1549,30 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
ThunkCreator tc;
AArch64Err843419Patcher a64p;
+ ARMErr657417Patcher a32p;
+ script->assignAddresses();
- // For some targets, like x86, this loop iterates only once.
+ int assignPasses = 0;
for (;;) {
- bool changed = false;
+ bool changed = target->needsThunks && tc.createThunks(outputSections);
- script->assignAddresses();
-
- if (target->needsThunks)
- changed |= tc.createThunks(outputSections);
+ // With Thunk Size much smaller than branch range we expect to
+ // converge quickly; if we get to 10 something has gone wrong.
+ if (changed && tc.pass >= 10) {
+ error("thunk creation not converged");
+ break;
+ }
if (config->fixCortexA53Errata843419) {
if (changed)
script->assignAddresses();
changed |= a64p.createFixes();
}
+ if (config->fixCortexA8) {
+ if (changed)
+ script->assignAddresses();
+ changed |= a32p.createFixes();
+ }
if (in.mipsGot)
in.mipsGot->updateAllocSize();
@@ -1594,8 +1583,19 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
changed |= part.relrDyn->updateAllocSize();
}
- if (!changed)
- return;
+ const Defined *changedSym = script->assignAddresses();
+ if (!changed) {
+ // Some symbols may be dependent on section addresses. When we break the
+ // loop, the symbol values are finalized because a previous
+ // assignAddresses() finalized section addresses.
+ if (!changedSym)
+ break;
+ if (++assignPasses == 5) {
+ errorOrWarn("assignment to symbol " + toString(*changedSym) +
+ " does not converge");
+ break;
+ }
+ }
}
}
@@ -1655,13 +1655,13 @@ static bool computeIsPreemptible(const Symbol &b) {
if (!b.isDefined())
return true;
- // If we have a dynamic list it specifies which local symbols are preemptible.
- if (config->hasDynamicList)
- return false;
-
if (!config->shared)
return false;
+ // If the dynamic list is present, it specifies preemptable symbols in a DSO.
+ if (config->hasDynamicList)
+ return b.inDynamicList;
+
// -Bsymbolic means that definitions are not preempted.
if (config->bsymbolic || (config->bsymbolicFunctions && b.isFunc()))
return false;
@@ -1696,12 +1696,16 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// Define __rel[a]_iplt_{start,end} symbols if needed.
addRelIpltSymbols();
- // RISC-V's gp can address +/- 2 KiB, set it to .sdata + 0x800 if not defined.
- // This symbol should only be defined in an executable.
- if (config->emachine == EM_RISCV && !config->shared)
+ // RISC-V's gp can address +/- 2 KiB, set it to .sdata + 0x800. This symbol
+ // should only be defined in an executable. If .sdata does not exist, its
+ // value/section does not matter but it has to be relative, so set its
+ // st_shndx arbitrarily to 1 (Out::elfHeader).
+ if (config->emachine == EM_RISCV && !config->shared) {
+ OutputSection *sec = findSection(".sdata");
ElfSym::riscvGlobalPointer =
- addOptionalRegular("__global_pointer$", findSection(".sdata"), 0x800,
- STV_DEFAULT, STB_GLOBAL);
+ addOptionalRegular("__global_pointer$", sec ? sec : Out::elfHeader,
+ 0x800, STV_DEFAULT, STB_GLOBAL);
+ }
if (config->emachine == EM_X86_64) {
// On targets that support TLSDESC, _TLS_MODULE_BASE_ is defined in such a
@@ -1730,20 +1734,22 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
for (Partition &part : partitions)
finalizeSynthetic(part.ehFrame);
- symtab->forEachSymbol([](Symbol *s) {
- if (!s->isPreemptible)
- s->isPreemptible = computeIsPreemptible(*s);
- });
+ symtab->forEachSymbol(
+ [](Symbol *s) { s->isPreemptible = computeIsPreemptible(*s); });
+
+ // Change values of linker-script-defined symbols from placeholders (assigned
+ // by declareSymbols) to actual definitions.
+ script->processSymbolAssignments();
// Scan relocations. This must be done after every symbol is declared so that
- // we can correctly decide if a dynamic relocation is needed.
+ // we can correctly decide if a dynamic relocation is needed. This is called
+ // after processSymbolAssignments() because it needs to know whether a
+ // linker-script-defined symbol is absolute.
if (!config->relocatable) {
forEachRelSec(scanRelocations<ELFT>);
reportUndefinedSymbols<ELFT>();
}
- addIRelativeRelocs();
-
if (in.plt && in.plt->isNeeded())
in.plt->addSymbols();
if (in.iplt && in.iplt->isNeeded())
@@ -1880,7 +1886,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
finalizeSynthetic(in.plt);
finalizeSynthetic(in.iplt);
finalizeSynthetic(in.ppc32Got2);
- finalizeSynthetic(in.riscvSdata);
finalizeSynthetic(in.partIndex);
// Dynamic section must be the last one in this list and dynamic
@@ -1905,6 +1910,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// SHFLinkOrder processing must be processed after relative section placements are
// known but before addresses are allocated.
resolveShfLinkOrder();
+ if (errorCount())
+ return;
// This is used to:
// 1) Create "thunks":
@@ -2049,27 +2056,32 @@ std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs(Partition &part) {
unsigned partNo = part.getNumber();
bool isMain = partNo == 1;
- // The first phdr entry is PT_PHDR which describes the program header itself.
- if (isMain)
- addHdr(PT_PHDR, PF_R)->add(Out::programHeaders);
- else
- addHdr(PT_PHDR, PF_R)->add(part.programHeaders->getParent());
-
- // PT_INTERP must be the second entry if exists.
- if (OutputSection *cmd = findSection(".interp", partNo))
- addHdr(PT_INTERP, cmd->getPhdrFlags())->add(cmd);
-
// Add the first PT_LOAD segment for regular output sections.
uint64_t flags = computeFlags(PF_R);
PhdrEntry *load = nullptr;
- // Add the headers. We will remove them if they don't fit.
- // In the other partitions the headers are ordinary sections, so they don't
- // need to be added here.
- if (isMain) {
- load = addHdr(PT_LOAD, flags);
- load->add(Out::elfHeader);
- load->add(Out::programHeaders);
+ // nmagic or omagic output does not have PT_PHDR, PT_INTERP, or the readonly
+ // PT_LOAD.
+ if (!config->nmagic && !config->omagic) {
+ // The first phdr entry is PT_PHDR which describes the program header
+ // itself.
+ if (isMain)
+ addHdr(PT_PHDR, PF_R)->add(Out::programHeaders);
+ else
+ addHdr(PT_PHDR, PF_R)->add(part.programHeaders->getParent());
+
+ // PT_INTERP must be the second entry if exists.
+ if (OutputSection *cmd = findSection(".interp", partNo))
+ addHdr(PT_INTERP, cmd->getPhdrFlags())->add(cmd);
+
+ // Add the headers. We will remove them if they don't fit.
+ // In the other partitions the headers are ordinary sections, so they don't
+ // need to be added here.
+ if (isMain) {
+ load = addHdr(PT_LOAD, flags);
+ load->add(Out::elfHeader);
+ load->add(Out::programHeaders);
+ }
}
// PT_GNU_RELRO includes all sections that should be marked as
@@ -2208,21 +2220,68 @@ void Writer<ELFT>::addPhdrForSection(Partition &part, unsigned shType,
part.phdrs.push_back(entry);
}
-// The first section of each PT_LOAD, the first section in PT_GNU_RELRO and the
-// first section after PT_GNU_RELRO have to be page aligned so that the dynamic
-// linker can set the permissions.
+// Place the first section of each PT_LOAD to a different page (of maxPageSize).
+// This is achieved by assigning an alignment expression to addrExpr of each
+// such section.
template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
- auto pageAlign = [](OutputSection *cmd) {
- if (cmd && !cmd->addrExpr)
- cmd->addrExpr = [=] {
- return alignTo(script->getDot(), config->maxPageSize);
- };
+ const PhdrEntry *prev;
+ auto pageAlign = [&](const PhdrEntry *p) {
+ OutputSection *cmd = p->firstSec;
+ if (cmd && !cmd->addrExpr) {
+ // Prefer advancing to align(dot, maxPageSize) + dot%maxPageSize to avoid
+ // padding in the file contents.
+ //
+ // When -z separate-code is used we must not have any overlap in pages
+ // between an executable segment and a non-executable segment. We align to
+ // the next maximum page size boundary on transitions between executable
+ // and non-executable segments.
+ //
+ // SHT_LLVM_PART_EHDR marks the start of a partition. The partition
+ // sections will be extracted to a separate file. Align to the next
+ // maximum page size boundary so that we can find the ELF header at the
+ // start. We cannot benefit from overlapping p_offset ranges with the
+ // previous segment anyway.
+ if (config->zSeparate == SeparateSegmentKind::Loadable ||
+ (config->zSeparate == SeparateSegmentKind::Code && prev &&
+ (prev->p_flags & PF_X) != (p->p_flags & PF_X)) ||
+ cmd->type == SHT_LLVM_PART_EHDR)
+ cmd->addrExpr = [] {
+ return alignTo(script->getDot(), config->maxPageSize);
+ };
+ // PT_TLS is at the start of the first RW PT_LOAD. If `p` includes PT_TLS,
+ // it must be the RW. Align to p_align(PT_TLS) to make sure
+ // p_vaddr(PT_LOAD)%p_align(PT_LOAD) = 0. Otherwise, if
+ // sh_addralign(.tdata) < sh_addralign(.tbss), we will set p_align(PT_TLS)
+ // to sh_addralign(.tbss), while p_vaddr(PT_TLS)=p_vaddr(PT_LOAD) may not
+ // be congruent to 0 modulo p_align(PT_TLS).
+ //
+ // Technically this is not required, but as of 2019, some dynamic loaders
+ // don't handle p_vaddr%p_align != 0 correctly, e.g. glibc (i386 and
+ // x86-64) doesn't make runtime address congruent to p_vaddr modulo
+ // p_align for dynamic TLS blocks (PR/24606), FreeBSD rtld has the same
+ // bug, musl (TLS Variant 1 architectures) before 1.1.23 handled TLS
+ // blocks correctly. We need to keep the workaround for a while.
+ else if (Out::tlsPhdr && Out::tlsPhdr->firstSec == p->firstSec)
+ cmd->addrExpr = [] {
+ return alignTo(script->getDot(), config->maxPageSize) +
+ alignTo(script->getDot() % config->maxPageSize,
+ Out::tlsPhdr->p_align);
+ };
+ else
+ cmd->addrExpr = [] {
+ return alignTo(script->getDot(), config->maxPageSize) +
+ script->getDot() % config->maxPageSize;
+ };
+ }
};
for (Partition &part : partitions) {
+ prev = nullptr;
for (const PhdrEntry *p : part.phdrs)
- if (p->p_type == PT_LOAD && p->firstSec)
- pageAlign(p->firstSec);
+ if (p->p_type == PT_LOAD && p->firstSec) {
+ pageAlign(p);
+ prev = p;
+ }
}
}
@@ -2231,12 +2290,9 @@ template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
// load executables without any address adjustment.
static uint64_t computeFileOffset(OutputSection *os, uint64_t off) {
// The first section in a PT_LOAD has to have congruent offset and address
- // module the page size.
- if (os->ptLoad && os->ptLoad->firstSec == os) {
- uint64_t alignment =
- std::max<uint64_t>(os->ptLoad->p_align, config->maxPageSize);
- return alignTo(off, alignment, os->addr);
- }
+ // modulo the maximum page size.
+ if (os->ptLoad && os->ptLoad->firstSec == os)
+ return alignTo(off, os->ptLoad->p_align, os->addr);
// File offsets are not significant for .bss sections other than the first one
// in a PT_LOAD. By convention, we keep section offsets monotonically
@@ -2291,13 +2347,12 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
for (OutputSection *sec : outputSections) {
off = setFileOffset(sec, off);
- if (script->hasSectionsCommand)
- continue;
// If this is a last section of the last executable segment and that
// segment is the last loadable segment, align the offset of the
// following section to avoid loading non-segments parts of the file.
- if (lastRX && lastRX->lastSec == sec)
+ if (config->zSeparate != SeparateSegmentKind::None && lastRX &&
+ lastRX->lastSec == sec)
off = alignTo(off, config->commonPageSize);
}
@@ -2348,14 +2403,13 @@ template <class ELFT> void Writer<ELFT>::setPhdrs(Partition &part) {
p->p_paddr = first->getLMA();
}
- if (p->p_type == PT_LOAD) {
- p->p_align = std::max<uint64_t>(p->p_align, config->maxPageSize);
- } else if (p->p_type == PT_GNU_RELRO) {
+ if (p->p_type == PT_GNU_RELRO) {
p->p_align = 1;
- // The glibc dynamic loader rounds the size down, so we need to round up
+ // musl/glibc ld.so rounds the size down, so we need to round up
// to protect the last page. This is a no-op on FreeBSD which always
// rounds up.
- p->p_memsz = alignTo(p->p_memsz, config->commonPageSize);
+ p->p_memsz = alignTo(p->p_offset + p->p_memsz, config->commonPageSize) -
+ p->p_offset;
}
}
}
@@ -2570,9 +2624,6 @@ static void fillTrap(uint8_t *i, uint8_t *end) {
// We'll leave other pages in segments as-is because the rest will be
// overwritten by output sections.
template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
- if (script->hasSectionsCommand)
- return;
-
for (Partition &part : partitions) {
// Fill the last page.
for (PhdrEntry *p : part.phdrs)
@@ -2685,7 +2736,15 @@ template <class ELFT> void Writer<ELFT>::writeBuildId() {
part.buildId->writeBuildId(buildId);
}
-template void elf::writeResult<ELF32LE>();
-template void elf::writeResult<ELF32BE>();
-template void elf::writeResult<ELF64LE>();
-template void elf::writeResult<ELF64BE>();
+template void createSyntheticSections<ELF32LE>();
+template void createSyntheticSections<ELF32BE>();
+template void createSyntheticSections<ELF64LE>();
+template void createSyntheticSections<ELF64BE>();
+
+template void writeResult<ELF32LE>();
+template void writeResult<ELF32BE>();
+template void writeResult<ELF64LE>();
+template void writeResult<ELF64BE>();
+
+} // namespace elf
+} // namespace lld
diff --git a/contrib/llvm-project/lld/ELF/Writer.h b/contrib/llvm-project/lld/ELF/Writer.h
index 784fba9c75a6..3698544d977b 100644
--- a/contrib/llvm-project/lld/ELF/Writer.h
+++ b/contrib/llvm-project/lld/ELF/Writer.h
@@ -9,6 +9,7 @@
#ifndef LLD_ELF_WRITER_H
#define LLD_ELF_WRITER_H
+#include "Config.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include <cstdint>
@@ -19,13 +20,18 @@ namespace elf {
class InputFile;
class OutputSection;
class InputSectionBase;
+void copySectionsIntoPartitions();
+template <class ELFT> void createSyntheticSections();
+void combineEhSections();
template <class ELFT> void writeResult();
// This describes a program header entry.
// Each contains type, access flags and range of output sections that will be
// placed in it.
struct PhdrEntry {
- PhdrEntry(unsigned type, unsigned flags) : p_type(type), p_flags(flags) {}
+ PhdrEntry(unsigned type, unsigned flags)
+ : p_align(type == llvm::ELF::PT_LOAD ? config->maxPageSize : 0),
+ p_type(type), p_flags(flags) {}
void add(OutputSection *sec);
uint64_t p_paddr = 0;
diff --git a/contrib/llvm-project/lld/docs/ReleaseNotes.rst b/contrib/llvm-project/lld/docs/ReleaseNotes.rst
index 237a80a9bed1..bc16417646c3 100644
--- a/contrib/llvm-project/lld/docs/ReleaseNotes.rst
+++ b/contrib/llvm-project/lld/docs/ReleaseNotes.rst
@@ -1,19 +1,22 @@
-=======================
-lld 9.0.0 Release Notes
-=======================
+========================
+lld 10.0.0 Release Notes
+========================
.. contents::
:local:
+.. warning::
+ These are in-progress notes for the upcoming LLVM 10.0.0 release.
+ Release notes for previous releases can be found on
+ `the Download Page <https://releases.llvm.org/download.html>`_.
+
Introduction
============
-lld is a high-performance linker that supports ELF (Unix), COFF
-(Windows), Mach-O (macOS), MinGW and WebAssembly. lld is
-command-line-compatible with GNU linkers and Microsoft link.exe and is
-significantly faster than the system default linkers.
-
-lld 9 has lots of feature improvements and bug fixes.
+This document contains the release notes for the lld linker, release 10.0.0.
+Here we describe the status of lld, including major improvements
+from the previous release. All lld releases may be downloaded
+from the `LLVM releases web site <https://llvm.org/releases/>`_.
Non-comprehensive list of changes in this release
=================================================
@@ -21,211 +24,31 @@ Non-comprehensive list of changes in this release
ELF Improvements
----------------
-* ld.lld now has typo suggestions for flags:
- ``$ ld.lld --call-shared`` now prints
- ``unknown argument '--call-shared', did you mean '--call_shared'``.
- (`r361518 <https://reviews.llvm.org/rL361518>`_)
-
-* ``--allow-shlib-undefined`` and ``--no-allow-shlib-undefined``
- options are added. ``--no-allow-shlib-undefined`` is the default for
- executables.
- (`r352826 <https://reviews.llvm.org/rL352826>`_)
-
-* ``-nmagic`` and ``-omagic`` options are fully supported.
- (`r360593 <https://reviews.llvm.org/rL360593>`_)
-
-* Segment layout has changed. PT_GNU_RELRO, which was previously
- placed in the middle of readable/writable PT_LOAD segments, is now
- placed at the beginning of them. This change permits lld-produced
- ELF files to be read correctly by GNU strip older than 2.31, which
- has a bug to discard a PT_GNU_RELRO in the former layout.
-
-* ``-z common-page-size`` is supported.
- (`r360593 <https://reviews.llvm.org/rL360593>`_)
-
-* Diagnostics messages have improved. A new flag ``--vs-diagnostics``
- alters the format of diagnostic output to enable source hyperlinks
- in Microsoft Visual Studio IDE.
-
-* Linker script compatibility with GNU BFD linker has generally improved.
-
-* The clang ``--dependent-library`` form of autolinking is supported.
-
- This feature is added to implement the Windows-style autolinking for
- Unix. On Unix, in order to use a library, you usually have to
- include a header file provided by the library and then explicitly
- link the library with the linker ``-l`` option. On Windows, header
- files usually contain pragmas that list needed libraries. Compilers
- copy that information to object files, so that linkers can
- automatically link needed libraries. ``--dependent-library`` is
- added for implementing that Windows semantics on Unix.
- (`r360984 <https://reviews.llvm.org/rL360984>`_)
-
-* AArch64 BTI and PAC are supported.
- (`r362793 <https://reviews.llvm.org/rL362793>`_)
-
-* lld now supports replacing ``JAL`` with ``JALX`` instructions in case
- of MIPS-microMIPS cross-mode jumps.
- (`r354311 <https://reviews.llvm.org/rL354311>`_)
-
-* lld now creates LA25 thunks for MIPS R6 code.
- (`r354312 <https://reviews.llvm.org/rL354312>`_)
-
-* Put MIPS-specific .reginfo, .MIPS.options, and .MIPS.abiflags sections
- into corresponding PT_MIPS_REGINFO, PT_MIPS_OPTIONS, and PT_MIPS_ABIFLAGS
- segments.
-
-* The quality of RISC-V and PowerPC ports have greatly improved. Many
- applications can now be linked by lld. PowerPC64 is now almost
- production ready.
-
-* The Linux kernel for arm32_7, arm64, ppc64le and x86_64 can now be
- linked by lld.
-
-* x86-64 TLSDESC is supported.
- (`r361911 <https://reviews.llvm.org/rL361911>`_,
- `r362078 <https://reviews.llvm.org/rL362078>`_)
-
-* DF_STATIC_TLS flag is set for i386 and x86-64 when needed.
- (`r353293 <https://reviews.llvm.org/rL353293>`_,
- `r353378 <https://reviews.llvm.org/rL353378>`_)
-
-* The experimental partitioning feature is added to allow a program to
- be split into multiple pieces.
-
- The feature allows you to semi-automatically split a single program
- into multiple ELF files called "partitions". Since all partitions
- share the same memory address space and don't use PLT/GOT, split
- programs run as fast as regular programs.
-
- With the mechanism, you can start a program only with a "main"
- partition and load remaining partitions on-demand. For example, you
- can split a web browser into a main partition and a PDF reader
- sub-partition and load the PDF reader partition only when a user
- tries to open a PDF file.
-
- See `the documentation <Partitions.html>`_ for more information.
-
-* If "-" is given as an output filename, lld writes the final result
- to the standard output. Previously, it created a file "-" in the
- current directory.
- (`r351852 <https://reviews.llvm.org/rL351852>`_)
-
-* ``-z ifunc-noplt`` option is added to reduce IFunc function call
- overhead in a freestanding environment such as the OS kernel.
-
- Functions resolved by the IFunc mechanism are usually dispatched via
- PLT and thus slower than regular functions because of the cost of
- indirection. With ``-z ifunc-noplt``, you can eliminate it by doing
- text relocations at load-time. You need a special loader to utilize
- this feature. This feature is added for the FreeBSD kernel but can
- be used by any operating systems.
- (`r360685 <https://reviews.llvm.org/rL360685>`_)
-
-* ``--undefined-glob`` option is added. The new option is an extension
- to ``--undefined`` to take a glob pattern instead of a single symbol
- name.
- (`r363396 <https://reviews.llvm.org/rL363396>`_)
-
+* Glob pattern, which you can use in linker scripts or version scripts,
+ now supports `\` and `[!...]`. Except character classes
+ (e.g. `[[:digit:]]`), lld's glob pattern should be fully compatible
+ with GNU now. (`r375051
+ <https://github.com/llvm/llvm-project/commit/48993d5ab9413f0e5b94dfa292a233ce55b09e3e>`_)
COFF Improvements
-----------------
-* Like the ELF driver, lld-link now has typo suggestions for flags.
- (`r361518 <https://reviews.llvm.org/rL361518>`_)
-
-* lld-link now correctly reports duplicate symbol errors for object
- files that were compiled with ``/Gy``.
- (`r352590 <https://reviews.llvm.org/rL352590>`_)
-
-* lld-link now correctly reports duplicate symbol errors when several
- resource (.res) input files define resources with the same type,
- name and language. This can be demoted to a warning using
- ``/force:multipleres``.
- (`r359829 <https://reviews.llvm.org/rL359829>`_)
-
-* lld-link now rejects more than one resource object input files,
- matching link.exe. Previously, lld-link would silently ignore all
- but one. If you hit this: Don't pass resource object files to the
- linker, instead pass res files to the linker directly. Don't put
- resource files in static libraries, pass them on the command line.
- (`r359749 <https://reviews.llvm.org/rL359749>`_)
-
-* Having more than two ``/natvis:`` now works correctly; it used to not
- work for larger binaries before.
- (`r359515 <https://reviews.llvm.org/rL359515>`_)
-
-* Undefined symbols are now printed only in demangled form. Pass
- ``/demangle:no`` to see raw symbol names instead.
- (`r355878 <https://reviews.llvm.org/rL355878>`_)
-
-* Several speed and memory usage improvements.
-
-* lld-link now supports resource object files created by GNU windres and
- MS cvtres, not only llvm-cvtres.
-
-* The generated thunks for delayimports now share the majority of code
- among thunks, significantly reducing the overhead of using delayimport.
- (`r365823 <https://reviews.llvm.org/rL365823>`_)
-
-* ``IMAGE_REL_ARM{,64}_REL32`` relocations are supported.
- (`r352325 <https://reviews.llvm.org/rL352325>`_)
-
-* Range extension thunks for AArch64 are now supported, so lld can
- create large executables for Windows/ARM64.
- (`r352929 <https://reviews.llvm.org/rL352929>`_)
-
-* The following flags have been added:
- ``/functionpadmin`` (`r354716 <https://reviews.llvm.org/rL354716>`_),
- ``/swaprun:`` (`r359192 <https://reviews.llvm.org/rL359192>`_),
- ``/threads:no`` (`r355029 <https://reviews.llvm.org/rL355029>`_),
- ``/filealign`` (`r361634 <https://reviews.llvm.org/rL361634>`_)
-
-WebAssembly Improvements
-------------------------
-
-* Imports from custom module names are supported.
- (`r352828 <https://reviews.llvm.org/rL352828>`_)
-
-* Symbols that are in llvm.used are now exported by default.
- (`r353364 <https://reviews.llvm.org/rL353364>`_)
-
-* Initial support for PIC and dynamic linking has landed.
- (`r357022 <https://reviews.llvm.org/rL357022>`_)
-
-* wasm-ld now add ``__start_``/``__stop_`` symbols for data sections.
- (`r361236 <https://reviews.llvm.org/rL361236>`_)
-
-* wasm-ld now doesn't report an error on archives without a symbol index.
- (`r364338 <https://reviews.llvm.org/rL364338>`_)
-
-* The following flags have been added:
- ``--emit-relocs`` (`r361635 <https://reviews.llvm.org/rL361635>`_),
- ``--wrap`` (`r361639 <https://reviews.llvm.org/rL361639>`_),
- ``--trace`` and ``--trace-symbol``
- (`r353264 <https://reviews.llvm.org/rL353264>`_).
-
+* ...
MinGW Improvements
------------------
-* lld now correctly links crtend.o as the last object file, handling
- terminators for the sections such as .eh_frame properly, fixing
- DWARF exception handling with libgcc and gcc's crtend.o.
-
-* lld now also handles DWARF unwind info generated by GCC, when linking
- with libgcc.
+* ...
-* PDB output can be requested without manually specifying the PDB file
- name, with the new option ``-pdb=`` with an empty value to the option.
- (The old existing syntax ``-pdb <filename>`` was more cumbersome to use
- with an empty parameter value.)
+MachO Improvements
+------------------
-* ``--no-insert-timestamp`` option is added as an alias to ``/timestamp:0``.
- (`r353145 <https://reviews.llvm.org/rL353145>`_)
+* Item 1.
-* Many more GNU ld options are now supported, which e.g. allows the lld
- MinGW frontend to be called by GCC.
+WebAssembly Improvements
+------------------------
-* The following options are added: ``--exclude-all-symbols``,
- ``--appcontainer``, ``--undefined``
+* `__data_end` and `__heap_base` are no longer exported by default,
+ as it's best to keep them internal when possible. They can be
+ explicitly exported with `--export=__data_end` and
+ `--export=__heap_base`, respectively.
diff --git a/contrib/llvm-project/lld/docs/WebAssembly.rst b/contrib/llvm-project/lld/docs/WebAssembly.rst
index 41522163bb85..6384a929d23d 100644
--- a/contrib/llvm-project/lld/docs/WebAssembly.rst
+++ b/contrib/llvm-project/lld/docs/WebAssembly.rst
@@ -109,7 +109,7 @@ trap at runtime (functions that contain only an ``unreachable`` instruction)
and use these stub functions at the otherwise invalid call sites.
The default behaviour is to generate these stub function and to produce
-a warning. The ``--falal-warnings`` flag can be used to disable this behaviour
+a warning. The ``--fatal-warnings`` flag can be used to disable this behaviour
and error out if mismatched are found.
Imports and Exports
diff --git a/contrib/llvm-project/lld/docs/conf.py b/contrib/llvm-project/lld/docs/conf.py
index dd65859fe121..9ce16f062941 100644
--- a/contrib/llvm-project/lld/docs/conf.py
+++ b/contrib/llvm-project/lld/docs/conf.py
@@ -48,9 +48,9 @@ copyright = u'2011-%d, LLVM Project' % date.today().year
# built documents.
#
# The short version.
-version = '9'
+version = '10'
# The full version, including alpha/beta/rc tags.
-release = '9'
+release = '10'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/contrib/llvm-project/lld/docs/ld.lld.1 b/contrib/llvm-project/lld/docs/ld.lld.1
index b5a4d2ec0016..1746ae9f5fd4 100644
--- a/contrib/llvm-project/lld/docs/ld.lld.1
+++ b/contrib/llvm-project/lld/docs/ld.lld.1
@@ -14,7 +14,6 @@
.Nm ld.lld
.Op Ar options
.Ar objfile ...
-
.Sh DESCRIPTION
A linker takes one or more object, archive, and library files, and combines
them into an output file (an executable, a shared library, or another object
@@ -40,7 +39,6 @@ All these targets are always supported however
was built, so you can always use
.Nm
as a native linker as well as a cross linker.
-
.Sh OPTIONS
Many options have both a single-letter and long form.
When using the long form options other than those beginning with the
@@ -175,8 +173,8 @@ A value of zero indicates that there is no limit.
.It Fl -error-unresolved-symbols
Report unresolved symbols as errors.
.It Fl -execute-only
-Mark executable sections unreadable. This option is currently only
-supported on AArch64.
+Mark executable sections unreadable.
+This option is currently only supported on AArch64.
.It Fl -exclude-libs Ns = Ns Ar value
Exclude static libraries from automatic export.
.It Fl -export-dynamic , Fl E
@@ -232,13 +230,16 @@ Enable safe identical code folding.
Disable identical code folding.
.It Fl -ignore-data-address-equality
Ignore address equality of data. C/C++ requires each data to have a unique
-address. This option allows lld to do unsafe optimization that breaks the
+address.
+This option allows lld to do unsafe optimization that breaks the
requirement: create copies of read-only data or merge two or more read-only data
that happen to have the same value.
.It Fl -ignore-function-address-equality
-Ignore address equality of functions. This option allows non-PIC calls to a
-function with non-default visibility in a shared object. The function may have
-different addresses within the executable and within the shared object.
+Ignore address equality of functions.
+This option allows non-PIC calls to a function with non-default visibility in
+a shared object.
+The function may have different addresses within the executable and within the
+shared object.
.It Fl -image-base Ns = Ns Ar value
Set the base address to
.Ar value .
@@ -344,7 +345,8 @@ is
.Cm binary ,
which produces output with no ELF header.
.It Fl -omagic , Fl N
-Set the text and data sections to be readable and writable, do not page align sections, link against static libraries.
+Set the text and data sections to be readable and writable, do not page align
+sections, link against static libraries.
.It Fl -opt-remarks-filename Ar file
Write optimization remarks in YAML format to
.Ar file .
@@ -354,8 +356,8 @@ Filter optimization remarks by only allowing the passes matching
.It Fl -opt-remarks-with-hotness
Include hotness information in the optimization remarks file.
.It Fl -orphan-handling Ns = Ns Ar mode
-Control how orphan sections are handled. An orphan section is one not
-specifically mentioned in a linker script.
+Control how orphan sections are handled.
+An orphan section is one not specifically mentioned in a linker script.
.Ar mode
may be:
.Pp
@@ -381,17 +383,21 @@ may be:
.Pp
.Bl -tag -width 2n -compact
.It Cm none
-Don't pack. Dynamic relocations are encoded in SHT_REL(A).
+Do not pack.
+Dynamic relocations are encoded in SHT_REL(A).
.It Cm android
Pack dynamic relocations in SHT_ANDROID_REL(A).
.It Cm relr
-Pack relative relocations in SHT_RELR, and the rest of dynamic relocations in SHT_REL(A).
+Pack relative relocations in SHT_RELR, and the rest of dynamic relocations in
+SHT_REL(A).
.It Cm android+relr
-Pack relative relocations in SHT_RELR, and the rest of dynamic relocations in SHT_ANDROID_REL(A).
+Pack relative relocations in SHT_RELR, and the rest of dynamic relocations in
+SHT_ANDROID_REL(A).
.El
.Pp
.Cm none
-is the default. If
+is the default.
+If
.Fl -use-android-relr-tags
is specified, use SHT_ANDROID_RELR instead of SHT_RELR.
.Pp
@@ -418,8 +424,14 @@ Undo the effect of
.Fl -push-state.
.It Fl -relocatable , Fl r
Create relocatable object file.
-.It Fl -reproduce Ns = Ns Ar value
-Dump linker invocation and input files for debugging.
+.It Fl -reproduce Ns = Ns Ar path
+Write a tar file to
+.Ar path,
+containing all the input files needed to reproduce the link, a text file called
+response.txt containing the command line options and a text file called
+version.txt containing the output of ld.lld --version.
+The archive when
+unpacked can be used to re-run the linker with the same options and input files.
.It Fl -retain-symbols-file Ns = Ns Ar file
Retain only the symbols listed in the file.
.It Fl -rpath Ns = Ns Ar value , Fl R Ar value
@@ -435,6 +447,8 @@ and
.It Fl -script Ns = Ns Ar file , Fl T Ar file
Read linker script from
.Ar file .
+If multiple linker scripts are given, they are processed as if they
+were concatenated in the order they appeared on the command line.
.It Fl -section-start Ns = Ns Ar section Ns = Ns Ar address
Set address of section.
.It Fl -shared , Fl -Bsharable
@@ -523,13 +537,15 @@ to include the object file in the output file.
.It Fl -undefined-glob Ns = Ns Ar pattern
Synonym for
.Fl -undefined ,
-except that it takes a glob pattern. In a glob pattern,
+except that it takes a glob pattern.
+In a glob pattern,
.Cm *
matches zero or more characters,
.Cm ?
matches any single character, and
.Cm [...]
-matches the characters within brackets. All symbols that match
+matches the characters within brackets.
+All symbols that match
a given pattern are handled as if they were given as arguments of
.Fl -undefined .
.It Fl -unresolved-symbols Ns = Ns Ar value
@@ -556,13 +572,17 @@ Warn about duplicate common symbols.
Warn about using ifunc symbols in conjunction with text relocations.
Older versions of glibc library (2.28 and earlier) has a bug that causes
the segment that includes ifunc symbols to be marked as not executable when
-they are relocated. As a result, although the program compiles and links
+they are relocated.
+As a result, although the program compiles and links
successfully, it gives segmentation fault when the instruction pointer reaches
-an ifunc symbol. Use -warn-ifunc-textrel to let lld give a warning, if the
+an ifunc symbol.
+Use -warn-ifunc-textrel to let lld give a warning, if the
code may include ifunc symbols, may do text relocations and be linked with
-an older glibc version. Otherwise, there is no need to use it, as the default
-value does not give a warning. This flag has been introduced in late 2018,
-has no counter part in ld and gold linkers, and may be removed in the future.
+an older glibc version.
+Otherwise, there is no need to use it, as the default value does not give a
+warning.
+This flag has been introduced in late 2018, has no counter part in ld and gold
+linkers, and may be removed in the future.
.It Fl -warn-unresolved-symbols
Report unresolved symbols as warnings.
.It Fl -whole-archive
@@ -571,18 +591,21 @@ Force load of all members in a static library.
Use wrapper functions for symbol.
.It Fl z Ar option
Linker option extensions.
-.Bl -tag -width indent
+.Bl -tag -width indent -compact
+.Pp
.It Cm execstack
Make the main stack executable.
Stack permissions are recorded in the
.Dv PT_GNU_STACK
segment.
+.Pp
.It Cm global
Sets the
.Dv DF_1_GLOBAL flag in the
.Dv DYNAMIC
section.
Different loaders can decide how to handle this flag on their own.
+.Pp
.It Cm ifunc-noplt
Do not emit PLT entries for ifunc symbols.
Instead, emit text relocations referencing the resolver.
@@ -591,64 +614,78 @@ environments where text relocations do not have the usual drawbacks.
This option must be combined with the
.Fl z Li notext
option.
+.Pp
.It Cm initfirst
Sets the
.Dv DF_1_INITFIRST
flag to indicate the module should be initialized first.
+.Pp
.It Cm interpose
Set the
.Dv DF_1_INTERPOSE
flag to indicate to the runtime linker that the object is an interposer.
During symbol resolution interposers are searched after the application
but before other dependencies.
+.Pp
.It Cm muldefs
Do not error if a symbol is defined multiple times.
The first definition will be used.
This is a synonym for
.Fl -allow-multiple-definition.
+.Pp
.It Cm nocombreloc
Disable combining and sorting multiple relocation sections.
+.Pp
.It Cm nocopyreloc
Disable the creation of copy relocations.
+.Pp
.It Cm nodefaultlib
Set the
.Dv DF_1_NODEFLIB
flag to indicate that default library search paths should be ignored.
+.Pp
.It Cm nodelete
Set the
.Dv DF_1_NODELETE
flag to indicate that the object cannot be unloaded from a process.
+.Pp
.It Cm nodlopen
Set the
.Dv DF_1_NOOPEN
flag to indicate that the object may not be opened by
.Xr dlopen 3 .
+.Pp
.It Cm norelro
Do not indicate that portions of the object shold be mapped read-only
after initial relocation processing.
The object will omit the
.Dv PT_GNU_RELRO
segment.
+.Pp
.It Cm notext
Allow relocations against read-only segments.
Sets the
.Dv DT_TEXTREL flag in the
.Dv DYNAMIC
section.
+.Pp
.It Cm now
Set the
.Dv DF_BIND_NOW
flag to indicate that the run-time loader should perform all relocation
processing as part of object initialization.
By default relocations may be performed on demand.
+.Pp
.It Cm origin
Set the
.Dv DF_ORIGIN
flag to indicate that the object requires
$ORIGIN
processing.
+.Pp
.It Cm retpolineplt
Emit retpoline format PLT entries as a mitigation for CVE-2017-5715.
+.Pp
.It Cm rodynamic
Make the
.Li .dynamic
@@ -656,6 +693,18 @@ section read-only.
The
.Dv DT_DEBUG
tag will not be emitted.
+.Pp
+.It Cm separate-loadable-segments
+.It Cm separate-code
+.It Cm noseparate-code
+Specify whether two adjacent PT_LOAD segments are allowed to overlap in pages.
+.Cm noseparate-code
+(default) allows overlap.
+.Cm separate-code
+allows overlap between two executable segments, or two non-executable segments.
+.Cm separate-loadable-segments
+disallows overlap.
+.Pp
.It Cm stack-size Ns = Ns Ar size
Set the main thread's stack size to
.Ar size .
@@ -663,9 +712,11 @@ The stack size is recorded as the size of the
.Ar size .
.Dv PT_GNU_STACK
program segment.
+.Pp
.It Cm text
Do not allow relocations against read-only segments.
This is the default.
+.Pp
.It Cm wxneeded
Create a
.Dv PT_OPENBSD_WXNEEDED
diff --git a/contrib/llvm-project/lld/include/lld/Common/DWARF.h b/contrib/llvm-project/lld/include/lld/Common/DWARF.h
new file mode 100644
index 000000000000..f0d3d2fbda77
--- /dev/null
+++ b/contrib/llvm-project/lld/include/lld/Common/DWARF.h
@@ -0,0 +1,47 @@
+//===- DWARF.h --------------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_DWARF_H
+#define LLD_DWARF_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
+#include <memory>
+#include <string>
+
+namespace llvm {
+struct DILineInfo;
+} // namespace llvm
+
+namespace lld {
+
+class DWARFCache {
+public:
+ DWARFCache(std::unique_ptr<llvm::DWARFContext> dwarf);
+ llvm::Optional<llvm::DILineInfo> getDILineInfo(uint64_t offset,
+ uint64_t sectionIndex);
+ llvm::Optional<std::pair<std::string, unsigned>>
+ getVariableLoc(StringRef name);
+
+private:
+ std::unique_ptr<llvm::DWARFContext> dwarf;
+ std::vector<const llvm::DWARFDebugLine::LineTable *> lineTables;
+ struct VarLoc {
+ const llvm::DWARFDebugLine::LineTable *lt;
+ unsigned file;
+ unsigned line;
+ };
+ llvm::DenseMap<StringRef, VarLoc> variableLoc;
+};
+
+} // namespace lld
+
+#endif
diff --git a/contrib/llvm-project/lld/include/lld/Common/ErrorHandler.h b/contrib/llvm-project/lld/include/lld/Common/ErrorHandler.h
index 7126a7bf410a..5086fa9862da 100644
--- a/contrib/llvm-project/lld/include/lld/Common/ErrorHandler.h
+++ b/contrib/llvm-project/lld/include/lld/Common/ErrorHandler.h
@@ -87,7 +87,6 @@ public:
StringRef errorLimitExceededMsg = "too many errors emitted, stopping now";
StringRef logName = "lld";
llvm::raw_ostream *errorOS = &llvm::errs();
- bool colorDiagnostics = llvm::errs().has_colors();
bool exitEarly = true;
bool fatalWarnings = false;
bool verbose = false;
@@ -102,12 +101,16 @@ public:
std::unique_ptr<llvm::FileOutputBuffer> outputBuffer;
private:
- void printHeader(StringRef s, raw_ostream::Colors c, const Twine &msg);
+ using Colors = raw_ostream::Colors;
+
+ std::string getLocation(const Twine &msg);
};
/// Returns the default error handler.
ErrorHandler &errorHandler();
+void enableColors(bool enable);
+
inline void error(const Twine &msg) { errorHandler().error(msg); }
inline LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &msg) {
errorHandler().fatal(msg);
diff --git a/contrib/llvm-project/lld/include/lld/Common/LLVM.h b/contrib/llvm-project/lld/include/lld/Common/LLVM.h
index f7ed1d793ca7..34b7b0d194ab 100644
--- a/contrib/llvm-project/lld/include/lld/Common/LLVM.h
+++ b/contrib/llvm-project/lld/include/lld/Common/LLVM.h
@@ -17,6 +17,7 @@
// This should be the only #include, force #includes of all the others on
// clients.
#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
#include <utility>
diff --git a/contrib/llvm-project/lld/include/lld/Common/Strings.h b/contrib/llvm-project/lld/include/lld/Common/Strings.h
index ded22dd769be..9d002bf336de 100644
--- a/contrib/llvm-project/lld/include/lld/Common/Strings.h
+++ b/contrib/llvm-project/lld/include/lld/Common/Strings.h
@@ -18,9 +18,8 @@
namespace lld {
// Returns a demangled C++ symbol name. If Name is not a mangled
-// name, it returns Optional::None.
-llvm::Optional<std::string> demangleItanium(llvm::StringRef name);
-llvm::Optional<std::string> demangleMSVC(llvm::StringRef s);
+// name, it returns name.
+std::string demangleItanium(llvm::StringRef name);
std::vector<uint8_t> parseHex(llvm::StringRef s);
bool isValidCIdentifier(llvm::StringRef s);
diff --git a/contrib/llvm-project/lld/include/lld/Common/TargetOptionsCommandFlags.h b/contrib/llvm-project/lld/include/lld/Common/TargetOptionsCommandFlags.h
index 9345e616f9a9..422bb630f9fe 100644
--- a/contrib/llvm-project/lld/include/lld/Common/TargetOptionsCommandFlags.h
+++ b/contrib/llvm-project/lld/include/lld/Common/TargetOptionsCommandFlags.h
@@ -16,6 +16,7 @@
namespace lld {
llvm::TargetOptions initTargetOptionsFromCodeGenFlags();
+llvm::Optional<llvm::Reloc::Model> getRelocModelFromCMModel();
llvm::Optional<llvm::CodeModel::Model> getCodeModelFromCMModel();
std::string getCPUStr();
std::vector<std::string> getMAttrs();
diff --git a/contrib/llvm-project/lld/include/lld/Core/File.h b/contrib/llvm-project/lld/include/lld/Core/File.h
index 492f35989f16..df014669eb62 100644
--- a/contrib/llvm-project/lld/include/lld/Core/File.h
+++ b/contrib/llvm-project/lld/include/lld/Core/File.h
@@ -16,6 +16,7 @@
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Allocator.h"
#include "llvm/Support/ErrorHandling.h"
#include <functional>
#include <memory>
diff --git a/contrib/llvm-project/lld/include/lld/ReaderWriter/MachOLinkingContext.h b/contrib/llvm-project/lld/include/lld/ReaderWriter/MachOLinkingContext.h
index f48ad77053e5..a950fd5b18e5 100644
--- a/contrib/llvm-project/lld/include/lld/ReaderWriter/MachOLinkingContext.h
+++ b/contrib/llvm-project/lld/include/lld/ReaderWriter/MachOLinkingContext.h
@@ -101,7 +101,7 @@ public:
auto file = std::unique_ptr<T>(new T(std::forward<Args>(args)...));
auto *filePtr = file.get();
auto *ctx = const_cast<MachOLinkingContext *>(this);
- ctx->getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
+ ctx->getNodes().push_back(std::make_unique<FileNode>(std::move(file)));
return filePtr;
}
diff --git a/contrib/llvm-project/lld/lib/Driver/DarwinLdDriver.cpp b/contrib/llvm-project/lld/lib/Driver/DarwinLdDriver.cpp
index 8646d86c08e4..8566ababc655 100644
--- a/contrib/llvm-project/lld/lib/Driver/DarwinLdDriver.cpp
+++ b/contrib/llvm-project/lld/lib/Driver/DarwinLdDriver.cpp
@@ -95,7 +95,7 @@ public:
static std::vector<std::unique_ptr<File>>
makeErrorFile(StringRef path, std::error_code ec) {
std::vector<std::unique_ptr<File>> result;
- result.push_back(llvm::make_unique<ErrorFile>(path, ec));
+ result.push_back(std::make_unique<ErrorFile>(path, ec));
return result;
}
@@ -160,7 +160,7 @@ static void addFile(StringRef path, MachOLinkingContext &ctx,
std::vector<std::unique_ptr<File>> files =
loadFile(ctx, path, loadWholeArchive, upwardDylib);
for (std::unique_ptr<File> &file : files)
- ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
+ ctx.getNodes().push_back(std::make_unique<FileNode>(std::move(file)));
}
// Export lists are one symbol per line. Blank lines are ignored.
@@ -1138,7 +1138,7 @@ static void createFiles(MachOLinkingContext &ctx, bool Implicit) {
ctx.createInternalFiles(Files);
for (auto i = Files.rbegin(), e = Files.rend(); i != e; ++i) {
auto &members = ctx.getNodes();
- members.insert(members.begin(), llvm::make_unique<FileNode>(std::move(*i)));
+ members.insert(members.begin(), std::make_unique<FileNode>(std::move(*i)));
}
}
@@ -1151,7 +1151,7 @@ bool link(llvm::ArrayRef<const char *> args, bool CanExitEarly,
"'-error-limit 0' to see all errors)";
errorHandler().errorOS = &Error;
errorHandler().exitEarly = CanExitEarly;
- errorHandler().colorDiagnostics = Error.has_colors();
+ enableColors(Error.has_colors());
MachOLinkingContext ctx;
if (!parse(args, ctx))
@@ -1185,7 +1185,7 @@ bool link(llvm::ArrayRef<const char *> args, bool CanExitEarly,
merged = mergedFile.get();
auto &members = ctx.getNodes();
members.insert(members.begin(),
- llvm::make_unique<FileNode>(std::move(mergedFile)));
+ std::make_unique<FileNode>(std::move(mergedFile)));
}
resolveTask.end();
diff --git a/contrib/llvm-project/lld/lib/ReaderWriter/FileArchive.cpp b/contrib/llvm-project/lld/lib/ReaderWriter/FileArchive.cpp
index b09bf34dc47c..98f4d06ee210 100644
--- a/contrib/llvm-project/lld/lib/ReaderWriter/FileArchive.cpp
+++ b/contrib/llvm-project/lld/lib/ReaderWriter/FileArchive.cpp
@@ -210,7 +210,7 @@ public:
const Registry &reg) const override {
StringRef path = mb->getBufferIdentifier();
std::unique_ptr<File> ret =
- llvm::make_unique<FileArchive>(std::move(mb), reg, path, _logLoading);
+ std::make_unique<FileArchive>(std::move(mb), reg, path, _logLoading);
return std::move(ret);
}
diff --git a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
index 316b5bbc6f4f..687407049d4b 100644
--- a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
+++ b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
@@ -181,6 +181,20 @@ public:
FindAddressForAtom addressForAtom,
normalized::Relocations &relocs) override;
+ bool isDataInCodeTransition(Reference::KindValue refKind) override {
+ return refKind == modeCode || refKind == modeData;
+ }
+
+ Reference::KindValue dataInCodeTransitionStart(
+ const MachODefinedAtom &atom) override {
+ return modeData;
+ }
+
+ Reference::KindValue dataInCodeTransitionEnd(
+ const MachODefinedAtom &atom) override {
+ return modeCode;
+ }
+
private:
static const Registry::KindStrings _sKindStrings[];
static const StubInfo _sStubInfo;
@@ -188,6 +202,9 @@ private:
enum X86_64Kind: Reference::KindValue {
invalid, /// for error condition
+ modeCode, /// Content starting at this offset is code.
+ modeData, /// Content starting at this offset is data.
+
// Kinds found in mach-o .o files:
branch32, /// ex: call _foo
ripRel32, /// ex: movq _foo(%rip), %rax
@@ -242,24 +259,34 @@ private:
};
const Registry::KindStrings ArchHandler_x86_64::_sKindStrings[] = {
- LLD_KIND_STRING_ENTRY(invalid), LLD_KIND_STRING_ENTRY(branch32),
- LLD_KIND_STRING_ENTRY(ripRel32), LLD_KIND_STRING_ENTRY(ripRel32Minus1),
- LLD_KIND_STRING_ENTRY(ripRel32Minus2), LLD_KIND_STRING_ENTRY(ripRel32Minus4),
+ LLD_KIND_STRING_ENTRY(invalid),
+ LLD_KIND_STRING_ENTRY(modeCode),
+ LLD_KIND_STRING_ENTRY(modeData),
+ LLD_KIND_STRING_ENTRY(branch32),
+ LLD_KIND_STRING_ENTRY(ripRel32),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus1),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus2),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus4),
LLD_KIND_STRING_ENTRY(ripRel32Anon),
LLD_KIND_STRING_ENTRY(ripRel32Minus1Anon),
LLD_KIND_STRING_ENTRY(ripRel32Minus2Anon),
LLD_KIND_STRING_ENTRY(ripRel32Minus4Anon),
LLD_KIND_STRING_ENTRY(ripRel32GotLoad),
LLD_KIND_STRING_ENTRY(ripRel32GotLoadNowLea),
- LLD_KIND_STRING_ENTRY(ripRel32Got), LLD_KIND_STRING_ENTRY(ripRel32Tlv),
+ LLD_KIND_STRING_ENTRY(ripRel32Got),
+ LLD_KIND_STRING_ENTRY(ripRel32Tlv),
LLD_KIND_STRING_ENTRY(lazyPointer),
LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
- LLD_KIND_STRING_ENTRY(pointer64), LLD_KIND_STRING_ENTRY(pointer64Anon),
- LLD_KIND_STRING_ENTRY(delta32), LLD_KIND_STRING_ENTRY(delta64),
- LLD_KIND_STRING_ENTRY(delta32Anon), LLD_KIND_STRING_ENTRY(delta64Anon),
+ LLD_KIND_STRING_ENTRY(pointer64),
+ LLD_KIND_STRING_ENTRY(pointer64Anon),
+ LLD_KIND_STRING_ENTRY(delta32),
+ LLD_KIND_STRING_ENTRY(delta64),
+ LLD_KIND_STRING_ENTRY(delta32Anon),
+ LLD_KIND_STRING_ENTRY(delta64Anon),
LLD_KIND_STRING_ENTRY(negDelta64),
LLD_KIND_STRING_ENTRY(negDelta32),
- LLD_KIND_STRING_ENTRY(imageOffset), LLD_KIND_STRING_ENTRY(imageOffsetGot),
+ LLD_KIND_STRING_ENTRY(imageOffset),
+ LLD_KIND_STRING_ENTRY(imageOffsetGot),
LLD_KIND_STRING_ENTRY(unwindFDEToFunction),
LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame),
LLD_KIND_STRING_ENTRY(tlvInitSectionOffset),
@@ -601,6 +628,8 @@ void ArchHandler_x86_64::applyFixupFinal(
case negDelta32:
*loc32 = fixupAddress - targetAddress + ref.addend();
return;
+ case modeCode:
+ case modeData:
case lazyPointer:
// Do nothing
return;
@@ -720,6 +749,8 @@ void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
case unwindInfoToEhFrame:
llvm_unreachable("fixup implies __unwind_info");
return;
+ case modeCode:
+ case modeData:
case unwindFDEToFunction:
// Do nothing for now
return;
@@ -743,6 +774,9 @@ void ArchHandler_x86_64::appendSectionRelocations(
assert(ref.kindArch() == Reference::KindArch::x86_64);
uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
switch (static_cast<X86_64Kind>(ref.kindValue())) {
+ case modeCode:
+ case modeData:
+ return;
case branch32:
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
X86_64_RELOC_BRANCH | rPcRel | rExtern | rLength4);
diff --git a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
index de5adb088799..44e6a29a0b60 100644
--- a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
+++ b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/CompactUnwindPass.cpp
@@ -573,7 +573,7 @@ private:
void addCompactUnwindPass(PassManager &pm, const MachOLinkingContext &ctx) {
assert(ctx.needsCompactUnwindPass());
- pm.add(llvm::make_unique<CompactUnwindPass>(ctx));
+ pm.add(std::make_unique<CompactUnwindPass>(ctx));
}
} // end namesapce mach_o
diff --git a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/DebugInfo.h b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/DebugInfo.h
index 959e10f9a073..591dd1ebad86 100644
--- a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/DebugInfo.h
+++ b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/DebugInfo.h
@@ -12,6 +12,7 @@
#include "lld/Core/Atom.h"
#include <vector>
+#include "llvm/Support/Allocator.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/GOTPass.cpp b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/GOTPass.cpp
index bc66d49eafb9..514dd4e09da8 100644
--- a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/GOTPass.cpp
+++ b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/GOTPass.cpp
@@ -176,7 +176,7 @@ private:
void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx) {
assert(ctx.needsGOTPass());
- pm.add(llvm::make_unique<GOTPass>(ctx));
+ pm.add(std::make_unique<GOTPass>(ctx));
}
} // end namesapce mach_o
diff --git a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/LayoutPass.cpp b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/LayoutPass.cpp
index 2718dfcf743f..8db6ffb958a4 100644
--- a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/LayoutPass.cpp
+++ b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/LayoutPass.cpp
@@ -478,7 +478,7 @@ llvm::Error LayoutPass::perform(SimpleFile &mergedFile) {
}
void addLayoutPass(PassManager &pm, const MachOLinkingContext &ctx) {
- pm.add(llvm::make_unique<LayoutPass>(
+ pm.add(std::make_unique<LayoutPass>(
ctx.registry(), [&](const DefinedAtom * left, const DefinedAtom * right,
bool & leftBeforeRight) ->bool {
return ctx.customAtomOrderer(left, right, leftBeforeRight);
diff --git a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
index 38456024c9f8..221d895a40d0 100644
--- a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
+++ b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
@@ -802,9 +802,9 @@ void MachOLinkingContext::addSectCreateSection(
std::unique_ptr<MemoryBuffer> content) {
if (!_sectCreateFile) {
- auto sectCreateFile = llvm::make_unique<mach_o::SectCreateFile>();
+ auto sectCreateFile = std::make_unique<mach_o::SectCreateFile>();
_sectCreateFile = sectCreateFile.get();
- getNodes().push_back(llvm::make_unique<FileNode>(std::move(sectCreateFile)));
+ getNodes().push_back(std::make_unique<FileNode>(std::move(sectCreateFile)));
}
assert(_sectCreateFile && "sectcreate file does not exist.");
@@ -897,8 +897,8 @@ static void addDependencyInfoHelper(llvm::raw_fd_ostream *DepInfo,
std::error_code MachOLinkingContext::createDependencyFile(StringRef path) {
std::error_code ec;
- _dependencyInfo = std::unique_ptr<llvm::raw_fd_ostream>(new
- llvm::raw_fd_ostream(path, ec, llvm::sys::fs::F_None));
+ _dependencyInfo = std::unique_ptr<llvm::raw_fd_ostream>(
+ new llvm::raw_fd_ostream(path, ec, llvm::sys::fs::OF_None));
if (ec) {
_dependencyInfo.reset();
return ec;
@@ -1019,7 +1019,7 @@ void MachOLinkingContext::finalizeInputFiles() {
return !isLibrary(a) && isLibrary(b);
});
size_t numLibs = std::count_if(elements.begin(), elements.end(), isLibrary);
- elements.push_back(llvm::make_unique<GroupEnd>(numLibs));
+ elements.push_back(std::make_unique<GroupEnd>(numLibs));
}
llvm::Error MachOLinkingContext::handleLoadedFile(File &file) {
diff --git a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
index 38b365374f36..963f1227fa44 100644
--- a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
+++ b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
@@ -542,7 +542,7 @@ public:
loadFile(std::unique_ptr<MemoryBuffer> mb,
const Registry &registry) const override {
std::unique_ptr<File> ret =
- llvm::make_unique<MachOFile>(std::move(mb), &_ctx);
+ std::make_unique<MachOFile>(std::move(mb), &_ctx);
return std::move(ret);
}
@@ -568,7 +568,7 @@ public:
loadFile(std::unique_ptr<MemoryBuffer> mb,
const Registry &registry) const override {
std::unique_ptr<File> ret =
- llvm::make_unique<MachODylibFile>(std::move(mb), &_ctx);
+ std::make_unique<MachODylibFile>(std::move(mb), &_ctx);
return std::move(ret);
}
diff --git a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
index da27c7cadf96..ab7ea7e07f23 100644
--- a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
+++ b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
@@ -626,17 +626,19 @@ llvm::Error MachOFileLayout::writeSingleSegmentLoadCommand(uint8_t *&lc) {
+ _file.sections.size() * sizeof(typename T::section);
uint8_t *next = lc + seg->cmdsize;
memset(seg->segname, 0, 16);
+ seg->flags = 0;
seg->vmaddr = 0;
- seg->vmsize = _file.sections.back().address
- + _file.sections.back().content.size();
seg->fileoff = _endOfLoadCommands;
- seg->filesize = _sectInfo[&_file.sections.back()].fileOffset +
- _file.sections.back().content.size() -
- _sectInfo[&_file.sections.front()].fileOffset;
seg->maxprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
seg->initprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
seg->nsects = _file.sections.size();
- seg->flags = 0;
+ if (seg->nsects) {
+ seg->vmsize = _file.sections.back().address
+ + _file.sections.back().content.size();
+ seg->filesize = _sectInfo[&_file.sections.back()].fileOffset +
+ _file.sections.back().content.size() -
+ _sectInfo[&_file.sections.front()].fileOffset;
+ }
if (_swap)
swapStruct(*seg);
typename T::section *sout = reinterpret_cast<typename T::section*>
diff --git a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
index 879f07fb4760..f34857b99676 100644
--- a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
+++ b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
@@ -717,7 +717,7 @@ llvm::Error parseStabs(MachOFile &file,
// FIXME: Kill this off when we can move to sane yaml parsing.
std::unique_ptr<BumpPtrAllocator> allocator;
if (copyRefs)
- allocator = llvm::make_unique<BumpPtrAllocator>();
+ allocator = std::make_unique<BumpPtrAllocator>();
enum { start, inBeginEnd } state = start;
@@ -812,7 +812,7 @@ llvm::Error parseStabs(MachOFile &file,
stabsList.push_back(stab);
}
- file.setDebugInfo(llvm::make_unique<StabsDebugInfo>(std::move(stabsList)));
+ file.setDebugInfo(std::make_unique<StabsDebugInfo>(std::move(stabsList)));
// FIXME: Kill this off when we fix YAML memory ownership.
file.debugInfo()->setAllocator(std::move(allocator));
@@ -832,10 +832,10 @@ dataExtractorFromSection(const NormalizedFile &normalizedFile,
// FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE
// inspection" code if possible.
-static uint32_t getCUAbbrevOffset(llvm::DataExtractor abbrevData,
+static uint64_t getCUAbbrevOffset(llvm::DataExtractor abbrevData,
uint64_t abbrCode) {
uint64_t curCode;
- uint32_t offset = 0;
+ uint64_t offset = 0;
while ((curCode = abbrevData.getULEB128(&offset)) != abbrCode) {
// Tag
abbrevData.getULEB128(&offset);
@@ -853,13 +853,13 @@ static uint32_t getCUAbbrevOffset(llvm::DataExtractor abbrevData,
static Expected<const char *>
getIndexedString(const NormalizedFile &normalizedFile,
llvm::dwarf::Form form, llvm::DataExtractor infoData,
- uint32_t &infoOffset, const Section &stringsSection) {
+ uint64_t &infoOffset, const Section &stringsSection) {
if (form == llvm::dwarf::DW_FORM_string)
return infoData.getCStr(&infoOffset);
if (form != llvm::dwarf::DW_FORM_strp)
return llvm::make_error<GenericError>(
"string field encoded without DW_FORM_strp");
- uint32_t stringOffset = infoData.getU32(&infoOffset);
+ uint64_t stringOffset = infoData.getU32(&infoOffset);
llvm::DataExtractor stringsData =
dataExtractorFromSection(normalizedFile, stringsSection);
return stringsData.getCStr(&stringOffset);
@@ -875,7 +875,7 @@ readCompUnit(const NormalizedFile &normalizedFile,
StringRef path) {
// FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE
// inspection" code if possible.
- uint32_t offset = 0;
+ uint64_t offset = 0;
llvm::dwarf::DwarfFormat Format = llvm::dwarf::DwarfFormat::DWARF32;
auto infoData = dataExtractorFromSection(normalizedFile, info);
uint32_t length = infoData.getU32(&offset);
@@ -897,7 +897,7 @@ readCompUnit(const NormalizedFile &normalizedFile,
uint32_t abbrCode = infoData.getULEB128(&offset);
auto abbrevData = dataExtractorFromSection(normalizedFile, abbrev);
- uint32_t abbrevOffset = getCUAbbrevOffset(abbrevData, abbrCode);
+ uint64_t abbrevOffset = getCUAbbrevOffset(abbrevData, abbrCode);
uint64_t tag = abbrevData.getULEB128(&abbrevOffset);
if (tag != llvm::dwarf::DW_TAG_compile_unit)
return llvm::make_error<GenericError>("top level DIE is not a compile unit");
@@ -974,11 +974,11 @@ llvm::Error parseDebugInfo(MachOFile &file,
// memory ownership.
std::unique_ptr<BumpPtrAllocator> allocator;
if (copyRefs) {
- allocator = llvm::make_unique<BumpPtrAllocator>();
+ allocator = std::make_unique<BumpPtrAllocator>();
tuOrErr->name = copyDebugString(tuOrErr->name, *allocator);
tuOrErr->path = copyDebugString(tuOrErr->path, *allocator);
}
- file.setDebugInfo(llvm::make_unique<DwarfDebugInfo>(std::move(*tuOrErr)));
+ file.setDebugInfo(std::make_unique<DwarfDebugInfo>(std::move(*tuOrErr)));
if (copyRefs)
file.debugInfo()->setAllocator(std::move(allocator));
} else
diff --git a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/ObjCPass.cpp b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/ObjCPass.cpp
index df121f0e1d5d..02a95b5aa0c0 100644
--- a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/ObjCPass.cpp
+++ b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/ObjCPass.cpp
@@ -124,7 +124,7 @@ private:
void addObjCPass(PassManager &pm, const MachOLinkingContext &ctx) {
- pm.add(llvm::make_unique<ObjCPass>(ctx));
+ pm.add(std::make_unique<ObjCPass>(ctx));
}
} // end namespace mach_o
diff --git a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/ShimPass.cpp b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/ShimPass.cpp
index b0775ad5fc26..a5b34cfe8de6 100644
--- a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/ShimPass.cpp
+++ b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/ShimPass.cpp
@@ -121,7 +121,7 @@ private:
void addShimPass(PassManager &pm, const MachOLinkingContext &ctx) {
- pm.add(llvm::make_unique<ShimPass>(ctx));
+ pm.add(std::make_unique<ShimPass>(ctx));
}
} // end namespace mach_o
diff --git a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/TLVPass.cpp b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/TLVPass.cpp
index 89b655e1f888..5f457b863d90 100644
--- a/contrib/llvm-project/lld/lib/ReaderWriter/MachO/TLVPass.cpp
+++ b/contrib/llvm-project/lld/lib/ReaderWriter/MachO/TLVPass.cpp
@@ -133,7 +133,7 @@ private:
void addTLVPass(PassManager &pm, const MachOLinkingContext &ctx) {
assert(ctx.needsTLVPass());
- pm.add(llvm::make_unique<TLVPass>(ctx));
+ pm.add(std::make_unique<TLVPass>(ctx));
}
} // end namesapce mach_o
diff --git a/contrib/llvm-project/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/contrib/llvm-project/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
index 5feff2a0514a..77936399c1af 100644
--- a/contrib/llvm-project/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
+++ b/contrib/llvm-project/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
@@ -1299,7 +1299,7 @@ public:
llvm::Error writeFile(const lld::File &file, StringRef outPath) override {
// Create stream to path.
std::error_code ec;
- llvm::raw_fd_ostream out(outPath, ec, llvm::sys::fs::F_Text);
+ llvm::raw_fd_ostream out(outPath, ec, llvm::sys::fs::OF_Text);
if (ec)
return llvm::errorCodeToError(ec);
diff --git a/contrib/llvm-project/lld/tools/lld/lld.cpp b/contrib/llvm-project/lld/tools/lld/lld.cpp
index d3bc9b68ea05..91211a80b95c 100644
--- a/contrib/llvm-project/lld/tools/lld/lld.cpp
+++ b/contrib/llvm-project/lld/tools/lld/lld.cpp
@@ -33,6 +33,7 @@
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Host.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Path.h"
#include <cstdlib>