Index: vendor/lld/dist-release_90/COFF/Driver.cpp =================================================================== --- vendor/lld/dist-release_90/COFF/Driver.cpp (revision 351311) +++ vendor/lld/dist-release_90/COFF/Driver.cpp (revision 351312) @@ -1,1891 +1,1893 @@ //===- Driver.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 "Driver.h" #include "Config.h" #include "DebugTypes.h" #include "ICF.h" #include "InputFiles.h" #include "MarkLive.h" #include "MinGW.h" #include "SymbolTable.h" #include "Symbols.h" #include "Writer.h" #include "lld/Common/Args.h" #include "lld/Common/Driver.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Filesystem.h" #include "lld/Common/Memory.h" #include "lld/Common/Threads.h" #include "lld/Common/Timer.h" #include "lld/Common/Version.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/BinaryFormat/Magic.h" #include "llvm/Object/ArchiveWriter.h" #include "llvm/Object/COFFImportFile.h" #include "llvm/Object/COFFModuleDefinition.h" #include "llvm/Object/WindowsMachineFlag.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" #include "llvm/Support/Debug.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ToolDrivers/llvm-lib/LibDriver.h" #include #include #include using namespace llvm; using namespace llvm::object; using namespace llvm::COFF; using llvm::sys::Process; namespace lld { namespace coff { static Timer inputFileTimer("Input File Reading", Timer::root()); Configuration *config; LinkerDriver *driver; bool link(ArrayRef 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(); symtab = make(); driver = make(); driver->link(args); // Call exit() if we can to avoid calling destructors. if (canExitEarly) exitLld(errorCount() ? 1 : 0); freeArena(); ObjFile::instances.clear(); ImportFile::instances.clear(); BitcodeFile::instances.clear(); memset(MergeChunk::instances, 0, sizeof(MergeChunk::instances)); return !errorCount(); } // Parse options of the form "old;new". static std::pair getOldNewOptions(opt::InputArgList &args, unsigned id) { auto *arg = args.getLastArg(id); if (!arg) return {"", ""}; StringRef s = arg->getValue(); std::pair ret = s.split(';'); if (ret.second.empty()) error(arg->getSpelling() + " expects 'old;new' format, but got " + s); return ret; } // Drop directory components and replace extension with ".exe" or ".dll". static std::string getOutputPath(StringRef path) { auto p = path.find_last_of("\\/"); StringRef s = (p == StringRef::npos) ? path : path.substr(p + 1); const char* e = config->dll ? ".dll" : ".exe"; return (s.substr(0, s.rfind('.')) + e).str(); } // Returns true if S matches /crtend.?\.o$/. static bool isCrtend(StringRef s) { if (!s.endswith(".o")) return false; s = s.drop_back(2); if (s.endswith("crtend")) return true; return !s.empty() && s.drop_back().endswith("crtend"); } // ErrorOr is not default constructible, so it cannot be used as the type // parameter of a future. // FIXME: We could open the file in createFutureForFile and avoid needing to // return an error here, but for the moment that would cost us a file descriptor // (a limited resource on Windows) for the duration that the future is pending. using MBErrPair = std::pair, std::error_code>; // Create a std::future that opens and maps a file using the best strategy for // the host platform. static std::future createFutureForFile(std::string path) { #if _WIN32 // On Windows, file I/O is relatively slow so it is best to do this // asynchronously. auto strategy = std::launch::async; #else auto strategy = std::launch::deferred; #endif return std::async(strategy, [=]() { auto mbOrErr = MemoryBuffer::getFile(path, /*FileSize*/ -1, /*RequiresNullTerminator*/ false); if (!mbOrErr) return MBErrPair{nullptr, mbOrErr.getError()}; return MBErrPair{std::move(*mbOrErr), std::error_code()}; }); } // Symbol names are mangled by prepending "_" on x86. static StringRef mangle(StringRef sym) { assert(config->machine != IMAGE_FILE_MACHINE_UNKNOWN); if (config->machine == I386) return saver.save("_" + sym); return sym; } static bool findUnderscoreMangle(StringRef sym) { Symbol *s = symtab->findMangle(mangle(sym)); return s && !isa(s); } MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr mb) { MemoryBufferRef mbref = *mb; make>(std::move(mb)); // take ownership if (driver->tar) driver->tar->append(relativeToRoot(mbref.getBufferIdentifier()), mbref.getBuffer()); return mbref; } void LinkerDriver::addBuffer(std::unique_ptr mb, bool wholeArchive) { StringRef filename = mb->getBufferIdentifier(); MemoryBufferRef mbref = takeBuffer(std::move(mb)); filePaths.push_back(filename); // File type is detected by contents, not by file extension. switch (identify_magic(mbref.getBuffer())) { case file_magic::windows_resource: resources.push_back(mbref); break; case file_magic::archive: if (wholeArchive) { std::unique_ptr file = CHECK(Archive::create(mbref), filename + ": failed to parse archive"); + Archive *archive = file.get(); + make>(std::move(file)); // take ownership - for (MemoryBufferRef m : getArchiveMembers(file.get())) + for (MemoryBufferRef m : getArchiveMembers(archive)) addArchiveBuffer(m, "", filename, 0); return; } symtab->addFile(make(mbref)); break; case file_magic::bitcode: symtab->addFile(make(mbref, "", 0)); break; case file_magic::coff_object: case file_magic::coff_import_library: symtab->addFile(make(mbref)); break; case file_magic::pdb: loadTypeServerSource(mbref); break; case file_magic::coff_cl_gl_object: error(filename + ": is not a native COFF file. Recompile without /GL"); break; case file_magic::pecoff_executable: if (filename.endswith_lower(".dll")) { error(filename + ": bad file type. Did you specify a DLL instead of an " "import library?"); break; } LLVM_FALLTHROUGH; default: error(mbref.getBufferIdentifier() + ": unknown file type"); break; } } void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive) { auto future = std::make_shared>(createFutureForFile(path)); std::string pathStr = path; enqueueTask([=]() { auto mbOrErr = future->get(); if (mbOrErr.second) { std::string msg = "could not open '" + pathStr + "': " + mbOrErr.second.message(); // Check if the filename is a typo for an option flag. OptTable thinks // that all args that are not known options and that start with / are // filenames, but e.g. `/nodefaultlibs` is more likely a typo for // the option `/nodefaultlib` than a reference to a file in the root // directory. std::string nearest; if (COFFOptTable().findNearest(pathStr, nearest) > 1) error(msg); else error(msg + "; did you mean '" + nearest + "'"); } else driver->addBuffer(std::move(mbOrErr.first), wholeArchive); }); } void LinkerDriver::addArchiveBuffer(MemoryBufferRef mb, StringRef symName, StringRef parentName, uint64_t offsetInArchive) { file_magic magic = identify_magic(mb.getBuffer()); if (magic == file_magic::coff_import_library) { InputFile *imp = make(mb); imp->parentName = parentName; symtab->addFile(imp); return; } InputFile *obj; if (magic == file_magic::coff_object) { obj = make(mb); } else if (magic == file_magic::bitcode) { obj = make(mb, parentName, offsetInArchive); } else { error("unknown file type: " + mb.getBufferIdentifier()); return; } obj->parentName = parentName; symtab->addFile(obj); log("Loaded " + toString(obj) + " for " + symName); } void LinkerDriver::enqueueArchiveMember(const Archive::Child &c, StringRef symName, StringRef parentName) { auto reportBufferError = [=](Error &&e, StringRef childName) { fatal("could not get the buffer for the member defining symbol " + symName + ": " + parentName + "(" + childName + "): " + toString(std::move(e))); }; if (!c.getParent()->isThin()) { uint64_t offsetInArchive = c.getChildOffset(); Expected mbOrErr = c.getMemoryBufferRef(); if (!mbOrErr) reportBufferError(mbOrErr.takeError(), check(c.getFullName())); MemoryBufferRef mb = mbOrErr.get(); enqueueTask([=]() { driver->addArchiveBuffer(mb, symName, parentName, offsetInArchive); }); return; } std::string childName = CHECK( c.getFullName(), "could not get the filename for the member defining symbol " + symName); auto future = std::make_shared>( createFutureForFile(childName)); enqueueTask([=]() { auto mbOrErr = future->get(); if (mbOrErr.second) reportBufferError(errorCodeToError(mbOrErr.second), childName); driver->addArchiveBuffer(takeBuffer(std::move(mbOrErr.first)), symName, parentName, /* OffsetInArchive */ 0); }); } static bool isDecorated(StringRef sym) { return sym.startswith("@") || sym.contains("@@") || sym.startswith("?") || (!config->mingw && sym.contains('@')); } // Parses .drectve section contents and returns a list of files // specified by /defaultlib. void LinkerDriver::parseDirectives(InputFile *file) { StringRef s = file->getDirectives(); if (s.empty()) return; log("Directives: " + toString(file) + ": " + s); ArgParser parser; // .drectve is always tokenized using Windows shell rules. // /EXPORT: option can appear too many times, processing in fastpath. opt::InputArgList args; std::vector exports; std::tie(args, exports) = parser.parseDirectives(s); for (StringRef e : exports) { // If a common header file contains dllexported function // declarations, many object files may end up with having the // same /EXPORT options. In order to save cost of parsing them, // we dedup them first. if (!directivesExports.insert(e).second) continue; Export exp = parseExport(e); if (config->machine == I386 && config->mingw) { if (!isDecorated(exp.name)) exp.name = saver.save("_" + exp.name); if (!exp.extName.empty() && !isDecorated(exp.extName)) exp.extName = saver.save("_" + exp.extName); } exp.directives = true; config->exports.push_back(exp); } for (auto *arg : args) { switch (arg->getOption().getID()) { case OPT_aligncomm: parseAligncomm(arg->getValue()); break; case OPT_alternatename: parseAlternateName(arg->getValue()); break; case OPT_defaultlib: if (Optional path = findLib(arg->getValue())) enqueuePath(*path, false); break; case OPT_entry: config->entry = addUndefined(mangle(arg->getValue())); break; case OPT_failifmismatch: checkFailIfMismatch(arg->getValue(), file); break; case OPT_incl: addUndefined(arg->getValue()); break; case OPT_merge: parseMerge(arg->getValue()); break; case OPT_nodefaultlib: config->noDefaultLibs.insert(doFindLib(arg->getValue()).lower()); break; case OPT_section: parseSection(arg->getValue()); break; case OPT_subsystem: parseSubsystem(arg->getValue(), &config->subsystem, &config->majorOSVersion, &config->minorOSVersion); break; // Only add flags here that link.exe accepts in // `#pragma comment(linker, "/flag")`-generated sections. case OPT_editandcontinue: case OPT_guardsym: case OPT_throwingnew: break; default: error(arg->getSpelling() + " is not allowed in .drectve"); } } } // Find file from search paths. You can omit ".obj", this function takes // care of that. Note that the returned path is not guaranteed to exist. StringRef LinkerDriver::doFindFile(StringRef filename) { bool hasPathSep = (filename.find_first_of("/\\") != StringRef::npos); if (hasPathSep) return filename; bool hasExt = filename.contains('.'); for (StringRef dir : searchPaths) { SmallString<128> path = dir; sys::path::append(path, filename); if (sys::fs::exists(path.str())) return saver.save(path.str()); if (!hasExt) { path.append(".obj"); if (sys::fs::exists(path.str())) return saver.save(path.str()); } } return filename; } static Optional getUniqueID(StringRef path) { sys::fs::UniqueID ret; if (sys::fs::getUniqueID(path, ret)) return None; return ret; } // Resolves a file path. This never returns the same path // (in that case, it returns None). Optional LinkerDriver::findFile(StringRef filename) { StringRef path = doFindFile(filename); if (Optional id = getUniqueID(path)) { bool seen = !visitedFiles.insert(*id).second; if (seen) return None; } if (path.endswith_lower(".lib")) visitedLibs.insert(sys::path::filename(path)); return path; } // MinGW specific. If an embedded directive specified to link to // foo.lib, but it isn't found, try libfoo.a instead. StringRef LinkerDriver::doFindLibMinGW(StringRef filename) { if (filename.contains('/') || filename.contains('\\')) return filename; SmallString<128> s = filename; sys::path::replace_extension(s, ".a"); StringRef libName = saver.save("lib" + s.str()); return doFindFile(libName); } // Find library file from search path. StringRef LinkerDriver::doFindLib(StringRef filename) { // Add ".lib" to Filename if that has no file extension. bool hasExt = filename.contains('.'); if (!hasExt) filename = saver.save(filename + ".lib"); StringRef ret = doFindFile(filename); // For MinGW, if the find above didn't turn up anything, try // looking for a MinGW formatted library name. if (config->mingw && ret == filename) return doFindLibMinGW(filename); return ret; } // Resolves a library path. /nodefaultlib options are taken into // consideration. This never returns the same path (in that case, // it returns None). Optional LinkerDriver::findLib(StringRef filename) { if (config->noDefaultLibAll) return None; if (!visitedLibs.insert(filename.lower()).second) return None; StringRef path = doFindLib(filename); if (config->noDefaultLibs.count(path.lower())) return None; if (Optional id = getUniqueID(path)) if (!visitedFiles.insert(*id).second) return None; return path; } // Parses LIB environment which contains a list of search paths. void LinkerDriver::addLibSearchPaths() { Optional envOpt = Process::GetEnv("LIB"); if (!envOpt.hasValue()) return; StringRef env = saver.save(*envOpt); while (!env.empty()) { StringRef path; std::tie(path, env) = env.split(';'); searchPaths.push_back(path); } } Symbol *LinkerDriver::addUndefined(StringRef name) { Symbol *b = symtab->addUndefined(name); if (!b->isGCRoot) { b->isGCRoot = true; config->gcroot.push_back(b); } return b; } StringRef LinkerDriver::mangleMaybe(Symbol *s) { // If the plain symbol name has already been resolved, do nothing. Undefined *unmangled = dyn_cast(s); if (!unmangled) return ""; // Otherwise, see if a similar, mangled symbol exists in the symbol table. Symbol *mangled = symtab->findMangle(unmangled->getName()); if (!mangled) return ""; // If we find a similar mangled symbol, make this an alias to it and return // its name. log(unmangled->getName() + " aliased to " + mangled->getName()); unmangled->weakAlias = symtab->addUndefined(mangled->getName()); return mangled->getName(); } // Windows specific -- find default entry point name. // // There are four different entry point functions for Windows executables, // each of which corresponds to a user-defined "main" function. This function // infers an entry point from a user-defined "main" function. StringRef LinkerDriver::findDefaultEntry() { assert(config->subsystem != IMAGE_SUBSYSTEM_UNKNOWN && "must handle /subsystem before calling this"); if (config->mingw) return mangle(config->subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI ? "WinMainCRTStartup" : "mainCRTStartup"); if (config->subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) { if (findUnderscoreMangle("wWinMain")) { if (!findUnderscoreMangle("WinMain")) return mangle("wWinMainCRTStartup"); warn("found both wWinMain and WinMain; using latter"); } return mangle("WinMainCRTStartup"); } if (findUnderscoreMangle("wmain")) { if (!findUnderscoreMangle("main")) return mangle("wmainCRTStartup"); warn("found both wmain and main; using latter"); } return mangle("mainCRTStartup"); } WindowsSubsystem LinkerDriver::inferSubsystem() { if (config->dll) return IMAGE_SUBSYSTEM_WINDOWS_GUI; if (config->mingw) return IMAGE_SUBSYSTEM_WINDOWS_CUI; // Note that link.exe infers the subsystem from the presence of these // functions even if /entry: or /nodefaultlib are passed which causes them // to not be called. bool haveMain = findUnderscoreMangle("main"); bool haveWMain = findUnderscoreMangle("wmain"); bool haveWinMain = findUnderscoreMangle("WinMain"); bool haveWWinMain = findUnderscoreMangle("wWinMain"); if (haveMain || haveWMain) { if (haveWinMain || haveWWinMain) { warn(std::string("found ") + (haveMain ? "main" : "wmain") + " and " + (haveWinMain ? "WinMain" : "wWinMain") + "; defaulting to /subsystem:console"); } return IMAGE_SUBSYSTEM_WINDOWS_CUI; } if (haveWinMain || haveWWinMain) return IMAGE_SUBSYSTEM_WINDOWS_GUI; return IMAGE_SUBSYSTEM_UNKNOWN; } static uint64_t getDefaultImageBase() { if (config->is64()) return config->dll ? 0x180000000 : 0x140000000; return config->dll ? 0x10000000 : 0x400000; } static std::string createResponseFile(const opt::InputArgList &args, ArrayRef filePaths, ArrayRef searchPaths) { SmallString<0> data; raw_svector_ostream os(data); for (auto *arg : args) { switch (arg->getOption().getID()) { case OPT_linkrepro: case OPT_INPUT: case OPT_defaultlib: case OPT_libpath: case OPT_manifest: case OPT_manifest_colon: case OPT_manifestdependency: case OPT_manifestfile: case OPT_manifestinput: case OPT_manifestuac: break; case OPT_implib: case OPT_pdb: case OPT_out: os << arg->getSpelling() << sys::path::filename(arg->getValue()) << "\n"; break; default: os << toString(*arg) << "\n"; } } for (StringRef path : searchPaths) { std::string relPath = relativeToRoot(path); os << "/libpath:" << quote(relPath) << "\n"; } for (StringRef path : filePaths) os << quote(relativeToRoot(path)) << "\n"; return data.str(); } enum class DebugKind { Unknown, None, Full, FastLink, GHash, Dwarf, Symtab }; static DebugKind parseDebugKind(const opt::InputArgList &args) { auto *a = args.getLastArg(OPT_debug, OPT_debug_opt); if (!a) return DebugKind::None; if (a->getNumValues() == 0) return DebugKind::Full; DebugKind debug = StringSwitch(a->getValue()) .CaseLower("none", DebugKind::None) .CaseLower("full", DebugKind::Full) .CaseLower("fastlink", DebugKind::FastLink) // LLD extensions .CaseLower("ghash", DebugKind::GHash) .CaseLower("dwarf", DebugKind::Dwarf) .CaseLower("symtab", DebugKind::Symtab) .Default(DebugKind::Unknown); if (debug == DebugKind::FastLink) { warn("/debug:fastlink unsupported; using /debug:full"); return DebugKind::Full; } if (debug == DebugKind::Unknown) { error("/debug: unknown option: " + Twine(a->getValue())); return DebugKind::None; } return debug; } static unsigned parseDebugTypes(const opt::InputArgList &args) { unsigned debugTypes = static_cast(DebugType::None); if (auto *a = args.getLastArg(OPT_debugtype)) { SmallVector types; StringRef(a->getValue()) .split(types, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false); for (StringRef type : types) { unsigned v = StringSwitch(type.lower()) .Case("cv", static_cast(DebugType::CV)) .Case("pdata", static_cast(DebugType::PData)) .Case("fixup", static_cast(DebugType::Fixup)) .Default(0); if (v == 0) { warn("/debugtype: unknown option '" + type + "'"); continue; } debugTypes |= v; } return debugTypes; } // Default debug types debugTypes = static_cast(DebugType::CV); if (args.hasArg(OPT_driver)) debugTypes |= static_cast(DebugType::PData); if (args.hasArg(OPT_profile)) debugTypes |= static_cast(DebugType::Fixup); return debugTypes; } static std::string getMapFile(const opt::InputArgList &args) { auto *arg = args.getLastArg(OPT_lldmap, OPT_lldmap_file); if (!arg) return ""; if (arg->getOption().getID() == OPT_lldmap_file) return arg->getValue(); assert(arg->getOption().getID() == OPT_lldmap); StringRef outFile = config->outputFile; return (outFile.substr(0, outFile.rfind('.')) + ".map").str(); } static std::string getImplibPath() { if (!config->implib.empty()) return config->implib; SmallString<128> out = StringRef(config->outputFile); sys::path::replace_extension(out, ".lib"); return out.str(); } // // The import name is caculated as the following: // // | LIBRARY w/ ext | LIBRARY w/o ext | no LIBRARY // -----+----------------+---------------------+------------------ // LINK | {value} | {value}.{.dll/.exe} | {output name} // LIB | {value} | {value}.dll | {output name}.dll // static std::string getImportName(bool asLib) { SmallString<128> out; if (config->importName.empty()) { out.assign(sys::path::filename(config->outputFile)); if (asLib) sys::path::replace_extension(out, ".dll"); } else { out.assign(config->importName); if (!sys::path::has_extension(out)) sys::path::replace_extension(out, (config->dll || asLib) ? ".dll" : ".exe"); } return out.str(); } static void createImportLibrary(bool asLib) { std::vector exports; for (Export &e1 : config->exports) { COFFShortExport e2; e2.Name = e1.name; e2.SymbolName = e1.symbolName; e2.ExtName = e1.extName; e2.Ordinal = e1.ordinal; e2.Noname = e1.noname; e2.Data = e1.data; e2.Private = e1.isPrivate; e2.Constant = e1.constant; exports.push_back(e2); } auto handleError = [](Error &&e) { handleAllErrors(std::move(e), [](ErrorInfoBase &eib) { error(eib.message()); }); }; std::string libName = getImportName(asLib); std::string path = getImplibPath(); if (!config->incremental) { handleError(writeImportLibrary(libName, path, exports, config->machine, config->mingw)); return; } // If the import library already exists, replace it only if the contents // have changed. ErrorOr> oldBuf = MemoryBuffer::getFile( path, /*FileSize*/ -1, /*RequiresNullTerminator*/ false); if (!oldBuf) { handleError(writeImportLibrary(libName, path, exports, config->machine, config->mingw)); return; } SmallString<128> tmpName; if (std::error_code ec = sys::fs::createUniqueFile(path + ".tmp-%%%%%%%%.lib", tmpName)) fatal("cannot create temporary file for import library " + path + ": " + ec.message()); if (Error e = writeImportLibrary(libName, tmpName, exports, config->machine, config->mingw)) { handleError(std::move(e)); return; } std::unique_ptr newBuf = check(MemoryBuffer::getFile( tmpName, /*FileSize*/ -1, /*RequiresNullTerminator*/ false)); if ((*oldBuf)->getBuffer() != newBuf->getBuffer()) { oldBuf->reset(); handleError(errorCodeToError(sys::fs::rename(tmpName, path))); } else { sys::fs::remove(tmpName); } } static void parseModuleDefs(StringRef path) { std::unique_ptr mb = CHECK( MemoryBuffer::getFile(path, -1, false, true), "could not open " + path); COFFModuleDefinition m = check(parseCOFFModuleDefinition( mb->getMemBufferRef(), config->machine, config->mingw)); if (config->outputFile.empty()) config->outputFile = saver.save(m.OutputFile); config->importName = saver.save(m.ImportName); if (m.ImageBase) config->imageBase = m.ImageBase; if (m.StackReserve) config->stackReserve = m.StackReserve; if (m.StackCommit) config->stackCommit = m.StackCommit; if (m.HeapReserve) config->heapReserve = m.HeapReserve; if (m.HeapCommit) config->heapCommit = m.HeapCommit; if (m.MajorImageVersion) config->majorImageVersion = m.MajorImageVersion; if (m.MinorImageVersion) config->minorImageVersion = m.MinorImageVersion; if (m.MajorOSVersion) config->majorOSVersion = m.MajorOSVersion; if (m.MinorOSVersion) config->minorOSVersion = m.MinorOSVersion; for (COFFShortExport e1 : m.Exports) { Export e2; // In simple cases, only Name is set. Renamed exports are parsed // and set as "ExtName = Name". If Name has the form "OtherDll.Func", // it shouldn't be a normal exported function but a forward to another // DLL instead. This is supported by both MS and GNU linkers. if (e1.ExtName != e1.Name && StringRef(e1.Name).contains('.')) { e2.name = saver.save(e1.ExtName); e2.forwardTo = saver.save(e1.Name); config->exports.push_back(e2); continue; } e2.name = saver.save(e1.Name); e2.extName = saver.save(e1.ExtName); e2.ordinal = e1.Ordinal; e2.noname = e1.Noname; e2.data = e1.Data; e2.isPrivate = e1.Private; e2.constant = e1.Constant; config->exports.push_back(e2); } } void LinkerDriver::enqueueTask(std::function task) { taskQueue.push_back(std::move(task)); } bool LinkerDriver::run() { ScopedTimer t(inputFileTimer); bool didWork = !taskQueue.empty(); while (!taskQueue.empty()) { taskQueue.front()(); taskQueue.pop_front(); } return didWork; } // Parse an /order file. If an option is given, the linker places // COMDAT sections in the same order as their names appear in the // given file. static void parseOrderFile(StringRef arg) { // For some reason, the MSVC linker requires a filename to be // preceded by "@". if (!arg.startswith("@")) { error("malformed /order option: '@' missing"); return; } // Get a list of all comdat sections for error checking. DenseSet set; for (Chunk *c : symtab->getChunks()) if (auto *sec = dyn_cast(c)) if (sec->sym) set.insert(sec->sym->getName()); // Open a file. StringRef path = arg.substr(1); std::unique_ptr mb = CHECK( MemoryBuffer::getFile(path, -1, false, true), "could not open " + path); // Parse a file. An order file contains one symbol per line. // All symbols that were not present in a given order file are // considered to have the lowest priority 0 and are placed at // end of an output section. for (std::string s : args::getLines(mb->getMemBufferRef())) { if (config->machine == I386 && !isDecorated(s)) s = "_" + s; if (set.count(s) == 0) { if (config->warnMissingOrderSymbol) warn("/order:" + arg + ": missing symbol: " + s + " [LNK4037]"); } else config->order[s] = INT_MIN + config->order.size(); } } static void markAddrsig(Symbol *s) { if (auto *d = dyn_cast_or_null(s)) if (SectionChunk *c = dyn_cast_or_null(d->getChunk())) c->keepUnique = true; } static void findKeepUniqueSections() { // Exported symbols could be address-significant in other executables or DSOs, // so we conservatively mark them as address-significant. for (Export &r : config->exports) markAddrsig(r.sym); // Visit the address-significance table in each object file and mark each // referenced symbol as address-significant. for (ObjFile *obj : ObjFile::instances) { ArrayRef syms = obj->getSymbols(); if (obj->addrsigSec) { ArrayRef contents; cantFail( obj->getCOFFObj()->getSectionContents(obj->addrsigSec, contents)); const uint8_t *cur = contents.begin(); while (cur != contents.end()) { unsigned size; const char *err; uint64_t symIndex = decodeULEB128(cur, &size, contents.end(), &err); if (err) fatal(toString(obj) + ": could not decode addrsig section: " + err); if (symIndex >= syms.size()) fatal(toString(obj) + ": invalid symbol index in addrsig section"); markAddrsig(syms[symIndex]); cur += size; } } else { // If an object file does not have an address-significance table, // conservatively mark all of its symbols as address-significant. for (Symbol *s : syms) markAddrsig(s); } } } // link.exe replaces each %foo% in altPath with the contents of environment // variable foo, and adds the two magic env vars _PDB (expands to the basename // of pdb's output path) and _EXT (expands to the extension of the output // binary). // lld only supports %_PDB% and %_EXT% and warns on references to all other env // vars. static void parsePDBAltPath(StringRef altPath) { SmallString<128> buf; StringRef pdbBasename = sys::path::filename(config->pdbPath, sys::path::Style::windows); StringRef binaryExtension = sys::path::extension(config->outputFile, sys::path::Style::windows); if (!binaryExtension.empty()) binaryExtension = binaryExtension.substr(1); // %_EXT% does not include '.'. // Invariant: // +--------- cursor ('a...' might be the empty string). // | +----- firstMark // | | +- secondMark // v v v // a...%...%... size_t cursor = 0; while (cursor < altPath.size()) { size_t firstMark, secondMark; if ((firstMark = altPath.find('%', cursor)) == StringRef::npos || (secondMark = altPath.find('%', firstMark + 1)) == StringRef::npos) { // Didn't find another full fragment, treat rest of string as literal. buf.append(altPath.substr(cursor)); break; } // Found a full fragment. Append text in front of first %, and interpret // text between first and second % as variable name. buf.append(altPath.substr(cursor, firstMark - cursor)); StringRef var = altPath.substr(firstMark, secondMark - firstMark + 1); if (var.equals_lower("%_pdb%")) buf.append(pdbBasename); else if (var.equals_lower("%_ext%")) buf.append(binaryExtension); else { warn("only %_PDB% and %_EXT% supported in /pdbaltpath:, keeping " + var + " as literal"); buf.append(var); } cursor = secondMark + 1; } config->pdbAltPath = buf; } /// Check that at most one resource obj file was used. /// 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; if (!resourceObjFile) { resourceObjFile = f; continue; } error(toString(f) + ": more than one resource obj file not allowed, already got " + toString(resourceObjFile)); } } // In MinGW, if no symbols are chosen to be exported, then all symbols are // automatically exported by default. This behavior can be forced by the // -export-all-symbols option, so that it happens even when exports are // explicitly specified. The automatic behavior can be disabled using the // -exclude-all-symbols option, so that lld-link behaves like link.exe rather // than MinGW in the case that nothing is explicitly exported. void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) { if (!config->dll) return; if (!args.hasArg(OPT_export_all_symbols)) { if (!config->exports.empty()) return; if (args.hasArg(OPT_exclude_all_symbols)) return; } AutoExporter exporter; for (auto *arg : args.filtered(OPT_wholearchive_file)) if (Optional path = doFindFile(arg->getValue())) exporter.addWholeArchive(*path); symtab->forEachSymbol([&](Symbol *s) { auto *def = dyn_cast(s); if (!exporter.shouldExport(def)) return; Export e; e.name = def->getName(); e.sym = def; if (Chunk *c = def->getChunk()) if (!(c->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) e.data = true; config->exports.push_back(e); }); } void LinkerDriver::link(ArrayRef argsArr) { // Needed for LTO. InitializeAllTargetInfos(); InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmParsers(); InitializeAllAsmPrinters(); // If the first command line argument is "/lib", link.exe acts like lib.exe. // We call our own implementation of lib.exe that understands bitcode files. if (argsArr.size() > 1 && StringRef(argsArr[1]).equals_lower("/lib")) { if (llvm::libDriverMain(argsArr.slice(1)) != 0) fatal("lib failed"); return; } // Parse command line options. ArgParser parser; opt::InputArgList args = parser.parseLINK(argsArr); // Parse and evaluate -mllvm options. std::vector v; v.push_back("lld-link (LLVM option parsing)"); for (auto *arg : args.filtered(OPT_mllvm)) v.push_back(arg->getValue()); cl::ParseCommandLineOptions(v.size(), v.data()); // Handle /errorlimit early, because error() depends on it. if (auto *arg = args.getLastArg(OPT_errorlimit)) { int n = 20; StringRef s = arg->getValue(); if (s.getAsInteger(10, n)) error(arg->getSpelling() + " number expected, but got " + s); errorHandler().errorLimit = n; } // Handle /help if (args.hasArg(OPT_help)) { printHelp(argsArr[0]); return; } lld::threadsEnabled = args.hasFlag(OPT_threads, OPT_threads_no, true); if (args.hasArg(OPT_show_timing)) config->showTiming = true; config->showSummary = args.hasArg(OPT_summary); ScopedTimer t(Timer::root()); // Handle --version, which is an lld extension. This option is a bit odd // because it doesn't start with "/", but we deliberately chose "--" to // avoid conflict with /version and for compatibility with clang-cl. if (args.hasArg(OPT_dash_dash_version)) { outs() << getLLDVersion() << "\n"; return; } // Handle /lldmingw early, since it can potentially affect how other // 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"); Expected> errOrWriter = TarWriter::create(path, "repro"); if (errOrWriter) { tar = std::move(*errOrWriter); } else { error("/linkrepro: failed to open " + path + ": " + toString(errOrWriter.takeError())); } } if (!args.hasArg(OPT_INPUT)) { if (args.hasArg(OPT_deffile)) config->noEntry = true; else fatal("no input files"); } // Construct search path list. searchPaths.push_back(""); for (auto *arg : args.filtered(OPT_libpath)) searchPaths.push_back(arg->getValue()); addLibSearchPaths(); // Handle /ignore for (auto *arg : args.filtered(OPT_ignore)) { SmallVector vec; StringRef(arg->getValue()).split(vec, ','); for (StringRef s : vec) { if (s == "4037") config->warnMissingOrderSymbol = false; else if (s == "4099") config->warnDebugInfoUnusable = false; else if (s == "4217") config->warnLocallyDefinedImported = false; // Other warning numbers are ignored. } } // Handle /out if (auto *arg = args.getLastArg(OPT_out)) config->outputFile = arg->getValue(); // Handle /verbose if (args.hasArg(OPT_verbose)) config->verbose = true; errorHandler().verbose = config->verbose; // Handle /force or /force:unresolved if (args.hasArg(OPT_force, OPT_force_unresolved)) config->forceUnresolved = true; // Handle /force or /force:multiple if (args.hasArg(OPT_force, OPT_force_multiple)) config->forceMultiple = true; // Handle /force or /force:multipleres if (args.hasArg(OPT_force, OPT_force_multipleres)) config->forceMultipleRes = true; // Handle /debug DebugKind debug = parseDebugKind(args); if (debug == DebugKind::Full || debug == DebugKind::Dwarf || debug == DebugKind::GHash) { config->debug = true; config->incremental = true; } // Handle /demangle config->demangle = args.hasFlag(OPT_demangle, OPT_demangle_no); // Handle /debugtype config->debugTypes = parseDebugTypes(args); // Handle /pdb bool shouldCreatePDB = (debug == DebugKind::Full || debug == DebugKind::GHash); if (shouldCreatePDB) { if (auto *arg = args.getLastArg(OPT_pdb)) config->pdbPath = arg->getValue(); if (auto *arg = args.getLastArg(OPT_pdbaltpath)) config->pdbAltPath = arg->getValue(); if (args.hasArg(OPT_natvis)) config->natvisFiles = args.getAllArgValues(OPT_natvis); if (auto *arg = args.getLastArg(OPT_pdb_source_path)) config->pdbSourcePath = arg->getValue(); } // Handle /noentry if (args.hasArg(OPT_noentry)) { if (args.hasArg(OPT_dll)) config->noEntry = true; else error("/noentry must be specified with /dll"); } // Handle /dll if (args.hasArg(OPT_dll)) { config->dll = true; config->manifestID = 2; } // Handle /dynamicbase and /fixed. We can't use hasFlag for /dynamicbase // because we need to explicitly check whether that option or its inverse was // present in the argument list in order to handle /fixed. auto *dynamicBaseArg = args.getLastArg(OPT_dynamicbase, OPT_dynamicbase_no); if (dynamicBaseArg && dynamicBaseArg->getOption().getID() == OPT_dynamicbase_no) config->dynamicBase = false; // MSDN claims "/FIXED:NO is the default setting for a DLL, and /FIXED is the // default setting for any other project type.", but link.exe defaults to // /FIXED:NO for exe outputs as well. Match behavior, not docs. bool fixed = args.hasFlag(OPT_fixed, OPT_fixed_no, false); if (fixed) { if (dynamicBaseArg && dynamicBaseArg->getOption().getID() == OPT_dynamicbase) { error("/fixed must not be specified with /dynamicbase"); } else { config->relocatable = false; config->dynamicBase = false; } } // Handle /appcontainer config->appContainer = args.hasFlag(OPT_appcontainer, OPT_appcontainer_no, false); // Handle /machine if (auto *arg = args.getLastArg(OPT_machine)) { config->machine = getMachineType(arg->getValue()); if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN) fatal(Twine("unknown /machine argument: ") + arg->getValue()); } // Handle /nodefaultlib: for (auto *arg : args.filtered(OPT_nodefaultlib)) config->noDefaultLibs.insert(doFindLib(arg->getValue()).lower()); // Handle /nodefaultlib if (args.hasArg(OPT_nodefaultlib_all)) config->noDefaultLibAll = true; // Handle /base if (auto *arg = args.getLastArg(OPT_base)) parseNumbers(arg->getValue(), &config->imageBase); // Handle /filealign if (auto *arg = args.getLastArg(OPT_filealign)) { parseNumbers(arg->getValue(), &config->fileAlign); if (!isPowerOf2_64(config->fileAlign)) error("/filealign: not a power of two: " + Twine(config->fileAlign)); } // Handle /stack if (auto *arg = args.getLastArg(OPT_stack)) parseNumbers(arg->getValue(), &config->stackReserve, &config->stackCommit); // Handle /guard:cf if (auto *arg = args.getLastArg(OPT_guard)) parseGuard(arg->getValue()); // Handle /heap if (auto *arg = args.getLastArg(OPT_heap)) parseNumbers(arg->getValue(), &config->heapReserve, &config->heapCommit); // Handle /version if (auto *arg = args.getLastArg(OPT_version)) parseVersion(arg->getValue(), &config->majorImageVersion, &config->minorImageVersion); // Handle /subsystem if (auto *arg = args.getLastArg(OPT_subsystem)) parseSubsystem(arg->getValue(), &config->subsystem, &config->majorOSVersion, &config->minorOSVersion); // Handle /timestamp if (llvm::opt::Arg *arg = args.getLastArg(OPT_timestamp, OPT_repro)) { if (arg->getOption().getID() == OPT_repro) { config->timestamp = 0; config->repro = true; } else { config->repro = false; StringRef value(arg->getValue()); if (value.getAsInteger(0, config->timestamp)) fatal(Twine("invalid timestamp: ") + value + ". Expected 32-bit integer"); } } else { config->repro = false; config->timestamp = time(nullptr); } // Handle /alternatename for (auto *arg : args.filtered(OPT_alternatename)) parseAlternateName(arg->getValue()); // Handle /include for (auto *arg : args.filtered(OPT_incl)) addUndefined(arg->getValue()); // Handle /implib if (auto *arg = args.getLastArg(OPT_implib)) config->implib = arg->getValue(); // Handle /opt. bool doGC = debug == DebugKind::None || args.hasArg(OPT_profile); unsigned icfLevel = args.hasArg(OPT_profile) ? 0 : 1; // 0: off, 1: limited, 2: on unsigned tailMerge = 1; for (auto *arg : args.filtered(OPT_opt)) { std::string str = StringRef(arg->getValue()).lower(); SmallVector vec; StringRef(str).split(vec, ','); for (StringRef s : vec) { if (s == "ref") { doGC = true; } else if (s == "noref") { doGC = false; } else if (s == "icf" || s.startswith("icf=")) { icfLevel = 2; } else if (s == "noicf") { icfLevel = 0; } else if (s == "lldtailmerge") { tailMerge = 2; } else if (s == "nolldtailmerge") { tailMerge = 0; } else if (s.startswith("lldlto=")) { StringRef optLevel = s.substr(7); if (optLevel.getAsInteger(10, config->ltoo) || config->ltoo > 3) error("/opt:lldlto: invalid optimization level: " + optLevel); } else if (s.startswith("lldltojobs=")) { StringRef jobs = s.substr(11); if (jobs.getAsInteger(10, config->thinLTOJobs) || config->thinLTOJobs == 0) error("/opt:lldltojobs: invalid job count: " + jobs); } else if (s.startswith("lldltopartitions=")) { StringRef n = s.substr(17); if (n.getAsInteger(10, config->ltoPartitions) || config->ltoPartitions == 0) error("/opt:lldltopartitions: invalid partition count: " + n); } else if (s != "lbr" && s != "nolbr") error("/opt: unknown option: " + s); } } // Limited ICF is enabled if GC is enabled and ICF was never mentioned // explicitly. // FIXME: LLD only implements "limited" ICF, i.e. it only merges identical // code. If the user passes /OPT:ICF explicitly, LLD should merge identical // comdat readonly data. if (icfLevel == 1 && !doGC) icfLevel = 0; config->doGC = doGC; config->doICF = icfLevel > 0; config->tailMerge = (tailMerge == 1 && config->doICF) || tailMerge == 2; // Handle /lldsavetemps if (args.hasArg(OPT_lldsavetemps)) config->saveTemps = true; // Handle /kill-at if (args.hasArg(OPT_kill_at)) config->killAt = true; // Handle /lldltocache if (auto *arg = args.getLastArg(OPT_lldltocache)) config->ltoCache = arg->getValue(); // Handle /lldsavecachepolicy if (auto *arg = args.getLastArg(OPT_lldltocachepolicy)) config->ltoCachePolicy = CHECK( parseCachePruningPolicy(arg->getValue()), Twine("/lldltocachepolicy: invalid cache policy: ") + arg->getValue()); // Handle /failifmismatch for (auto *arg : args.filtered(OPT_failifmismatch)) checkFailIfMismatch(arg->getValue(), nullptr); // Handle /merge for (auto *arg : args.filtered(OPT_merge)) parseMerge(arg->getValue()); // Add default section merging rules after user rules. User rules take // precedence, but we will emit a warning if there is a conflict. parseMerge(".idata=.rdata"); parseMerge(".didat=.rdata"); parseMerge(".edata=.rdata"); parseMerge(".xdata=.rdata"); parseMerge(".bss=.data"); if (config->mingw) { parseMerge(".ctors=.rdata"); parseMerge(".dtors=.rdata"); parseMerge(".CRT=.rdata"); } // Handle /section for (auto *arg : args.filtered(OPT_section)) parseSection(arg->getValue()); // Handle /aligncomm for (auto *arg : args.filtered(OPT_aligncomm)) parseAligncomm(arg->getValue()); // Handle /manifestdependency. This enables /manifest unless /manifest:no is // also passed. if (auto *arg = args.getLastArg(OPT_manifestdependency)) { config->manifestDependency = arg->getValue(); config->manifest = Configuration::SideBySide; } // Handle /manifest and /manifest: if (auto *arg = args.getLastArg(OPT_manifest, OPT_manifest_colon)) { if (arg->getOption().getID() == OPT_manifest) config->manifest = Configuration::SideBySide; else parseManifest(arg->getValue()); } // Handle /manifestuac if (auto *arg = args.getLastArg(OPT_manifestuac)) parseManifestUAC(arg->getValue()); // Handle /manifestfile if (auto *arg = args.getLastArg(OPT_manifestfile)) config->manifestFile = arg->getValue(); // Handle /manifestinput for (auto *arg : args.filtered(OPT_manifestinput)) config->manifestInput.push_back(arg->getValue()); if (!config->manifestInput.empty() && config->manifest != Configuration::Embed) { fatal("/manifestinput: requires /manifest:embed"); } config->thinLTOEmitImportsFiles = args.hasArg(OPT_thinlto_emit_imports_files); config->thinLTOIndexOnly = args.hasArg(OPT_thinlto_index_only) || args.hasArg(OPT_thinlto_index_only_arg); config->thinLTOIndexOnlyArg = args.getLastArgValue(OPT_thinlto_index_only_arg); config->thinLTOPrefixReplace = getOldNewOptions(args, OPT_thinlto_prefix_replace); config->thinLTOObjectSuffixReplace = getOldNewOptions(args, OPT_thinlto_object_suffix_replace); // Handle miscellaneous boolean flags. config->allowBind = args.hasFlag(OPT_allowbind, OPT_allowbind_no, true); config->allowIsolation = args.hasFlag(OPT_allowisolation, OPT_allowisolation_no, true); config->incremental = args.hasFlag(OPT_incremental, OPT_incremental_no, !config->doGC && !config->doICF && !args.hasArg(OPT_order) && !args.hasArg(OPT_profile)); config->integrityCheck = args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false); config->nxCompat = args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true); for (auto *arg : args.filtered(OPT_swaprun)) parseSwaprun(arg->getValue()); config->terminalServerAware = !config->dll && args.hasFlag(OPT_tsaware, OPT_tsaware_no, true); config->debugDwarf = debug == DebugKind::Dwarf; config->debugGHashes = debug == DebugKind::GHash; config->debugSymtab = debug == DebugKind::Symtab; config->mapFile = getMapFile(args); if (config->incremental && args.hasArg(OPT_profile)) { warn("ignoring '/incremental' due to '/profile' specification"); config->incremental = false; } if (config->incremental && args.hasArg(OPT_order)) { warn("ignoring '/incremental' due to '/order' specification"); config->incremental = false; } if (config->incremental && config->doGC) { warn("ignoring '/incremental' because REF is enabled; use '/opt:noref' to " "disable"); config->incremental = false; } if (config->incremental && config->doICF) { warn("ignoring '/incremental' because ICF is enabled; use '/opt:noicf' to " "disable"); config->incremental = false; } if (errorCount()) return; std::set wholeArchives; for (auto *arg : args.filtered(OPT_wholearchive_file)) if (Optional path = doFindFile(arg->getValue())) if (Optional id = getUniqueID(*path)) wholeArchives.insert(*id); // A predicate returning true if a given path is an argument for // /wholearchive:, or /wholearchive is enabled globally. // This function is a bit tricky because "foo.obj /wholearchive:././foo.obj" // needs to be handled as "/wholearchive:foo.obj foo.obj". auto isWholeArchive = [&](StringRef path) -> bool { if (args.hasArg(OPT_wholearchive_flag)) return true; if (Optional id = getUniqueID(path)) return wholeArchives.count(*id); 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 path = findFile(arg->getValue())) enqueuePath(*path, isWholeArchive(*path)); for (auto *arg : args.filtered(OPT_defaultlib)) if (Optional path = findLib(arg->getValue())) enqueuePath(*path, false); // Windows specific -- Create a resource file containing a manifest file. if (config->manifest == Configuration::Embed) addBuffer(createManifestRes(), false); // Read all input files given via the command line. run(); if (errorCount()) return; // We should have inferred a machine type by now from the input files, but if // not we assume x64. if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN) { warn("/machine is not specified. x64 is assumed"); config->machine = AMD64; } config->wordsize = config->is64() ? 8 : 4; // Handle /safeseh, x86 only, on by default, except for mingw. if (config->machine == I386 && args.hasFlag(OPT_safeseh, OPT_safeseh_no, !config->mingw)) config->safeSEH = true; // Handle /functionpadmin 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(convertResToCOFF(resources))); if (tar) tar->append("response.txt", createResponseFile(args, filePaths, ArrayRef(searchPaths).slice(1))); // Handle /largeaddressaware config->largeAddressAware = args.hasFlag( OPT_largeaddressaware, OPT_largeaddressaware_no, config->is64()); // Handle /highentropyva config->highEntropyVA = config->is64() && args.hasFlag(OPT_highentropyva, OPT_highentropyva_no, true); if (!config->dynamicBase && (config->machine == ARMNT || config->machine == ARM64)) error("/dynamicbase:no is not compatible with " + machineToStr(config->machine)); // Handle /export for (auto *arg : args.filtered(OPT_export)) { Export e = parseExport(arg->getValue()); if (config->machine == I386) { if (!isDecorated(e.name)) e.name = saver.save("_" + e.name); if (!e.extName.empty() && !isDecorated(e.extName)) e.extName = saver.save("_" + e.extName); } config->exports.push_back(e); } // Handle /def if (auto *arg = args.getLastArg(OPT_deffile)) { // parseModuleDefs mutates Config object. parseModuleDefs(arg->getValue()); } // Handle generation of import library from a def file. if (!args.hasArg(OPT_INPUT)) { fixupExports(); createImportLibrary(/*asLib=*/true); return; } // Windows specific -- if no /subsystem is given, we need to infer // that from entry point name. Must happen before /entry handling, // and after the early return when just writing an import library. if (config->subsystem == IMAGE_SUBSYSTEM_UNKNOWN) { config->subsystem = inferSubsystem(); if (config->subsystem == IMAGE_SUBSYSTEM_UNKNOWN) fatal("subsystem must be defined"); } // Handle /entry and /dll if (auto *arg = args.getLastArg(OPT_entry)) { config->entry = addUndefined(mangle(arg->getValue())); } else if (!config->entry && !config->noEntry) { if (args.hasArg(OPT_dll)) { StringRef s = (config->machine == I386) ? "__DllMainCRTStartup@12" : "_DllMainCRTStartup"; config->entry = addUndefined(s); } else { // Windows specific -- If entry point name is not given, we need to // infer that from user-defined entry name. StringRef s = findDefaultEntry(); if (s.empty()) fatal("entry point must be defined"); config->entry = addUndefined(s); log("Entry name inferred: " + s); } } // Handle /delayload for (auto *arg : args.filtered(OPT_delayload)) { config->delayLoads.insert(StringRef(arg->getValue()).lower()); if (config->machine == I386) { config->delayLoadHelper = addUndefined("___delayLoadHelper2@8"); } else { config->delayLoadHelper = addUndefined("__delayLoadHelper2"); } } // Set default image name if neither /out or /def set it. if (config->outputFile.empty()) { config->outputFile = getOutputPath((*args.filtered(OPT_INPUT).begin())->getValue()); } // Fail early if an output file is not writable. if (auto e = tryCreateFile(config->outputFile)) { error("cannot open output file " + config->outputFile + ": " + e.message()); return; } if (shouldCreatePDB) { // Put the PDB next to the image if no /pdb flag was passed. if (config->pdbPath.empty()) { config->pdbPath = config->outputFile; sys::path::replace_extension(config->pdbPath, ".pdb"); } // The embedded PDB path should be the absolute path to the PDB if no // /pdbaltpath flag was passed. if (config->pdbAltPath.empty()) { config->pdbAltPath = config->pdbPath; // It's important to make the path absolute and remove dots. This path // will eventually be written into the PE header, and certain Microsoft // tools won't work correctly if these assumptions are not held. sys::fs::make_absolute(config->pdbAltPath); sys::path::remove_dots(config->pdbAltPath); } else { // Don't do this earlier, so that Config->OutputFile is ready. parsePDBAltPath(config->pdbAltPath); } } // Set default image base if /base is not given. if (config->imageBase == uint64_t(-1)) config->imageBase = getDefaultImageBase(); symtab->addSynthetic(mangle("__ImageBase"), nullptr); if (config->machine == I386) { symtab->addAbsolute("___safe_se_handler_table", 0); symtab->addAbsolute("___safe_se_handler_count", 0); } symtab->addAbsolute(mangle("__guard_fids_count"), 0); symtab->addAbsolute(mangle("__guard_fids_table"), 0); symtab->addAbsolute(mangle("__guard_flags"), 0); symtab->addAbsolute(mangle("__guard_iat_count"), 0); symtab->addAbsolute(mangle("__guard_iat_table"), 0); symtab->addAbsolute(mangle("__guard_longjmp_count"), 0); symtab->addAbsolute(mangle("__guard_longjmp_table"), 0); // Needed for MSVC 2017 15.5 CRT. symtab->addAbsolute(mangle("__enclave_config"), 0); if (config->mingw) { symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0); symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0); symtab->addAbsolute(mangle("__CTOR_LIST__"), 0); symtab->addAbsolute(mangle("__DTOR_LIST__"), 0); } // This code may add new undefined symbols to the link, which may enqueue more // symbol resolution tasks, so we need to continue executing tasks until we // converge. do { // Windows specific -- if entry point is not found, // search for its mangled names. if (config->entry) mangleMaybe(config->entry); // Windows specific -- Make sure we resolve all dllexported symbols. for (Export &e : config->exports) { if (!e.forwardTo.empty()) continue; e.sym = addUndefined(e.name); if (!e.directives) e.symbolName = mangleMaybe(e.sym); } // Add weak aliases. Weak aliases is a mechanism to give remaining // undefined symbols final chance to be resolved successfully. for (auto pair : config->alternateNames) { StringRef from = pair.first; StringRef to = pair.second; Symbol *sym = symtab->find(from); if (!sym) continue; if (auto *u = dyn_cast(sym)) if (!u->weakAlias) u->weakAlias = symtab->addUndefined(to); } // Windows specific -- if __load_config_used can be resolved, resolve it. if (symtab->findUnderscore("_load_config_used")) 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(symtab->find(arg->getValue()))) addUndefined(arg->getValue()); while (run()); } if (config->mingw) { // Load any further object files that might be needed for doing automatic // imports. // // For cases with no automatically imported symbols, this iterates once // over the symbol table and doesn't do anything. // // For the normal case with a few automatically imported symbols, this // should only need to be run once, since each new object file imported // is an import library and wouldn't add any new undefined references, // but there's nothing stopping the __imp_ symbols from coming from a // normal object file as well (although that won't be used for the // actual autoimport later on). If this pass adds new undefined references, // we won't iterate further to resolve them. symtab->loadMinGWAutomaticImports(); run(); } // Make sure we have resolved all symbols. symtab->reportRemainingUndefines(); if (errorCount()) return; if (config->mingw) { // In MinGW, all symbols are automatically exported if no symbols // are chosen to be exported. maybeExportMinGWSymbols(args); // Make sure the crtend.o object is the last object file. This object // file can contain terminating section chunks that need to be placed // last. GNU ld processes files and static libraries explicitly in the // order provided on the command line, while lld will pull in needed // files from static libraries only after the last object file on the // command line. for (auto i = ObjFile::instances.begin(), e = ObjFile::instances.end(); i != e; i++) { ObjFile *file = *i; if (isCrtend(file->getName())) { ObjFile::instances.erase(i); ObjFile::instances.push_back(file); break; } } } // Windows specific -- when we are creating a .dll file, we also // need to create a .lib file. if (!config->exports.empty() || config->dll) { fixupExports(); createImportLibrary(/*asLib=*/false); assignExportOrdinals(); } // Handle /output-def (MinGW specific). if (auto *arg = args.getLastArg(OPT_output_def)) writeDefFile(arg->getValue()); // Set extra alignment for .comm symbols for (auto pair : config->alignComm) { StringRef name = pair.first; uint32_t alignment = pair.second; Symbol *sym = symtab->find(name); if (!sym) { warn("/aligncomm symbol " + name + " not found"); continue; } // If the symbol isn't common, it must have been replaced with a regular // symbol, which will carry its own alignment. auto *dc = dyn_cast(sym); if (!dc) continue; CommonChunk *c = dc->getChunk(); c->setAlignment(std::max(c->getAlignment(), alignment)); } // Windows specific -- Create a side-by-side manifest file. if (config->manifest == Configuration::SideBySide) createSideBySideManifest(); // Handle /order. We want to do this at this moment because we // need a complete list of comdat sections to warn on nonexistent // functions. if (auto *arg = args.getLastArg(OPT_order)) parseOrderFile(arg->getValue()); // Identify unreferenced COMDAT sections. if (config->doGC) markLive(symtab->getChunks()); // Needs to happen after the last call to addFile(). diagnoseMultipleResourceObjFiles(); // Identify identical COMDAT sections to merge them. if (config->doICF) { findKeepUniqueSections(); doICF(symtab->getChunks()); } // Write the result. writeResult(); // Stop early so we can print the results. Timer::root().stop(); if (config->showTiming) Timer::root().print(); } } // namespace coff } // namespace lld Index: vendor/lld/dist-release_90/COFF/Writer.cpp =================================================================== --- vendor/lld/dist-release_90/COFF/Writer.cpp (revision 351311) +++ vendor/lld/dist-release_90/COFF/Writer.cpp (revision 351312) @@ -1,1901 +1,1927 @@ //===- Writer.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 "Writer.h" #include "Config.h" #include "DLL.h" #include "InputFiles.h" #include "MapFile.h" #include "PDB.h" #include "SymbolTable.h" #include "Symbols.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" #include "lld/Common/Threads.h" #include "lld/Common/Timer.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/Parallel.h" #include "llvm/Support/Path.h" #include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Support/xxhash.h" #include #include #include #include #include using namespace llvm; using namespace llvm::COFF; using namespace llvm::object; using namespace llvm::support; using namespace llvm::support::endian; using namespace lld; using namespace lld::coff; /* To re-generate DOSProgram: $ cat > /tmp/DOSProgram.asm org 0 ; Copy cs to ds. push cs pop ds ; Point ds:dx at the $-terminated string. mov dx, str ; Int 21/AH=09h: Write string to standard output. mov ah, 0x9 int 0x21 ; Int 21/AH=4Ch: Exit with return code (in AL). mov ax, 0x4C01 int 0x21 str: db 'This program cannot be run in DOS mode.$' align 8, db 0 $ nasm -fbin /tmp/DOSProgram.asm -o /tmp/DOSProgram.bin $ xxd -i /tmp/DOSProgram.bin */ static unsigned char dosProgram[] = { 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x24, 0x00, 0x00 }; static_assert(sizeof(dosProgram) % 8 == 0, "DOSProgram size must be multiple of 8"); static const int dosStubSize = sizeof(dos_header) + sizeof(dosProgram); static_assert(dosStubSize % 8 == 0, "DOSStub size must be multiple of 8"); static const int numberOfDataDirectory = 16; // Global vector of all output sections. After output sections are finalized, // this can be indexed by Chunk::getOutputSection. static std::vector outputSections; OutputSection *Chunk::getOutputSection() const { return osidx == 0 ? nullptr : outputSections[osidx - 1]; } namespace { class DebugDirectoryChunk : public NonSectionChunk { public: DebugDirectoryChunk(const std::vector &r, bool writeRepro) : records(r), writeRepro(writeRepro) {} size_t getSize() const override { return (records.size() + int(writeRepro)) * sizeof(debug_directory); } void writeTo(uint8_t *b) const override { auto *d = reinterpret_cast(b); for (const Chunk *record : records) { OutputSection *os = record->getOutputSection(); uint64_t offs = os->getFileOff() + (record->getRVA() - os->getRVA()); fillEntry(d, COFF::IMAGE_DEBUG_TYPE_CODEVIEW, record->getSize(), record->getRVA(), offs); ++d; } if (writeRepro) { // FIXME: The COFF spec allows either a 0-sized entry to just say // "the timestamp field is really a hash", or a 4-byte size field // followed by that many bytes containing a longer hash (with the // lowest 4 bytes usually being the timestamp in little-endian order). // Consider storing the full 8 bytes computed by xxHash64 here. fillEntry(d, COFF::IMAGE_DEBUG_TYPE_REPRO, 0, 0, 0); } } void setTimeDateStamp(uint32_t timeDateStamp) { for (support::ulittle32_t *tds : timeDateStamps) *tds = timeDateStamp; } private: void fillEntry(debug_directory *d, COFF::DebugType debugType, size_t size, uint64_t rva, uint64_t offs) const { d->Characteristics = 0; d->TimeDateStamp = 0; d->MajorVersion = 0; d->MinorVersion = 0; d->Type = debugType; d->SizeOfData = size; d->AddressOfRawData = rva; d->PointerToRawData = offs; timeDateStamps.push_back(&d->TimeDateStamp); } mutable std::vector timeDateStamps; const std::vector &records; bool writeRepro; }; class CVDebugRecordChunk : public NonSectionChunk { public: size_t getSize() const override { return sizeof(codeview::DebugInfo) + config->pdbAltPath.size() + 1; } void writeTo(uint8_t *b) const override { // Save off the DebugInfo entry to backfill the file signature (build id) // in Writer::writeBuildId buildId = reinterpret_cast(b); // variable sized field (PDB Path) char *p = reinterpret_cast(b + sizeof(*buildId)); if (!config->pdbAltPath.empty()) memcpy(p, config->pdbAltPath.data(), config->pdbAltPath.size()); p[config->pdbAltPath.size()] = '\0'; } mutable codeview::DebugInfo *buildId = nullptr; }; // PartialSection represents a group of chunks that contribute to an // OutputSection. Collating a collection of PartialSections of same name and // characteristics constitutes the OutputSection. class PartialSectionKey { public: StringRef name; unsigned characteristics; bool operator<(const PartialSectionKey &other) const { int c = name.compare(other.name); if (c == 1) return false; if (c == 0) return characteristics < other.characteristics; return true; } }; // The writer writes a SymbolTable result to a file. class Writer { public: Writer() : buffer(errorHandler().outputBuffer) {} void run(); private: void createSections(); void createMiscChunks(); void createImportTables(); void appendImportThunks(); void locateImportTables(); void createExportTable(); void mergeSections(); void removeUnusedSections(); void assignAddresses(); void finalizeAddresses(); void removeEmptySections(); void assignOutputSectionIndices(); void createSymbolAndStringTable(); void openFile(StringRef outputPath); template void writeHeader(); void createSEHTable(); void createRuntimePseudoRelocs(); void insertCtorDtorSymbols(); void createGuardCFTables(); void markSymbolsForRVATable(ObjFile *file, ArrayRef symIdxChunks, SymbolRVASet &tableSymbols); void maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym, StringRef countSym); void setSectionPermissions(); void writeSections(); void writeBuildId(); void sortExceptionTable(); void sortCRTSectionChunks(std::vector &chunks); void addSyntheticIdata(); void fixPartialSectionChars(StringRef name, uint32_t chars); bool fixGnuImportChunks(); PartialSection *createPartialSection(StringRef name, uint32_t outChars); PartialSection *findPartialSection(StringRef name, uint32_t outChars); llvm::Optional createSymbol(Defined *d); size_t addEntryToStringTable(StringRef str); OutputSection *findSection(StringRef name); void addBaserels(); void addBaserelBlocks(std::vector &v); uint32_t getSizeOfInitializedData(); std::unique_ptr &buffer; std::map partialSections; std::vector strtab; std::vector outputSymtab; IdataContents idata; Chunk *importTableStart = nullptr; uint64_t importTableSize = 0; Chunk *iatStart = nullptr; uint64_t iatSize = 0; DelayLoadContents delayIdata; EdataContents edata; bool setNoSEHCharacteristic = false; DebugDirectoryChunk *debugDirectory = nullptr; std::vector debugRecords; CVDebugRecordChunk *buildId = nullptr; ArrayRef sectionTable; uint64_t fileSize; uint32_t pointerToSymbolTable = 0; uint64_t sizeOfImage; uint64_t sizeOfHeaders; OutputSection *textSec; OutputSection *rdataSec; OutputSection *buildidSec; OutputSection *dataSec; OutputSection *pdataSec; OutputSection *idataSec; OutputSection *edataSec; OutputSection *didatSec; OutputSection *rsrcSec; OutputSection *relocSec; OutputSection *ctorsSec; OutputSection *dtorsSec; // The first and last .pdata sections in the output file. // // We need to keep track of the location of .pdata in whichever section it // gets merged into so that we can sort its contents and emit a correct data // directory entry for the exception table. This is also the case for some // other sections (such as .edata) but because the contents of those sections // are entirely linker-generated we can keep track of their locations using // the chunks that the linker creates. All .pdata chunks come from input // files, so we need to keep track of them separately. Chunk *firstPdata = nullptr; Chunk *lastPdata; }; } // anonymous namespace namespace lld { namespace coff { static Timer codeLayoutTimer("Code Layout", Timer::root()); static Timer diskCommitTimer("Commit Output File", Timer::root()); void writeResult() { Writer().run(); } void OutputSection::addChunk(Chunk *c) { chunks.push_back(c); } void OutputSection::insertChunkAtStart(Chunk *c) { chunks.insert(chunks.begin(), c); } void OutputSection::setPermissions(uint32_t c) { header.Characteristics &= ~permMask; header.Characteristics |= c; } void OutputSection::merge(OutputSection *other) { chunks.insert(chunks.end(), other->chunks.begin(), other->chunks.end()); other->chunks.clear(); contribSections.insert(contribSections.end(), other->contribSections.begin(), other->contribSections.end()); other->contribSections.clear(); } // Write the section header to a given buffer. void OutputSection::writeHeaderTo(uint8_t *buf) { auto *hdr = reinterpret_cast(buf); *hdr = header; if (stringTableOff) { // If name is too long, write offset into the string table as a name. sprintf(hdr->Name, "/%d", stringTableOff); } else { assert(!config->debug || name.size() <= COFF::NameSize || (hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0); strncpy(hdr->Name, name.data(), std::min(name.size(), (size_t)COFF::NameSize)); } } 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) { if (config->machine == ARMNT) { int64_t diff = AbsoluteDifference(s, p + 4) + margin; switch (relType) { case IMAGE_REL_ARM_BRANCH20T: return isInt<21>(diff); case IMAGE_REL_ARM_BRANCH24T: case IMAGE_REL_ARM_BLX23T: return isInt<25>(diff); default: return true; } } else if (config->machine == ARM64) { int64_t diff = AbsoluteDifference(s, p) + margin; switch (relType) { case IMAGE_REL_ARM64_BRANCH26: return isInt<28>(diff); case IMAGE_REL_ARM64_BRANCH19: return isInt<21>(diff); case IMAGE_REL_ARM64_BRANCH14: return isInt<16>(diff); default: return true; } } else { llvm_unreachable("Unexpected architecture"); } } // Return the last thunk for the given target if it is in range, // or create a new one. static std::pair getThunk(DenseMap &lastThunks, Defined *target, uint64_t p, uint16_t type, int margin) { Defined *&lastThunk = lastThunks[target->getRVA()]; if (lastThunk && isInRange(type, lastThunk->getRVA(), p, margin)) return {lastThunk, false}; Chunk *c; switch (config->machine) { case ARMNT: c = make(target); break; case ARM64: c = make(target); break; default: llvm_unreachable("Unexpected architecture"); } Defined *d = make("", c); lastThunk = d; return {d, true}; } // This checks all relocations, and for any relocation which isn't in range // it adds a thunk after the section chunk that contains the relocation. // If the latest thunk for the specific target is in range, that is used // instead of creating a new thunk. All range checks are done with the // specified margin, to make sure that relocations that originally are in // range, but only barely, also get thunks - in case other added thunks makes // the target go out of range. // // After adding thunks, we verify that all relocations are in range (with // no extra margin requirements). If this failed, we restart (throwing away // the previously created thunks) and retry with a wider margin. static bool createThunks(OutputSection *os, int margin) { bool addressesChanged = false; DenseMap lastThunks; DenseMap, uint32_t> thunkSymtabIndices; size_t thunksSize = 0; // Recheck Chunks.size() each iteration, since we can insert more // elements into it. for (size_t i = 0; i != os->chunks.size(); ++i) { SectionChunk *sc = dyn_cast_or_null(os->chunks[i]); if (!sc) continue; size_t thunkInsertionSpot = i + 1; // Try to get a good enough estimate of where new thunks will be placed. // Offset this by the size of the new thunks added so far, to make the // estimate slightly better. size_t thunkInsertionRVA = sc->getRVA() + sc->getSize() + thunksSize; ObjFile *file = sc->file; std::vector> relocReplacements; ArrayRef originalRelocs = file->getCOFFObj()->getRelocations(sc->header); for (size_t j = 0, e = originalRelocs.size(); j < e; ++j) { const coff_relocation &rel = originalRelocs[j]; Symbol *relocTarget = file->getSymbol(rel.SymbolTableIndex); // The estimate of the source address P should be pretty accurate, // but we don't know whether the target Symbol address should be // offset by thunksSize or not (or by some of thunksSize but not all of // it), giving us some uncertainty once we have added one thunk. uint64_t p = sc->getRVA() + rel.VirtualAddress + thunksSize; Defined *sym = dyn_cast_or_null(relocTarget); if (!sym) continue; uint64_t s = sym->getRVA(); if (isInRange(rel.Type, s, p, margin)) continue; // If the target isn't in range, hook it up to an existing or new // thunk. Defined *thunk; bool wasNew; std::tie(thunk, wasNew) = getThunk(lastThunks, sym, p, rel.Type, margin); if (wasNew) { Chunk *thunkChunk = thunk->getChunk(); thunkChunk->setRVA( thunkInsertionRVA); // Estimate of where it will be located. os->chunks.insert(os->chunks.begin() + thunkInsertionSpot, thunkChunk); thunkInsertionSpot++; thunksSize += thunkChunk->getSize(); thunkInsertionRVA += thunkChunk->getSize(); addressesChanged = true; } // To redirect the relocation, add a symbol to the parent object file's // symbol table, and replace the relocation symbol table index with the // new index. auto insertion = thunkSymtabIndices.insert({{file, thunk}, ~0U}); uint32_t &thunkSymbolIndex = insertion.first->second; if (insertion.second) thunkSymbolIndex = file->addRangeThunkSymbol(thunk); relocReplacements.push_back({j, thunkSymbolIndex}); } // Get a writable copy of this section's relocations so they can be // modified. If the relocations point into the object file, allocate new // memory. Otherwise, this must be previously allocated memory that can be // modified in place. ArrayRef curRelocs = sc->getRelocs(); MutableArrayRef newRelocs; if (originalRelocs.data() == curRelocs.data()) { newRelocs = makeMutableArrayRef( bAlloc.Allocate(originalRelocs.size()), originalRelocs.size()); } else { newRelocs = makeMutableArrayRef( const_cast(curRelocs.data()), curRelocs.size()); } // Copy each relocation, but replace the symbol table indices which need // thunks. auto nextReplacement = relocReplacements.begin(); auto endReplacement = relocReplacements.end(); for (size_t i = 0, e = originalRelocs.size(); i != e; ++i) { newRelocs[i] = originalRelocs[i]; if (nextReplacement != endReplacement && nextReplacement->first == i) { newRelocs[i].SymbolTableIndex = nextReplacement->second; ++nextReplacement; } } sc->setRelocs(newRelocs); } return addressesChanged; } // Verify that all relocations are in range, with no extra margin requirements. static bool verifyRanges(const std::vector chunks) { for (Chunk *c : chunks) { SectionChunk *sc = dyn_cast_or_null(c); if (!sc) continue; ArrayRef relocs = sc->getRelocs(); for (size_t j = 0, e = relocs.size(); j < e; ++j) { const coff_relocation &rel = relocs[j]; Symbol *relocTarget = sc->file->getSymbol(rel.SymbolTableIndex); Defined *sym = dyn_cast_or_null(relocTarget); if (!sym) continue; uint64_t p = sc->getRVA() + rel.VirtualAddress; uint64_t s = sym->getRVA(); if (!isInRange(rel.Type, s, p, 0)) return false; } } return true; } // Assign addresses and add thunks if necessary. void Writer::finalizeAddresses() { assignAddresses(); if (config->machine != ARMNT && config->machine != ARM64) return; size_t origNumChunks = 0; for (OutputSection *sec : outputSections) { sec->origChunks = sec->chunks; origNumChunks += sec->chunks.size(); } int pass = 0; int margin = 1024 * 100; while (true) { // First check whether we need thunks at all, or if the previous pass of // adding them turned out ok. bool rangesOk = true; size_t numChunks = 0; for (OutputSection *sec : outputSections) { if (!verifyRanges(sec->chunks)) { rangesOk = false; break; } numChunks += sec->chunks.size(); } if (rangesOk) { if (pass > 0) log("Added " + Twine(numChunks - origNumChunks) + " thunks with " + "margin " + Twine(margin) + " in " + Twine(pass) + " passes"); return; } if (pass >= 10) fatal("adding thunks hasn't converged after " + Twine(pass) + " passes"); if (pass > 0) { // If the previous pass didn't work out, reset everything back to the // original conditions before retrying with a wider margin. This should // ideally never happen under real circumstances. for (OutputSection *sec : outputSections) sec->chunks = sec->origChunks; margin *= 2; } // Try adding thunks everywhere where it is needed, with a margin // to avoid things going out of range due to the added thunks. bool addressesChanged = false; for (OutputSection *sec : outputSections) addressesChanged |= createThunks(sec, margin); // If the verification above thought we needed thunks, we should have // added some. assert(addressesChanged); // Recalculate the layout for the whole image (and verify the ranges at // the start of the next round). assignAddresses(); pass++; } } // The main function of the writer. void Writer::run() { ScopedTimer t1(codeLayoutTimer); createImportTables(); createSections(); createMiscChunks(); appendImportThunks(); createExportTable(); mergeSections(); removeUnusedSections(); finalizeAddresses(); removeEmptySections(); assignOutputSectionIndices(); setSectionPermissions(); createSymbolAndStringTable(); if (fileSize > UINT32_MAX) fatal("image size (" + Twine(fileSize) + ") " + "exceeds maximum allowable size (" + Twine(UINT32_MAX) + ")"); openFile(config->outputFile); if (config->is64()) { writeHeader(); } else { writeHeader(); } writeSections(); sortExceptionTable(); t1.stop(); if (!config->pdbPath.empty() && config->debug) { assert(buildId); createPDB(symtab, outputSections, sectionTable, buildId->buildId); } writeBuildId(); writeMapFile(outputSections); ScopedTimer t2(diskCommitTimer); if (auto e = buffer->commit()) fatal("failed to write the output file: " + toString(std::move(e))); } static StringRef getOutputSectionName(StringRef name) { StringRef s = name.split('$').first; // Treat a later period as a separator for MinGW, for sections like // ".ctors.01234". return s.substr(0, s.find('.', 1)); } // For /order. static void sortBySectionOrder(std::vector &chunks) { auto getPriority = [](const Chunk *c) { if (auto *sec = dyn_cast(c)) if (sec->sym) return config->order.lookup(sec->sym->getName()); return 0; }; llvm::stable_sort(chunks, [=](const Chunk *a, const Chunk *b) { return getPriority(a) < getPriority(b); }); } // Change the characteristics of existing PartialSections that belong to the // section Name to Chars. void Writer::fixPartialSectionChars(StringRef name, uint32_t chars) { for (auto it : partialSections) { PartialSection *pSec = it.second; StringRef curName = pSec->name; if (!curName.consume_front(name) || (!curName.empty() && !curName.startswith("$"))) continue; if (pSec->characteristics == chars) continue; PartialSection *destSec = createPartialSection(pSec->name, chars); destSec->chunks.insert(destSec->chunks.end(), pSec->chunks.begin(), pSec->chunks.end()); pSec->chunks.clear(); } } // Sort concrete section chunks from GNU import libraries. // // GNU binutils doesn't use short import files, but instead produces import // libraries that consist of object files, with section chunks for the .idata$* // sections. These are linked just as regular static libraries. Each import // library consists of one header object, one object file for every imported // symbol, and one trailer object. In order for the .idata tables/lists to // be formed correctly, the section chunks within each .idata$* section need // to be grouped by library, and sorted alphabetically within each library // (which makes sure the header comes first and the trailer last). bool Writer::fixGnuImportChunks() { uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; // Make sure all .idata$* section chunks are mapped as RDATA in order to // be sorted into the same sections as our own synthesized .idata chunks. fixPartialSectionChars(".idata", rdata); bool hasIdata = false; // Sort all .idata$* chunks, grouping chunks from the same library, // with alphabetical ordering of the object fils within a library. for (auto it : partialSections) { PartialSection *pSec = it.second; if (!pSec->name.startswith(".idata")) continue; if (!pSec->chunks.empty()) hasIdata = true; llvm::stable_sort(pSec->chunks, [&](Chunk *s, Chunk *t) { SectionChunk *sc1 = dyn_cast_or_null(s); SectionChunk *sc2 = dyn_cast_or_null(t); if (!sc1 || !sc2) { // if SC1, order them ascending. If SC2 or both null, // S is not less than T. return sc1 != nullptr; } // Make a string with "libraryname/objectfile" for sorting, achieving // both grouping by library and sorting of objects within a library, // at once. std::string key1 = (sc1->file->parentName + "/" + sc1->file->getName()).str(); std::string key2 = (sc2->file->parentName + "/" + sc2->file->getName()).str(); return key1 < key2; }); } return hasIdata; } // Add generated idata chunks, for imported symbols and DLLs, and a // terminator in .idata$2. void Writer::addSyntheticIdata() { uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; idata.create(); // Add the .idata content in the right section groups, to allow // chunks from other linked in object files to be grouped together. // See Microsoft PE/COFF spec 5.4 for details. auto add = [&](StringRef n, std::vector &v) { PartialSection *pSec = createPartialSection(n, rdata); pSec->chunks.insert(pSec->chunks.end(), v.begin(), v.end()); }; // The loader assumes a specific order of data. // Add each type in the correct order. add(".idata$2", idata.dirs); add(".idata$4", idata.lookups); add(".idata$5", idata.addresses); add(".idata$6", idata.hints); add(".idata$7", idata.dllNames); } // Locate the first Chunk and size of the import directory list and the // IAT. void Writer::locateImportTables() { uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; if (PartialSection *importDirs = findPartialSection(".idata$2", rdata)) { if (!importDirs->chunks.empty()) importTableStart = importDirs->chunks.front(); for (Chunk *c : importDirs->chunks) importTableSize += c->getSize(); } if (PartialSection *importAddresses = findPartialSection(".idata$5", rdata)) { if (!importAddresses->chunks.empty()) iatStart = importAddresses->chunks.front(); for (Chunk *c : importAddresses->chunks) iatSize += c->getSize(); } } +// Return whether a SectionChunk's suffix (the dollar and any trailing +// suffix) should be removed and sorted into the main suffixless +// PartialSection. +static bool shouldStripSectionSuffix(SectionChunk *sc, StringRef name) { + // On MinGW, comdat groups are formed by putting the comdat group name + // after the '$' in the section name. For .eh_frame$, that must + // still be sorted before the .eh_frame trailer from crtend.o, thus just + // strip the section name trailer. For other sections, such as + // .tls$$ (where non-comdat .tls symbols are otherwise stored in + // ".tls$"), they must be strictly sorted after .tls. And for the + // hypothetical case of comdat .CRT$XCU, we definitely need to keep the + // suffix for sorting. Thus, to play it safe, only strip the suffix for + // the standard sections. + if (!config->mingw) + return false; + if (!sc || !sc->isCOMDAT()) + return false; + return name.startswith(".text$") || name.startswith(".data$") || + name.startswith(".rdata$") || name.startswith(".pdata$") || + name.startswith(".xdata$") || name.startswith(".eh_frame$"); +} + // Create output section objects and add them to OutputSections. void Writer::createSections() { // First, create the builtin sections. const uint32_t data = IMAGE_SCN_CNT_INITIALIZED_DATA; const uint32_t bss = IMAGE_SCN_CNT_UNINITIALIZED_DATA; const uint32_t code = IMAGE_SCN_CNT_CODE; const uint32_t discardable = IMAGE_SCN_MEM_DISCARDABLE; const uint32_t r = IMAGE_SCN_MEM_READ; const uint32_t w = IMAGE_SCN_MEM_WRITE; const uint32_t x = IMAGE_SCN_MEM_EXECUTE; SmallDenseMap, OutputSection *> sections; auto createSection = [&](StringRef name, uint32_t outChars) { OutputSection *&sec = sections[{name, outChars}]; if (!sec) { sec = make(name, outChars); outputSections.push_back(sec); } return sec; }; // Try to match the section order used by link.exe. textSec = createSection(".text", code | r | x); createSection(".bss", bss | r | w); rdataSec = createSection(".rdata", data | r); buildidSec = createSection(".buildid", data | r); dataSec = createSection(".data", data | r | w); pdataSec = createSection(".pdata", data | r); idataSec = createSection(".idata", data | r); edataSec = createSection(".edata", data | r); didatSec = createSection(".didat", data | r); rsrcSec = createSection(".rsrc", data | r); relocSec = createSection(".reloc", data | discardable | r); ctorsSec = createSection(".ctors", data | r | w); dtorsSec = createSection(".dtors", data | r | w); // Then bin chunks by name and output characteristics. for (Chunk *c : symtab->getChunks()) { auto *sc = dyn_cast(c); if (sc && !sc->live) { if (config->verbose) sc->printDiscardedMessage(); continue; } StringRef name = c->getSectionName(); - // On MinGW, comdat groups are formed by putting the comdat group name - // after the '$' in the section name. Such a section name suffix shouldn't - // imply separate alphabetical sorting of those section chunks though. - if (config->mingw && sc && sc->isCOMDAT()) + if (shouldStripSectionSuffix(sc, name)) name = name.split('$').first; PartialSection *pSec = createPartialSection(name, c->getOutputCharacteristics()); pSec->chunks.push_back(c); } fixPartialSectionChars(".rsrc", data | r); // Even in non MinGW cases, we might need to link against GNU import // libraries. bool hasIdata = fixGnuImportChunks(); if (!idata.empty()) hasIdata = true; if (hasIdata) addSyntheticIdata(); // Process an /order option. if (!config->order.empty()) for (auto it : partialSections) sortBySectionOrder(it.second->chunks); if (hasIdata) locateImportTables(); // Then create an OutputSection for each section. // '$' and all following characters in input section names are // discarded when determining output section. So, .text$foo // contributes to .text, for example. See PE/COFF spec 3.2. for (auto it : partialSections) { PartialSection *pSec = it.second; StringRef name = getOutputSectionName(pSec->name); uint32_t outChars = pSec->characteristics; if (name == ".CRT") { // In link.exe, there is a special case for the I386 target where .CRT // sections are treated as if they have output characteristics DATA | R if // their characteristics are DATA | R | W. This implements the same // special case for all architectures. outChars = data | r; log("Processing section " + pSec->name + " -> " + name); sortCRTSectionChunks(pSec->chunks); } OutputSection *sec = createSection(name, outChars); for (Chunk *c : pSec->chunks) sec->addChunk(c); sec->addContributingPartialSection(pSec); } // Finally, move some output sections to the end. auto sectionOrder = [&](const OutputSection *s) { // Move DISCARDABLE (or non-memory-mapped) sections to the end of file // because the loader cannot handle holes. Stripping can remove other // discardable ones than .reloc, which is first of them (created early). if (s->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) return 2; // .rsrc should come at the end of the non-discardable sections because its // size may change by the Win32 UpdateResources() function, causing // subsequent sections to move (see https://crbug.com/827082). if (s == rsrcSec) return 1; return 0; }; llvm::stable_sort(outputSections, [&](const OutputSection *s, const OutputSection *t) { return sectionOrder(s) < sectionOrder(t); }); } void Writer::createMiscChunks() { for (MergeChunk *p : MergeChunk::instances) { if (p) { p->finalizeContents(); rdataSec->addChunk(p); } } // Create thunks for locally-dllimported symbols. if (!symtab->localImportChunks.empty()) { for (Chunk *c : symtab->localImportChunks) rdataSec->addChunk(c); } // Create Debug Information Chunks OutputSection *debugInfoSec = config->mingw ? buildidSec : rdataSec; if (config->debug || config->repro) { debugDirectory = make(debugRecords, config->repro); debugInfoSec->addChunk(debugDirectory); } if (config->debug) { // Make a CVDebugRecordChunk even when /DEBUG:CV is not specified. We // output a PDB no matter what, and this chunk provides the only means of // allowing a debugger to match a PDB and an executable. So we need it even // if we're ultimately not going to write CodeView data to the PDB. buildId = make(); debugRecords.push_back(buildId); for (Chunk *c : debugRecords) debugInfoSec->addChunk(c); } // Create SEH table. x86-only. if (config->safeSEH) createSEHTable(); // Create /guard:cf tables if requested. if (config->guardCF != GuardCFLevel::Off) createGuardCFTables(); if (config->mingw) { createRuntimePseudoRelocs(); insertCtorDtorSymbols(); } } // Create .idata section for the DLL-imported symbol table. // The format of this section is inherently Windows-specific. // IdataContents class abstracted away the details for us, // so we just let it create chunks and add them to the section. void Writer::createImportTables() { // Initialize DLLOrder so that import entries are ordered in // the same order as in the command line. (That affects DLL // initialization order, and this ordering is MSVC-compatible.) for (ImportFile *file : ImportFile::instances) { if (!file->live) continue; std::string dll = StringRef(file->dllName).lower(); if (config->dllOrder.count(dll) == 0) config->dllOrder[dll] = config->dllOrder.size(); if (file->impSym && !isa(file->impSym)) fatal(toString(*file->impSym) + " was replaced"); DefinedImportData *impSym = cast_or_null(file->impSym); if (config->delayLoads.count(StringRef(file->dllName).lower())) { if (!file->thunkSym) fatal("cannot delay-load " + toString(file) + " due to import of data: " + toString(*impSym)); delayIdata.add(impSym); } else { idata.add(impSym); } } } void Writer::appendImportThunks() { if (ImportFile::instances.empty()) return; for (ImportFile *file : ImportFile::instances) { if (!file->live) continue; if (!file->thunkSym) continue; if (!isa(file->thunkSym)) fatal(toString(*file->thunkSym) + " was replaced"); DefinedImportThunk *thunk = cast(file->thunkSym); if (file->thunkLive) textSec->addChunk(thunk->getChunk()); } if (!delayIdata.empty()) { Defined *helper = cast(config->delayLoadHelper); delayIdata.create(helper); for (Chunk *c : delayIdata.getChunks()) didatSec->addChunk(c); for (Chunk *c : delayIdata.getDataChunks()) dataSec->addChunk(c); for (Chunk *c : delayIdata.getCodeChunks()) textSec->addChunk(c); } } void Writer::createExportTable() { if (config->exports.empty()) return; for (Chunk *c : edata.chunks) edataSec->addChunk(c); } void Writer::removeUnusedSections() { // Remove sections that we can be sure won't get content, to avoid // allocating space for their section headers. auto isUnused = [this](OutputSection *s) { if (s == relocSec) return false; // This section is populated later. // MergeChunks have zero size at this point, as their size is finalized // later. Only remove sections that have no Chunks at all. return s->chunks.empty(); }; outputSections.erase( std::remove_if(outputSections.begin(), outputSections.end(), isUnused), outputSections.end()); } // The Windows loader doesn't seem to like empty sections, // so we remove them if any. void Writer::removeEmptySections() { auto isEmpty = [](OutputSection *s) { return s->getVirtualSize() == 0; }; outputSections.erase( std::remove_if(outputSections.begin(), outputSections.end(), isEmpty), outputSections.end()); } void Writer::assignOutputSectionIndices() { // Assign final output section indices, and assign each chunk to its output // section. uint32_t idx = 1; for (OutputSection *os : outputSections) { os->sectionIndex = idx; for (Chunk *c : os->chunks) c->setOutputSectionIdx(idx); ++idx; } // Merge chunks are containers of chunks, so assign those an output section // too. for (MergeChunk *mc : MergeChunk::instances) if (mc) for (SectionChunk *sc : mc->sections) if (sc && sc->live) sc->setOutputSectionIdx(mc->getOutputSectionIdx()); } size_t Writer::addEntryToStringTable(StringRef str) { assert(str.size() > COFF::NameSize); size_t offsetOfEntry = strtab.size() + 4; // +4 for the size field strtab.insert(strtab.end(), str.begin(), str.end()); strtab.push_back('\0'); return offsetOfEntry; } Optional Writer::createSymbol(Defined *def) { coff_symbol16 sym; switch (def->kind()) { case Symbol::DefinedAbsoluteKind: sym.Value = def->getRVA(); sym.SectionNumber = IMAGE_SYM_ABSOLUTE; break; case Symbol::DefinedSyntheticKind: // Relative symbols are unrepresentable in a COFF symbol table. return None; default: { // Don't write symbols that won't be written to the output to the symbol // table. Chunk *c = def->getChunk(); if (!c) return None; OutputSection *os = c->getOutputSection(); if (!os) return None; sym.Value = def->getRVA() - os->getRVA(); sym.SectionNumber = os->sectionIndex; break; } } + + // Symbols that are runtime pseudo relocations don't point to the actual + // symbol data itself (as they are imported), but points to the IAT entry + // instead. Avoid emitting them to the symbol table, as they can confuse + // debuggers. + if (def->isRuntimePseudoReloc) + return None; StringRef name = def->getName(); if (name.size() > COFF::NameSize) { sym.Name.Offset.Zeroes = 0; sym.Name.Offset.Offset = addEntryToStringTable(name); } else { memset(sym.Name.ShortName, 0, COFF::NameSize); memcpy(sym.Name.ShortName, name.data(), name.size()); } if (auto *d = dyn_cast(def)) { COFFSymbolRef ref = d->getCOFFSymbol(); sym.Type = ref.getType(); sym.StorageClass = ref.getStorageClass(); } else { sym.Type = IMAGE_SYM_TYPE_NULL; sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; } sym.NumberOfAuxSymbols = 0; return sym; } void Writer::createSymbolAndStringTable() { // PE/COFF images are limited to 8 byte section names. Longer names can be // supported by writing a non-standard string table, but this string table is // not mapped at runtime and the long names will therefore be inaccessible. // link.exe always truncates section names to 8 bytes, whereas binutils always // preserves long section names via the string table. LLD adopts a hybrid // solution where discardable sections have long names preserved and // non-discardable sections have their names truncated, to ensure that any // section which is mapped at runtime also has its name mapped at runtime. for (OutputSection *sec : outputSections) { if (sec->name.size() <= COFF::NameSize) continue; if ((sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) continue; sec->setStringTableOff(addEntryToStringTable(sec->name)); } if (config->debugDwarf || config->debugSymtab) { for (ObjFile *file : ObjFile::instances) { for (Symbol *b : file->getSymbols()) { auto *d = dyn_cast_or_null(b); if (!d || d->writtenToSymtab) continue; d->writtenToSymtab = true; if (Optional sym = createSymbol(d)) outputSymtab.push_back(*sym); } } } if (outputSymtab.empty() && strtab.empty()) return; // We position the symbol table to be adjacent to the end of the last section. uint64_t fileOff = fileSize; pointerToSymbolTable = fileOff; fileOff += outputSymtab.size() * sizeof(coff_symbol16); fileOff += 4 + strtab.size(); fileSize = alignTo(fileOff, config->fileAlign); } void Writer::mergeSections() { if (!pdataSec->chunks.empty()) { firstPdata = pdataSec->chunks.front(); lastPdata = pdataSec->chunks.back(); } for (auto &p : config->merge) { StringRef toName = p.second; if (p.first == toName) continue; StringSet<> names; while (1) { if (!names.insert(toName).second) fatal("/merge: cycle found for section '" + p.first + "'"); auto i = config->merge.find(toName); if (i == config->merge.end()) break; toName = i->second; } OutputSection *from = findSection(p.first); OutputSection *to = findSection(toName); if (!from) continue; if (!to) { from->name = toName; continue; } to->merge(from); } } // Visits all sections to assign incremental, non-overlapping RVAs and // file offsets. void Writer::assignAddresses() { sizeOfHeaders = dosStubSize + sizeof(PEMagic) + sizeof(coff_file_header) + sizeof(data_directory) * numberOfDataDirectory + sizeof(coff_section) * outputSections.size(); sizeOfHeaders += config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header); sizeOfHeaders = alignTo(sizeOfHeaders, config->fileAlign); uint64_t rva = pageSize; // The first page is kept unmapped. fileSize = sizeOfHeaders; for (OutputSection *sec : outputSections) { if (sec == relocSec) addBaserels(); uint64_t rawSize = 0, virtualSize = 0; sec->header.VirtualAddress = rva; // If /FUNCTIONPADMIN is used, functions are padded in order to create a // hotpatchable image. const bool isCodeSection = (sec->header.Characteristics & IMAGE_SCN_CNT_CODE) && (sec->header.Characteristics & IMAGE_SCN_MEM_READ) && (sec->header.Characteristics & IMAGE_SCN_MEM_EXECUTE); uint32_t padding = isCodeSection ? config->functionPadMin : 0; for (Chunk *c : sec->chunks) { if (padding && c->isHotPatchable()) virtualSize += padding; virtualSize = alignTo(virtualSize, c->getAlignment()); c->setRVA(rva + virtualSize); virtualSize += c->getSize(); if (c->hasData) rawSize = alignTo(virtualSize, config->fileAlign); } if (virtualSize > UINT32_MAX) error("section larger than 4 GiB: " + sec->name); sec->header.VirtualSize = virtualSize; sec->header.SizeOfRawData = rawSize; if (rawSize != 0) sec->header.PointerToRawData = fileSize; rva += alignTo(virtualSize, pageSize); fileSize += alignTo(rawSize, config->fileAlign); } sizeOfImage = alignTo(rva, pageSize); // Assign addresses to sections in MergeChunks. for (MergeChunk *mc : MergeChunk::instances) if (mc) mc->assignSubsectionRVAs(); } template void Writer::writeHeader() { // Write DOS header. For backwards compatibility, the first part of a PE/COFF // executable consists of an MS-DOS MZ executable. If the executable is run // under DOS, that program gets run (usually to just print an error message). // When run under Windows, the loader looks at AddressOfNewExeHeader and uses // the PE header instead. uint8_t *buf = buffer->getBufferStart(); auto *dos = reinterpret_cast(buf); buf += sizeof(dos_header); dos->Magic[0] = 'M'; dos->Magic[1] = 'Z'; dos->UsedBytesInTheLastPage = dosStubSize % 512; dos->FileSizeInPages = divideCeil(dosStubSize, 512); dos->HeaderSizeInParagraphs = sizeof(dos_header) / 16; dos->AddressOfRelocationTable = sizeof(dos_header); dos->AddressOfNewExeHeader = dosStubSize; // Write DOS program. memcpy(buf, dosProgram, sizeof(dosProgram)); buf += sizeof(dosProgram); // Write PE magic memcpy(buf, PEMagic, sizeof(PEMagic)); buf += sizeof(PEMagic); // Write COFF header auto *coff = reinterpret_cast(buf); buf += sizeof(*coff); coff->Machine = config->machine; coff->NumberOfSections = outputSections.size(); coff->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; if (config->largeAddressAware) coff->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; if (!config->is64()) coff->Characteristics |= IMAGE_FILE_32BIT_MACHINE; if (config->dll) coff->Characteristics |= IMAGE_FILE_DLL; if (!config->relocatable) coff->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED; if (config->swaprunCD) coff->Characteristics |= IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP; if (config->swaprunNet) coff->Characteristics |= IMAGE_FILE_NET_RUN_FROM_SWAP; coff->SizeOfOptionalHeader = sizeof(PEHeaderTy) + sizeof(data_directory) * numberOfDataDirectory; // Write PE header auto *pe = reinterpret_cast(buf); buf += sizeof(*pe); pe->Magic = config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32; // If {Major,Minor}LinkerVersion is left at 0.0, then for some // reason signing the resulting PE file with Authenticode produces a // signature that fails to validate on Windows 7 (but is OK on 10). // Set it to 14.0, which is what VS2015 outputs, and which avoids // that problem. pe->MajorLinkerVersion = 14; pe->MinorLinkerVersion = 0; pe->ImageBase = config->imageBase; pe->SectionAlignment = pageSize; pe->FileAlignment = config->fileAlign; pe->MajorImageVersion = config->majorImageVersion; pe->MinorImageVersion = config->minorImageVersion; pe->MajorOperatingSystemVersion = config->majorOSVersion; pe->MinorOperatingSystemVersion = config->minorOSVersion; pe->MajorSubsystemVersion = config->majorOSVersion; pe->MinorSubsystemVersion = config->minorOSVersion; pe->Subsystem = config->subsystem; pe->SizeOfImage = sizeOfImage; pe->SizeOfHeaders = sizeOfHeaders; if (!config->noEntry) { Defined *entry = cast(config->entry); pe->AddressOfEntryPoint = entry->getRVA(); // Pointer to thumb code must have the LSB set, so adjust it. if (config->machine == ARMNT) pe->AddressOfEntryPoint |= 1; } pe->SizeOfStackReserve = config->stackReserve; pe->SizeOfStackCommit = config->stackCommit; pe->SizeOfHeapReserve = config->heapReserve; pe->SizeOfHeapCommit = config->heapCommit; if (config->appContainer) pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER; if (config->dynamicBase) pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; if (config->highEntropyVA) pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA; if (!config->allowBind) pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND; if (config->nxCompat) pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; if (!config->allowIsolation) pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION; if (config->guardCF != GuardCFLevel::Off) pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF; if (config->integrityCheck) pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY; if (setNoSEHCharacteristic) pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH; if (config->terminalServerAware) pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE; pe->NumberOfRvaAndSize = numberOfDataDirectory; if (textSec->getVirtualSize()) { pe->BaseOfCode = textSec->getRVA(); pe->SizeOfCode = textSec->getRawSize(); } pe->SizeOfInitializedData = getSizeOfInitializedData(); // Write data directory auto *dir = reinterpret_cast(buf); buf += sizeof(*dir) * numberOfDataDirectory; if (!config->exports.empty()) { dir[EXPORT_TABLE].RelativeVirtualAddress = edata.getRVA(); dir[EXPORT_TABLE].Size = edata.getSize(); } if (importTableStart) { dir[IMPORT_TABLE].RelativeVirtualAddress = importTableStart->getRVA(); dir[IMPORT_TABLE].Size = importTableSize; } if (iatStart) { dir[IAT].RelativeVirtualAddress = iatStart->getRVA(); dir[IAT].Size = iatSize; } if (rsrcSec->getVirtualSize()) { dir[RESOURCE_TABLE].RelativeVirtualAddress = rsrcSec->getRVA(); dir[RESOURCE_TABLE].Size = rsrcSec->getVirtualSize(); } if (firstPdata) { dir[EXCEPTION_TABLE].RelativeVirtualAddress = firstPdata->getRVA(); dir[EXCEPTION_TABLE].Size = lastPdata->getRVA() + lastPdata->getSize() - firstPdata->getRVA(); } if (relocSec->getVirtualSize()) { dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = relocSec->getRVA(); dir[BASE_RELOCATION_TABLE].Size = relocSec->getVirtualSize(); } if (Symbol *sym = symtab->findUnderscore("_tls_used")) { if (Defined *b = dyn_cast(sym)) { dir[TLS_TABLE].RelativeVirtualAddress = b->getRVA(); dir[TLS_TABLE].Size = config->is64() ? sizeof(object::coff_tls_directory64) : sizeof(object::coff_tls_directory32); } } if (debugDirectory) { dir[DEBUG_DIRECTORY].RelativeVirtualAddress = debugDirectory->getRVA(); dir[DEBUG_DIRECTORY].Size = debugDirectory->getSize(); } if (Symbol *sym = symtab->findUnderscore("_load_config_used")) { if (auto *b = dyn_cast(sym)) { SectionChunk *sc = b->getChunk(); assert(b->getRVA() >= sc->getRVA()); uint64_t offsetInChunk = b->getRVA() - sc->getRVA(); if (!sc->hasData || offsetInChunk + 4 > sc->getSize()) fatal("_load_config_used is malformed"); ArrayRef secContents = sc->getContents(); uint32_t loadConfigSize = *reinterpret_cast(&secContents[offsetInChunk]); if (offsetInChunk + loadConfigSize > sc->getSize()) fatal("_load_config_used is too large"); dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = b->getRVA(); dir[LOAD_CONFIG_TABLE].Size = loadConfigSize; } } if (!delayIdata.empty()) { dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress = delayIdata.getDirRVA(); dir[DELAY_IMPORT_DESCRIPTOR].Size = delayIdata.getDirSize(); } // Write section table for (OutputSection *sec : outputSections) { sec->writeHeaderTo(buf); buf += sizeof(coff_section); } sectionTable = ArrayRef( buf - outputSections.size() * sizeof(coff_section), buf); if (outputSymtab.empty() && strtab.empty()) return; coff->PointerToSymbolTable = pointerToSymbolTable; uint32_t numberOfSymbols = outputSymtab.size(); coff->NumberOfSymbols = numberOfSymbols; auto *symbolTable = reinterpret_cast( buffer->getBufferStart() + coff->PointerToSymbolTable); for (size_t i = 0; i != numberOfSymbols; ++i) symbolTable[i] = outputSymtab[i]; // Create the string table, it follows immediately after the symbol table. // The first 4 bytes is length including itself. buf = reinterpret_cast(&symbolTable[numberOfSymbols]); write32le(buf, strtab.size() + 4); if (!strtab.empty()) memcpy(buf + 4, strtab.data(), strtab.size()); } void Writer::openFile(StringRef path) { buffer = CHECK( FileOutputBuffer::create(path, fileSize, FileOutputBuffer::F_executable), "failed to open " + path); } void Writer::createSEHTable() { SymbolRVASet handlers; for (ObjFile *file : ObjFile::instances) { if (!file->hasSafeSEH()) error("/safeseh: " + file->getName() + " is not compatible with SEH"); markSymbolsForRVATable(file, file->getSXDataChunks(), handlers); } // Set the "no SEH" characteristic if there really were no handlers, or if // there is no load config object to point to the table of handlers. setNoSEHCharacteristic = handlers.empty() || !symtab->findUnderscore("_load_config_used"); maybeAddRVATable(std::move(handlers), "__safe_se_handler_table", "__safe_se_handler_count"); } // Add a symbol to an RVA set. Two symbols may have the same RVA, but an RVA set // cannot contain duplicates. Therefore, the set is uniqued by Chunk and the // symbol's offset into that Chunk. static void addSymbolToRVASet(SymbolRVASet &rvaSet, Defined *s) { Chunk *c = s->getChunk(); if (auto *sc = dyn_cast(c)) c = sc->repl; // Look through ICF replacement. uint32_t off = s->getRVA() - (c ? c->getRVA() : 0); rvaSet.insert({c, off}); } // Given a symbol, add it to the GFIDs table if it is a live, defined, function // symbol in an executable section. static void maybeAddAddressTakenFunction(SymbolRVASet &addressTakenSyms, Symbol *s) { if (!s) return; switch (s->kind()) { case Symbol::DefinedLocalImportKind: case Symbol::DefinedImportDataKind: // Defines an __imp_ pointer, so it is data, so it is ignored. break; case Symbol::DefinedCommonKind: // Common is always data, so it is ignored. break; case Symbol::DefinedAbsoluteKind: case Symbol::DefinedSyntheticKind: // Absolute is never code, synthetic generally isn't and usually isn't // determinable. break; case Symbol::LazyKind: case Symbol::UndefinedKind: // Undefined symbols resolve to zero, so they don't have an RVA. Lazy // symbols shouldn't have relocations. break; case Symbol::DefinedImportThunkKind: // Thunks are always code, include them. addSymbolToRVASet(addressTakenSyms, cast(s)); break; case Symbol::DefinedRegularKind: { // This is a regular, defined, symbol from a COFF file. Mark the symbol as // address taken if the symbol type is function and it's in an executable // section. auto *d = cast(s); if (d->getCOFFSymbol().getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) { SectionChunk *sc = dyn_cast(d->getChunk()); if (sc && sc->live && sc->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE) addSymbolToRVASet(addressTakenSyms, d); } break; } } } // Visit all relocations from all section contributions of this object file and // mark the relocation target as address-taken. static void markSymbolsWithRelocations(ObjFile *file, SymbolRVASet &usedSymbols) { for (Chunk *c : file->getChunks()) { // We only care about live section chunks. Common chunks and other chunks // don't generally contain relocations. SectionChunk *sc = dyn_cast(c); if (!sc || !sc->live) continue; for (const coff_relocation &reloc : sc->getRelocs()) { if (config->machine == I386 && reloc.Type == COFF::IMAGE_REL_I386_REL32) // Ignore relative relocations on x86. On x86_64 they can't be ignored // since they're also used to compute absolute addresses. continue; Symbol *ref = sc->file->getSymbol(reloc.SymbolTableIndex); maybeAddAddressTakenFunction(usedSymbols, ref); } } } // Create the guard function id table. This is a table of RVAs of all // address-taken functions. It is sorted and uniqued, just like the safe SEH // table. void Writer::createGuardCFTables() { SymbolRVASet addressTakenSyms; SymbolRVASet longJmpTargets; for (ObjFile *file : ObjFile::instances) { // If the object was compiled with /guard:cf, the address taken symbols // are in .gfids$y sections, and the longjmp targets are in .gljmp$y // sections. If the object was not compiled with /guard:cf, we assume there // were no setjmp targets, and that all code symbols with relocations are // possibly address-taken. if (file->hasGuardCF()) { markSymbolsForRVATable(file, file->getGuardFidChunks(), addressTakenSyms); markSymbolsForRVATable(file, file->getGuardLJmpChunks(), longJmpTargets); } else { markSymbolsWithRelocations(file, addressTakenSyms); } } // Mark the image entry as address-taken. if (config->entry) maybeAddAddressTakenFunction(addressTakenSyms, config->entry); // Mark exported symbols in executable sections as address-taken. for (Export &e : config->exports) maybeAddAddressTakenFunction(addressTakenSyms, e.sym); // Ensure sections referenced in the gfid table are 16-byte aligned. for (const ChunkAndOffset &c : addressTakenSyms) if (c.inputChunk->getAlignment() < 16) c.inputChunk->setAlignment(16); maybeAddRVATable(std::move(addressTakenSyms), "__guard_fids_table", "__guard_fids_count"); // Add the longjmp target table unless the user told us not to. if (config->guardCF == GuardCFLevel::Full) maybeAddRVATable(std::move(longJmpTargets), "__guard_longjmp_table", "__guard_longjmp_count"); // Set __guard_flags, which will be used in the load config to indicate that // /guard:cf was enabled. uint32_t guardFlags = uint32_t(coff_guard_flags::CFInstrumented) | uint32_t(coff_guard_flags::HasFidTable); if (config->guardCF == GuardCFLevel::Full) guardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable); Symbol *flagSym = symtab->findUnderscore("__guard_flags"); cast(flagSym)->setVA(guardFlags); } // Take a list of input sections containing symbol table indices and add those // symbols to an RVA table. The challenge is that symbol RVAs are not known and // depend on the table size, so we can't directly build a set of integers. void Writer::markSymbolsForRVATable(ObjFile *file, ArrayRef symIdxChunks, SymbolRVASet &tableSymbols) { for (SectionChunk *c : symIdxChunks) { // Skip sections discarded by linker GC. This comes up when a .gfids section // is associated with something like a vtable and the vtable is discarded. // In this case, the associated gfids section is discarded, and we don't // mark the virtual member functions as address-taken by the vtable. if (!c->live) continue; // Validate that the contents look like symbol table indices. ArrayRef data = c->getContents(); if (data.size() % 4 != 0) { warn("ignoring " + c->getSectionName() + " symbol table index section in object " + toString(file)); continue; } // Read each symbol table index and check if that symbol was included in the // final link. If so, add it to the table symbol set. ArrayRef symIndices( reinterpret_cast(data.data()), data.size() / 4); ArrayRef objSymbols = file->getSymbols(); for (uint32_t symIndex : symIndices) { if (symIndex >= objSymbols.size()) { warn("ignoring invalid symbol table index in section " + c->getSectionName() + " in object " + toString(file)); continue; } if (Symbol *s = objSymbols[symIndex]) { if (s->isLive()) addSymbolToRVASet(tableSymbols, cast(s)); } } } } // Replace the absolute table symbol with a synthetic symbol pointing to // tableChunk so that we can emit base relocations for it and resolve section // relative relocations. void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym, StringRef countSym) { if (tableSymbols.empty()) return; RVATableChunk *tableChunk = make(std::move(tableSymbols)); rdataSec->addChunk(tableChunk); Symbol *t = symtab->findUnderscore(tableSym); Symbol *c = symtab->findUnderscore(countSym); replaceSymbol(t, t->getName(), tableChunk); cast(c)->setVA(tableChunk->getSize() / 4); } // MinGW specific. Gather all relocations that are imported from a DLL even // though the code didn't expect it to, produce the table that the runtime // uses for fixing them up, and provide the synthetic symbols that the // runtime uses for finding the table. void Writer::createRuntimePseudoRelocs() { std::vector rels; for (Chunk *c : symtab->getChunks()) { auto *sc = dyn_cast(c); if (!sc || !sc->live) continue; sc->getRuntimePseudoRelocs(rels); } if (!rels.empty()) log("Writing " + Twine(rels.size()) + " runtime pseudo relocations"); PseudoRelocTableChunk *table = make(rels); rdataSec->addChunk(table); EmptyChunk *endOfList = make(); rdataSec->addChunk(endOfList); Symbol *headSym = symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__"); Symbol *endSym = symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__"); replaceSymbol(headSym, headSym->getName(), table); replaceSymbol(endSym, endSym->getName(), endOfList); } // MinGW specific. // The MinGW .ctors and .dtors lists have sentinels at each end; // a (uintptr_t)-1 at the start and a (uintptr_t)0 at the end. // There's a symbol pointing to the start sentinel pointer, __CTOR_LIST__ // and __DTOR_LIST__ respectively. void Writer::insertCtorDtorSymbols() { AbsolutePointerChunk *ctorListHead = make(-1); AbsolutePointerChunk *ctorListEnd = make(0); AbsolutePointerChunk *dtorListHead = make(-1); AbsolutePointerChunk *dtorListEnd = make(0); ctorsSec->insertChunkAtStart(ctorListHead); ctorsSec->addChunk(ctorListEnd); dtorsSec->insertChunkAtStart(dtorListHead); dtorsSec->addChunk(dtorListEnd); Symbol *ctorListSym = symtab->findUnderscore("__CTOR_LIST__"); Symbol *dtorListSym = symtab->findUnderscore("__DTOR_LIST__"); replaceSymbol(ctorListSym, ctorListSym->getName(), ctorListHead); replaceSymbol(dtorListSym, dtorListSym->getName(), dtorListHead); } // Handles /section options to allow users to overwrite // section attributes. void Writer::setSectionPermissions() { for (auto &p : config->section) { StringRef name = p.first; uint32_t perm = p.second; for (OutputSection *sec : outputSections) if (sec->name == name) sec->setPermissions(perm); } } // Write section contents to a mmap'ed file. void Writer::writeSections() { // Record the number of sections to apply section index relocations // against absolute symbols. See applySecIdx in Chunks.cpp.. DefinedAbsolute::numOutputSections = outputSections.size(); uint8_t *buf = buffer->getBufferStart(); for (OutputSection *sec : outputSections) { uint8_t *secBuf = buf + sec->getFileOff(); // Fill gaps between functions in .text with INT3 instructions // instead of leaving as NUL bytes (which can be interpreted as // ADD instructions). if (sec->header.Characteristics & IMAGE_SCN_CNT_CODE) memset(secBuf, 0xCC, sec->getRawSize()); parallelForEach(sec->chunks, [&](Chunk *c) { c->writeTo(secBuf + c->getRVA() - sec->getRVA()); }); } } void Writer::writeBuildId() { // There are two important parts to the build ID. // 1) If building with debug info, the COFF debug directory contains a // timestamp as well as a Guid and Age of the PDB. // 2) In all cases, the PE COFF file header also contains a timestamp. // For reproducibility, instead of a timestamp we want to use a hash of the // PE contents. if (config->debug) { assert(buildId && "BuildId is not set!"); // BuildId->BuildId was filled in when the PDB was written. } // At this point the only fields in the COFF file which remain unset are the // "timestamp" in the COFF file header, and the ones in the coff debug // directory. Now we can hash the file and write that hash to the various // timestamp fields in the file. StringRef outputFileData( reinterpret_cast(buffer->getBufferStart()), buffer->getBufferSize()); uint32_t timestamp = config->timestamp; uint64_t hash = 0; bool generateSyntheticBuildId = config->mingw && config->debug && config->pdbPath.empty(); if (config->repro || generateSyntheticBuildId) hash = xxHash64(outputFileData); if (config->repro) timestamp = static_cast(hash); if (generateSyntheticBuildId) { // For MinGW builds without a PDB file, we still generate a build id // to allow associating a crash dump to the executable. buildId->buildId->PDB70.CVSignature = OMF::Signature::PDB70; buildId->buildId->PDB70.Age = 1; memcpy(buildId->buildId->PDB70.Signature, &hash, 8); // xxhash only gives us 8 bytes, so put some fixed data in the other half. memcpy(&buildId->buildId->PDB70.Signature[8], "LLD PDB.", 8); } if (debugDirectory) debugDirectory->setTimeDateStamp(timestamp); uint8_t *buf = buffer->getBufferStart(); buf += dosStubSize + sizeof(PEMagic); object::coff_file_header *coffHeader = reinterpret_cast(buf); coffHeader->TimeDateStamp = timestamp; } // Sort .pdata section contents according to PE/COFF spec 5.5. void Writer::sortExceptionTable() { if (!firstPdata) return; // We assume .pdata contains function table entries only. auto bufAddr = [&](Chunk *c) { OutputSection *os = c->getOutputSection(); return buffer->getBufferStart() + os->getFileOff() + c->getRVA() - os->getRVA(); }; uint8_t *begin = bufAddr(firstPdata); uint8_t *end = bufAddr(lastPdata) + lastPdata->getSize(); if (config->machine == AMD64) { struct Entry { ulittle32_t begin, end, unwind; }; parallelSort( MutableArrayRef((Entry *)begin, (Entry *)end), [](const Entry &a, const Entry &b) { return a.begin < b.begin; }); return; } if (config->machine == ARMNT || config->machine == ARM64) { struct Entry { ulittle32_t begin, unwind; }; parallelSort( MutableArrayRef((Entry *)begin, (Entry *)end), [](const Entry &a, const Entry &b) { return a.begin < b.begin; }); return; } errs() << "warning: don't know how to handle .pdata.\n"; } // The CRT section contains, among other things, the array of function // pointers that initialize every global variable that is not trivially // constructed. The CRT calls them one after the other prior to invoking // main(). // // As per C++ spec, 3.6.2/2.3, // "Variables with ordered initialization defined within a single // translation unit shall be initialized in the order of their definitions // in the translation unit" // // It is therefore critical to sort the chunks containing the function // pointers in the order that they are listed in the object file (top to // bottom), otherwise global objects might not be initialized in the // correct order. void Writer::sortCRTSectionChunks(std::vector &chunks) { auto sectionChunkOrder = [](const Chunk *a, const Chunk *b) { auto sa = dyn_cast(a); auto sb = dyn_cast(b); assert(sa && sb && "Non-section chunks in CRT section!"); StringRef sAObj = sa->file->mb.getBufferIdentifier(); StringRef sBObj = sb->file->mb.getBufferIdentifier(); return sAObj == sBObj && sa->getSectionNumber() < sb->getSectionNumber(); }; llvm::stable_sort(chunks, sectionChunkOrder); if (config->verbose) { for (auto &c : chunks) { auto sc = dyn_cast(c); log(" " + sc->file->mb.getBufferIdentifier().str() + ", SectionID: " + Twine(sc->getSectionNumber())); } } } OutputSection *Writer::findSection(StringRef name) { for (OutputSection *sec : outputSections) if (sec->name == name) return sec; return nullptr; } uint32_t Writer::getSizeOfInitializedData() { uint32_t res = 0; for (OutputSection *s : outputSections) if (s->header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) res += s->getRawSize(); return res; } // Add base relocations to .reloc section. void Writer::addBaserels() { if (!config->relocatable) return; relocSec->chunks.clear(); std::vector v; for (OutputSection *sec : outputSections) { if (sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) continue; // Collect all locations for base relocations. for (Chunk *c : sec->chunks) c->getBaserels(&v); // Add the addresses to .reloc section. if (!v.empty()) addBaserelBlocks(v); v.clear(); } } // Add addresses to .reloc section. Note that addresses are grouped by page. void Writer::addBaserelBlocks(std::vector &v) { const uint32_t mask = ~uint32_t(pageSize - 1); uint32_t page = v[0].rva & mask; size_t i = 0, j = 1; for (size_t e = v.size(); j < e; ++j) { uint32_t p = v[j].rva & mask; if (p == page) continue; relocSec->addChunk(make(page, &v[i], &v[0] + j)); i = j; page = p; } if (i == j) return; relocSec->addChunk(make(page, &v[i], &v[0] + j)); } PartialSection *Writer::createPartialSection(StringRef name, uint32_t outChars) { PartialSection *&pSec = partialSections[{name, outChars}]; if (pSec) return pSec; pSec = make(name, outChars); return pSec; } PartialSection *Writer::findPartialSection(StringRef name, uint32_t outChars) { auto it = partialSections.find({name, outChars}); if (it != partialSections.end()) return it->second; return nullptr; } Index: vendor/lld/dist-release_90/ELF/SyntheticSections.cpp =================================================================== --- vendor/lld/dist-release_90/ELF/SyntheticSections.cpp (revision 351311) +++ vendor/lld/dist-release_90/ELF/SyntheticSections.cpp (revision 351312) @@ -1,3618 +1,3630 @@ //===- SyntheticSections.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 contains linker-synthesized sections. Currently, // synthetic sections are created either output sections or input sections, // but we are rewriting code so that all synthetic sections are created as // input sections. // //===----------------------------------------------------------------------===// #include "SyntheticSections.h" #include "Config.h" #include "InputFiles.h" #include "LinkerScript.h" #include "OutputSections.h" #include "SymbolTable.h" #include "Symbols.h" #include "Target.h" #include "Writer.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" #include "lld/Common/Strings.h" #include "lld/Common/Threads.h" #include "lld/Common/Version.h" #include "llvm/ADT/SetOperations.h" #include "llvm/ADT/StringExtras.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MD5.h" #include #include using namespace llvm; using namespace llvm::dwarf; 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; constexpr size_t MergeNoTailSection::numShards; static uint64_t readUint(uint8_t *buf) { return config->is64 ? read64(buf) : read32(buf); } static void writeUint(uint8_t *buf, uint64_t val) { if (config->is64) write64(buf, val); else write32(buf, val); } // Returns an LLD version string. static ArrayRef getVersion() { // Check LLD_VERSION first for ease of testing. // You can get consistent output by using the environment variable. // This is only for testing. StringRef s = getenv("LLD_VERSION"); if (s.empty()) s = saver.save(Twine("Linker: ") + getLLDVersion()); // +1 to include the terminating '\0'. return {(const uint8_t *)s.data(), s.size() + 1}; } // Creates a .comment section containing LLD version info. // With this feature, you can identify LLD-generated binaries easily // by "readelf --string-dump .comment ". // The returned object is a mergeable string section. MergeInputSection *elf::createCommentSection() { return make(SHF_MERGE | SHF_STRINGS, SHT_PROGBITS, 1, getVersion(), ".comment"); } // .MIPS.abiflags section. template MipsAbiFlagsSection::MipsAbiFlagsSection(Elf_Mips_ABIFlags flags) : SyntheticSection(SHF_ALLOC, SHT_MIPS_ABIFLAGS, 8, ".MIPS.abiflags"), flags(flags) { this->entsize = sizeof(Elf_Mips_ABIFlags); } template void MipsAbiFlagsSection::writeTo(uint8_t *buf) { memcpy(buf, &flags, sizeof(flags)); } template MipsAbiFlagsSection *MipsAbiFlagsSection::create() { Elf_Mips_ABIFlags flags = {}; bool create = false; for (InputSectionBase *sec : inputSections) { if (sec->type != SHT_MIPS_ABIFLAGS) continue; sec->markDead(); create = true; std::string filename = toString(sec->file); const size_t size = sec->data().size(); // Older version of BFD (such as the default FreeBSD linker) concatenate // .MIPS.abiflags instead of merging. To allow for this case (or potential // zero padding) we ignore everything after the first Elf_Mips_ABIFlags if (size < sizeof(Elf_Mips_ABIFlags)) { error(filename + ": invalid size of .MIPS.abiflags section: got " + Twine(size) + " instead of " + Twine(sizeof(Elf_Mips_ABIFlags))); return nullptr; } auto *s = reinterpret_cast(sec->data().data()); if (s->version != 0) { error(filename + ": unexpected .MIPS.abiflags version " + Twine(s->version)); return nullptr; } // LLD checks ISA compatibility in calcMipsEFlags(). Here we just // select the highest number of ISA/Rev/Ext. flags.isa_level = std::max(flags.isa_level, s->isa_level); flags.isa_rev = std::max(flags.isa_rev, s->isa_rev); flags.isa_ext = std::max(flags.isa_ext, s->isa_ext); flags.gpr_size = std::max(flags.gpr_size, s->gpr_size); flags.cpr1_size = std::max(flags.cpr1_size, s->cpr1_size); flags.cpr2_size = std::max(flags.cpr2_size, s->cpr2_size); flags.ases |= s->ases; flags.flags1 |= s->flags1; flags.flags2 |= s->flags2; flags.fp_abi = elf::getMipsFpAbiFlag(flags.fp_abi, s->fp_abi, filename); }; if (create) return make>(flags); return nullptr; } // .MIPS.options section. template MipsOptionsSection::MipsOptionsSection(Elf_Mips_RegInfo reginfo) : SyntheticSection(SHF_ALLOC, SHT_MIPS_OPTIONS, 8, ".MIPS.options"), reginfo(reginfo) { this->entsize = sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo); } template void MipsOptionsSection::writeTo(uint8_t *buf) { auto *options = reinterpret_cast(buf); options->kind = ODK_REGINFO; options->size = getSize(); if (!config->relocatable) reginfo.ri_gp_value = in.mipsGot->getGp(); memcpy(buf + sizeof(Elf_Mips_Options), ®info, sizeof(reginfo)); } template MipsOptionsSection *MipsOptionsSection::create() { // N64 ABI only. if (!ELFT::Is64Bits) return nullptr; std::vector sections; for (InputSectionBase *sec : inputSections) if (sec->type == SHT_MIPS_OPTIONS) sections.push_back(sec); if (sections.empty()) return nullptr; Elf_Mips_RegInfo reginfo = {}; for (InputSectionBase *sec : sections) { sec->markDead(); std::string filename = toString(sec->file); ArrayRef d = sec->data(); while (!d.empty()) { if (d.size() < sizeof(Elf_Mips_Options)) { error(filename + ": invalid size of .MIPS.options section"); break; } auto *opt = reinterpret_cast(d.data()); if (opt->kind == ODK_REGINFO) { reginfo.ri_gprmask |= opt->getRegInfo().ri_gprmask; sec->getFile()->mipsGp0 = opt->getRegInfo().ri_gp_value; break; } if (!opt->size) fatal(filename + ": zero option descriptor size"); d = d.slice(opt->size); } }; return make>(reginfo); } // MIPS .reginfo section. template MipsReginfoSection::MipsReginfoSection(Elf_Mips_RegInfo reginfo) : SyntheticSection(SHF_ALLOC, SHT_MIPS_REGINFO, 4, ".reginfo"), reginfo(reginfo) { this->entsize = sizeof(Elf_Mips_RegInfo); } template void MipsReginfoSection::writeTo(uint8_t *buf) { if (!config->relocatable) reginfo.ri_gp_value = in.mipsGot->getGp(); memcpy(buf, ®info, sizeof(reginfo)); } template MipsReginfoSection *MipsReginfoSection::create() { // Section should be alive for O32 and N32 ABIs only. if (ELFT::Is64Bits) return nullptr; std::vector sections; for (InputSectionBase *sec : inputSections) if (sec->type == SHT_MIPS_REGINFO) sections.push_back(sec); if (sections.empty()) return nullptr; Elf_Mips_RegInfo reginfo = {}; for (InputSectionBase *sec : sections) { sec->markDead(); if (sec->data().size() != sizeof(Elf_Mips_RegInfo)) { error(toString(sec->file) + ": invalid size of .reginfo section"); return nullptr; } auto *r = reinterpret_cast(sec->data().data()); reginfo.ri_gprmask |= r->ri_gprmask; sec->getFile()->mipsGp0 = r->ri_gp_value; }; return make>(reginfo); } InputSection *elf::createInterpSection() { // StringSaver guarantees that the returned string ends with '\0'. StringRef s = saver.save(config->dynamicLinker); ArrayRef contents = {(const uint8_t *)s.data(), s.size() + 1}; auto *sec = make(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, contents, ".interp"); sec->markLive(); return sec; } Defined *elf::addSyntheticLocal(StringRef name, uint8_t type, uint64_t value, uint64_t size, InputSectionBase §ion) { auto *s = make(section.file, name, STB_LOCAL, STV_DEFAULT, type, value, size, §ion); if (in.symTab) in.symTab->addSymbol(s); return s; } static size_t getHashSize() { switch (config->buildId) { case BuildIdKind::Fast: return 8; case BuildIdKind::Md5: case BuildIdKind::Uuid: return 16; case BuildIdKind::Sha1: return 20; case BuildIdKind::Hexstring: return config->buildIdVector.size(); default: llvm_unreachable("unknown BuildIdKind"); } } // This class represents a linker-synthesized .note.gnu.property section. // // In x86 and AArch64, object files may contain feature flags indicating the // features that they have used. The flags are stored in a .note.gnu.property // section. // // lld reads the sections from input files and merges them by computing AND of // the flags. The result is written as a new .note.gnu.property section. // // If the flag is zero (which indicates that the intersection of the feature // sets is empty, or some input files didn't have .note.gnu.property sections), // we don't create this section. GnuPropertySection::GnuPropertySection() : SyntheticSection(llvm::ELF::SHF_ALLOC, llvm::ELF::SHT_NOTE, 4, ".note.gnu.property") {} void GnuPropertySection::writeTo(uint8_t *buf) { uint32_t featureAndType = config->emachine == EM_AARCH64 ? GNU_PROPERTY_AARCH64_FEATURE_1_AND : GNU_PROPERTY_X86_FEATURE_1_AND; write32(buf, 4); // Name size write32(buf + 4, config->is64 ? 16 : 12); // Content size write32(buf + 8, NT_GNU_PROPERTY_TYPE_0); // Type memcpy(buf + 12, "GNU", 4); // Name string write32(buf + 16, featureAndType); // Feature type write32(buf + 20, 4); // Feature size write32(buf + 24, config->andFeatures); // Feature flags if (config->is64) write32(buf + 28, 0); // Padding } size_t GnuPropertySection::getSize() const { return config->is64 ? 32 : 28; } BuildIdSection::BuildIdSection() : SyntheticSection(SHF_ALLOC, SHT_NOTE, 4, ".note.gnu.build-id"), hashSize(getHashSize()) {} void BuildIdSection::writeTo(uint8_t *buf) { write32(buf, 4); // Name size write32(buf + 4, hashSize); // Content size write32(buf + 8, NT_GNU_BUILD_ID); // Type memcpy(buf + 12, "GNU", 4); // Name string hashBuf = buf + 16; } void BuildIdSection::writeBuildId(ArrayRef buf) { assert(buf.size() == hashSize); memcpy(hashBuf, buf.data(), hashSize); } BssSection::BssSection(StringRef name, uint64_t size, uint32_t alignment) : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, alignment, name) { this->bss = true; this->size = size; } EhFrameSection::EhFrameSection() : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame") {} // Search for an existing CIE record or create a new one. // CIE records from input object files are uniquified by their contents // and where their relocations point to. template CieRecord *EhFrameSection::addCie(EhSectionPiece &cie, ArrayRef rels) { Symbol *personality = nullptr; unsigned firstRelI = cie.firstRelocation; if (firstRelI != (unsigned)-1) personality = &cie.sec->template getFile()->getRelocTargetSym(rels[firstRelI]); // Search for an existing CIE by CIE contents/relocation target pair. CieRecord *&rec = cieMap[{cie.data(), personality}]; // If not found, create a new one. if (!rec) { rec = make(); rec->cie = &cie; cieRecords.push_back(rec); } return rec; } // There is one FDE per function. Returns true if a given FDE // points to a live function. template bool EhFrameSection::isFdeLive(EhSectionPiece &fde, ArrayRef rels) { auto *sec = cast(fde.sec); unsigned firstRelI = fde.firstRelocation; // An FDE should point to some function because FDEs are to describe // functions. That's however not always the case due to an issue of // ld.gold with -r. ld.gold may discard only functions and leave their // corresponding FDEs, which results in creating bad .eh_frame sections. // To deal with that, we ignore such FDEs. if (firstRelI == (unsigned)-1) return false; const RelTy &rel = rels[firstRelI]; Symbol &b = sec->template getFile()->getRelocTargetSym(rel); // FDEs for garbage-collected or merged-by-ICF sections, or sections in // another partition, are dead. if (auto *d = dyn_cast(&b)) if (SectionBase *sec = d->section) return sec->partition == partition; return false; } // .eh_frame is a sequence of CIE or FDE records. In general, there // is one CIE record per input object file which is followed by // a list of FDEs. This function searches an existing CIE or create a new // one and associates FDEs to the CIE. template void EhFrameSection::addSectionAux(EhInputSection *sec, ArrayRef rels) { offsetToCie.clear(); for (EhSectionPiece &piece : sec->pieces) { // The empty record is the end marker. if (piece.size == 4) return; size_t offset = piece.inputOff; uint32_t id = read32(piece.data().data() + 4); if (id == 0) { offsetToCie[offset] = addCie(piece, rels); continue; } uint32_t cieOffset = offset + 4 - id; CieRecord *rec = offsetToCie[cieOffset]; if (!rec) fatal(toString(sec) + ": invalid CIE reference"); if (!isFdeLive(piece, rels)) continue; rec->fdes.push_back(&piece); numFdes++; } } template void EhFrameSection::addSection(InputSectionBase *c) { auto *sec = cast(c); sec->parent = this; alignment = std::max(alignment, sec->alignment); sections.push_back(sec); for (auto *ds : sec->dependentSections) dependentSections.push_back(ds); if (sec->pieces.empty()) return; if (sec->areRelocsRela) addSectionAux(sec, sec->template relas()); else addSectionAux(sec, sec->template rels()); } static void writeCieFde(uint8_t *buf, ArrayRef d) { memcpy(buf, d.data(), d.size()); size_t aligned = alignTo(d.size(), config->wordsize); // Zero-clear trailing padding if it exists. memset(buf + d.size(), 0, aligned - d.size()); // Fix the size field. -4 since size does not include the size field itself. write32(buf, aligned - 4); } void EhFrameSection::finalizeContents() { assert(!this->size); // Not finalized. size_t off = 0; for (CieRecord *rec : cieRecords) { rec->cie->outputOff = off; off += alignTo(rec->cie->size, config->wordsize); for (EhSectionPiece *fde : rec->fdes) { fde->outputOff = off; off += alignTo(fde->size, config->wordsize); } } // The LSB standard does not allow a .eh_frame section with zero // Call Frame Information records. glibc unwind-dw2-fde.c // classify_object_over_fdes expects there is a CIE record length 0 as a // terminator. Thus we add one unconditionally. off += 4; this->size = off; } // Returns data for .eh_frame_hdr. .eh_frame_hdr is a binary search table // to get an FDE from an address to which FDE is applied. This function // returns a list of such pairs. std::vector EhFrameSection::getFdeData() const { uint8_t *buf = Out::bufferStart + getParent()->offset + outSecOff; std::vector ret; uint64_t va = getPartition().ehFrameHdr->getVA(); for (CieRecord *rec : cieRecords) { uint8_t enc = getFdeEncoding(rec->cie); for (EhSectionPiece *fde : rec->fdes) { uint64_t pc = getFdePc(buf, fde->outputOff, enc); uint64_t fdeVA = getParent()->addr + fde->outputOff; if (!isInt<32>(pc - va)) fatal(toString(fde->sec) + ": PC offset is too large: 0x" + Twine::utohexstr(pc - va)); ret.push_back({uint32_t(pc - va), uint32_t(fdeVA - va)}); } } // Sort the FDE list by their PC and uniqueify. Usually there is only // one FDE for a PC (i.e. function), but if ICF merges two functions // into one, there can be more than one FDEs pointing to the address. auto less = [](const FdeData &a, const FdeData &b) { return a.pcRel < b.pcRel; }; llvm::stable_sort(ret, less); auto eq = [](const FdeData &a, const FdeData &b) { return a.pcRel == b.pcRel; }; ret.erase(std::unique(ret.begin(), ret.end(), eq), ret.end()); return ret; } static uint64_t readFdeAddr(uint8_t *buf, int size) { switch (size) { case DW_EH_PE_udata2: return read16(buf); case DW_EH_PE_sdata2: return (int16_t)read16(buf); case DW_EH_PE_udata4: return read32(buf); case DW_EH_PE_sdata4: return (int32_t)read32(buf); case DW_EH_PE_udata8: case DW_EH_PE_sdata8: return read64(buf); case DW_EH_PE_absptr: return readUint(buf); } fatal("unknown FDE size encoding"); } // Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to. // We need it to create .eh_frame_hdr section. uint64_t EhFrameSection::getFdePc(uint8_t *buf, size_t fdeOff, uint8_t enc) const { // The starting address to which this FDE applies is // stored at FDE + 8 byte. size_t off = fdeOff + 8; uint64_t addr = readFdeAddr(buf + off, enc & 0xf); if ((enc & 0x70) == DW_EH_PE_absptr) return addr; if ((enc & 0x70) == DW_EH_PE_pcrel) return addr + getParent()->addr + off; fatal("unknown FDE size relative encoding"); } void EhFrameSection::writeTo(uint8_t *buf) { // Write CIE and FDE records. for (CieRecord *rec : cieRecords) { size_t cieOffset = rec->cie->outputOff; writeCieFde(buf + cieOffset, rec->cie->data()); for (EhSectionPiece *fde : rec->fdes) { size_t off = fde->outputOff; writeCieFde(buf + off, fde->data()); // FDE's second word should have the offset to an associated CIE. // Write it. write32(buf + off + 4, off + 4 - cieOffset); } } // Apply relocations. .eh_frame section contents are not contiguous // in the output buffer, but relocateAlloc() still works because // getOffset() takes care of discontiguous section pieces. for (EhInputSection *s : sections) s->relocateAlloc(buf, nullptr); if (getPartition().ehFrameHdr && getPartition().ehFrameHdr->getParent()) getPartition().ehFrameHdr->write(); } GotSection::GotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, config->wordsize, ".got") { // If ElfSym::globalOffsetTable is relative to .got and is referenced, // increase numEntries by the number of entries used to emit // ElfSym::globalOffsetTable. if (ElfSym::globalOffsetTable && !target->gotBaseSymInGotPlt) numEntries += target->gotHeaderEntriesNum; } void GotSection::addEntry(Symbol &sym) { sym.gotIndex = numEntries; ++numEntries; } bool GotSection::addDynTlsEntry(Symbol &sym) { if (sym.globalDynIndex != -1U) return false; sym.globalDynIndex = numEntries; // Global Dynamic TLS entries take two GOT slots. numEntries += 2; return true; } // Reserves TLS entries for a TLS module ID and a TLS block offset. // In total it takes two GOT slots. bool GotSection::addTlsIndex() { if (tlsIndexOff != uint32_t(-1)) return false; tlsIndexOff = numEntries * config->wordsize; numEntries += 2; return true; } uint64_t GotSection::getGlobalDynAddr(const Symbol &b) const { return this->getVA() + b.globalDynIndex * config->wordsize; } uint64_t GotSection::getGlobalDynOffset(const Symbol &b) const { return b.globalDynIndex * config->wordsize; } void GotSection::finalizeContents() { size = numEntries * config->wordsize; } bool GotSection::isNeeded() const { // We need to emit a GOT even if it's empty if there's a relocation that is // relative to GOT(such as GOTOFFREL). return numEntries || hasGotOffRel; } void GotSection::writeTo(uint8_t *buf) { // Buf points to the start of this section's buffer, // whereas InputSectionBase::relocateAlloc() expects its argument // to point to the start of the output section. target->writeGotHeader(buf); relocateAlloc(buf - outSecOff, buf - outSecOff + size); } static uint64_t getMipsPageAddr(uint64_t addr) { return (addr + 0x8000) & ~0xffff; } static uint64_t getMipsPageCount(uint64_t size) { return (size + 0xfffe) / 0xffff + 1; } MipsGotSection::MipsGotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16, ".got") {} void MipsGotSection::addEntry(InputFile &file, Symbol &sym, int64_t addend, RelExpr expr) { FileGot &g = getGot(file); if (expr == R_MIPS_GOT_LOCAL_PAGE) { if (const OutputSection *os = sym.getOutputSection()) g.pagesMap.insert({os, {}}); else g.local16.insert({{nullptr, getMipsPageAddr(sym.getVA(addend))}, 0}); } else if (sym.isTls()) g.tls.insert({&sym, 0}); else if (sym.isPreemptible && expr == R_ABS) g.relocs.insert({&sym, 0}); else if (sym.isPreemptible) g.global.insert({&sym, 0}); else if (expr == R_MIPS_GOT_OFF32) g.local32.insert({{&sym, addend}, 0}); else g.local16.insert({{&sym, addend}, 0}); } void MipsGotSection::addDynTlsEntry(InputFile &file, Symbol &sym) { getGot(file).dynTlsSymbols.insert({&sym, 0}); } void MipsGotSection::addTlsIndex(InputFile &file) { getGot(file).dynTlsSymbols.insert({nullptr, 0}); } size_t MipsGotSection::FileGot::getEntriesNum() const { return getPageEntriesNum() + local16.size() + global.size() + relocs.size() + tls.size() + dynTlsSymbols.size() * 2; } size_t MipsGotSection::FileGot::getPageEntriesNum() const { size_t num = 0; for (const std::pair &p : pagesMap) num += p.second.count; return num; } size_t MipsGotSection::FileGot::getIndexedEntriesNum() const { size_t count = getPageEntriesNum() + local16.size() + global.size(); // If there are relocation-only entries in the GOT, TLS entries // are allocated after them. TLS entries should be addressable // by 16-bit index so count both reloc-only and TLS entries. if (!tls.empty() || !dynTlsSymbols.empty()) count += relocs.size() + tls.size() + dynTlsSymbols.size() * 2; return count; } MipsGotSection::FileGot &MipsGotSection::getGot(InputFile &f) { if (!f.mipsGotIndex.hasValue()) { gots.emplace_back(); gots.back().file = &f; f.mipsGotIndex = gots.size() - 1; } return gots[*f.mipsGotIndex]; } uint64_t MipsGotSection::getPageEntryOffset(const InputFile *f, const Symbol &sym, int64_t addend) const { const FileGot &g = gots[*f->mipsGotIndex]; uint64_t index = 0; if (const OutputSection *outSec = sym.getOutputSection()) { uint64_t secAddr = getMipsPageAddr(outSec->addr); uint64_t symAddr = getMipsPageAddr(sym.getVA(addend)); index = g.pagesMap.lookup(outSec).firstIndex + (symAddr - secAddr) / 0xffff; } else { index = g.local16.lookup({nullptr, getMipsPageAddr(sym.getVA(addend))}); } return index * config->wordsize; } uint64_t MipsGotSection::getSymEntryOffset(const InputFile *f, const Symbol &s, int64_t addend) const { const FileGot &g = gots[*f->mipsGotIndex]; Symbol *sym = const_cast(&s); if (sym->isTls()) return g.tls.lookup(sym) * config->wordsize; if (sym->isPreemptible) return g.global.lookup(sym) * config->wordsize; return g.local16.lookup({sym, addend}) * config->wordsize; } uint64_t MipsGotSection::getTlsIndexOffset(const InputFile *f) const { const FileGot &g = gots[*f->mipsGotIndex]; return g.dynTlsSymbols.lookup(nullptr) * config->wordsize; } uint64_t MipsGotSection::getGlobalDynOffset(const InputFile *f, const Symbol &s) const { const FileGot &g = gots[*f->mipsGotIndex]; Symbol *sym = const_cast(&s); return g.dynTlsSymbols.lookup(sym) * config->wordsize; } const Symbol *MipsGotSection::getFirstGlobalEntry() const { if (gots.empty()) return nullptr; const FileGot &primGot = gots.front(); if (!primGot.global.empty()) return primGot.global.front().first; if (!primGot.relocs.empty()) return primGot.relocs.front().first; return nullptr; } unsigned MipsGotSection::getLocalEntriesNum() const { if (gots.empty()) return headerEntriesNum; return headerEntriesNum + gots.front().getPageEntriesNum() + gots.front().local16.size(); } bool MipsGotSection::tryMergeGots(FileGot &dst, FileGot &src, bool isPrimary) { FileGot tmp = dst; set_union(tmp.pagesMap, src.pagesMap); set_union(tmp.local16, src.local16); set_union(tmp.global, src.global); set_union(tmp.relocs, src.relocs); set_union(tmp.tls, src.tls); set_union(tmp.dynTlsSymbols, src.dynTlsSymbols); size_t count = isPrimary ? headerEntriesNum : 0; count += tmp.getIndexedEntriesNum(); if (count * config->wordsize > config->mipsGotSize) return false; std::swap(tmp, dst); return true; } void MipsGotSection::finalizeContents() { updateAllocSize(); } bool MipsGotSection::updateAllocSize() { size = headerEntriesNum * config->wordsize; for (const FileGot &g : gots) size += g.getEntriesNum() * config->wordsize; return false; } void MipsGotSection::build() { if (gots.empty()) return; std::vector mergedGots(1); // For each GOT move non-preemptible symbols from the `Global` // to `Local16` list. Preemptible symbol might become non-preemptible // one if, for example, it gets a related copy relocation. for (FileGot &got : gots) { for (auto &p: got.global) if (!p.first->isPreemptible) got.local16.insert({{p.first, 0}, 0}); got.global.remove_if([&](const std::pair &p) { return !p.first->isPreemptible; }); } // For each GOT remove "reloc-only" entry if there is "global" // entry for the same symbol. And add local entries which indexed // using 32-bit value at the end of 16-bit entries. for (FileGot &got : gots) { got.relocs.remove_if([&](const std::pair &p) { return got.global.count(p.first); }); set_union(got.local16, got.local32); got.local32.clear(); } // Evaluate number of "reloc-only" entries in the resulting GOT. // To do that put all unique "reloc-only" and "global" entries // from all GOTs to the future primary GOT. FileGot *primGot = &mergedGots.front(); for (FileGot &got : gots) { set_union(primGot->relocs, got.global); set_union(primGot->relocs, got.relocs); got.relocs.clear(); } // Evaluate number of "page" entries in each GOT. for (FileGot &got : gots) { for (std::pair &p : got.pagesMap) { const OutputSection *os = p.first; uint64_t secSize = 0; for (BaseCommand *cmd : os->sectionCommands) { if (auto *isd = dyn_cast(cmd)) for (InputSection *isec : isd->sections) { uint64_t off = alignTo(secSize, isec->alignment); secSize = off + isec->getSize(); } } p.second.count = getMipsPageCount(secSize); } } // Merge GOTs. Try to join as much as possible GOTs but do not exceed // maximum GOT size. At first, try to fill the primary GOT because // the primary GOT can be accessed in the most effective way. If it // is not possible, try to fill the last GOT in the list, and finally // create a new GOT if both attempts failed. for (FileGot &srcGot : gots) { InputFile *file = srcGot.file; if (tryMergeGots(mergedGots.front(), srcGot, true)) { file->mipsGotIndex = 0; } else { // If this is the first time we failed to merge with the primary GOT, // MergedGots.back() will also be the primary GOT. We must make sure not // to try to merge again with isPrimary=false, as otherwise, if the // inputs are just right, we could allow the primary GOT to become 1 or 2 // words bigger due to ignoring the header size. if (mergedGots.size() == 1 || !tryMergeGots(mergedGots.back(), srcGot, false)) { mergedGots.emplace_back(); std::swap(mergedGots.back(), srcGot); } file->mipsGotIndex = mergedGots.size() - 1; } } std::swap(gots, mergedGots); // Reduce number of "reloc-only" entries in the primary GOT // by substracting "global" entries exist in the primary GOT. primGot = &gots.front(); primGot->relocs.remove_if([&](const std::pair &p) { return primGot->global.count(p.first); }); // Calculate indexes for each GOT entry. size_t index = headerEntriesNum; for (FileGot &got : gots) { got.startIndex = &got == primGot ? 0 : index; for (std::pair &p : got.pagesMap) { // For each output section referenced by GOT page relocations calculate // and save into pagesMap an upper bound of MIPS GOT entries required // to store page addresses of local symbols. We assume the worst case - // each 64kb page of the output section has at least one GOT relocation // against it. And take in account the case when the section intersects // page boundaries. p.second.firstIndex = index; index += p.second.count; } for (auto &p: got.local16) p.second = index++; for (auto &p: got.global) p.second = index++; for (auto &p: got.relocs) p.second = index++; for (auto &p: got.tls) p.second = index++; for (auto &p: got.dynTlsSymbols) { p.second = index; index += 2; } } // Update Symbol::gotIndex field to use this // value later in the `sortMipsSymbols` function. for (auto &p : primGot->global) p.first->gotIndex = p.second; for (auto &p : primGot->relocs) p.first->gotIndex = p.second; // Create dynamic relocations. for (FileGot &got : gots) { // Create dynamic relocations for TLS entries. for (std::pair &p : got.tls) { Symbol *s = p.first; uint64_t offset = p.second * config->wordsize; if (s->isPreemptible) mainPart->relaDyn->addReloc(target->tlsGotRel, this, offset, s); } for (std::pair &p : got.dynTlsSymbols) { Symbol *s = p.first; uint64_t offset = p.second * config->wordsize; if (s == nullptr) { if (!config->isPic) continue; mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, this, offset, s); } else { // When building a shared library we still need a dynamic relocation // for the module index. Therefore only checking for // S->isPreemptible is not sufficient (this happens e.g. for // thread-locals that have been marked as local through a linker script) if (!s->isPreemptible && !config->isPic) continue; mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, this, offset, s); // However, we can skip writing the TLS offset reloc for non-preemptible // symbols since it is known even in shared libraries if (!s->isPreemptible) continue; offset += config->wordsize; mainPart->relaDyn->addReloc(target->tlsOffsetRel, this, offset, s); } } // Do not create dynamic relocations for non-TLS // entries in the primary GOT. if (&got == primGot) continue; // Dynamic relocations for "global" entries. for (const std::pair &p : got.global) { uint64_t offset = p.second * config->wordsize; mainPart->relaDyn->addReloc(target->relativeRel, this, offset, p.first); } if (!config->isPic) continue; // Dynamic relocations for "local" entries in case of PIC. for (const std::pair &l : got.pagesMap) { size_t pageCount = l.second.count; for (size_t pi = 0; pi < pageCount; ++pi) { uint64_t offset = (l.second.firstIndex + pi) * config->wordsize; mainPart->relaDyn->addReloc({target->relativeRel, this, offset, l.first, int64_t(pi * 0x10000)}); } } for (const std::pair &p : got.local16) { uint64_t offset = p.second * config->wordsize; mainPart->relaDyn->addReloc({target->relativeRel, this, offset, true, p.first.first, p.first.second}); } } } bool MipsGotSection::isNeeded() const { // We add the .got section to the result for dynamic MIPS target because // its address and properties are mentioned in the .dynamic section. return !config->relocatable; } uint64_t MipsGotSection::getGp(const InputFile *f) const { // For files without related GOT or files refer a primary GOT // returns "common" _gp value. For secondary GOTs calculate // individual _gp values. if (!f || !f->mipsGotIndex.hasValue() || *f->mipsGotIndex == 0) return ElfSym::mipsGp->getVA(0); return getVA() + gots[*f->mipsGotIndex].startIndex * config->wordsize + 0x7ff0; } void MipsGotSection::writeTo(uint8_t *buf) { // Set the MSB of the second GOT slot. This is not required by any // MIPS ABI documentation, though. // // There is a comment in glibc saying that "The MSB of got[1] of a // gnu object is set to identify gnu objects," and in GNU gold it // says "the second entry will be used by some runtime loaders". // But how this field is being used is unclear. // // We are not really willing to mimic other linkers behaviors // without understanding why they do that, but because all files // generated by GNU tools have this special GOT value, and because // we've been doing this for years, it is probably a safe bet to // keep doing this for now. We really need to revisit this to see // if we had to do this. writeUint(buf + config->wordsize, (uint64_t)1 << (config->wordsize * 8 - 1)); for (const FileGot &g : gots) { auto write = [&](size_t i, const Symbol *s, int64_t a) { uint64_t va = a; if (s) va = s->getVA(a); writeUint(buf + i * config->wordsize, va); }; // Write 'page address' entries to the local part of the GOT. for (const std::pair &l : g.pagesMap) { size_t pageCount = l.second.count; uint64_t firstPageAddr = getMipsPageAddr(l.first->addr); for (size_t pi = 0; pi < pageCount; ++pi) write(l.second.firstIndex + pi, nullptr, firstPageAddr + pi * 0x10000); } // Local, global, TLS, reloc-only entries. // If TLS entry has a corresponding dynamic relocations, leave it // initialized by zero. Write down adjusted TLS symbol's values otherwise. // To calculate the adjustments use offsets for thread-local storage. // https://www.linux-mips.org/wiki/NPTL for (const std::pair &p : g.local16) write(p.second, p.first.first, p.first.second); // Write VA to the primary GOT only. For secondary GOTs that // will be done by REL32 dynamic relocations. if (&g == &gots.front()) for (const std::pair &p : g.global) write(p.second, p.first, 0); for (const std::pair &p : g.relocs) write(p.second, p.first, 0); for (const std::pair &p : g.tls) write(p.second, p.first, p.first->isPreemptible ? 0 : -0x7000); for (const std::pair &p : g.dynTlsSymbols) { if (p.first == nullptr && !config->isPic) write(p.second, nullptr, 1); else if (p.first && !p.first->isPreemptible) { // If we are emitting PIC code with relocations we mustn't write // anything to the GOT here. When using Elf_Rel relocations the value // one will be treated as an addend and will cause crashes at runtime if (!config->isPic) write(p.second, nullptr, 1); write(p.second + 1, p.first, -0x8000); } } } } // On PowerPC the .plt section is used to hold the table of function addresses // instead of the .got.plt, and the type is SHT_NOBITS similar to a .bss // section. I don't know why we have a BSS style type for the section but it is // consitent across both 64-bit PowerPC ABIs as well as the 32-bit PowerPC ABI. GotPltSection::GotPltSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, config->wordsize, ".got.plt") { if (config->emachine == EM_PPC) { name = ".plt"; } else if (config->emachine == EM_PPC64) { type = SHT_NOBITS; name = ".plt"; } } void GotPltSection::addEntry(Symbol &sym) { assert(sym.pltIndex == entries.size()); entries.push_back(&sym); } size_t GotPltSection::getSize() const { return (target->gotPltHeaderEntriesNum + entries.size()) * config->wordsize; } void GotPltSection::writeTo(uint8_t *buf) { target->writeGotPltHeader(buf); buf += target->gotPltHeaderEntriesNum * config->wordsize; for (const Symbol *b : entries) { target->writeGotPlt(buf, *b); buf += config->wordsize; } } bool GotPltSection::isNeeded() const { // We need to emit GOTPLT even if it's empty if there's a relocation relative // to it. return !entries.empty() || hasGotPltOffRel; } static StringRef getIgotPltName() { // On ARM the IgotPltSection is part of the GotSection. if (config->emachine == EM_ARM) return ".got"; // On PowerPC64 the GotPltSection is renamed to '.plt' so the IgotPltSection // needs to be named the same. if (config->emachine == EM_PPC64) return ".plt"; return ".got.plt"; } // On PowerPC64 the GotPltSection type is SHT_NOBITS so we have to follow suit // with the IgotPltSection. IgotPltSection::IgotPltSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, config->emachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS, config->wordsize, getIgotPltName()) {} void IgotPltSection::addEntry(Symbol &sym) { assert(sym.pltIndex == entries.size()); entries.push_back(&sym); } size_t IgotPltSection::getSize() const { return entries.size() * config->wordsize; } void IgotPltSection::writeTo(uint8_t *buf) { for (const Symbol *b : entries) { target->writeIgotPlt(buf, *b); buf += config->wordsize; } } StringTableSection::StringTableSection(StringRef name, bool dynamic) : SyntheticSection(dynamic ? (uint64_t)SHF_ALLOC : 0, SHT_STRTAB, 1, name), dynamic(dynamic) { // ELF string tables start with a NUL byte. addString(""); } // Adds a string to the string table. If `hashIt` is true we hash and check for // duplicates. It is optional because the name of global symbols are already // uniqued and hashing them again has a big cost for a small value: uniquing // them with some other string that happens to be the same. unsigned StringTableSection::addString(StringRef s, bool hashIt) { if (hashIt) { auto r = stringMap.insert(std::make_pair(s, this->size)); if (!r.second) return r.first->second; } unsigned ret = this->size; this->size = this->size + s.size() + 1; strings.push_back(s); return ret; } void StringTableSection::writeTo(uint8_t *buf) { for (StringRef s : strings) { memcpy(buf, s.data(), s.size()); buf[s.size()] = '\0'; buf += s.size() + 1; } } // 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; } template DynamicSection::DynamicSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_DYNAMIC, config->wordsize, ".dynamic") { this->entsize = ELFT::Is64Bits ? 16 : 8; // .dynamic section is not writable on MIPS and on Fuchsia OS // which passes -z rodynamic. // See "Special Section" in Chapter 4 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf if (config->emachine == EM_MIPS || config->zRodynamic) this->flags = SHF_ALLOC; } template void DynamicSection::add(int32_t tag, std::function fn) { entries.push_back({tag, fn}); } template void DynamicSection::addInt(int32_t tag, uint64_t val) { entries.push_back({tag, [=] { return val; }}); } template void DynamicSection::addInSec(int32_t tag, InputSection *sec) { entries.push_back({tag, [=] { return sec->getVA(0); }}); } template void DynamicSection::addInSecRelative(int32_t tag, InputSection *sec) { size_t tagOffset = entries.size() * entsize; entries.push_back( {tag, [=] { return sec->getVA(0) - (getVA() + tagOffset); }}); } template void DynamicSection::addOutSec(int32_t tag, OutputSection *sec) { entries.push_back({tag, [=] { return sec->addr; }}); } template void DynamicSection::addSize(int32_t tag, OutputSection *sec) { entries.push_back({tag, [=] { return sec->size; }}); } template void DynamicSection::addSym(int32_t tag, Symbol *sym) { entries.push_back({tag, [=] { return sym->getVA(); }}); } // 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 // overlap with the [DT_RELA, DT_RELA + DT_RELASZ). static uint64_t addPltRelSz() { size_t size = in.relaPlt->getSize(); if (in.relaIplt->getParent() == in.relaPlt->getParent() && in.relaIplt->name == in.relaPlt->name) size += in.relaIplt->getSize(); return size; } // Add remaining entries to complete .dynamic contents. template void DynamicSection::finalizeContents() { elf::Partition &part = getPartition(); bool isMain = part.name.empty(); for (StringRef s : config->filterList) addInt(DT_FILTER, part.dynStrTab->addString(s)); for (StringRef s : config->auxiliaryList) addInt(DT_AUXILIARY, part.dynStrTab->addString(s)); if (!config->rpath.empty()) addInt(config->enableNewDtags ? DT_RUNPATH : DT_RPATH, part.dynStrTab->addString(config->rpath)); for (SharedFile *file : sharedFiles) if (file->isNeeded) addInt(DT_NEEDED, part.dynStrTab->addString(file->soName)); if (isMain) { if (!config->soName.empty()) addInt(DT_SONAME, part.dynStrTab->addString(config->soName)); } else { if (!config->soName.empty()) addInt(DT_NEEDED, part.dynStrTab->addString(config->soName)); addInt(DT_SONAME, part.dynStrTab->addString(part.name)); } // Set DT_FLAGS and DT_FLAGS_1. uint32_t dtFlags = 0; uint32_t dtFlags1 = 0; if (config->bsymbolic) dtFlags |= DF_SYMBOLIC; if (config->zGlobal) dtFlags1 |= DF_1_GLOBAL; if (config->zInitfirst) dtFlags1 |= DF_1_INITFIRST; if (config->zInterpose) dtFlags1 |= DF_1_INTERPOSE; if (config->zNodefaultlib) dtFlags1 |= DF_1_NODEFLIB; if (config->zNodelete) dtFlags1 |= DF_1_NODELETE; if (config->zNodlopen) dtFlags1 |= DF_1_NOOPEN; if (config->zNow) { dtFlags |= DF_BIND_NOW; dtFlags1 |= DF_1_NOW; } if (config->zOrigin) { dtFlags |= DF_ORIGIN; dtFlags1 |= DF_1_ORIGIN; } if (!config->zText) dtFlags |= DF_TEXTREL; if (config->hasStaticTlsModel) dtFlags |= DF_STATIC_TLS; if (dtFlags) addInt(DT_FLAGS, dtFlags); if (dtFlags1) addInt(DT_FLAGS_1, dtFlags1); // DT_DEBUG is a pointer to debug informaion used by debuggers at runtime. We // need it for each process, so we don't write it for DSOs. The loader writes // the pointer into this entry. // // DT_DEBUG is the only .dynamic entry that needs to be written to. Some // systems (currently only Fuchsia OS) provide other means to give the // debugger this information. Such systems may choose make .dynamic read-only. // If the target is such a system (used -z rodynamic) don't write DT_DEBUG. if (!config->shared && !config->relocatable && !config->zRodynamic) addInt(DT_DEBUG, 0); if (OutputSection *sec = part.dynStrTab->getParent()) this->link = sec->sectionIndex; if (part.relaDyn->isNeeded()) { addInSec(part.relaDyn->dynamicTag, part.relaDyn); addSize(part.relaDyn->sizeDynamicTag, part.relaDyn->getParent()); bool isRela = config->isRela; addInt(isRela ? DT_RELAENT : DT_RELENT, isRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel)); // MIPS dynamic loader does not support RELCOUNT tag. // The problem is in the tight relation between dynamic // relocations and GOT. So do not emit this tag on MIPS. if (config->emachine != EM_MIPS) { size_t numRelativeRels = part.relaDyn->getRelativeRelocCount(); if (config->zCombreloc && numRelativeRels) addInt(isRela ? DT_RELACOUNT : DT_RELCOUNT, numRelativeRels); } } if (part.relrDyn && !part.relrDyn->relocs.empty()) { addInSec(config->useAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR, part.relrDyn); addSize(config->useAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ, part.relrDyn->getParent()); addInt(config->useAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT, sizeof(Elf_Relr)); } // .rel[a].plt section usually consists of two parts, containing plt and // iplt relocations. It is possible to have only iplt relocations in the // output. In that case relaPlt is empty and have zero offset, the same offset // as relaIplt has. And we still want to emit proper dynamic tags for that // case, so here we always use relaPlt as marker for the begining of // .rel[a].plt section. if (isMain && (in.relaPlt->isNeeded() || in.relaIplt->isNeeded())) { addInSec(DT_JMPREL, in.relaPlt); entries.push_back({DT_PLTRELSZ, addPltRelSz}); switch (config->emachine) { case EM_MIPS: addInSec(DT_MIPS_PLTGOT, in.gotPlt); break; case EM_SPARCV9: addInSec(DT_PLTGOT, in.plt); break; default: addInSec(DT_PLTGOT, in.gotPlt); break; } addInt(DT_PLTREL, config->isRela ? DT_RELA : DT_REL); } if (config->emachine == EM_AARCH64) { if (config->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) addInt(DT_AARCH64_BTI_PLT, 0); if (config->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_PAC) addInt(DT_AARCH64_PAC_PLT, 0); } addInSec(DT_SYMTAB, part.dynSymTab); addInt(DT_SYMENT, sizeof(Elf_Sym)); addInSec(DT_STRTAB, part.dynStrTab); addInt(DT_STRSZ, part.dynStrTab->getSize()); if (!config->zText) addInt(DT_TEXTREL, 0); if (part.gnuHashTab) addInSec(DT_GNU_HASH, part.gnuHashTab); if (part.hashTab) addInSec(DT_HASH, part.hashTab); if (isMain) { if (Out::preinitArray) { addOutSec(DT_PREINIT_ARRAY, Out::preinitArray); addSize(DT_PREINIT_ARRAYSZ, Out::preinitArray); } if (Out::initArray) { addOutSec(DT_INIT_ARRAY, Out::initArray); addSize(DT_INIT_ARRAYSZ, Out::initArray); } if (Out::finiArray) { addOutSec(DT_FINI_ARRAY, Out::finiArray); addSize(DT_FINI_ARRAYSZ, Out::finiArray); } if (Symbol *b = symtab->find(config->init)) if (b->isDefined()) addSym(DT_INIT, b); if (Symbol *b = symtab->find(config->fini)) if (b->isDefined()) addSym(DT_FINI, b); } bool hasVerNeed = SharedFile::vernauxNum != 0; if (hasVerNeed || part.verDef) addInSec(DT_VERSYM, part.verSym); if (part.verDef) { addInSec(DT_VERDEF, part.verDef); addInt(DT_VERDEFNUM, getVerDefNum()); } if (hasVerNeed) { addInSec(DT_VERNEED, part.verNeed); unsigned needNum = 0; for (SharedFile *f : sharedFiles) if (!f->vernauxs.empty()) ++needNum; addInt(DT_VERNEEDNUM, needNum); } if (config->emachine == EM_MIPS) { addInt(DT_MIPS_RLD_VERSION, 1); addInt(DT_MIPS_FLAGS, RHF_NOTPOT); addInt(DT_MIPS_BASE_ADDRESS, target->getImageBase()); addInt(DT_MIPS_SYMTABNO, part.dynSymTab->getNumSymbols()); add(DT_MIPS_LOCAL_GOTNO, [] { return in.mipsGot->getLocalEntriesNum(); }); if (const Symbol *b = in.mipsGot->getFirstGlobalEntry()) addInt(DT_MIPS_GOTSYM, b->dynsymIndex); else addInt(DT_MIPS_GOTSYM, part.dynSymTab->getNumSymbols()); addInSec(DT_PLTGOT, in.mipsGot); if (in.mipsRldMap) { if (!config->pie) addInSec(DT_MIPS_RLD_MAP, in.mipsRldMap); // Store the offset to the .rld_map section // relative to the address of the tag. addInSecRelative(DT_MIPS_RLD_MAP_REL, in.mipsRldMap); } } // DT_PPC_GOT indicates to glibc Secure PLT is used. If DT_PPC_GOT is absent, // glibc assumes the old-style BSS PLT layout which we don't support. if (config->emachine == EM_PPC) add(DT_PPC_GOT, [] { return in.got->getVA(); }); // Glink dynamic tag is required by the V2 abi if the plt section isn't empty. if (config->emachine == EM_PPC64 && in.plt->isNeeded()) { // The Glink tag points to 32 bytes before the first lazy symbol resolution // stub, which starts directly after the header. entries.push_back({DT_PPC64_GLINK, [=] { unsigned offset = target->pltHeaderSize - 32; return in.plt->getVA(0) + offset; }}); } addInt(DT_NULL, 0); getParent()->link = this->link; this->size = entries.size() * this->entsize; } template void DynamicSection::writeTo(uint8_t *buf) { auto *p = reinterpret_cast(buf); for (std::pair> &kv : entries) { p->d_tag = kv.first; p->d_un.d_val = kv.second(); ++p; } } uint64_t DynamicReloc::getOffset() const { return inputSec->getVA(offsetInSec); } int64_t DynamicReloc::computeAddend() const { if (useSymVA) return sym->getVA(addend); if (!outputSec) return addend; // See the comment in the DynamicReloc ctor. return getMipsPageAddr(outputSec->addr) + addend; } uint32_t DynamicReloc::getSymIndex(SymbolTableBaseSection *symTab) const { if (sym && !useSymVA) return symTab->getSymbolIndex(sym); return 0; } RelocationBaseSection::RelocationBaseSection(StringRef name, uint32_t type, int32_t dynamicTag, int32_t sizeDynamicTag) : SyntheticSection(SHF_ALLOC, type, config->wordsize, name), dynamicTag(dynamicTag), sizeDynamicTag(sizeDynamicTag) {} void RelocationBaseSection::addReloc(RelType dynType, InputSectionBase *isec, uint64_t offsetInSec, Symbol *sym) { addReloc({dynType, isec, offsetInSec, false, sym, 0}); } void RelocationBaseSection::addReloc(RelType dynType, InputSectionBase *inputSec, uint64_t offsetInSec, Symbol *sym, int64_t addend, RelExpr expr, RelType type) { // Write the addends to the relocated address if required. We skip // it if the written value would be zero. if (config->writeAddends && (expr != R_ADDEND || addend != 0)) inputSec->relocations.push_back({expr, type, offsetInSec, addend, sym}); addReloc({dynType, inputSec, offsetInSec, expr != R_ADDEND, sym, addend}); } void RelocationBaseSection::addReloc(const DynamicReloc &reloc) { if (reloc.type == target->relativeRel) ++numRelativeRelocs; relocs.push_back(reloc); } void RelocationBaseSection::finalizeContents() { SymbolTableBaseSection *symTab = getPartition().dynSymTab; // When linking glibc statically, .rel{,a}.plt contains R_*_IRELATIVE // relocations due to IFUNC (e.g. strcpy). sh_link will be set to 0 in that // case. if (symTab && symTab->getParent()) getParent()->link = symTab->getParent()->sectionIndex; else getParent()->link = 0; if (in.relaPlt == this) getParent()->info = in.gotPlt->getParent()->sectionIndex; if (in.relaIplt == this) getParent()->info = in.igotPlt->getParent()->sectionIndex; } RelrBaseSection::RelrBaseSection() : SyntheticSection(SHF_ALLOC, config->useAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR, config->wordsize, ".relr.dyn") {} template static void encodeDynamicReloc(SymbolTableBaseSection *symTab, typename ELFT::Rela *p, const DynamicReloc &rel) { if (config->isRela) p->r_addend = rel.computeAddend(); p->r_offset = rel.getOffset(); p->setSymbolAndType(rel.getSymIndex(symTab), rel.type, config->isMips64EL); } template RelocationSection::RelocationSection(StringRef name, bool sort) : RelocationBaseSection(name, config->isRela ? SHT_RELA : SHT_REL, config->isRela ? DT_RELA : DT_REL, config->isRela ? DT_RELASZ : DT_RELSZ), sort(sort) { this->entsize = config->isRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); } template void RelocationSection::writeTo(uint8_t *buf) { SymbolTableBaseSection *symTab = getPartition().dynSymTab; // Sort by (!IsRelative,SymIndex,r_offset). DT_REL[A]COUNT requires us to // place R_*_RELATIVE first. SymIndex is to improve locality, while r_offset // is to make results easier to read. if (sort) llvm::stable_sort( relocs, [&](const DynamicReloc &a, const DynamicReloc &b) { return std::make_tuple(a.type != target->relativeRel, a.getSymIndex(symTab), a.getOffset()) < std::make_tuple(b.type != target->relativeRel, b.getSymIndex(symTab), b.getOffset()); }); for (const DynamicReloc &rel : relocs) { encodeDynamicReloc(symTab, reinterpret_cast(buf), rel); buf += config->isRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); } } template AndroidPackedRelocationSection::AndroidPackedRelocationSection( StringRef name) : RelocationBaseSection( name, config->isRela ? SHT_ANDROID_RELA : SHT_ANDROID_REL, config->isRela ? DT_ANDROID_RELA : DT_ANDROID_REL, config->isRela ? DT_ANDROID_RELASZ : DT_ANDROID_RELSZ) { this->entsize = 1; } template bool AndroidPackedRelocationSection::updateAllocSize() { // This function computes the contents of an Android-format packed relocation // section. // // This format compresses relocations by using relocation groups to factor out // fields that are common between relocations and storing deltas from previous // relocations in SLEB128 format (which has a short representation for small // numbers). A good example of a relocation type with common fields is // R_*_RELATIVE, which is normally used to represent function pointers in // vtables. In the REL format, each relative relocation has the same r_info // field, and is only different from other relative relocations in terms of // the r_offset field. By sorting relocations by offset, grouping them by // r_info and representing each relocation with only the delta from the // previous offset, each 8-byte relocation can be compressed to as little as 1 // byte (or less with run-length encoding). This relocation packer was able to // reduce the size of the relocation section in an Android Chromium DSO from // 2,911,184 bytes to 174,693 bytes, or 6% of the original size. // // A relocation section consists of a header containing the literal bytes // 'APS2' followed by a sequence of SLEB128-encoded integers. The first two // elements are the total number of relocations in the section and an initial // r_offset value. The remaining elements define a sequence of relocation // groups. Each relocation group starts with a header consisting of the // following elements: // // - the number of relocations in the relocation group // - flags for the relocation group // - (if RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG is set) the r_offset delta // for each relocation in the group. // - (if RELOCATION_GROUPED_BY_INFO_FLAG is set) the value of the r_info // field for each relocation in the group. // - (if RELOCATION_GROUP_HAS_ADDEND_FLAG and // RELOCATION_GROUPED_BY_ADDEND_FLAG are set) the r_addend delta for // each relocation in the group. // // Following the relocation group header are descriptions of each of the // relocations in the group. They consist of the following elements: // // - (if RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG is not set) the r_offset // delta for this relocation. // - (if RELOCATION_GROUPED_BY_INFO_FLAG is not set) the value of the r_info // field for this relocation. // - (if RELOCATION_GROUP_HAS_ADDEND_FLAG is set and // RELOCATION_GROUPED_BY_ADDEND_FLAG is not set) the r_addend delta for // this relocation. size_t oldSize = relocData.size(); relocData = {'A', 'P', 'S', '2'}; raw_svector_ostream os(relocData); auto add = [&](int64_t v) { encodeSLEB128(v, os); }; // The format header includes the number of relocations and the initial // offset (we set this to zero because the first relocation group will // perform the initial adjustment). add(relocs.size()); add(0); std::vector relatives, nonRelatives; for (const DynamicReloc &rel : relocs) { Elf_Rela r; encodeDynamicReloc(getPartition().dynSymTab, &r, rel); if (r.getType(config->isMips64EL) == target->relativeRel) relatives.push_back(r); else nonRelatives.push_back(r); } llvm::sort(relatives, [](const Elf_Rel &a, const Elf_Rel &b) { return a.r_offset < b.r_offset; }); // Try to find groups of relative relocations which are spaced one word // apart from one another. These generally correspond to vtable entries. The // format allows these groups to be encoded using a sort of run-length // encoding, but each group will cost 7 bytes in addition to the offset from // the previous group, so it is only profitable to do this for groups of // size 8 or larger. std::vector ungroupedRelatives; std::vector> relativeGroups; for (auto i = relatives.begin(), e = relatives.end(); i != e;) { std::vector group; do { group.push_back(*i++); } while (i != e && (i - 1)->r_offset + config->wordsize == i->r_offset); if (group.size() < 8) ungroupedRelatives.insert(ungroupedRelatives.end(), group.begin(), group.end()); else relativeGroups.emplace_back(std::move(group)); } unsigned hasAddendIfRela = config->isRela ? RELOCATION_GROUP_HAS_ADDEND_FLAG : 0; uint64_t offset = 0; uint64_t addend = 0; // Emit the run-length encoding for the groups of adjacent relative // relocations. Each group is represented using two groups in the packed // format. The first is used to set the current offset to the start of the // group (and also encodes the first relocation), and the second encodes the // remaining relocations. for (std::vector &g : relativeGroups) { // The first relocation in the group. add(1); add(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG | RELOCATION_GROUPED_BY_INFO_FLAG | hasAddendIfRela); add(g[0].r_offset - offset); add(target->relativeRel); if (config->isRela) { add(g[0].r_addend - addend); addend = g[0].r_addend; } // The remaining relocations. add(g.size() - 1); add(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG | RELOCATION_GROUPED_BY_INFO_FLAG | hasAddendIfRela); add(config->wordsize); add(target->relativeRel); if (config->isRela) { for (auto i = g.begin() + 1, e = g.end(); i != e; ++i) { add(i->r_addend - addend); addend = i->r_addend; } } offset = g.back().r_offset; } // Now the ungrouped relatives. if (!ungroupedRelatives.empty()) { add(ungroupedRelatives.size()); add(RELOCATION_GROUPED_BY_INFO_FLAG | hasAddendIfRela); add(target->relativeRel); for (Elf_Rela &r : ungroupedRelatives) { add(r.r_offset - offset); offset = r.r_offset; if (config->isRela) { add(r.r_addend - addend); addend = r.r_addend; } } } // 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()); add(hasAddendIfRela); for (Elf_Rela &r : nonRelatives) { add(r.r_offset - offset); offset = r.r_offset; add(r.r_info); if (config->isRela) { add(r.r_addend - addend); addend = r.r_addend; } } } // Don't allow the section to shrink; otherwise the size of the section can // oscillate infinitely. if (relocData.size() < oldSize) relocData.append(oldSize - relocData.size(), 0); // Returns whether the section size changed. We need to keep recomputing both // section layout and the contents of this section until the size converges // because changing this section's size can affect section layout, which in // turn can affect the sizes of the LEB-encoded integers stored in this // section. return relocData.size() != oldSize; } template RelrSection::RelrSection() { this->entsize = config->wordsize; } template bool RelrSection::updateAllocSize() { // This function computes the contents of an SHT_RELR packed relocation // section. // // Proposal for adding SHT_RELR sections to generic-abi is here: // https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg // // The encoded sequence of Elf64_Relr entries in a SHT_RELR section looks // like [ AAAAAAAA BBBBBBB1 BBBBBBB1 ... AAAAAAAA BBBBBB1 ... ] // // i.e. start with an address, followed by any number of bitmaps. The address // entry encodes 1 relocation. The subsequent bitmap entries encode up to 63 // relocations each, at subsequent offsets following the last address entry. // // The bitmap entries must have 1 in the least significant bit. The assumption // here is that an address cannot have 1 in lsb. Odd addresses are not // supported. // // Excluding the least significant bit in the bitmap, each non-zero bit in // the bitmap represents a relocation to be applied to a corresponding machine // word that follows the base address word. The second least significant bit // represents the machine word immediately following the initial address, and // each bit that follows represents the next word, in linear order. As such, // a single bitmap can encode up to 31 relocations in a 32-bit object, and // 63 relocations in a 64-bit object. // // This encoding has a couple of interesting properties: // 1. Looking at any entry, it is clear whether it's an address or a bitmap: // even means address, odd means bitmap. // 2. Just a simple list of addresses is a valid encoding. size_t oldSize = relrRelocs.size(); relrRelocs.clear(); // Same as Config->Wordsize but faster because this is a compile-time // constant. const size_t wordsize = sizeof(typename ELFT::uint); // Number of bits to use for the relocation offsets bitmap. // Must be either 63 or 31. const size_t nBits = wordsize * 8 - 1; // Get offsets for all relative relocations and sort them. std::vector offsets; for (const RelativeReloc &rel : relocs) offsets.push_back(rel.getOffset()); llvm::sort(offsets); // For each leading relocation, find following ones that can be folded // as a bitmap and fold them. for (size_t i = 0, e = offsets.size(); i < e;) { // Add a leading relocation. relrRelocs.push_back(Elf_Relr(offsets[i])); uint64_t base = offsets[i] + wordsize; ++i; // Find foldable relocations to construct bitmaps. while (i < e) { uint64_t bitmap = 0; while (i < e) { uint64_t delta = offsets[i] - base; // If it is too far, it cannot be folded. if (delta >= nBits * wordsize) break; // If it is not a multiple of wordsize away, it cannot be folded. if (delta % wordsize) break; // Fold it. bitmap |= 1ULL << (delta / wordsize); ++i; } if (!bitmap) break; relrRelocs.push_back(Elf_Relr((bitmap << 1) | 1)); base += nBits * wordsize; } } return relrRelocs.size() != oldSize; } SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &strTabSec) : SyntheticSection(strTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0, strTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB, config->wordsize, strTabSec.isDynamic() ? ".dynsym" : ".symtab"), strTabSec(strTabSec) {} // Orders symbols according to their positions in the GOT, // in compliance with MIPS ABI rules. // See "Global Offset Table" in Chapter 5 in the following document // for detailed description: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf static bool sortMipsSymbols(const SymbolTableEntry &l, const SymbolTableEntry &r) { // Sort entries related to non-local preemptible symbols by GOT indexes. // All other entries go to the beginning of a dynsym in arbitrary order. if (l.sym->isInGot() && r.sym->isInGot()) return l.sym->gotIndex < r.sym->gotIndex; if (!l.sym->isInGot() && !r.sym->isInGot()) return false; return !l.sym->isInGot(); } void SymbolTableBaseSection::finalizeContents() { if (OutputSection *sec = strTabSec.getParent()) getParent()->link = sec->sectionIndex; if (this->type != SHT_DYNSYM) { sortSymTabSymbols(); return; } // If it is a .dynsym, there should be no local symbols, but we need // to do a few things for the dynamic linker. // Section's Info field has the index of the first non-local symbol. // Because the first symbol entry is a null entry, 1 is the first. getParent()->info = 1; if (getPartition().gnuHashTab) { // NB: It also sorts Symbols to meet the GNU hash table requirements. getPartition().gnuHashTab->addSymbols(symbols); } else if (config->emachine == EM_MIPS) { llvm::stable_sort(symbols, sortMipsSymbols); } // Only the main partition's dynsym indexes are stored in the symbols // themselves. All other partitions use a lookup table. if (this == mainPart->dynSymTab) { size_t i = 0; for (const SymbolTableEntry &s : symbols) s.sym->dynsymIndex = ++i; } } // The ELF spec requires that all local symbols precede global symbols, so we // sort symbol entries in this function. (For .dynsym, we don't do that because // symbols for dynamic linking are inherently all globals.) // // Aside from above, we put local symbols in groups starting with the STT_FILE // symbol. That is convenient for purpose of identifying where are local symbols // coming from. void SymbolTableBaseSection::sortSymTabSymbols() { // Move all local symbols before global symbols. auto e = std::stable_partition( symbols.begin(), symbols.end(), [](const SymbolTableEntry &s) { return s.sym->isLocal() || s.sym->computeBinding() == STB_LOCAL; }); size_t numLocals = e - symbols.begin(); getParent()->info = numLocals + 1; // We want to group the local symbols by file. For that we rebuild the local // part of the symbols vector. We do not need to care about the STT_FILE // symbols, they are already naturally placed first in each group. That // happens because STT_FILE is always the first symbol in the object and hence // precede all other local symbols we add for a file. MapVector> arr; for (const SymbolTableEntry &s : llvm::make_range(symbols.begin(), e)) arr[s.sym->file].push_back(s); auto i = symbols.begin(); for (std::pair> &p : arr) for (SymbolTableEntry &entry : p.second) *i++ = entry; } void SymbolTableBaseSection::addSymbol(Symbol *b) { // Adding a local symbol to a .dynsym is a bug. assert(this->type != SHT_DYNSYM || !b->isLocal()); bool hashIt = b->isLocal(); symbols.push_back({b, strTabSec.addString(b->getName(), hashIt)}); } size_t SymbolTableBaseSection::getSymbolIndex(Symbol *sym) { if (this == mainPart->dynSymTab) return sym->dynsymIndex; // Initializes symbol lookup tables lazily. This is used only for -r, // -emit-relocs and dynsyms in partitions other than the main one. llvm::call_once(onceFlag, [&] { symbolIndexMap.reserve(symbols.size()); size_t i = 0; for (const SymbolTableEntry &e : symbols) { if (e.sym->type == STT_SECTION) sectionIndexMap[e.sym->getOutputSection()] = ++i; else symbolIndexMap[e.sym] = ++i; } }); // Section symbols are mapped based on their output sections // to maintain their semantics. if (sym->type == STT_SECTION) return sectionIndexMap.lookup(sym->getOutputSection()); return symbolIndexMap.lookup(sym); } template SymbolTableSection::SymbolTableSection(StringTableSection &strTabSec) : SymbolTableBaseSection(strTabSec) { this->entsize = sizeof(Elf_Sym); } static BssSection *getCommonSec(Symbol *sym) { if (!config->defineCommon) if (auto *d = dyn_cast(sym)) return dyn_cast_or_null(d->section); return nullptr; } static uint32_t getSymSectionIndex(Symbol *sym) { if (getCommonSec(sym)) return SHN_COMMON; if (!isa(sym) || sym->needsPltAddr) return SHN_UNDEF; if (const OutputSection *os = sym->getOutputSection()) return os->sectionIndex >= SHN_LORESERVE ? (uint32_t)SHN_XINDEX : os->sectionIndex; return SHN_ABS; } // Write the internal symbol table contents to the output symbol table. template void SymbolTableSection::writeTo(uint8_t *buf) { // The first entry is a null entry as per the ELF spec. memset(buf, 0, sizeof(Elf_Sym)); buf += sizeof(Elf_Sym); auto *eSym = reinterpret_cast(buf); for (SymbolTableEntry &ent : symbols) { Symbol *sym = ent.sym; bool isDefinedHere = type == SHT_SYMTAB || sym->partition == partition; // Set st_info and st_other. eSym->st_other = 0; if (sym->isLocal()) { eSym->setBindingAndType(STB_LOCAL, sym->type); } else { eSym->setBindingAndType(sym->computeBinding(), sym->type); eSym->setVisibility(sym->visibility); } // The 3 most significant bits of st_other are used by OpenPOWER ABI. // See getPPC64GlobalEntryToLocalEntryOffset() for more details. if (config->emachine == EM_PPC64) eSym->st_other |= sym->stOther & 0xe0; eSym->st_name = ent.strTabOffset; if (isDefinedHere) eSym->st_shndx = getSymSectionIndex(ent.sym); else eSym->st_shndx = 0; // Copy symbol size if it is a defined symbol. st_size is not significant // for undefined symbols, so whether copying it or not is up to us if that's // the case. We'll leave it as zero because by not setting a value, we can // get the exact same outputs for two sets of input files that differ only // in undefined symbol size in DSOs. if (eSym->st_shndx == SHN_UNDEF || !isDefinedHere) eSym->st_size = 0; else eSym->st_size = sym->getSize(); // st_value is usually an address of a symbol, but that has a // special meaining for uninstantiated common symbols (this can // occur if -r is given). if (BssSection *commonSec = getCommonSec(ent.sym)) eSym->st_value = commonSec->alignment; else if (isDefinedHere) eSym->st_value = sym->getVA(); else eSym->st_value = 0; ++eSym; } // On MIPS we need to mark symbol which has a PLT entry and requires // pointer equality by STO_MIPS_PLT flag. That is necessary to help // dynamic linker distinguish such symbols and MIPS lazy-binding stubs. // https://sourceware.org/ml/binutils/2008-07/txt00000.txt if (config->emachine == EM_MIPS) { auto *eSym = reinterpret_cast(buf); for (SymbolTableEntry &ent : symbols) { Symbol *sym = ent.sym; if (sym->isInPlt() && sym->needsPltAddr) eSym->st_other |= STO_MIPS_PLT; if (isMicroMips()) { // We already set the less-significant bit for symbols // marked by the `STO_MIPS_MICROMIPS` flag and for microMIPS PLT // records. That allows us to distinguish such symbols in // the `MIPS::relocateOne()` routine. Now we should // clear that bit for non-dynamic symbol table, so tools // like `objdump` will be able to deal with a correct // symbol position. if (sym->isDefined() && ((sym->stOther & STO_MIPS_MICROMIPS) || sym->needsPltAddr)) { if (!strTabSec.isDynamic()) eSym->st_value &= ~1; eSym->st_other |= STO_MIPS_MICROMIPS; } } if (config->relocatable) if (auto *d = dyn_cast(sym)) if (isMipsPIC(d)) eSym->st_other |= STO_MIPS_PIC; ++eSym; } } } SymtabShndxSection::SymtabShndxSection() : SyntheticSection(0, SHT_SYMTAB_SHNDX, 4, ".symtab_shndx") { this->entsize = 4; } void SymtabShndxSection::writeTo(uint8_t *buf) { // We write an array of 32 bit values, where each value has 1:1 association // with an entry in .symtab. If the corresponding entry contains SHN_XINDEX, // we need to write actual index, otherwise, we must write SHN_UNDEF(0). buf += 4; // Ignore .symtab[0] entry. for (const SymbolTableEntry &entry : in.symTab->getSymbols()) { if (getSymSectionIndex(entry.sym) == SHN_XINDEX) write32(buf, entry.sym->getOutputSection()->sectionIndex); buf += 4; } } bool SymtabShndxSection::isNeeded() const { // SHT_SYMTAB can hold symbols with section indices values up to // SHN_LORESERVE. If we need more, we want to use extension SHT_SYMTAB_SHNDX // section. Problem is that we reveal the final section indices a bit too // late, and we do not know them here. For simplicity, we just always create // a .symtab_shndx section when the amount of output sections is huge. size_t size = 0; for (BaseCommand *base : script->sectionCommands) if (isa(base)) ++size; return size >= SHN_LORESERVE; } void SymtabShndxSection::finalizeContents() { getParent()->link = in.symTab->getParent()->sectionIndex; } size_t SymtabShndxSection::getSize() const { return in.symTab->getNumSymbols() * 4; } // .hash and .gnu.hash sections contain on-disk hash tables that map // symbol names to their dynamic symbol table indices. Their purpose // is to help the dynamic linker resolve symbols quickly. If ELF files // don't have them, the dynamic linker has to do linear search on all // dynamic symbols, which makes programs slower. Therefore, a .hash // section is added to a DSO by default. A .gnu.hash is added if you // give the -hash-style=gnu or -hash-style=both option. // // The Unix semantics of resolving dynamic symbols is somewhat expensive. // Each ELF file has a list of DSOs that the ELF file depends on and a // list of dynamic symbols that need to be resolved from any of the // DSOs. That means resolving all dynamic symbols takes O(m)*O(n) // where m is the number of DSOs and n is the number of dynamic // symbols. For modern large programs, both m and n are large. So // making each step faster by using hash tables substiantially // improves time to load programs. // // (Note that this is not the only way to design the shared library. // For instance, the Windows DLL takes a different approach. On // Windows, each dynamic symbol has a name of DLL from which the symbol // has to be resolved. That makes the cost of symbol resolution O(n). // This disables some hacky techniques you can use on Unix such as // LD_PRELOAD, but this is arguably better semantics than the Unix ones.) // // Due to historical reasons, we have two different hash tables, .hash // and .gnu.hash. They are for the same purpose, and .gnu.hash is a new // and better version of .hash. .hash is just an on-disk hash table, but // .gnu.hash has a bloom filter in addition to a hash table to skip // DSOs very quickly. If you are sure that your dynamic linker knows // about .gnu.hash, you want to specify -hash-style=gnu. Otherwise, a // safe bet is to specify -hash-style=both for backward compatibilty. GnuHashTableSection::GnuHashTableSection() : SyntheticSection(SHF_ALLOC, SHT_GNU_HASH, config->wordsize, ".gnu.hash") { } void GnuHashTableSection::finalizeContents() { if (OutputSection *sec = getPartition().dynSymTab->getParent()) getParent()->link = sec->sectionIndex; // Computes bloom filter size in word size. We want to allocate 12 // bits for each symbol. It must be a power of two. if (symbols.empty()) { maskWords = 1; } else { uint64_t numBits = symbols.size() * 12; maskWords = NextPowerOf2(numBits / (config->wordsize * 8)); } size = 16; // Header size += config->wordsize * maskWords; // Bloom filter size += nBuckets * 4; // Hash buckets size += symbols.size() * 4; // Hash values } void GnuHashTableSection::writeTo(uint8_t *buf) { // The output buffer is not guaranteed to be zero-cleared because we pre- // fill executable sections with trap instructions. This is a precaution // for that case, which happens only when -no-rosegment is given. memset(buf, 0, size); // Write a header. write32(buf, nBuckets); write32(buf + 4, getPartition().dynSymTab->getNumSymbols() - symbols.size()); write32(buf + 8, maskWords); write32(buf + 12, Shift2); buf += 16; // Write a bloom filter and a hash table. writeBloomFilter(buf); buf += config->wordsize * maskWords; writeHashTable(buf); } // This function writes a 2-bit bloom filter. This bloom filter alone // usually filters out 80% or more of all symbol lookups [1]. // The dynamic linker uses the hash table only when a symbol is not // filtered out by a bloom filter. // // [1] Ulrich Drepper (2011), "How To Write Shared Libraries" (Ver. 4.1.2), // p.9, https://www.akkadia.org/drepper/dsohowto.pdf void GnuHashTableSection::writeBloomFilter(uint8_t *buf) { unsigned c = config->is64 ? 64 : 32; for (const Entry &sym : symbols) { // When C = 64, we choose a word with bits [6:...] and set 1 to two bits in // the word using bits [0:5] and [26:31]. size_t i = (sym.hash / c) & (maskWords - 1); uint64_t val = readUint(buf + i * config->wordsize); val |= uint64_t(1) << (sym.hash % c); val |= uint64_t(1) << ((sym.hash >> Shift2) % c); writeUint(buf + i * config->wordsize, val); } } void GnuHashTableSection::writeHashTable(uint8_t *buf) { uint32_t *buckets = reinterpret_cast(buf); uint32_t oldBucket = -1; uint32_t *values = buckets + nBuckets; for (auto i = symbols.begin(), e = symbols.end(); i != e; ++i) { // Write a hash value. It represents a sequence of chains that share the // same hash modulo value. The last element of each chain is terminated by // LSB 1. uint32_t hash = i->hash; bool isLastInChain = (i + 1) == e || i->bucketIdx != (i + 1)->bucketIdx; hash = isLastInChain ? hash | 1 : hash & ~1; write32(values++, hash); if (i->bucketIdx == oldBucket) continue; // Write a hash bucket. Hash buckets contain indices in the following hash // value table. write32(buckets + i->bucketIdx, getPartition().dynSymTab->getSymbolIndex(i->sym)); oldBucket = i->bucketIdx; } } static uint32_t hashGnu(StringRef name) { uint32_t h = 5381; for (uint8_t c : name) h = (h << 5) + h + c; return h; } // Add symbols to this symbol hash table. Note that this function // destructively sort a given vector -- which is needed because // GNU-style hash table places some sorting requirements. void GnuHashTableSection::addSymbols(std::vector &v) { // We cannot use 'auto' for Mid because GCC 6.1 cannot deduce // its type correctly. std::vector::iterator mid = std::stable_partition(v.begin(), v.end(), [&](const SymbolTableEntry &s) { return !s.sym->isDefined() || s.sym->partition != partition; }); // We chose load factor 4 for the on-disk hash table. For each hash // collision, the dynamic linker will compare a uint32_t hash value. // Since the integer comparison is quite fast, we believe we can // make the load factor even larger. 4 is just a conservative choice. // // Note that we don't want to create a zero-sized hash table because // Android loader as of 2018 doesn't like a .gnu.hash containing such // table. If that's the case, we create a hash table with one unused // dummy slot. nBuckets = std::max((v.end() - mid) / 4, 1); if (mid == v.end()) return; for (SymbolTableEntry &ent : llvm::make_range(mid, v.end())) { Symbol *b = ent.sym; uint32_t hash = hashGnu(b->getName()); uint32_t bucketIdx = hash % nBuckets; symbols.push_back({b, ent.strTabOffset, hash, bucketIdx}); } llvm::stable_sort(symbols, [](const Entry &l, const Entry &r) { return l.bucketIdx < r.bucketIdx; }); v.erase(mid, v.end()); for (const Entry &ent : symbols) v.push_back({ent.sym, ent.strTabOffset}); } HashTableSection::HashTableSection() : SyntheticSection(SHF_ALLOC, SHT_HASH, 4, ".hash") { this->entsize = 4; } void HashTableSection::finalizeContents() { SymbolTableBaseSection *symTab = getPartition().dynSymTab; if (OutputSection *sec = symTab->getParent()) getParent()->link = sec->sectionIndex; unsigned numEntries = 2; // nbucket and nchain. numEntries += symTab->getNumSymbols(); // The chain entries. // Create as many buckets as there are symbols. numEntries += symTab->getNumSymbols(); this->size = numEntries * 4; } void HashTableSection::writeTo(uint8_t *buf) { SymbolTableBaseSection *symTab = getPartition().dynSymTab; // See comment in GnuHashTableSection::writeTo. memset(buf, 0, size); unsigned numSymbols = symTab->getNumSymbols(); uint32_t *p = reinterpret_cast(buf); write32(p++, numSymbols); // nbucket write32(p++, numSymbols); // nchain uint32_t *buckets = p; uint32_t *chains = p + numSymbols; for (const SymbolTableEntry &s : symTab->getSymbols()) { Symbol *sym = s.sym; StringRef name = sym->getName(); unsigned i = sym->dynsymIndex; uint32_t hash = hashSysV(name) % numSymbols; chains[i] = buckets[hash]; write32(buckets + hash, i); } } // On PowerPC64 the lazy symbol resolvers go into the `global linkage table` // in the .glink section, rather then the typical .plt section. PltSection::PltSection(bool isIplt) : SyntheticSection( SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, (config->emachine == EM_PPC || config->emachine == EM_PPC64) ? ".glink" : ".plt"), headerSize(!isIplt || config->zRetpolineplt ? target->pltHeaderSize : 0), isIplt(isIplt) { // The PLT needs to be writable on SPARC as the dynamic linker will // modify the instructions in the PLT entries. if (config->emachine == EM_SPARCV9) this->flags |= SHF_WRITE; } void PltSection::writeTo(uint8_t *buf) { if (config->emachine == EM_PPC) { writePPC32GlinkSection(buf, entries.size()); return; } // At beginning of PLT or retpoline IPLT, we have code to call the dynamic // linker to resolve dynsyms at runtime. Write such code. if (headerSize) target->writePltHeader(buf); size_t off = headerSize; RelocationBaseSection *relSec = isIplt ? in.relaIplt : in.relaPlt; // The IPlt is immediately after the Plt, account for this in relOff size_t pltOff = isIplt ? in.plt->getSize() : 0; for (size_t i = 0, e = entries.size(); i != e; ++i) { const Symbol *b = entries[i]; unsigned relOff = relSec->entsize * i + pltOff; uint64_t got = b->getGotPltVA(); uint64_t plt = this->getVA() + off; target->writePlt(buf + off, got, plt, b->pltIndex, relOff); off += target->pltEntrySize; } } template void PltSection::addEntry(Symbol &sym) { sym.pltIndex = entries.size(); entries.push_back(&sym); } size_t PltSection::getSize() const { return headerSize + entries.size() * target->pltEntrySize; } // Some architectures such as additional symbols in the PLT section. For // example ARM uses mapping symbols to aid disassembly void PltSection::addSymbols() { // The PLT may have symbols defined for the Header, the IPLT has no header if (!isIplt) target->addPltHeaderSymbols(*this); size_t off = headerSize; for (size_t i = 0; i < entries.size(); ++i) { target->addPltSymbols(*this, off); off += target->pltEntrySize; } } // The string hash function for .gdb_index. static uint32_t computeGdbHash(StringRef s) { uint32_t h = 0; for (uint8_t c : s) h = h * 67 + toLower(c) - 113; return h; } GdbIndexSection::GdbIndexSection() : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index") {} // Returns the desired size of an on-disk hash table for a .gdb_index section. // There's a tradeoff between size and collision rate. We aim 75% utilization. size_t GdbIndexSection::computeSymtabSize() const { return std::max(NextPowerOf2(symbols.size() * 4 / 3), 1024); } // Compute the output section size. void GdbIndexSection::initOutputSize() { size = sizeof(GdbIndexHeader) + computeSymtabSize() * 8; for (GdbChunk &chunk : chunks) size += chunk.compilationUnits.size() * 16 + chunk.addressAreas.size() * 20; // Add the constant pool size if exists. if (!symbols.empty()) { GdbSymbol &sym = symbols.back(); size += sym.nameOff + sym.name.size() + 1; } } static std::vector getDebugInfoSections() { std::vector ret; for (InputSectionBase *s : inputSections) if (InputSection *isec = dyn_cast(s)) if (isec->name == ".debug_info") ret.push_back(isec); return ret; } static std::vector readCuList(DWARFContext &dwarf) { std::vector ret; for (std::unique_ptr &cu : dwarf.compile_units()) ret.push_back({cu->getOffset(), cu->getLength() + 4}); return ret; } static std::vector readAddressAreas(DWARFContext &dwarf, InputSection *sec) { std::vector ret; uint32_t cuIdx = 0; for (std::unique_ptr &cu : dwarf.compile_units()) { Expected ranges = cu->collectAddressRanges(); if (!ranges) { error(toString(sec) + ": " + toString(ranges.takeError())); return {}; } ArrayRef sections = sec->file->getSections(); for (DWARFAddressRange &r : *ranges) { if (r.SectionIndex == -1ULL) continue; InputSectionBase *s = sections[r.SectionIndex]; if (!s || s == &InputSection::discarded || !s->isLive()) continue; // Range list with zero size has no effect. if (r.LowPC == r.HighPC) continue; auto *isec = cast(s); uint64_t offset = isec->getOffsetInFile(); ret.push_back({isec, r.LowPC - offset, r.HighPC - offset, cuIdx}); } ++cuIdx; } return ret; } template static std::vector readPubNamesAndTypes(const LLDDwarfObj &obj, const std::vector &cUs) { const DWARFSection &pubNames = obj.getGnuPubNamesSection(); const DWARFSection &pubTypes = obj.getGnuPubTypesSection(); std::vector ret; for (const DWARFSection *pub : {&pubNames, &pubTypes}) { DWARFDebugPubTable table(obj, *pub, config->isLE, true); for (const DWARFDebugPubTable::Set &set : table.getData()) { // The value written into the constant pool is kind << 24 | cuIndex. As we // 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(); for (const DWARFDebugPubTable::Entry &ent : set.Entries) ret.push_back({{ent.Name, computeGdbHash(ent.Name)}, (ent.Descriptor.toBits() << 24) | i}); } } return ret; } // Create a list of symbols from a given list of symbol names and types // by uniquifying them by name. static std::vector createSymbols(ArrayRef> nameAttrs, const std::vector &chunks) { using GdbSymbol = GdbIndexSection::GdbSymbol; using NameAttrEntry = GdbIndexSection::NameAttrEntry; // For each chunk, compute the number of compilation units preceding it. uint32_t cuIdx = 0; std::vector cuIdxs(chunks.size()); for (uint32_t i = 0, e = chunks.size(); i != e; ++i) { cuIdxs[i] = cuIdx; cuIdx += chunks[i].compilationUnits.size(); } // The number of symbols we will handle in this function is of the order // of millions for very large executables, so we use multi-threading to // speed it up. size_t numShards = 32; size_t concurrency = 1; if (threadsEnabled) concurrency = std::min(PowerOf2Floor(hardware_concurrency()), numShards); // A sharded map to uniquify symbols by name. std::vector> map(numShards); size_t shift = 32 - countTrailingZeros(numShards); // Instantiate GdbSymbols while uniqufying them by name. std::vector> symbols(numShards); parallelForEachN(0, concurrency, [&](size_t threadId) { uint32_t i = 0; for (ArrayRef entries : nameAttrs) { for (const NameAttrEntry &ent : entries) { size_t shardId = ent.name.hash() >> shift; if ((shardId & (concurrency - 1)) != threadId) continue; uint32_t v = ent.cuIndexAndAttrs + cuIdxs[i]; size_t &idx = map[shardId][ent.name]; if (idx) { symbols[shardId][idx - 1].cuVector.push_back(v); continue; } idx = symbols[shardId].size() + 1; symbols[shardId].push_back({ent.name, {v}, 0, 0}); } ++i; } }); size_t numSymbols = 0; for (ArrayRef v : symbols) numSymbols += v.size(); // The return type is a flattened vector, so we'll copy each vector // contents to Ret. std::vector ret; ret.reserve(numSymbols); for (std::vector &vec : symbols) for (GdbSymbol &sym : vec) ret.push_back(std::move(sym)); // CU vectors and symbol names are adjacent in the output file. // We can compute their offsets in the output file now. size_t off = 0; for (GdbSymbol &sym : ret) { sym.cuVectorOff = off; off += (sym.cuVector.size() + 1) * 4; } for (GdbSymbol &sym : ret) { sym.nameOff = off; off += sym.name.size() + 1; } return ret; } // Returns a newly-created .gdb_index section. template GdbIndexSection *GdbIndexSection::create() { std::vector sections = getDebugInfoSections(); // .debug_gnu_pub{names,types} are useless in executables. // They are present in input object files solely for creating // a .gdb_index. So we can remove them from the output. for (InputSectionBase *s : inputSections) if (s->name == ".debug_gnu_pubnames" || s->name == ".debug_gnu_pubtypes") s->markDead(); std::vector chunks(sections.size()); std::vector> nameAttrs(sections.size()); parallelForEachN(0, sections.size(), [&](size_t i) { ObjFile *file = sections[i]->getFile(); DWARFContext dwarf(make_unique>(file)); chunks[i].sec = sections[i]; chunks[i].compilationUnits = readCuList(dwarf); chunks[i].addressAreas = readAddressAreas(dwarf, sections[i]); nameAttrs[i] = readPubNamesAndTypes( static_cast &>(dwarf.getDWARFObj()), chunks[i].compilationUnits); }); auto *ret = make(); ret->chunks = std::move(chunks); ret->symbols = createSymbols(nameAttrs, ret->chunks); ret->initOutputSize(); return ret; } void GdbIndexSection::writeTo(uint8_t *buf) { // Write the header. auto *hdr = reinterpret_cast(buf); uint8_t *start = buf; hdr->version = 7; buf += sizeof(*hdr); // Write the CU list. hdr->cuListOff = buf - start; for (GdbChunk &chunk : chunks) { for (CuEntry &cu : chunk.compilationUnits) { write64le(buf, chunk.sec->outSecOff + cu.cuOffset); write64le(buf + 8, cu.cuLength); buf += 16; } } // Write the address area. hdr->cuTypesOff = buf - start; hdr->addressAreaOff = buf - start; uint32_t cuOff = 0; for (GdbChunk &chunk : chunks) { for (AddressEntry &e : chunk.addressAreas) { uint64_t baseAddr = e.section->getVA(0); write64le(buf, baseAddr + e.lowAddress); write64le(buf + 8, baseAddr + e.highAddress); write32le(buf + 16, e.cuIndex + cuOff); buf += 20; } cuOff += chunk.compilationUnits.size(); } // Write the on-disk open-addressing hash table containing symbols. hdr->symtabOff = buf - start; size_t symtabSize = computeSymtabSize(); uint32_t mask = symtabSize - 1; for (GdbSymbol &sym : symbols) { uint32_t h = sym.name.hash(); uint32_t i = h & mask; uint32_t step = ((h * 17) & mask) | 1; while (read32le(buf + i * 8)) i = (i + step) & mask; write32le(buf + i * 8, sym.nameOff); write32le(buf + i * 8 + 4, sym.cuVectorOff); } buf += symtabSize * 8; // Write the string pool. hdr->constantPoolOff = buf - start; parallelForEach(symbols, [&](GdbSymbol &sym) { memcpy(buf + sym.nameOff, sym.name.data(), sym.name.size()); }); // Write the CU vectors. for (GdbSymbol &sym : symbols) { write32le(buf, sym.cuVector.size()); buf += 4; for (uint32_t val : sym.cuVector) { write32le(buf, val); buf += 4; } } } bool GdbIndexSection::isNeeded() const { return !chunks.empty(); } EhFrameHeader::EhFrameHeader() : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".eh_frame_hdr") {} void EhFrameHeader::writeTo(uint8_t *buf) { // Unlike most sections, the EhFrameHeader section is written while writing // another section, namely EhFrameSection, which calls the write() function // below from its writeTo() function. This is necessary because the contents // of EhFrameHeader depend on the relocated contents of EhFrameSection and we // don't know which order the sections will be written in. } // .eh_frame_hdr contains a binary search table of pointers to FDEs. // Each entry of the search table consists of two values, // the starting PC from where FDEs covers, and the FDE's address. // It is sorted by PC. void EhFrameHeader::write() { uint8_t *buf = Out::bufferStart + getParent()->offset + outSecOff; using FdeData = EhFrameSection::FdeData; std::vector fdes = getPartition().ehFrame->getFdeData(); buf[0] = 1; buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; buf[2] = DW_EH_PE_udata4; buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; write32(buf + 4, getPartition().ehFrame->getParent()->addr - this->getVA() - 4); write32(buf + 8, fdes.size()); buf += 12; for (FdeData &fde : fdes) { write32(buf, fde.pcRel); write32(buf + 4, fde.fdeVARel); buf += 8; } } size_t EhFrameHeader::getSize() const { // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs. return 12 + getPartition().ehFrame->numFdes * 8; } bool EhFrameHeader::isNeeded() const { return isLive() && getPartition().ehFrame->isNeeded(); } VersionDefinitionSection::VersionDefinitionSection() : SyntheticSection(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t), ".gnu.version_d") {} StringRef VersionDefinitionSection::getFileDefName() { if (!getPartition().name.empty()) return getPartition().name; if (!config->soName.empty()) return config->soName; return config->outputFile; } void VersionDefinitionSection::finalizeContents() { fileDefNameOff = getPartition().dynStrTab->addString(getFileDefName()); for (VersionDefinition &v : config->versionDefinitions) verDefNameOffs.push_back(getPartition().dynStrTab->addString(v.name)); if (OutputSection *sec = getPartition().dynStrTab->getParent()) getParent()->link = sec->sectionIndex; // sh_info should be set to the number of definitions. This fact is missed in // documentation, but confirmed by binutils community: // https://sourceware.org/ml/binutils/2014-11/msg00355.html getParent()->info = getVerDefNum(); } void VersionDefinitionSection::writeOne(uint8_t *buf, uint32_t index, StringRef name, size_t nameOff) { uint16_t flags = index == 1 ? VER_FLG_BASE : 0; // Write a verdef. write16(buf, 1); // vd_version write16(buf + 2, flags); // vd_flags write16(buf + 4, index); // vd_ndx write16(buf + 6, 1); // vd_cnt write32(buf + 8, hashSysV(name)); // vd_hash write32(buf + 12, 20); // vd_aux write32(buf + 16, 28); // vd_next // Write a veraux. write32(buf + 20, nameOff); // vda_name write32(buf + 24, 0); // vda_next } void VersionDefinitionSection::writeTo(uint8_t *buf) { writeOne(buf, 1, getFileDefName(), fileDefNameOff); auto nameOffIt = verDefNameOffs.begin(); for (VersionDefinition &v : config->versionDefinitions) { buf += EntrySize; writeOne(buf, v.id, v.name, *nameOffIt++); } // Need to terminate the last version definition. write32(buf + 16, 0); // vd_next } size_t VersionDefinitionSection::getSize() const { return EntrySize * getVerDefNum(); } // .gnu.version is a table where each entry is 2 byte long. VersionTableSection::VersionTableSection() : SyntheticSection(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t), ".gnu.version") { this->entsize = 2; } void VersionTableSection::finalizeContents() { // At the moment of june 2016 GNU docs does not mention that sh_link field // should be set, but Sun docs do. Also readelf relies on this field. getParent()->link = getPartition().dynSymTab->getParent()->sectionIndex; } size_t VersionTableSection::getSize() const { return (getPartition().dynSymTab->getSymbols().size() + 1) * 2; } void VersionTableSection::writeTo(uint8_t *buf) { buf += 2; for (const SymbolTableEntry &s : getPartition().dynSymTab->getSymbols()) { write16(buf, s.sym->versionId); buf += 2; } } bool VersionTableSection::isNeeded() const { return getPartition().verDef || getPartition().verNeed->isNeeded(); } void elf::addVerneed(Symbol *ss) { auto &file = cast(*ss->file); if (ss->verdefIndex == VER_NDX_GLOBAL) { ss->versionId = VER_NDX_GLOBAL; return; } if (file.vernauxs.empty()) file.vernauxs.resize(file.verdefs.size()); // Select a version identifier for the vernaux data structure, if we haven't // already allocated one. The verdef identifiers cover the range // [1..getVerDefNum()]; this causes the vernaux identifiers to start from // getVerDefNum()+1. if (file.vernauxs[ss->verdefIndex] == 0) file.vernauxs[ss->verdefIndex] = ++SharedFile::vernauxNum + getVerDefNum(); ss->versionId = file.vernauxs[ss->verdefIndex]; } template VersionNeedSection::VersionNeedSection() : SyntheticSection(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t), ".gnu.version_r") {} template void VersionNeedSection::finalizeContents() { for (SharedFile *f : sharedFiles) { if (f->vernauxs.empty()) continue; verneeds.emplace_back(); Verneed &vn = verneeds.back(); vn.nameStrTab = getPartition().dynStrTab->addString(f->soName); for (unsigned i = 0; i != f->vernauxs.size(); ++i) { if (f->vernauxs[i] == 0) continue; auto *verdef = reinterpret_cast(f->verdefs[i]); vn.vernauxs.push_back( {verdef->vd_hash, f->vernauxs[i], getPartition().dynStrTab->addString(f->getStringTable().data() + verdef->getAux()->vda_name)}); } } if (OutputSection *sec = getPartition().dynStrTab->getParent()) getParent()->link = sec->sectionIndex; getParent()->info = verneeds.size(); } template void VersionNeedSection::writeTo(uint8_t *buf) { // The Elf_Verneeds need to appear first, followed by the Elf_Vernauxs. auto *verneed = reinterpret_cast(buf); auto *vernaux = reinterpret_cast(verneed + verneeds.size()); for (auto &vn : verneeds) { // Create an Elf_Verneed for this DSO. verneed->vn_version = 1; verneed->vn_cnt = vn.vernauxs.size(); verneed->vn_file = vn.nameStrTab; verneed->vn_aux = reinterpret_cast(vernaux) - reinterpret_cast(verneed); verneed->vn_next = sizeof(Elf_Verneed); ++verneed; // Create the Elf_Vernauxs for this Elf_Verneed. for (auto &vna : vn.vernauxs) { vernaux->vna_hash = vna.hash; vernaux->vna_flags = 0; vernaux->vna_other = vna.verneedIndex; vernaux->vna_name = vna.nameStrTab; vernaux->vna_next = sizeof(Elf_Vernaux); ++vernaux; } vernaux[-1].vna_next = 0; } verneed[-1].vn_next = 0; } template size_t VersionNeedSection::getSize() const { return verneeds.size() * sizeof(Elf_Verneed) + SharedFile::vernauxNum * sizeof(Elf_Vernaux); } template bool VersionNeedSection::isNeeded() const { return SharedFile::vernauxNum != 0; } void MergeSyntheticSection::addSection(MergeInputSection *ms) { ms->parent = this; sections.push_back(ms); assert(alignment == ms->alignment || !(ms->flags & SHF_STRINGS)); alignment = std::max(alignment, ms->alignment); } MergeTailSection::MergeTailSection(StringRef name, uint32_t type, uint64_t flags, uint32_t alignment) : MergeSyntheticSection(name, type, flags, alignment), builder(StringTableBuilder::RAW, alignment) {} size_t MergeTailSection::getSize() const { return builder.getSize(); } void MergeTailSection::writeTo(uint8_t *buf) { builder.write(buf); } void MergeTailSection::finalizeContents() { // Add all string pieces to the string table builder to create section // contents. for (MergeInputSection *sec : sections) for (size_t i = 0, e = sec->pieces.size(); i != e; ++i) if (sec->pieces[i].live) builder.add(sec->getData(i)); // Fix the string table content. After this, the contents will never change. builder.finalize(); // finalize() fixed tail-optimized strings, so we can now get // offsets of strings. Get an offset for each string and save it // to a corresponding SectionPiece for easy access. for (MergeInputSection *sec : sections) for (size_t i = 0, e = sec->pieces.size(); i != e; ++i) if (sec->pieces[i].live) sec->pieces[i].outputOff = builder.getOffset(sec->getData(i)); } void MergeNoTailSection::writeTo(uint8_t *buf) { for (size_t i = 0; i < numShards; ++i) shards[i].write(buf + shardOffsets[i]); } // This function is very hot (i.e. it can take several seconds to finish) // because sometimes the number of inputs is in an order of magnitude of // millions. So, we use multi-threading. // // For any strings S and T, we know S is not mergeable with T if S's hash // value is different from T's. If that's the case, we can safely put S and // T into different string builders without worrying about merge misses. // We do it in parallel. void MergeNoTailSection::finalizeContents() { // Initializes string table builders. for (size_t i = 0; i < numShards; ++i) shards.emplace_back(StringTableBuilder::RAW, alignment); // Concurrency level. Must be a power of 2 to avoid expensive modulo // operations in the following tight loop. size_t concurrency = 1; if (threadsEnabled) concurrency = std::min(PowerOf2Floor(hardware_concurrency()), numShards); // Add section pieces to the builders. parallelForEachN(0, concurrency, [&](size_t threadId) { for (MergeInputSection *sec : sections) { for (size_t i = 0, e = sec->pieces.size(); i != e; ++i) { if (!sec->pieces[i].live) continue; size_t shardId = getShardId(sec->pieces[i].hash); if ((shardId & (concurrency - 1)) == threadId) sec->pieces[i].outputOff = shards[shardId].add(sec->getData(i)); } } }); // Compute an in-section offset for each shard. size_t off = 0; for (size_t i = 0; i < numShards; ++i) { shards[i].finalizeInOrder(); if (shards[i].getSize() > 0) off = alignTo(off, alignment); shardOffsets[i] = off; off += shards[i].getSize(); } size = off; // So far, section pieces have offsets from beginning of shards, but // we want offsets from beginning of the whole section. Fix them. parallelForEach(sections, [&](MergeInputSection *sec) { for (size_t i = 0, e = sec->pieces.size(); i != e; ++i) if (sec->pieces[i].live) sec->pieces[i].outputOff += shardOffsets[getShardId(sec->pieces[i].hash)]; }); } static 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(name, type, flags, alignment); return make(name, type, flags, alignment); } template void elf::splitSections() { // splitIntoPieces needs to be called on each MergeInputSection // before calling finalizeContents(). parallelForEach(inputSections, [](InputSectionBase *sec) { if (auto *s = dyn_cast(sec)) s->splitIntoPieces(); else if (auto *eh = dyn_cast(sec)) eh->split(); }); } // 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 mergeSections; for (InputSectionBase *&s : inputSections) { MergeInputSection *ms = dyn_cast(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 &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") {} ARMExidxSyntheticSection::ARMExidxSyntheticSection() : SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX, config->wordsize, ".ARM.exidx") {} static InputSection *findExidxSection(InputSection *isec) { for (InputSection *d : isec->dependentSections) if (d->type == SHT_ARM_EXIDX) return d; return nullptr; } bool ARMExidxSyntheticSection::addSection(InputSection *isec) { if (isec->type == SHT_ARM_EXIDX) { exidxSections.push_back(isec); return true; } if ((isec->flags & SHF_ALLOC) && (isec->flags & SHF_EXECINSTR) && isec->getSize() > 0) { executableSections.push_back(isec); if (empty && findExidxSection(isec)) empty = false; return false; } // FIXME: we do not output a relocation section when --emit-relocs is used // as we do not have relocation sections for linker generated table entries // and we would have to erase at a late stage relocations from merged entries. // Given that exception tables are already position independent and a binary // analyzer could derive the relocations we choose to erase the relocations. if (config->emitRelocs && isec->type == SHT_REL) if (InputSectionBase *ex = isec->getRelocatedSection()) if (isa(ex) && ex->type == SHT_ARM_EXIDX) return true; return false; } // References to .ARM.Extab Sections have bit 31 clear and are not the // special EXIDX_CANTUNWIND bit-pattern. static bool isExtabRef(uint32_t unwind) { return (unwind & 0x80000000) == 0 && unwind != 0x1; } // Return true if the .ARM.exidx section Cur can be merged into the .ARM.exidx // section Prev, where Cur follows Prev in the table. This can be done if the // unwinding instructions in Cur are identical to Prev. Linker generated // EXIDX_CANTUNWIND entries are represented by nullptr as they do not have an // InputSection. static bool isDuplicateArmExidxSec(InputSection *prev, InputSection *cur) { struct ExidxEntry { ulittle32_t fn; ulittle32_t unwind; }; // Get the last table Entry from the previous .ARM.exidx section. If Prev is // nullptr then it will be a synthesized EXIDX_CANTUNWIND entry. ExidxEntry prevEntry = {ulittle32_t(0), ulittle32_t(1)}; if (prev) prevEntry = prev->getDataAs().back(); if (isExtabRef(prevEntry.unwind)) return false; // We consider the unwind instructions of an .ARM.exidx table entry // a duplicate if the previous unwind instructions if: // - Both are the special EXIDX_CANTUNWIND. // - Both are the same inline unwind instructions. // We do not attempt to follow and check links into .ARM.extab tables as // consecutive identical entries are rare and the effort to check that they // are identical is high. // If Cur is nullptr then this is synthesized EXIDX_CANTUNWIND entry. if (cur == nullptr) return prevEntry.unwind == 1; for (const ExidxEntry entry : cur->getDataAs()) if (isExtabRef(entry.unwind) || entry.unwind != prevEntry.unwind) return false; // All table entries in this .ARM.exidx Section can be merged into the // previous Section. return true; } // The .ARM.exidx table must be sorted in ascending order of the address of the // functions the table describes. Optionally duplicate adjacent table entries -// can be removed. At the end of the function the ExecutableSections must be +// can be removed. At the end of the function the executableSections must be // sorted in ascending order of address, Sentinel is set to the InputSection // 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); + } + // Sort the executable sections that may or may not have associated // .ARM.exidx sections by order of ascending address. This requires the // relative positions of InputSections to be known. auto compareByFilePosition = [](const InputSection *a, const InputSection *b) { OutputSection *aOut = a->getParent(); OutputSection *bOut = b->getParent(); if (aOut != bOut) return aOut->sectionIndex < bOut->sectionIndex; return a->outSecOff < b->outSecOff; }; llvm::stable_sort(executableSections, compareByFilePosition); sentinel = executableSections.back(); // Optionally merge adjacent duplicate entries. if (config->mergeArmExidx) { std::vector selectedSections; selectedSections.reserve(executableSections.size()); selectedSections.push_back(executableSections[0]); size_t prev = 0; for (size_t i = 1; i < executableSections.size(); ++i) { InputSection *ex1 = findExidxSection(executableSections[prev]); InputSection *ex2 = findExidxSection(executableSections[i]); if (!isDuplicateArmExidxSec(ex1, ex2)) { selectedSections.push_back(executableSections[i]); prev = i; } } executableSections = std::move(selectedSections); } size_t offset = 0; size = 0; for (InputSection *isec : executableSections) { if (InputSection *d = findExidxSection(isec)) { d->outSecOff = offset; d->parent = getParent(); offset += d->getSize(); } else { offset += 8; } } // Size includes Sentinel. size = offset + 8; } InputSection *ARMExidxSyntheticSection::getLinkOrderDep() const { return executableSections.front(); } // To write the .ARM.exidx table from the ExecutableSections we have three cases // 1.) The InputSection has a .ARM.exidx InputSection in its dependent sections. // We write the .ARM.exidx section contents and apply its relocations. // 2.) The InputSection does not have a dependent .ARM.exidx InputSection. We // must write the contents of an EXIDX_CANTUNWIND directly. We use the // start of the InputSection as the purpose of the linker generated // section is to terminate the address range of the previous entry. // 3.) A trailing EXIDX_CANTUNWIND sentinel section is required at the end of // the table to terminate the address range of the final entry. void ARMExidxSyntheticSection::writeTo(uint8_t *buf) { const uint8_t cantUnwindData[8] = {0, 0, 0, 0, // PREL31 to target 1, 0, 0, 0}; // EXIDX_CANTUNWIND uint64_t offset = 0; for (InputSection *isec : executableSections) { assert(isec->getParent() != nullptr); if (InputSection *d = findExidxSection(isec)) { memcpy(buf + offset, d->data().data(), d->data().size()); d->relocateAlloc(buf, buf + d->getSize()); offset += d->getSize(); } else { // A Linker generated CANTUNWIND section. memcpy(buf + offset, cantUnwindData, sizeof(cantUnwindData)); uint64_t s = isec->getVA(); uint64_t p = getVA() + offset; target->relocateOne(buf + offset, R_ARM_PREL31, s - p); offset += 8; } } // Write Sentinel. memcpy(buf + offset, cantUnwindData, sizeof(cantUnwindData)); uint64_t s = sentinel->getVA(sentinel->getSize()); uint64_t p = getVA() + offset; target->relocateOne(buf + offset, R_ARM_PREL31, s - p); assert(size == offset + 8); } bool ARMExidxSyntheticSection::classof(const SectionBase *d) { return d->kind() == InputSectionBase::Synthetic && d->type == SHT_ARM_EXIDX; } ThunkSection::ThunkSection(OutputSection *os, uint64_t off) : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, config->wordsize, ".text.thunk") { this->parent = os; this->outSecOff = off; } void ThunkSection::addThunk(Thunk *t) { thunks.push_back(t); t->addSymbols(*this); } void ThunkSection::writeTo(uint8_t *buf) { for (Thunk *t : thunks) t->writeTo(buf + t->offset); } InputSection *ThunkSection::getTargetInputSection() const { if (thunks.empty()) return nullptr; const Thunk *t = thunks.front(); return t->getTargetInputSection(); } bool ThunkSection::assignOffsets() { uint64_t off = 0; for (Thunk *t : thunks) { off = alignTo(off, t->alignment); t->setOffset(off); uint32_t size = t->size(); t->getThunkTargetSym()->size = size; off += size; } bool changed = off != size; size = off; return changed; } PPC32Got2Section::PPC32Got2Section() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 4, ".got2") {} bool PPC32Got2Section::isNeeded() const { // See the comment below. This is not needed if there is no other // InputSection. for (BaseCommand *base : getParent()->sectionCommands) if (auto *isd = dyn_cast(base)) for (InputSection *isec : isd->sections) if (isec != this) return true; return false; } void PPC32Got2Section::finalizeContents() { // PPC32 may create multiple GOT sections for -fPIC/-fPIE, one per file in // .got2 . This function computes outSecOff of each .got2 to be used in // PPC32PltCallStub::writeTo(). The purpose of this empty synthetic section is // to collect input sections named ".got2". uint32_t offset = 0; for (BaseCommand *base : getParent()->sectionCommands) if (auto *isd = dyn_cast(base)) { for (InputSection *isec : isd->sections) { if (isec == this) continue; isec->file->ppc32Got2OutSecOff = offset; offset += (uint32_t)isec->getSize(); } } } // If linking position-dependent code then the table will store the addresses // directly in the binary so the section has type SHT_PROGBITS. If linking // position-independent code the section has type SHT_NOBITS since it will be // allocated and filled in by the dynamic linker. PPC64LongBranchTargetSection::PPC64LongBranchTargetSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, config->isPic ? SHT_NOBITS : SHT_PROGBITS, 8, ".branch_lt") {} void PPC64LongBranchTargetSection::addEntry(Symbol &sym) { assert(sym.ppc64BranchltIndex == 0xffff); sym.ppc64BranchltIndex = entries.size(); entries.push_back(&sym); } size_t PPC64LongBranchTargetSection::getSize() const { return entries.size() * 8; } void PPC64LongBranchTargetSection::writeTo(uint8_t *buf) { // If linking non-pic we have the final addresses of the targets and they get // written to the table directly. For pic the dynamic linker will allocate // the section and fill it it. if (config->isPic) return; for (const Symbol *sym : entries) { assert(sym->getVA()); // Need calls to branch to the local entry-point since a long-branch // must be a local-call. write64(buf, sym->getVA() + getPPC64GlobalEntryToLocalEntryOffset(sym->stOther)); buf += 8; } } bool PPC64LongBranchTargetSection::isNeeded() const { // `removeUnusedSyntheticSections()` is called before thunk allocation which // is too early to determine if this section will be empty or not. We need // Finalized to keep the section alive until after thunk creation. Finalized // only gets set to true once `finalizeSections()` is called after thunk // creation. Becuase of this, if we don't create any long-branch thunks we end // up with an empty .branch_lt section in the binary. 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(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) { if (!config->isPic && !config->relocatable && (config->eflags & (EF_MIPS_PIC | EF_MIPS_CPIC)) == EF_MIPS_CPIC) return 1; return 0; } if (config->emachine == EM_AMDGPU) { uint8_t ver = objectFiles[0]->abiVersion; for (InputFile *file : makeArrayRef(objectFiles).slice(1)) if (file->abiVersion != ver) error("incompatible ABI version: " + toString(file)); return ver; } return 0; } template void elf::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. memset(buf, 0, sizeof(typename ELFT::Ehdr)); memcpy(buf, "\177ELF", 4); auto *eHdr = reinterpret_cast(buf); eHdr->e_ident[EI_CLASS] = config->is64 ? ELFCLASS64 : ELFCLASS32; eHdr->e_ident[EI_DATA] = config->isLE ? ELFDATA2LSB : ELFDATA2MSB; eHdr->e_ident[EI_VERSION] = EV_CURRENT; eHdr->e_ident[EI_OSABI] = config->osabi; eHdr->e_ident[EI_ABIVERSION] = getAbiVersion(); eHdr->e_machine = config->emachine; eHdr->e_version = EV_CURRENT; eHdr->e_flags = config->eflags; eHdr->e_ehsize = sizeof(typename ELFT::Ehdr); eHdr->e_phnum = part.phdrs.size(); eHdr->e_shentsize = sizeof(typename ELFT::Shdr); if (!config->relocatable) { eHdr->e_phoff = sizeof(typename ELFT::Ehdr); eHdr->e_phentsize = sizeof(typename ELFT::Phdr); } } template void elf::writePhdrs(uint8_t *buf, Partition &part) { // Write the program header table. auto *hBuf = reinterpret_cast(buf); for (PhdrEntry *p : part.phdrs) { hBuf->p_type = p->p_type; hBuf->p_flags = p->p_flags; hBuf->p_offset = p->p_offset; hBuf->p_vaddr = p->p_vaddr; hBuf->p_paddr = p->p_paddr; hBuf->p_filesz = p->p_filesz; hBuf->p_memsz = p->p_memsz; hBuf->p_align = p->p_align; ++hBuf; } } template PartitionElfHeaderSection::PartitionElfHeaderSection() : SyntheticSection(SHF_ALLOC, SHT_LLVM_PART_EHDR, 1, "") {} template size_t PartitionElfHeaderSection::getSize() const { return sizeof(typename ELFT::Ehdr); } template void PartitionElfHeaderSection::writeTo(uint8_t *buf) { writeEhdr(buf, getPartition()); // Loadable partitions are always ET_DYN. auto *eHdr = reinterpret_cast(buf); eHdr->e_type = ET_DYN; } template PartitionProgramHeadersSection::PartitionProgramHeadersSection() : SyntheticSection(SHF_ALLOC, SHT_LLVM_PART_PHDR, 1, ".phdrs") {} template size_t PartitionProgramHeadersSection::getSize() const { return sizeof(typename ELFT::Phdr) * getPartition().phdrs.size(); } template void PartitionProgramHeadersSection::writeTo(uint8_t *buf) { writePhdrs(buf, getPartition()); } PartitionIndexSection::PartitionIndexSection() : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".rodata") {} size_t PartitionIndexSection::getSize() const { return 12 * (partitions.size() - 1); } void PartitionIndexSection::finalizeContents() { for (size_t i = 1; i != partitions.size(); ++i) partitions[i].nameStrTab = mainPart->dynStrTab->addString(partitions[i].name); } void PartitionIndexSection::writeTo(uint8_t *buf) { uint64_t va = getVA(); for (size_t i = 1; i != partitions.size(); ++i) { write32(buf, mainPart->dynStrTab->getVA() + partitions[i].nameStrTab - va); write32(buf + 4, partitions[i].elfHeader->getVA() - (va + 4)); SyntheticSection *next = i == partitions.size() - 1 ? in.partEnd : partitions[i + 1].elfHeader; write32(buf + 8, next->getVA() - partitions[i].elfHeader->getVA()); va += 12; buf += 12; } } InStruct elf::in; std::vector elf::partitions; Partition *elf::mainPart; template GdbIndexSection *GdbIndexSection::create(); template GdbIndexSection *GdbIndexSection::create(); template GdbIndexSection *GdbIndexSection::create(); template GdbIndexSection *GdbIndexSection::create(); template void elf::splitSections(); template void elf::splitSections(); template void elf::splitSections(); template void elf::splitSections(); template void EhFrameSection::addSection(InputSectionBase *); template void EhFrameSection::addSection(InputSectionBase *); template void EhFrameSection::addSection(InputSectionBase *); template void EhFrameSection::addSection(InputSectionBase *); template void PltSection::addEntry(Symbol &Sym); template void PltSection::addEntry(Symbol &Sym); template void PltSection::addEntry(Symbol &Sym); template void PltSection::addEntry(Symbol &Sym); template class elf::MipsAbiFlagsSection; template class elf::MipsAbiFlagsSection; template class elf::MipsAbiFlagsSection; template class elf::MipsAbiFlagsSection; template class elf::MipsOptionsSection; template class elf::MipsOptionsSection; template class elf::MipsOptionsSection; template class elf::MipsOptionsSection; template class elf::MipsReginfoSection; template class elf::MipsReginfoSection; template class elf::MipsReginfoSection; template class elf::MipsReginfoSection; template class elf::DynamicSection; template class elf::DynamicSection; template class elf::DynamicSection; template class elf::DynamicSection; template class elf::RelocationSection; template class elf::RelocationSection; template class elf::RelocationSection; template class elf::RelocationSection; template class elf::AndroidPackedRelocationSection; template class elf::AndroidPackedRelocationSection; template class elf::AndroidPackedRelocationSection; template class elf::AndroidPackedRelocationSection; template class elf::RelrSection; template class elf::RelrSection; template class elf::RelrSection; template class elf::RelrSection; template class elf::SymbolTableSection; template class elf::SymbolTableSection; template class elf::SymbolTableSection; template class elf::SymbolTableSection; template class elf::VersionNeedSection; template class elf::VersionNeedSection; template class elf::VersionNeedSection; template class elf::VersionNeedSection; template void elf::writeEhdr(uint8_t *Buf, Partition &Part); template void elf::writeEhdr(uint8_t *Buf, Partition &Part); template void elf::writeEhdr(uint8_t *Buf, Partition &Part); template void elf::writeEhdr(uint8_t *Buf, Partition &Part); template void elf::writePhdrs(uint8_t *Buf, Partition &Part); template void elf::writePhdrs(uint8_t *Buf, Partition &Part); template void elf::writePhdrs(uint8_t *Buf, Partition &Part); template void elf::writePhdrs(uint8_t *Buf, Partition &Part); template class elf::PartitionElfHeaderSection; template class elf::PartitionElfHeaderSection; template class elf::PartitionElfHeaderSection; template class elf::PartitionElfHeaderSection; template class elf::PartitionProgramHeadersSection; template class elf::PartitionProgramHeadersSection; template class elf::PartitionProgramHeadersSection; template class elf::PartitionProgramHeadersSection; Index: vendor/lld/dist-release_90/docs/ReleaseNotes.rst =================================================================== --- vendor/lld/dist-release_90/docs/ReleaseNotes.rst (revision 351311) +++ vendor/lld/dist-release_90/docs/ReleaseNotes.rst (revision 351312) @@ -1,73 +1,101 @@ ======================= lld 9.0.0 Release Notes ======================= .. contents:: :local: .. warning:: These are in-progress notes for the upcoming LLVM 9.0.0 release. Release notes for previous releases can be found on `the Download Page `_. Introduction ============ This document contains the release notes for the lld linker, release 9.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 `_. 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'``. +* lld now supports replacing ``JAL`` with ``JALX`` instructions in case + of MIPS - microMIPS cross-mode jumps. + +* lld now creates LA25 thunks for MIPS R6 code. + +* Put MIPS-specific .reginfo, .MIPS.options, and .MIPS.abiflags sections + into corresponding PT_MIPS_REGINFO, PT_MIPS_OPTIONS, and PT_MIPS_ABIFLAGS + segments. + * ... COFF Improvements ----------------- * Like the ELF driver, lld-link now has typo suggestions for flags. * lld-link now correctly reports duplicate symbol errors for obj files that were compiled with /Gy. * lld-link now correctly reports duplicate symbol errors when several res input files define resources with the same type, name, and language. This can be demoted to a warning using ``/force:multipleres``. * Having more than two ``/natvis:`` now works correctly; it used to not work for larger binaries before. * Undefined symbols are now printed only in demangled form. Pass ``/demangle:no`` to see raw symbol names instead. * The following flags have been added: ``/functionpadmin``, ``/swaprun:``, ``/threads:no`` * Several speed and memory usage improvements. +* Range extension thunks are now created for ARM64, if needed + +* 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 + * ... 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 + +* Many more GNU ld options are now supported, which e.g. allows the lld + MinGW frontend to be called by GCC + +* 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 `` was more cumbersome to use + with an empty parameter value.) MachO Improvements ------------------ * Item 1. WebAssembly Improvements ------------------------ * ...