diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp index b47041dcca70..eaec1d22e6e5 100644 --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -1,810 +1,813 @@ //===--- MinGW.cpp - MinGWToolChain Implementation ------------------------===// // // 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 "MinGW.h" #include "CommonArgs.h" #include "clang/Config/config.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/VirtualFileSystem.h" #include using namespace clang::diag; using namespace clang::driver; using namespace clang; using namespace llvm::opt; /// MinGW Tools void tools::MinGW::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { claimNoWarnArgs(Args); ArgStringList CmdArgs; if (getToolChain().getArch() == llvm::Triple::x86) { CmdArgs.push_back("--32"); } else if (getToolChain().getArch() == llvm::Triple::x86_64) { CmdArgs.push_back("--64"); } Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); C.addCommand(std::make_unique(JA, *this, ResponseFileSupport::None(), Exec, CmdArgs, Inputs, Output)); if (Args.hasArg(options::OPT_gsplit_dwarf)) SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, SplitDebugName(JA, Args, Inputs[0], Output)); } void tools::MinGW::Linker::AddLibGCC(const ArgList &Args, ArgStringList &CmdArgs) const { if (Args.hasArg(options::OPT_mthreads)) CmdArgs.push_back("-lmingwthrd"); CmdArgs.push_back("-lmingw32"); // Make use of compiler-rt if --rtlib option is used ToolChain::RuntimeLibType RLT = getToolChain().GetRuntimeLibType(Args); if (RLT == ToolChain::RLT_Libgcc) { bool Static = Args.hasArg(options::OPT_static_libgcc) || Args.hasArg(options::OPT_static); bool Shared = Args.hasArg(options::OPT_shared); bool CXX = getToolChain().getDriver().CCCIsCXX(); if (Static || (!CXX && !Shared)) { CmdArgs.push_back("-lgcc"); CmdArgs.push_back("-lgcc_eh"); } else { CmdArgs.push_back("-lgcc_s"); CmdArgs.push_back("-lgcc"); } } else { AddRunTimeLibs(getToolChain(), getToolChain().getDriver(), CmdArgs, Args); } CmdArgs.push_back("-lmoldname"); CmdArgs.push_back("-lmingwex"); for (auto Lib : Args.getAllArgValues(options::OPT_l)) if (StringRef(Lib).startswith("msvcr") || StringRef(Lib).startswith("ucrt") || StringRef(Lib).startswith("crtdll")) return; CmdArgs.push_back("-lmsvcrt"); } void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const ToolChain &TC = getToolChain(); const Driver &D = TC.getDriver(); const SanitizerArgs &Sanitize = TC.getSanitizerArgs(Args); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" Args.ClaimAllArgs(options::OPT_g_Group); // and "clang -emit-llvm foo.o -o foo" Args.ClaimAllArgs(options::OPT_emit_llvm); // and for "clang -w foo.o -o foo". Other warning options are already // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("-s"); CmdArgs.push_back("-m"); switch (TC.getArch()) { case llvm::Triple::x86: CmdArgs.push_back("i386pe"); break; case llvm::Triple::x86_64: CmdArgs.push_back("i386pep"); break; case llvm::Triple::arm: case llvm::Triple::thumb: // FIXME: this is incorrect for WinCE CmdArgs.push_back("thumb2pe"); break; case llvm::Triple::aarch64: CmdArgs.push_back("arm64pe"); break; default: D.Diag(diag::err_target_unknown_triple) << TC.getEffectiveTriple().str(); } Arg *SubsysArg = Args.getLastArg(options::OPT_mwindows, options::OPT_mconsole); if (SubsysArg && SubsysArg->getOption().matches(options::OPT_mwindows)) { CmdArgs.push_back("--subsystem"); CmdArgs.push_back("windows"); } else if (SubsysArg && SubsysArg->getOption().matches(options::OPT_mconsole)) { CmdArgs.push_back("--subsystem"); CmdArgs.push_back("console"); } if (Args.hasArg(options::OPT_mdll)) CmdArgs.push_back("--dll"); else if (Args.hasArg(options::OPT_shared)) CmdArgs.push_back("--shared"); if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("-Bstatic"); else CmdArgs.push_back("-Bdynamic"); if (Args.hasArg(options::OPT_mdll) || Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-e"); if (TC.getArch() == llvm::Triple::x86) CmdArgs.push_back("_DllMainCRTStartup@12"); else CmdArgs.push_back("DllMainCRTStartup"); CmdArgs.push_back("--enable-auto-image-base"); } if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); if (Arg *A = Args.getLastArg(options::OPT_mguard_EQ)) { StringRef GuardArgs = A->getValue(); if (GuardArgs == "none") CmdArgs.push_back("--no-guard-cf"); else if (GuardArgs == "cf" || GuardArgs == "cf-nochecks") CmdArgs.push_back("--guard-cf"); else D.Diag(diag::err_drv_unsupported_option_argument) << A->getSpelling() << GuardArgs; } CmdArgs.push_back("-o"); const char *OutputFile = Output.getFilename(); // GCC implicitly adds an .exe extension if it is given an output file name // that lacks an extension. // GCC used to do this only when the compiler itself runs on windows, but // since GCC 8 it does the same when cross compiling as well. if (!llvm::sys::path::has_extension(OutputFile)) { CmdArgs.push_back(Args.MakeArgString(Twine(OutputFile) + ".exe")); OutputFile = CmdArgs.back(); } else CmdArgs.push_back(OutputFile); // FIXME: add -N, -n flags Args.AddLastArg(CmdArgs, options::OPT_r); Args.AddLastArg(CmdArgs, options::OPT_s); Args.AddLastArg(CmdArgs, options::OPT_t); Args.AddAllArgs(CmdArgs, options::OPT_u_Group); Args.AddLastArg(CmdArgs, options::OPT_Z_Flag); // Add asan_dynamic as the first import lib before other libs. This allows // asan to be initialized as early as possible to increase its instrumentation // coverage to include other user DLLs which has not been built with asan. if (Sanitize.needsAsanRt() && !Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { // MinGW always links against a shared MSVCRT. CmdArgs.push_back( TC.getCompilerRTArgString(Args, "asan_dynamic", ToolChain::FT_Shared)); } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_mdll)) { CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("dllcrt2.o"))); } else { if (Args.hasArg(options::OPT_municode)) CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt2u.o"))); else CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt2.o"))); } if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("gcrt2.o"))); CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o"))); } Args.AddAllArgs(CmdArgs, options::OPT_L); TC.AddFilePathLibArgs(Args, CmdArgs); // Add the compiler-rt library directories if they exist to help // the linker find the various sanitizer, builtin, and profiling runtimes. for (const auto &LibPath : TC.getLibraryPaths()) { if (TC.getVFS().exists(LibPath)) CmdArgs.push_back(Args.MakeArgString("-L" + LibPath)); } auto CRTPath = TC.getCompilerRTPath(); if (TC.getVFS().exists(CRTPath)) CmdArgs.push_back(Args.MakeArgString("-L" + CRTPath)); AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); if (C.getDriver().IsFlangMode()) { addFortranRuntimeLibraryPath(TC, Args, CmdArgs); addFortranRuntimeLibs(TC, CmdArgs); } // TODO: Add profile stuff here if (TC.ShouldLinkCXXStdlib(Args)) { bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && !Args.hasArg(options::OPT_static); if (OnlyLibstdcxxStatic) CmdArgs.push_back("-Bstatic"); TC.AddCXXStdlibLibArgs(Args, CmdArgs); if (OnlyLibstdcxxStatic) CmdArgs.push_back("-Bdynamic"); } bool HasWindowsApp = false; for (auto Lib : Args.getAllArgValues(options::OPT_l)) { if (Lib == "windowsapp") { HasWindowsApp = true; break; } } if (!Args.hasArg(options::OPT_nostdlib)) { if (!Args.hasArg(options::OPT_nodefaultlibs)) { if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("--start-group"); if (Args.hasArg(options::OPT_fstack_protector) || Args.hasArg(options::OPT_fstack_protector_strong) || Args.hasArg(options::OPT_fstack_protector_all)) { CmdArgs.push_back("-lssp_nonshared"); CmdArgs.push_back("-lssp"); } if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, options::OPT_fno_openmp, false)) { switch (TC.getDriver().getOpenMPRuntime(Args)) { case Driver::OMPRT_OMP: CmdArgs.push_back("-lomp"); break; case Driver::OMPRT_IOMP5: CmdArgs.push_back("-liomp5md"); break; case Driver::OMPRT_GOMP: CmdArgs.push_back("-lgomp"); break; case Driver::OMPRT_Unknown: // Already diagnosed. break; } } AddLibGCC(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lgmon"); if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); if (Sanitize.needsAsanRt()) { // MinGW always links against a shared MSVCRT. CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dynamic", ToolChain::FT_Shared)); CmdArgs.push_back( TC.getCompilerRTArgString(Args, "asan_dynamic_runtime_thunk")); CmdArgs.push_back("--require-defined"); CmdArgs.push_back(TC.getArch() == llvm::Triple::x86 ? "___asan_seh_interceptor" : "__asan_seh_interceptor"); // Make sure the linker consider all object files from the dynamic // runtime thunk. CmdArgs.push_back("--whole-archive"); CmdArgs.push_back( TC.getCompilerRTArgString(Args, "asan_dynamic_runtime_thunk")); CmdArgs.push_back("--no-whole-archive"); } TC.addProfileRTLibs(Args, CmdArgs); if (!HasWindowsApp) { // Add system libraries. If linking to libwindowsapp.a, that import // library replaces all these and we shouldn't accidentally try to // link to the normal desktop mode dlls. if (Args.hasArg(options::OPT_mwindows)) { CmdArgs.push_back("-lgdi32"); CmdArgs.push_back("-lcomdlg32"); } CmdArgs.push_back("-ladvapi32"); CmdArgs.push_back("-lshell32"); CmdArgs.push_back("-luser32"); CmdArgs.push_back("-lkernel32"); } if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("--end-group"); } else { AddLibGCC(Args, CmdArgs); if (!HasWindowsApp) CmdArgs.push_back("-lkernel32"); } } if (!Args.hasArg(options::OPT_nostartfiles)) { // Add crtfastmath.o if available and fast math is enabled. TC.addFastMathRuntimeIfAvailable(Args, CmdArgs); CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); } } const char *Exec = Args.MakeArgString(TC.GetLinkerPath()); C.addCommand(std::make_unique(JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs, Output)); } static bool isCrossCompiling(const llvm::Triple &T, bool RequireArchMatch) { llvm::Triple HostTriple(llvm::Triple::normalize(LLVM_HOST_TRIPLE)); if (HostTriple.getOS() != llvm::Triple::Win32) return true; if (RequireArchMatch && HostTriple.getArch() != T.getArch()) return true; return false; } // Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple. static bool findGccVersion(StringRef LibDir, std::string &GccLibDir, std::string &Ver, toolchains::Generic_GCC::GCCVersion &Version) { Version = toolchains::Generic_GCC::GCCVersion::Parse("0.0.0"); std::error_code EC; for (llvm::sys::fs::directory_iterator LI(LibDir, EC), LE; !EC && LI != LE; LI = LI.increment(EC)) { StringRef VersionText = llvm::sys::path::filename(LI->path()); auto CandidateVersion = toolchains::Generic_GCC::GCCVersion::Parse(VersionText); if (CandidateVersion.Major == -1) continue; if (CandidateVersion <= Version) continue; Version = CandidateVersion; Ver = std::string(VersionText); GccLibDir = LI->path(); } return Ver.size(); } static llvm::Triple getLiteralTriple(const Driver &D, const llvm::Triple &T) { llvm::Triple LiteralTriple(D.getTargetTriple()); // The arch portion of the triple may be overridden by -m32/-m64. LiteralTriple.setArchName(T.getArchName()); return LiteralTriple; } void toolchains::MinGW::findGccLibDir(const llvm::Triple &LiteralTriple) { llvm::SmallVector, 5> SubdirNames; SubdirNames.emplace_back(LiteralTriple.str()); SubdirNames.emplace_back(getTriple().str()); SubdirNames.emplace_back(getTriple().getArchName()); SubdirNames.back() += "-w64-mingw32"; SubdirNames.emplace_back(getTriple().getArchName()); SubdirNames.back() += "-w64-mingw32ucrt"; SubdirNames.emplace_back("mingw32"); if (SubdirName.empty()) { SubdirName = getTriple().getArchName(); SubdirName += "-w64-mingw32"; } // lib: Arch Linux, Ubuntu, Windows // lib64: openSUSE Linux for (StringRef CandidateLib : {"lib", "lib64"}) { for (StringRef CandidateSysroot : SubdirNames) { llvm::SmallString<1024> LibDir(Base); llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateSysroot); if (findGccVersion(LibDir, GccLibDir, Ver, GccVer)) { SubdirName = std::string(CandidateSysroot); return; } } } } static llvm::ErrorOr findGcc(const llvm::Triple &LiteralTriple, const llvm::Triple &T) { llvm::SmallVector, 5> Gccs; Gccs.emplace_back(LiteralTriple.str()); Gccs.back() += "-gcc"; Gccs.emplace_back(T.str()); Gccs.back() += "-gcc"; Gccs.emplace_back(T.getArchName()); Gccs.back() += "-w64-mingw32-gcc"; Gccs.emplace_back(T.getArchName()); Gccs.back() += "-w64-mingw32ucrt-gcc"; Gccs.emplace_back("mingw32-gcc"); // Please do not add "gcc" here for (StringRef CandidateGcc : Gccs) if (llvm::ErrorOr GPPName = llvm::sys::findProgramByName(CandidateGcc)) return GPPName; return make_error_code(std::errc::no_such_file_or_directory); } static llvm::ErrorOr findClangRelativeSysroot(const Driver &D, const llvm::Triple &LiteralTriple, const llvm::Triple &T, std::string &SubdirName) { llvm::SmallVector, 4> Subdirs; Subdirs.emplace_back(LiteralTriple.str()); Subdirs.emplace_back(T.str()); Subdirs.emplace_back(T.getArchName()); Subdirs.back() += "-w64-mingw32"; Subdirs.emplace_back(T.getArchName()); Subdirs.back() += "-w64-mingw32ucrt"; StringRef ClangRoot = llvm::sys::path::parent_path(D.getInstalledDir()); StringRef Sep = llvm::sys::path::get_separator(); for (StringRef CandidateSubdir : Subdirs) { if (llvm::sys::fs::is_directory(ClangRoot + Sep + CandidateSubdir)) { SubdirName = std::string(CandidateSubdir); return (ClangRoot + Sep + CandidateSubdir).str(); } } return make_error_code(std::errc::no_such_file_or_directory); } toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args), RocmInstallation(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); // The sequence for detecting a sysroot here should be kept in sync with // the testTriple function below. llvm::Triple LiteralTriple = getLiteralTriple(D, getTriple()); if (getDriver().SysRoot.size()) Base = getDriver().SysRoot; // Look for /../; if found, use /.. as the // base as it could still be a base for a gcc setup with libgcc. else if (llvm::ErrorOr TargetSubdir = findClangRelativeSysroot( getDriver(), LiteralTriple, getTriple(), SubdirName)) Base = std::string(llvm::sys::path::parent_path(TargetSubdir.get())); else if (llvm::ErrorOr GPPName = findGcc(LiteralTriple, getTriple())) Base = std::string(llvm::sys::path::parent_path( llvm::sys::path::parent_path(GPPName.get()))); else Base = std::string( llvm::sys::path::parent_path(getDriver().getInstalledDir())); Base += llvm::sys::path::get_separator(); findGccLibDir(LiteralTriple); TripleDirName = SubdirName; // GccLibDir must precede Base/lib so that the // correct crtbegin.o ,cetend.o would be found. getFilePaths().push_back(GccLibDir); // openSUSE/Fedora std::string CandidateSubdir = SubdirName + "/sys-root/mingw"; if (getDriver().getVFS().exists(Base + CandidateSubdir)) SubdirName = CandidateSubdir; getFilePaths().push_back( (Base + SubdirName + llvm::sys::path::get_separator() + "lib").str()); // Gentoo getFilePaths().push_back( (Base + SubdirName + llvm::sys::path::get_separator() + "mingw/lib").str()); // Only include /lib if we're not cross compiling (not even for // windows->windows to a different arch), or if the sysroot has been set // (where we presume the user has pointed it at an arch specific // subdirectory). if (!::isCrossCompiling(getTriple(), /*RequireArchMatch=*/true) || getDriver().SysRoot.size()) getFilePaths().push_back(Base + "lib"); NativeLLVMSupport = Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER) .equals_insensitive("lld"); } Tool *toolchains::MinGW::getTool(Action::ActionClass AC) const { switch (AC) { case Action::PreprocessJobClass: if (!Preprocessor) Preprocessor.reset(new tools::gcc::Preprocessor(*this)); return Preprocessor.get(); case Action::CompileJobClass: if (!Compiler) Compiler.reset(new tools::gcc::Compiler(*this)); return Compiler.get(); default: return ToolChain::getTool(AC); } } Tool *toolchains::MinGW::buildAssembler() const { return new tools::MinGW::Assembler(*this); } Tool *toolchains::MinGW::buildLinker() const { return new tools::MinGW::Linker(*this); } bool toolchains::MinGW::HasNativeLLVMSupport() const { return NativeLLVMSupport; } ToolChain::UnwindTableLevel toolchains::MinGW::getDefaultUnwindTableLevel(const ArgList &Args) const { Arg *ExceptionArg = Args.getLastArg(options::OPT_fsjlj_exceptions, options::OPT_fseh_exceptions, options::OPT_fdwarf_exceptions); if (ExceptionArg && ExceptionArg->getOption().matches(options::OPT_fseh_exceptions)) return UnwindTableLevel::Asynchronous; if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm || getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64) return UnwindTableLevel::Asynchronous; return UnwindTableLevel::None; } bool toolchains::MinGW::isPICDefault() const { return getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::aarch64; } bool toolchains::MinGW::isPIEDefault(const llvm::opt::ArgList &Args) const { return false; } bool toolchains::MinGW::isPICDefaultForced() const { return true; } llvm::ExceptionHandling toolchains::MinGW::GetExceptionModel(const ArgList &Args) const { if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::aarch64 || getArch() == llvm::Triple::arm || getArch() == llvm::Triple::thumb) return llvm::ExceptionHandling::WinEH; return llvm::ExceptionHandling::DwarfCFI; } SanitizerMask toolchains::MinGW::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; Res |= SanitizerKind::PointerCompare; Res |= SanitizerKind::PointerSubtract; Res |= SanitizerKind::Vptr; return Res; } void toolchains::MinGW::AddCudaIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); } void toolchains::MinGW::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); } void toolchains::MinGW::printVerboseInfo(raw_ostream &OS) const { CudaInstallation.print(OS); RocmInstallation.print(OS); } // Include directories for various hosts: // Windows, mingw.org // c:\mingw\lib\gcc\mingw32\4.8.1\include\c++ // c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\mingw32 // c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\backward // c:\mingw\include // c:\mingw\mingw32\include // Windows, mingw-w64 mingw-builds // c:\mingw32\i686-w64-mingw32\include // c:\mingw32\i686-w64-mingw32\include\c++ // c:\mingw32\i686-w64-mingw32\include\c++\i686-w64-mingw32 // c:\mingw32\i686-w64-mingw32\include\c++\backward // Windows, mingw-w64 msys2 // c:\msys64\mingw32\include // c:\msys64\mingw32\i686-w64-mingw32\include // c:\msys64\mingw32\include\c++\4.9.2 // c:\msys64\mingw32\include\c++\4.9.2\i686-w64-mingw32 // c:\msys64\mingw32\include\c++\4.9.2\backward // openSUSE // /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++ // /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/x86_64-w64-mingw32 // /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/backward // /usr/x86_64-w64-mingw32/sys-root/mingw/include // Arch Linux // /usr/i686-w64-mingw32/include/c++/5.1.0 // /usr/i686-w64-mingw32/include/c++/5.1.0/i686-w64-mingw32 // /usr/i686-w64-mingw32/include/c++/5.1.0/backward // /usr/i686-w64-mingw32/include // Ubuntu // /usr/include/c++/4.8 // /usr/include/c++/4.8/x86_64-w64-mingw32 // /usr/include/c++/4.8/backward // /usr/x86_64-w64-mingw32/include // Fedora // /usr/x86_64-w64-mingw32ucrt/sys-root/mingw/include/c++/x86_64-w64-mingw32ucrt // /usr/x86_64-w64-mingw32ucrt/sys-root/mingw/include/c++/backward // /usr/x86_64-w64-mingw32ucrt/sys-root/mingw/include // /usr/lib/gcc/x86_64-w64-mingw32ucrt/12.2.1/include-fixed void toolchains::MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdinc)) return; if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { SmallString<1024> P(getDriver().ResourceDir); llvm::sys::path::append(P, "include"); addSystemInclude(DriverArgs, CC1Args, P.str()); } if (DriverArgs.hasArg(options::OPT_nostdlibinc)) return; addSystemInclude(DriverArgs, CC1Args, Base + SubdirName + llvm::sys::path::get_separator() + "include"); // Gentoo addSystemInclude(DriverArgs, CC1Args, Base + SubdirName + llvm::sys::path::get_separator() + "usr/include"); // Only include /include if we're not cross compiling (but do allow it // if we're on Windows and building for Windows on another architecture), // or if the sysroot has been set (where we presume the user has pointed it // at an arch specific subdirectory). if (!::isCrossCompiling(getTriple(), /*RequireArchMatch=*/false) || getDriver().SysRoot.size()) addSystemInclude(DriverArgs, CC1Args, Base + "include"); } void toolchains::MinGW::addClangTargetOptions( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const { if (Arg *A = DriverArgs.getLastArg(options::OPT_mguard_EQ)) { StringRef GuardArgs = A->getValue(); if (GuardArgs == "none") { // Do nothing. } else if (GuardArgs == "cf") { // Emit CFG instrumentation and the table of address-taken functions. CC1Args.push_back("-cfguard"); } else if (GuardArgs == "cf-nochecks") { // Emit only the table of address-taken functions. CC1Args.push_back("-cfguard-no-checks"); } else { getDriver().Diag(diag::err_drv_unsupported_option_argument) << A->getSpelling() << GuardArgs; } } - if (Arg *A = DriverArgs.getLastArgNoClaim(options::OPT_mthreads)) - A->ignoreTargetSpecific(); + for (auto Opt : {options::OPT_mthreads, options::OPT_mwindows, + options::OPT_mconsole, options::OPT_mdll}) { + if (Arg *A = DriverArgs.getLastArgNoClaim(Opt)) + A->ignoreTargetSpecific(); + } } void toolchains::MinGW::AddClangCXXStdlibIncludeArgs( const ArgList &DriverArgs, ArgStringList &CC1Args) const { if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc, options::OPT_nostdincxx)) return; StringRef Slash = llvm::sys::path::get_separator(); switch (GetCXXStdlibType(DriverArgs)) { case ToolChain::CST_Libcxx: { std::string TargetDir = (Base + "include" + Slash + getTripleString() + Slash + "c++" + Slash + "v1") .str(); if (getDriver().getVFS().exists(TargetDir)) addSystemInclude(DriverArgs, CC1Args, TargetDir); addSystemInclude(DriverArgs, CC1Args, Base + SubdirName + Slash + "include" + Slash + "c++" + Slash + "v1"); addSystemInclude(DriverArgs, CC1Args, Base + "include" + Slash + "c++" + Slash + "v1"); break; } case ToolChain::CST_Libstdcxx: llvm::SmallVector, 7> CppIncludeBases; CppIncludeBases.emplace_back(Base); llvm::sys::path::append(CppIncludeBases[0], SubdirName, "include", "c++"); CppIncludeBases.emplace_back(Base); llvm::sys::path::append(CppIncludeBases[1], SubdirName, "include", "c++", Ver); CppIncludeBases.emplace_back(Base); llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver); CppIncludeBases.emplace_back(GccLibDir); llvm::sys::path::append(CppIncludeBases[3], "include", "c++"); CppIncludeBases.emplace_back(GccLibDir); llvm::sys::path::append(CppIncludeBases[4], "include", "g++-v" + GccVer.Text); CppIncludeBases.emplace_back(GccLibDir); llvm::sys::path::append(CppIncludeBases[5], "include", "g++-v" + GccVer.MajorStr + "." + GccVer.MinorStr); CppIncludeBases.emplace_back(GccLibDir); llvm::sys::path::append(CppIncludeBases[6], "include", "g++-v" + GccVer.MajorStr); for (auto &CppIncludeBase : CppIncludeBases) { addSystemInclude(DriverArgs, CC1Args, CppIncludeBase); CppIncludeBase += Slash; addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + TripleDirName); addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward"); } break; } } static bool testTriple(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) { // If an explicit sysroot is set, that will be used and we shouldn't try to // detect anything else. std::string SubdirName; if (D.SysRoot.size()) return true; llvm::Triple LiteralTriple = getLiteralTriple(D, Triple); if (llvm::ErrorOr TargetSubdir = findClangRelativeSysroot(D, LiteralTriple, Triple, SubdirName)) return true; if (llvm::ErrorOr GPPName = findGcc(LiteralTriple, Triple)) return true; // If we neither found a colocated sysroot or a matching gcc executable, // conclude that we can't know if this is the correct spelling of the triple. return false; } static llvm::Triple adjustTriple(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) { // First test if the original triple can find a sysroot with the triple // name. if (testTriple(D, Triple, Args)) return Triple; llvm::SmallVector Archs; // If not, test a couple other possible arch names that might be what was // intended. if (Triple.getArch() == llvm::Triple::x86) { Archs.emplace_back("i386"); Archs.emplace_back("i586"); Archs.emplace_back("i686"); } else if (Triple.getArch() == llvm::Triple::arm || Triple.getArch() == llvm::Triple::thumb) { Archs.emplace_back("armv7"); } for (auto A : Archs) { llvm::Triple TestTriple(Triple); TestTriple.setArchName(A); if (testTriple(D, TestTriple, Args)) return TestTriple; } // If none was found, just proceed with the original value. return Triple; } void toolchains::MinGW::fixTripleArch(const Driver &D, llvm::Triple &Triple, const ArgList &Args) { if (Triple.getArch() == llvm::Triple::x86 || Triple.getArch() == llvm::Triple::arm || Triple.getArch() == llvm::Triple::thumb) Triple = adjustTriple(D, Triple, Args); } diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h index 43c9dbec737b..6b8c43dbe6e4 100644 --- a/libcxx/include/__utility/pair.h +++ b/libcxx/include/__utility/pair.h @@ -1,902 +1,902 @@ //===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef _LIBCPP___UTILITY_PAIR_H #define _LIBCPP___UTILITY_PAIR_H #include <__compare/common_comparison_category.h> #include <__compare/synth_three_way.h> #include <__concepts/different_from.h> #include <__config> #include <__fwd/array.h> #include <__fwd/get.h> #include <__fwd/pair.h> #include <__fwd/subrange.h> #include <__fwd/tuple.h> #include <__tuple/pair_like.h> #include <__tuple/sfinae_helpers.h> #include <__tuple/tuple_element.h> #include <__tuple/tuple_indices.h> #include <__tuple/tuple_size.h> #include <__type_traits/common_reference.h> #include <__type_traits/common_type.h> #include <__type_traits/conditional.h> #include <__type_traits/decay.h> #include <__type_traits/integral_constant.h> #include <__type_traits/is_assignable.h> #include <__type_traits/is_constructible.h> #include <__type_traits/is_convertible.h> #include <__type_traits/is_copy_assignable.h> #include <__type_traits/is_default_constructible.h> #include <__type_traits/is_implicitly_default_constructible.h> #include <__type_traits/is_move_assignable.h> #include <__type_traits/is_nothrow_assignable.h> #include <__type_traits/is_nothrow_constructible.h> #include <__type_traits/is_nothrow_copy_assignable.h> #include <__type_traits/is_nothrow_copy_constructible.h> #include <__type_traits/is_nothrow_default_constructible.h> #include <__type_traits/is_nothrow_move_assignable.h> #include <__type_traits/is_same.h> #include <__type_traits/is_swappable.h> #include <__type_traits/nat.h> #include <__type_traits/remove_cvref.h> #include <__type_traits/unwrap_ref.h> #include <__utility/declval.h> #include <__utility/forward.h> #include <__utility/move.h> #include <__utility/piecewise_construct.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif _LIBCPP_PUSH_MACROS #include <__undef_macros> _LIBCPP_BEGIN_NAMESPACE_STD template struct __non_trivially_copyable_base { _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI __non_trivially_copyable_base() _NOEXCEPT {} _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI __non_trivially_copyable_base(__non_trivially_copyable_base const&) _NOEXCEPT {} }; #if _LIBCPP_STD_VER >= 23 template struct __is_specialization_of_subrange : false_type {}; template struct __is_specialization_of_subrange> : true_type {}; #endif template struct _LIBCPP_TEMPLATE_VIS pair #if defined(_LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR) : private __non_trivially_copyable_base<_T1, _T2> #endif { using first_type = _T1; using second_type = _T2; _T1 first; _T2 second; _LIBCPP_HIDE_FROM_ABI pair(pair const&) = default; _LIBCPP_HIDE_FROM_ABI pair(pair&&) = default; #ifdef _LIBCPP_CXX03_LANG _LIBCPP_HIDE_FROM_ABI pair() : first(), second() {} _LIBCPP_HIDE_FROM_ABI pair(_T1 const& __t1, _T2 const& __t2) : first(__t1), second(__t2) {} template _LIBCPP_HIDE_FROM_ABI pair(const pair<_U1, _U2>& __p) : first(__p.first), second(__p.second) {} _LIBCPP_HIDE_FROM_ABI pair& operator=(pair const& __p) { first = __p.first; second = __p.second; return *this; } // Extension: This is provided in C++03 because it allows properly handling the // assignment to a pair containing references, which would be a hard // error otherwise. template ::value && is_assignable::value > > _LIBCPP_HIDE_FROM_ABI pair& operator=(pair<_U1, _U2> const& __p) { first = __p.first; second = __p.second; return *this; } #else struct _CheckArgs { template static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_explicit_default() { return is_default_constructible<_T1>::value && is_default_constructible<_T2>::value && !__enable_implicit_default<>(); } template static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_implicit_default() { return __is_implicitly_default_constructible<_T1>::value && __is_implicitly_default_constructible<_T2>::value; } template static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_pair_constructible() { return is_constructible::value && is_constructible::value; } template static _LIBCPP_HIDE_FROM_ABI constexpr bool __is_implicit() { return is_convertible<_U1, first_type>::value && is_convertible<_U2, second_type>::value; } template static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_explicit() { return __is_pair_constructible<_U1, _U2>() && !__is_implicit<_U1, _U2>(); } template static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_implicit() { return __is_pair_constructible<_U1, _U2>() && __is_implicit<_U1, _U2>(); } }; template using _CheckArgsDep _LIBCPP_NODEBUG = typename conditional< _MaybeEnable, _CheckArgs, __check_tuple_constructor_fail>::type; template::__enable_explicit_default() >::type* = nullptr> explicit _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR pair() _NOEXCEPT_(is_nothrow_default_constructible::value && is_nothrow_default_constructible::value) : first(), second() {} template::__enable_implicit_default() >::type* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR pair() _NOEXCEPT_(is_nothrow_default_constructible::value && is_nothrow_default_constructible::value) : first(), second() {} template ::template __enable_explicit<_T1 const&, _T2 const&>() >::type* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit pair(_T1 const& __t1, _T2 const& __t2) _NOEXCEPT_(is_nothrow_copy_constructible::value && is_nothrow_copy_constructible::value) : first(__t1), second(__t2) {} template::template __enable_implicit<_T1 const&, _T2 const&>() >::type* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair(_T1 const& __t1, _T2 const& __t2) _NOEXCEPT_(is_nothrow_copy_constructible::value && is_nothrow_copy_constructible::value) : first(__t1), second(__t2) {} template < #if _LIBCPP_STD_VER >= 23 // http://wg21.link/P1951 class _U1 = _T1, class _U2 = _T2, #else class _U1, class _U2, #endif typename enable_if<_CheckArgs::template __enable_explicit<_U1, _U2>()>::type* = nullptr > _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit pair(_U1&& __u1, _U2&& __u2) _NOEXCEPT_((is_nothrow_constructible::value && is_nothrow_constructible::value)) : first(std::forward<_U1>(__u1)), second(std::forward<_U2>(__u2)) {} template < #if _LIBCPP_STD_VER >= 23 // http://wg21.link/P1951 class _U1 = _T1, class _U2 = _T2, #else class _U1, class _U2, #endif typename enable_if<_CheckArgs::template __enable_implicit<_U1, _U2>()>::type* = nullptr > _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair(_U1&& __u1, _U2&& __u2) _NOEXCEPT_((is_nothrow_constructible::value && is_nothrow_constructible::value)) : first(std::forward<_U1>(__u1)), second(std::forward<_U2>(__u2)) {} #if _LIBCPP_STD_VER >= 23 template() >* = nullptr> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_CheckArgs::template __is_implicit<_U1&, _U2&>()) pair(pair<_U1, _U2>& __p) noexcept((is_nothrow_constructible::value && is_nothrow_constructible::value)) : first(__p.first), second(__p.second) {} #endif template() >::type* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit pair(pair<_U1, _U2> const& __p) _NOEXCEPT_((is_nothrow_constructible::value && is_nothrow_constructible::value)) : first(__p.first), second(__p.second) {} template() >::type* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair(pair<_U1, _U2> const& __p) _NOEXCEPT_((is_nothrow_constructible::value && is_nothrow_constructible::value)) : first(__p.first), second(__p.second) {} template() >::type* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit pair(pair<_U1, _U2>&&__p) _NOEXCEPT_((is_nothrow_constructible::value && is_nothrow_constructible::value)) : first(std::forward<_U1>(__p.first)), second(std::forward<_U2>(__p.second)) {} template() >::type* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair(pair<_U1, _U2>&& __p) _NOEXCEPT_((is_nothrow_constructible::value && is_nothrow_constructible::value)) : first(std::forward<_U1>(__p.first)), second(std::forward<_U2>(__p.second)) {} #if _LIBCPP_STD_VER >= 23 template() >* = nullptr> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_CheckArgs::template __is_implicit()) pair(const pair<_U1, _U2>&& __p) noexcept(is_nothrow_constructible::value && is_nothrow_constructible::value) : first(std::move(__p.first)), second(std::move(__p.second)) {} #endif # if _LIBCPP_STD_VER >= 23 // This is a workaround for http://llvm.org/PR60710. We should be able to remove it once Clang is fixed. - template >::value == 2> + template _LIBCPP_HIDE_FROM_ABI static constexpr bool __pair_like_explicit_wknd() { - if constexpr (tuple_size>::value == 2) { + if constexpr (__pair_like<_PairLike>) { return !is_convertible_v(std::declval<_PairLike&&>())), first_type> || !is_convertible_v(std::declval<_PairLike&&>())), second_type>; } return false; } template <__pair_like _PairLike> requires(is_constructible_v(std::declval<_PairLike&&>()))> && is_constructible_v(std::declval<_PairLike&&>()))>) _LIBCPP_HIDE_FROM_ABI constexpr explicit(__pair_like_explicit_wknd<_PairLike>()) pair(_PairLike&& __p) : first(std::get<0>(std::forward<_PairLike>(__p))), second(std::get<1>(std::forward<_PairLike>(__p))) {} # endif template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair(piecewise_construct_t __pc, tuple<_Args1...> __first_args, tuple<_Args2...> __second_args) _NOEXCEPT_((is_nothrow_constructible::value && is_nothrow_constructible::value)) : pair(__pc, __first_args, __second_args, typename __make_tuple_indices::type(), typename __make_tuple_indices::type()) {} _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair& operator=(__conditional_t< is_copy_assignable::value && is_copy_assignable::value, pair, __nat> const& __p) _NOEXCEPT_(is_nothrow_copy_assignable::value && is_nothrow_copy_assignable::value) { first = __p.first; second = __p.second; return *this; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair& operator=(__conditional_t< is_move_assignable::value && is_move_assignable::value, pair, __nat>&& __p) _NOEXCEPT_(is_nothrow_move_assignable::value && is_nothrow_move_assignable::value) { first = std::forward(__p.first); second = std::forward(__p.second); return *this; } template ::value && is_assignable::value >* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair& operator=(pair<_U1, _U2> const& __p) { first = __p.first; second = __p.second; return *this; } template ::value && is_assignable::value >* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair& operator=(pair<_U1, _U2>&& __p) { first = std::forward<_U1>(__p.first); second = std::forward<_U2>(__p.second); return *this; } # if _LIBCPP_STD_VER >= 23 _LIBCPP_HIDE_FROM_ABI constexpr const pair& operator=(pair const& __p) const noexcept(is_nothrow_copy_assignable_v && is_nothrow_copy_assignable_v) requires(is_copy_assignable_v && is_copy_assignable_v) { first = __p.first; second = __p.second; return *this; } _LIBCPP_HIDE_FROM_ABI constexpr const pair& operator=(pair&& __p) const noexcept(is_nothrow_assignable_v && is_nothrow_assignable_v) requires(is_assignable_v && is_assignable_v) { first = std::forward(__p.first); second = std::forward(__p.second); return *this; } template _LIBCPP_HIDE_FROM_ABI constexpr const pair& operator=(const pair<_U1, _U2>& __p) const requires(is_assignable_v && is_assignable_v) { first = __p.first; second = __p.second; return *this; } template _LIBCPP_HIDE_FROM_ABI constexpr const pair& operator=(pair<_U1, _U2>&& __p) const requires(is_assignable_v && is_assignable_v) { first = std::forward<_U1>(__p.first); second = std::forward<_U2>(__p.second); return *this; } template <__pair_like _PairLike> requires(__different_from<_PairLike, pair> && !__is_specialization_of_subrange>::value && is_assignable_v(std::declval<_PairLike>()))> && is_assignable_v(std::declval<_PairLike>()))>) _LIBCPP_HIDE_FROM_ABI constexpr pair& operator=(_PairLike&& __p) { first = std::get<0>(std::forward<_PairLike>(__p)); second = std::get<1>(std::forward<_PairLike>(__p)); return *this; } template <__pair_like _PairLike> requires(__different_from<_PairLike, pair> && !__is_specialization_of_subrange>::value && is_assignable_v(std::declval<_PairLike>()))> && is_assignable_v(std::declval<_PairLike>()))>) _LIBCPP_HIDE_FROM_ABI constexpr pair const& operator=(_PairLike&& __p) const { first = std::get<0>(std::forward<_PairLike>(__p)); second = std::get<1>(std::forward<_PairLike>(__p)); return *this; } # endif // _LIBCPP_STD_VER >= 23 // Prior to C++23, we provide an approximation of constructors and assignment operators from // pair-like types. This was historically provided as an extension. #if _LIBCPP_STD_VER < 23 // from std::tuple template::value && is_convertible<_U2 const&, _T2>::value >* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair(tuple<_U1, _U2> const& __p) : first(std::get<0>(__p)), second(std::get<1>(__p)) {} template::value && is_constructible<_T2, _U2 const&>::value && !(is_convertible<_U1 const&, _T1>::value && is_convertible<_U2 const&, _T2>::value) >* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit pair(tuple<_U1, _U2> const& __p) : first(std::get<0>(__p)), second(std::get<1>(__p)) {} template::value && is_convertible<_U2, _T2>::value >* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair(tuple<_U1, _U2>&& __p) : first(std::get<0>(std::move(__p))), second(std::get<1>(std::move(__p))) {} template::value && is_constructible<_T2, _U2>::value && !(is_convertible<_U1, _T1>::value && is_convertible<_U2, _T2>::value) >* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit pair(tuple<_U1, _U2>&& __p) : first(std::get<0>(std::move(__p))), second(std::get<1>(std::move(__p))) {} template::value && is_assignable<_T2&, _U2 const&>::value >* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair& operator=(tuple<_U1, _U2> const& __p) { first = std::get<0>(__p); second = std::get<1>(__p); return *this; } template::value && is_assignable<_T2&, _U2&&>::value >* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair& operator=(tuple<_U1, _U2>&& __p) { first = std::get<0>(std::move(__p)); second = std::get<1>(std::move(__p)); return *this; } // from std::array template::value && is_convertible<_Up const&, _T2>::value >* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair(array<_Up, 2> const& __p) : first(__p[0]), second(__p[1]) {} template::value && is_constructible<_T2, _Up const&>::value && !(is_convertible<_Up const&, _T1>::value && is_convertible<_Up const&, _T2>::value) >* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit pair(array<_Up, 2> const& __p) : first(__p[0]), second(__p[1]) {} template::value && is_convertible<_Up, _T2>::value >* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair(array<_Up, 2>&& __p) : first(std::move(__p)[0]), second(std::move(__p)[1]) {} template::value && is_constructible<_T2, _Up>::value && !(is_convertible<_Up, _T1>::value && is_convertible<_Up, _T2>::value) >* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit pair(array<_Up, 2>&& __p) : first(std::move(__p)[0]), second(std::move(__p)[1]) {} template::value && is_assignable<_T2&, _Up const&>::value >* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair& operator=(array<_Up, 2> const& __p) { first = std::get<0>(__p); second = std::get<1>(__p); return *this; } template::value && is_assignable<_T2&, _Up>::value >* = nullptr> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair& operator=(array<_Up, 2>&& __p) { first = std::get<0>(std::move(__p)); second = std::get<1>(std::move(__p)); return *this; } #endif // _LIBCPP_STD_VER < 23 #endif // _LIBCPP_CXX03_LANG _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(pair& __p) _NOEXCEPT_(__is_nothrow_swappable::value && __is_nothrow_swappable::value) { using std::swap; swap(first, __p.first); swap(second, __p.second); } #if _LIBCPP_STD_VER >= 23 _LIBCPP_HIDE_FROM_ABI constexpr void swap(const pair& __p) const noexcept(__is_nothrow_swappable::value && __is_nothrow_swappable::value) { using std::swap; swap(first, __p.first); swap(second, __p.second); } #endif private: #ifndef _LIBCPP_CXX03_LANG template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair(piecewise_construct_t, tuple<_Args1...>& __first_args, tuple<_Args2...>& __second_args, __tuple_indices<_I1...>, __tuple_indices<_I2...>); #endif }; #if _LIBCPP_STD_VER >= 17 template pair(_T1, _T2) -> pair<_T1, _T2>; #endif // [pairs.spec], specialized algorithms template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator==(const pair<_T1,_T2>& __x, const pair<_U1,_U2>& __y) { return __x.first == __y.first && __x.second == __y.second; } #if _LIBCPP_STD_VER >= 20 template _LIBCPP_HIDE_FROM_ABI constexpr common_comparison_category_t< __synth_three_way_result<_T1, _U1>, __synth_three_way_result<_T2, _U2> > operator<=>(const pair<_T1,_T2>& __x, const pair<_U1,_U2>& __y) { if (auto __c = std::__synth_three_way(__x.first, __y.first); __c != 0) { return __c; } return std::__synth_three_way(__x.second, __y.second); } #else // _LIBCPP_STD_VER >= 20 template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator!=(const pair<_T1,_T2>& __x, const pair<_U1,_U2>& __y) { return !(__x == __y); } template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator< (const pair<_T1,_T2>& __x, const pair<_U1,_U2>& __y) { return __x.first < __y.first || (!(__y.first < __x.first) && __x.second < __y.second); } template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator> (const pair<_T1,_T2>& __x, const pair<_U1,_U2>& __y) { return __y < __x; } template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator>=(const pair<_T1,_T2>& __x, const pair<_U1,_U2>& __y) { return !(__x < __y); } template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator<=(const pair<_T1,_T2>& __x, const pair<_U1,_U2>& __y) { return !(__y < __x); } #endif // _LIBCPP_STD_VER >= 20 #if _LIBCPP_STD_VER >= 23 template class _TQual, template class _UQual> requires requires { typename pair, _UQual<_U1>>, common_reference_t<_TQual<_T2>, _UQual<_U2>>>; } struct basic_common_reference, pair<_U1, _U2>, _TQual, _UQual> { using type = pair, _UQual<_U1>>, common_reference_t<_TQual<_T2>, _UQual<_U2>>>; }; template requires requires { typename pair, common_type_t<_T2, _U2>>; } struct common_type, pair<_U1, _U2>> { using type = pair, common_type_t<_T2, _U2>>; }; #endif // _LIBCPP_STD_VER >= 23 template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 typename enable_if < __is_swappable<_T1>::value && __is_swappable<_T2>::value, void >::type swap(pair<_T1, _T2>& __x, pair<_T1, _T2>& __y) _NOEXCEPT_((__is_nothrow_swappable<_T1>::value && __is_nothrow_swappable<_T2>::value)) { __x.swap(__y); } #if _LIBCPP_STD_VER >= 23 template requires (__is_swappable::value && __is_swappable::value) _LIBCPP_HIDE_FROM_ABI constexpr void swap(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) noexcept(noexcept(__x.swap(__y))) { __x.swap(__y); } #endif template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair::type, typename __unwrap_ref_decay<_T2>::type> make_pair(_T1&& __t1, _T2&& __t2) { return pair::type, typename __unwrap_ref_decay<_T2>::type> (std::forward<_T1>(__t1), std::forward<_T2>(__t2)); } template struct _LIBCPP_TEMPLATE_VIS tuple_size > : public integral_constant {}; template struct _LIBCPP_TEMPLATE_VIS tuple_element<_Ip, pair<_T1, _T2> > { static_assert(_Ip < 2, "Index out of bounds in std::tuple_element>"); }; template struct _LIBCPP_TEMPLATE_VIS tuple_element<0, pair<_T1, _T2> > { using type _LIBCPP_NODEBUG = _T1; }; template struct _LIBCPP_TEMPLATE_VIS tuple_element<1, pair<_T1, _T2> > { using type _LIBCPP_NODEBUG = _T2; }; template struct __get_pair; template <> struct __get_pair<0> { template static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _T1& get(pair<_T1, _T2>& __p) _NOEXCEPT {return __p.first;} template static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _T1& get(const pair<_T1, _T2>& __p) _NOEXCEPT {return __p.first;} template static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _T1&& get(pair<_T1, _T2>&& __p) _NOEXCEPT {return std::forward<_T1>(__p.first);} template static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _T1&& get(const pair<_T1, _T2>&& __p) _NOEXCEPT {return std::forward(__p.first);} }; template <> struct __get_pair<1> { template static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _T2& get(pair<_T1, _T2>& __p) _NOEXCEPT {return __p.second;} template static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _T2& get(const pair<_T1, _T2>& __p) _NOEXCEPT {return __p.second;} template static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _T2&& get(pair<_T1, _T2>&& __p) _NOEXCEPT {return std::forward<_T2>(__p.second);} template static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _T2&& get(const pair<_T1, _T2>&& __p) _NOEXCEPT {return std::forward(__p.second);} }; template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename tuple_element<_Ip, pair<_T1, _T2> >::type& get(pair<_T1, _T2>& __p) _NOEXCEPT { return __get_pair<_Ip>::get(__p); } template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, pair<_T1, _T2> >::type& get(const pair<_T1, _T2>& __p) _NOEXCEPT { return __get_pair<_Ip>::get(__p); } template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename tuple_element<_Ip, pair<_T1, _T2> >::type&& get(pair<_T1, _T2>&& __p) _NOEXCEPT { return __get_pair<_Ip>::get(std::move(__p)); } template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, pair<_T1, _T2> >::type&& get(const pair<_T1, _T2>&& __p) _NOEXCEPT { return __get_pair<_Ip>::get(std::move(__p)); } #if _LIBCPP_STD_VER >= 14 template inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 & get(pair<_T1, _T2>& __p) _NOEXCEPT { return __get_pair<0>::get(__p); } template inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const & get(pair<_T1, _T2> const& __p) _NOEXCEPT { return __get_pair<0>::get(__p); } template inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 && get(pair<_T1, _T2>&& __p) _NOEXCEPT { return __get_pair<0>::get(std::move(__p)); } template inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const && get(pair<_T1, _T2> const&& __p) _NOEXCEPT { return __get_pair<0>::get(std::move(__p)); } template inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 & get(pair<_T2, _T1>& __p) _NOEXCEPT { return __get_pair<1>::get(__p); } template inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const & get(pair<_T2, _T1> const& __p) _NOEXCEPT { return __get_pair<1>::get(__p); } template inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 && get(pair<_T2, _T1>&& __p) _NOEXCEPT { return __get_pair<1>::get(std::move(__p)); } template inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const && get(pair<_T2, _T1> const&& __p) _NOEXCEPT { return __get_pair<1>::get(std::move(__p)); } #endif // _LIBCPP_STD_VER >= 14 _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS #endif // _LIBCPP___UTILITY_PAIR_H diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index d7476e91e03e..e2f414f78ecb 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -1,2537 +1,2539 @@ //===- 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 "COFFLinkerContext.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/CommonLinkerContext.h" #include "lld/Common/Driver.h" #include "lld/Common/Filesystem.h" #include "lld/Common/Timer.h" #include "lld/Common/Version.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/BinaryFormat/Magic.h" #include "llvm/Config/llvm-config.h" #include "llvm/LTO/LTO.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/BinaryStreamReader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/Parallel.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TargetParser/Triple.h" #include "llvm/ToolDrivers/llvm-lib/LibDriver.h" #include #include #include #include #include using namespace llvm; using namespace llvm::object; using namespace llvm::COFF; using namespace llvm::sys; namespace lld::coff { bool link(ArrayRef args, llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput) { // This driver-specific context will be freed later by unsafeLldMain(). auto *ctx = new COFFLinkerContext; ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput); ctx->e.logName = args::getFilenameWithoutExe(args[0]); ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now" " (use /errorlimit:0 to see all errors)"; ctx->driver.linkerMain(args); return errorCount() == 0; } // 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; } // Parse options of the form "old;new[;extra]". static std::tuple getOldNewOptionsExtra(opt::InputArgList &args, unsigned id) { auto [oldDir, second] = getOldNewOptions(args, id); auto [newDir, extraDir] = second.split(';'); return {oldDir, newDir, extraDir}; } // Drop directory components and replace extension with // ".exe", ".dll" or ".sys". static std::string getOutputPath(StringRef path, bool isDll, bool isDriver) { StringRef ext = ".exe"; if (isDll) ext = ".dll"; else if (isDriver) ext = ".sys"; return (sys::path::stem(path) + ext).str(); } // Returns true if S matches /crtend.?\.o$/. static bool isCrtend(StringRef s) { if (!s.ends_with(".o")) return false; s = s.drop_back(2); if (s.ends_with("crtend")) return true; return !s.empty() && s.drop_back().ends_with("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 _WIN64 // On Windows, file I/O is relatively slow so it is best to do this // asynchronously. But 32-bit has issues with potentially launching tons // of threads auto strategy = std::launch::async; #else auto strategy = std::launch::deferred; #endif return std::async(strategy, [=]() { auto mbOrErr = MemoryBuffer::getFile(path, /*IsText=*/false, /*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. StringRef LinkerDriver::mangle(StringRef sym) { assert(ctx.config.machine != IMAGE_FILE_MACHINE_UNKNOWN); if (ctx.config.machine == I386) return saver().save("_" + sym); return sym; } llvm::Triple::ArchType LinkerDriver::getArch() { switch (ctx.config.machine) { case I386: return llvm::Triple::ArchType::x86; case AMD64: return llvm::Triple::ArchType::x86_64; case ARMNT: return llvm::Triple::ArchType::arm; case ARM64: return llvm::Triple::ArchType::aarch64; default: return llvm::Triple::ArchType::UnknownArch; } } bool LinkerDriver::findUnderscoreMangle(StringRef sym) { Symbol *s = ctx.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 (ctx.driver.tar) ctx.driver.tar->append(relativeToRoot(mbref.getBufferIdentifier()), mbref.getBuffer()); return mbref; } void LinkerDriver::addBuffer(std::unique_ptr mb, bool wholeArchive, bool lazy) { 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 int memberIndex = 0; for (MemoryBufferRef m : getArchiveMembers(archive)) addArchiveBuffer(m, "", filename, memberIndex++); return; } ctx.symtab.addFile(make(ctx, mbref)); break; case file_magic::bitcode: ctx.symtab.addFile(make(ctx, mbref, "", 0, lazy)); break; case file_magic::coff_object: case file_magic::coff_import_library: ctx.symtab.addFile(make(ctx, mbref, lazy)); break; case file_magic::pdb: ctx.symtab.addFile(make(ctx, 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 (ctx.config.mingw) { ctx.symtab.addFile(make(ctx, mbref)); break; } if (filename.ends_with_insensitive(".dll")) { error(filename + ": bad file type. Did you specify a DLL instead of an " "import library?"); break; } [[fallthrough]]; default: error(mbref.getBufferIdentifier() + ": unknown file type"); break; } } void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) { auto future = std::make_shared>( createFutureForFile(std::string(path))); std::string pathStr = std::string(path); enqueueTask([=]() { auto [mb, ec] = future->get(); if (ec) { // Retry reading the file (synchronously) now that we may have added // winsysroot search paths from SymbolTable::addFile(). // Retrying synchronously is important for keeping the order of inputs // consistent. // This makes it so that if the user passes something in the winsysroot // before something we can find with an architecture, we won't find the // winsysroot file. if (std::optional retryPath = findFileIfNew(pathStr)) { auto retryMb = MemoryBuffer::getFile(*retryPath, /*IsText=*/false, /*RequiresNullTerminator=*/false); ec = retryMb.getError(); if (!ec) mb = std::move(*retryMb); } else { // We've already handled this file. return; } } if (ec) { std::string msg = "could not open '" + pathStr + "': " + ec.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 (ctx.optTable.findNearest(pathStr, nearest) > 1) error(msg); else error(msg + "; did you mean '" + nearest + "'"); } else ctx.driver.addBuffer(std::move(mb), wholeArchive, lazy); }); } 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(ctx, mb); imp->parentName = parentName; ctx.symtab.addFile(imp); return; } InputFile *obj; if (magic == file_magic::coff_object) { obj = make(ctx, mb); } else if (magic == file_magic::bitcode) { obj = make(ctx, mb, parentName, offsetInArchive, /*lazy=*/false); } else if (magic == file_magic::coff_cl_gl_object) { error(mb.getBufferIdentifier() + ": is not a native COFF file. Recompile without /GL?"); return; } else { error("unknown file type: " + mb.getBufferIdentifier()); return; } obj->parentName = parentName; ctx.symtab.addFile(obj); log("Loaded " + toString(obj) + " for " + symName); } void LinkerDriver::enqueueArchiveMember(const Archive::Child &c, const Archive::Symbol &sym, StringRef parentName) { auto reportBufferError = [=](Error &&e, StringRef childName) { fatal("could not get the buffer for the member defining symbol " + toCOFFString(ctx, sym) + ": " + 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([=]() { ctx.driver.addArchiveBuffer(mb, toCOFFString(ctx, sym), parentName, offsetInArchive); }); return; } std::string childName = CHECK(c.getFullName(), "could not get the filename for the member defining symbol " + toCOFFString(ctx, sym)); - auto future = std::make_shared>( - createFutureForFile(childName)); + auto future = + std::make_shared>(createFutureForFile(childName)); enqueueTask([=]() { auto mbOrErr = future->get(); if (mbOrErr.second) reportBufferError(errorCodeToError(mbOrErr.second), childName); // Pass empty string as archive name so that the original filename is // used as the buffer identifier. ctx.driver.addArchiveBuffer(takeBuffer(std::move(mbOrErr.first)), toCOFFString(ctx, sym), "", /*OffsetInArchive=*/0); }); } bool LinkerDriver::isDecorated(StringRef sym) { return sym.starts_with("@") || sym.contains("@@") || sym.starts_with("?") || (!ctx.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(ctx); // .drectve is always tokenized using Windows shell rules. // /EXPORT: option can appear too many times, processing in fastpath. ParsedDirectives directives = parser.parseDirectives(s); for (StringRef e : directives.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 (ctx.config.machine == I386 && ctx.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.source = ExportSource::Directives; ctx.config.exports.push_back(exp); } // Handle /include: in bulk. for (StringRef inc : directives.includes) addUndefined(inc); // Handle /exclude-symbols: in bulk. for (StringRef e : directives.excludes) { SmallVector vec; e.split(vec, ','); for (StringRef sym : vec) excludedSymbols.insert(mangle(sym)); } // https://docs.microsoft.com/en-us/cpp/preprocessor/comment-c-cpp?view=msvc-160 for (auto *arg : directives.args) { switch (arg->getOption().getID()) { case OPT_aligncomm: parseAligncomm(arg->getValue()); break; case OPT_alternatename: parseAlternateName(arg->getValue()); break; case OPT_defaultlib: if (std::optional path = findLibIfNew(arg->getValue())) enqueuePath(*path, false, false); break; case OPT_entry: ctx.config.entry = addUndefined(mangle(arg->getValue())); break; case OPT_failifmismatch: checkFailIfMismatch(arg->getValue(), file); break; case OPT_incl: addUndefined(arg->getValue()); break; case OPT_manifestdependency: ctx.config.manifestDependencies.insert(arg->getValue()); break; case OPT_merge: parseMerge(arg->getValue()); break; case OPT_nodefaultlib: ctx.config.noDefaultLibs.insert(findLib(arg->getValue()).lower()); break; case OPT_release: ctx.config.writeCheckSum = true; break; case OPT_section: parseSection(arg->getValue()); break; case OPT_stack: parseNumbers(arg->getValue(), &ctx.config.stackReserve, &ctx.config.stackCommit); break; case OPT_subsystem: { bool gotVersion = false; parseSubsystem(arg->getValue(), &ctx.config.subsystem, &ctx.config.majorSubsystemVersion, &ctx.config.minorSubsystemVersion, &gotVersion); if (gotVersion) { ctx.config.majorOSVersion = ctx.config.majorSubsystemVersion; ctx.config.minorOSVersion = ctx.config.minorSubsystemVersion; } 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: case OPT_inferasanlibs: case OPT_inferasanlibs_no: break; default: error(arg->getSpelling() + " is not allowed in .drectve (" + toString(file) + ")"); } } } // 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::findFile(StringRef filename) { auto getFilename = [this](StringRef filename) -> StringRef { if (ctx.config.vfs) if (auto statOrErr = ctx.config.vfs->status(filename)) return saver().save(statOrErr->getName()); return filename; }; if (sys::path::is_absolute(filename)) return getFilename(filename); bool hasExt = filename.contains('.'); for (StringRef dir : searchPaths) { SmallString<128> path = dir; sys::path::append(path, filename); path = SmallString<128>{getFilename(path.str())}; if (sys::fs::exists(path.str())) return saver().save(path.str()); if (!hasExt) { path.append(".obj"); path = SmallString<128>{getFilename(path.str())}; if (sys::fs::exists(path.str())) return saver().save(path.str()); } } return filename; } static std::optional getUniqueID(StringRef path) { sys::fs::UniqueID ret; if (sys::fs::getUniqueID(path, ret)) return std::nullopt; return ret; } // Resolves a file path. This never returns the same path // (in that case, it returns std::nullopt). std::optional LinkerDriver::findFileIfNew(StringRef filename) { StringRef path = findFile(filename); if (std::optional id = getUniqueID(path)) { bool seen = !visitedFiles.insert(*id).second; if (seen) return std::nullopt; } if (path.ends_with_insensitive(".lib")) visitedLibs.insert(std::string(sys::path::filename(path).lower())); 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::findLibMinGW(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 findFile(libName); } // Find library file from search path. StringRef LinkerDriver::findLib(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 = findFile(filename); // For MinGW, if the find above didn't turn up anything, try // looking for a MinGW formatted library name. if (ctx.config.mingw && ret == filename) return findLibMinGW(filename); return ret; } // Resolves a library path. /nodefaultlib options are taken into // consideration. This never returns the same path (in that case, // it returns std::nullopt). std::optional LinkerDriver::findLibIfNew(StringRef filename) { if (ctx.config.noDefaultLibAll) return std::nullopt; if (!visitedLibs.insert(filename.lower()).second) return std::nullopt; StringRef path = findLib(filename); if (ctx.config.noDefaultLibs.count(path.lower())) return std::nullopt; if (std::optional id = getUniqueID(path)) if (!visitedFiles.insert(*id).second) return std::nullopt; return path; } void LinkerDriver::detectWinSysRoot(const opt::InputArgList &Args) { IntrusiveRefCntPtr VFS = vfs::getRealFileSystem(); // Check the command line first, that's the user explicitly telling us what to // use. Check the environment next, in case we're being invoked from a VS // command prompt. Failing that, just try to find the newest Visual Studio // version we can and use its default VC toolchain. std::optional VCToolsDir, VCToolsVersion, WinSysRoot; if (auto *A = Args.getLastArg(OPT_vctoolsdir)) VCToolsDir = A->getValue(); if (auto *A = Args.getLastArg(OPT_vctoolsversion)) VCToolsVersion = A->getValue(); if (auto *A = Args.getLastArg(OPT_winsysroot)) WinSysRoot = A->getValue(); if (!findVCToolChainViaCommandLine(*VFS, VCToolsDir, VCToolsVersion, WinSysRoot, vcToolChainPath, vsLayout) && (Args.hasArg(OPT_lldignoreenv) || !findVCToolChainViaEnvironment(*VFS, vcToolChainPath, vsLayout)) && !findVCToolChainViaSetupConfig(*VFS, {}, vcToolChainPath, vsLayout) && !findVCToolChainViaRegistry(vcToolChainPath, vsLayout)) return; // If the VC environment hasn't been configured (perhaps because the user did // not run vcvarsall), try to build a consistent link environment. If the // environment variable is set however, assume the user knows what they're // doing. If the user passes /vctoolsdir or /winsdkdir, trust that over env // vars. if (const auto *A = Args.getLastArg(OPT_diasdkdir, OPT_winsysroot)) { diaPath = A->getValue(); if (A->getOption().getID() == OPT_winsysroot) path::append(diaPath, "DIA SDK"); } useWinSysRootLibPath = Args.hasArg(OPT_lldignoreenv) || !Process::GetEnv("LIB") || Args.getLastArg(OPT_vctoolsdir, OPT_winsysroot); if (Args.hasArg(OPT_lldignoreenv) || !Process::GetEnv("LIB") || Args.getLastArg(OPT_winsdkdir, OPT_winsysroot)) { std::optional WinSdkDir, WinSdkVersion; if (auto *A = Args.getLastArg(OPT_winsdkdir)) WinSdkDir = A->getValue(); if (auto *A = Args.getLastArg(OPT_winsdkversion)) WinSdkVersion = A->getValue(); if (useUniversalCRT(vsLayout, vcToolChainPath, getArch(), *VFS)) { std::string UniversalCRTSdkPath; std::string UCRTVersion; if (getUniversalCRTSdkDir(*VFS, WinSdkDir, WinSdkVersion, WinSysRoot, UniversalCRTSdkPath, UCRTVersion)) { universalCRTLibPath = UniversalCRTSdkPath; path::append(universalCRTLibPath, "Lib", UCRTVersion, "ucrt"); } } std::string sdkPath; std::string windowsSDKIncludeVersion; std::string windowsSDKLibVersion; if (getWindowsSDKDir(*VFS, WinSdkDir, WinSdkVersion, WinSysRoot, sdkPath, sdkMajor, windowsSDKIncludeVersion, windowsSDKLibVersion)) { windowsSdkLibPath = sdkPath; path::append(windowsSdkLibPath, "Lib"); if (sdkMajor >= 8) path::append(windowsSdkLibPath, windowsSDKLibVersion, "um"); } } } void LinkerDriver::addClangLibSearchPaths(const std::string &argv0) { std::string lldBinary = sys::fs::getMainExecutable(argv0.c_str(), nullptr); SmallString<128> binDir(lldBinary); - sys::path::remove_filename(binDir); // remove lld-link.exe + sys::path::remove_filename(binDir); // remove lld-link.exe StringRef rootDir = sys::path::parent_path(binDir); // remove 'bin' SmallString<128> libDir(rootDir); sys::path::append(libDir, "lib"); - // We need to prepend the paths here in order to make sure that we always - // try to link the clang versions of the builtins over the ones supplied by MSVC. - searchPaths.insert(searchPaths.begin(), saver().save(libDir.str())); // Add the resource dir library path SmallString<128> runtimeLibDir(rootDir); - sys::path::append(runtimeLibDir, "lib", "clang", std::to_string(LLVM_VERSION_MAJOR), "lib"); - searchPaths.insert(searchPaths.begin(), saver().save(runtimeLibDir.str())); - + sys::path::append(runtimeLibDir, "lib", "clang", + std::to_string(LLVM_VERSION_MAJOR), "lib"); // Resource dir + osname, which is hardcoded to windows since we are in the // COFF driver. SmallString<128> runtimeLibDirWithOS(runtimeLibDir); sys::path::append(runtimeLibDirWithOS, "windows"); - searchPaths.insert(searchPaths.begin(), saver().save(runtimeLibDirWithOS.str())); + searchPaths.push_back(saver().save(runtimeLibDirWithOS.str())); + searchPaths.push_back(saver().save(runtimeLibDir.str())); + searchPaths.push_back(saver().save(libDir.str())); } void LinkerDriver::addWinSysRootLibSearchPaths() { if (!diaPath.empty()) { // The DIA SDK always uses the legacy vc arch, even in new MSVC versions. path::append(diaPath, "lib", archToLegacyVCArch(getArch())); searchPaths.push_back(saver().save(diaPath.str())); } if (useWinSysRootLibPath) { searchPaths.push_back(saver().save(getSubDirectoryPath( SubDirectoryType::Lib, vsLayout, vcToolChainPath, getArch()))); searchPaths.push_back(saver().save( getSubDirectoryPath(SubDirectoryType::Lib, vsLayout, vcToolChainPath, getArch(), "atlmfc"))); } if (!universalCRTLibPath.empty()) { StringRef ArchName = archToWindowsSDKArch(getArch()); if (!ArchName.empty()) { path::append(universalCRTLibPath, ArchName); searchPaths.push_back(saver().save(universalCRTLibPath.str())); } } if (!windowsSdkLibPath.empty()) { std::string path; if (appendArchToWindowsSDKLibPath(sdkMajor, windowsSdkLibPath, getArch(), path)) searchPaths.push_back(saver().save(path)); } } // Parses LIB environment which contains a list of search paths. void LinkerDriver::addLibSearchPaths() { std::optional envOpt = Process::GetEnv("LIB"); if (!envOpt) 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 = ctx.symtab.addUndefined(name); if (!b->isGCRoot) { b->isGCRoot = true; ctx.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 = ctx.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 = ctx.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(ctx.config.subsystem != IMAGE_SUBSYSTEM_UNKNOWN && "must handle /subsystem before calling this"); if (ctx.config.mingw) return mangle(ctx.config.subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI ? "WinMainCRTStartup" : "mainCRTStartup"); if (ctx.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 (ctx.config.dll) return IMAGE_SUBSYSTEM_WINDOWS_GUI; if (ctx.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; } uint64_t LinkerDriver::getDefaultImageBase() { if (ctx.config.is64()) return ctx.config.dll ? 0x180000000 : 0x140000000; return ctx.config.dll ? 0x10000000 : 0x400000; } static std::string rewritePath(StringRef s) { if (fs::exists(s)) return relativeToRoot(s); return std::string(s); } // Reconstructs command line arguments so that so that you can re-run // the same command with the same inputs. This is for --reproduce. 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_reproduce: case OPT_INPUT: case OPT_defaultlib: case OPT_libpath: case OPT_winsysroot: break; case OPT_call_graph_ordering_file: case OPT_deffile: case OPT_manifestinput: case OPT_natvis: os << arg->getSpelling() << quote(rewritePath(arg->getValue())) << '\n'; break; case OPT_order: { StringRef orderFile = arg->getValue(); orderFile.consume_front("@"); os << arg->getSpelling() << '@' << quote(rewritePath(orderFile)) << '\n'; break; } case OPT_pdbstream: { const std::pair nameFile = StringRef(arg->getValue()).split("="); os << arg->getSpelling() << nameFile.first << '=' << quote(rewritePath(nameFile.second)) << '\n'; break; } case OPT_implib: case OPT_manifestfile: case OPT_pdb: case OPT_pdbstripped: 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 std::string(data.str()); } enum class DebugKind { Unknown, None, Full, FastLink, GHash, NoGHash, 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("noghash", DebugKind::NoGHash) .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; } std::string LinkerDriver::getMapFile(const opt::InputArgList &args, opt::OptSpecifier os, opt::OptSpecifier osFile) { auto *arg = args.getLastArg(os, osFile); if (!arg) return ""; if (arg->getOption().getID() == osFile.getID()) return arg->getValue(); assert(arg->getOption().getID() == os.getID()); StringRef outFile = ctx.config.outputFile; return (outFile.substr(0, outFile.rfind('.')) + ".map").str(); } std::string LinkerDriver::getImplibPath() { if (!ctx.config.implib.empty()) return std::string(ctx.config.implib); SmallString<128> out = StringRef(ctx.config.outputFile); sys::path::replace_extension(out, ".lib"); return std::string(out.str()); } // The import name is calculated as follows: // // | LIBRARY w/ ext | LIBRARY w/o ext | no LIBRARY // -----+----------------+---------------------+------------------ // LINK | {value} | {value}.{.dll/.exe} | {output name} // LIB | {value} | {value}.dll | {output name}.dll // std::string LinkerDriver::getImportName(bool asLib) { SmallString<128> out; if (ctx.config.importName.empty()) { out.assign(sys::path::filename(ctx.config.outputFile)); if (asLib) sys::path::replace_extension(out, ".dll"); } else { out.assign(ctx.config.importName); if (!sys::path::has_extension(out)) sys::path::replace_extension(out, (ctx.config.dll || asLib) ? ".dll" : ".exe"); } return std::string(out.str()); } void LinkerDriver::createImportLibrary(bool asLib) { std::vector exports; for (Export &e1 : ctx.config.exports) { COFFShortExport e2; e2.Name = std::string(e1.name); e2.SymbolName = std::string(e1.symbolName); e2.ExtName = std::string(e1.extName); e2.AliasTarget = std::string(e1.aliasTarget); e2.Ordinal = e1.ordinal; e2.Noname = e1.noname; e2.Data = e1.data; e2.Private = e1.isPrivate; e2.Constant = e1.constant; exports.push_back(e2); } std::string libName = getImportName(asLib); std::string path = getImplibPath(); if (!ctx.config.incremental) { checkError(writeImportLibrary(libName, path, exports, ctx.config.machine, ctx.config.mingw)); return; } // If the import library already exists, replace it only if the contents // have changed. ErrorOr> oldBuf = MemoryBuffer::getFile( path, /*IsText=*/false, /*RequiresNullTerminator=*/false); if (!oldBuf) { checkError(writeImportLibrary(libName, path, exports, ctx.config.machine, ctx.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, ctx.config.machine, ctx.config.mingw)) { checkError(std::move(e)); return; } std::unique_ptr newBuf = check(MemoryBuffer::getFile( tmpName, /*IsText=*/false, /*RequiresNullTerminator=*/false)); if ((*oldBuf)->getBuffer() != newBuf->getBuffer()) { oldBuf->reset(); checkError(errorCodeToError(sys::fs::rename(tmpName, path))); } else { sys::fs::remove(tmpName); } } void LinkerDriver::parseModuleDefs(StringRef path) { std::unique_ptr mb = CHECK(MemoryBuffer::getFile(path, /*IsText=*/false, /*RequiresNullTerminator=*/false, /*IsVolatile=*/true), "could not open " + path); COFFModuleDefinition m = check(parseCOFFModuleDefinition( mb->getMemBufferRef(), ctx.config.machine, ctx.config.mingw)); // Include in /reproduce: output if applicable. ctx.driver.takeBuffer(std::move(mb)); if (ctx.config.outputFile.empty()) ctx.config.outputFile = std::string(saver().save(m.OutputFile)); ctx.config.importName = std::string(saver().save(m.ImportName)); if (m.ImageBase) ctx.config.imageBase = m.ImageBase; if (m.StackReserve) ctx.config.stackReserve = m.StackReserve; if (m.StackCommit) ctx.config.stackCommit = m.StackCommit; if (m.HeapReserve) ctx.config.heapReserve = m.HeapReserve; if (m.HeapCommit) ctx.config.heapCommit = m.HeapCommit; if (m.MajorImageVersion) ctx.config.majorImageVersion = m.MajorImageVersion; if (m.MinorImageVersion) ctx.config.minorImageVersion = m.MinorImageVersion; if (m.MajorOSVersion) ctx.config.majorOSVersion = m.MajorOSVersion; if (m.MinorOSVersion) ctx.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.empty() && e1.ExtName != e1.Name && StringRef(e1.Name).contains('.')) { e2.name = saver().save(e1.ExtName); e2.forwardTo = saver().save(e1.Name); ctx.config.exports.push_back(e2); continue; } e2.name = saver().save(e1.Name); e2.extName = saver().save(e1.ExtName); e2.aliasTarget = saver().save(e1.AliasTarget); e2.ordinal = e1.Ordinal; e2.noname = e1.Noname; e2.data = e1.Data; e2.isPrivate = e1.Private; e2.constant = e1.Constant; e2.source = ExportSource::ModuleDefinition; ctx.config.exports.push_back(e2); } } void LinkerDriver::enqueueTask(std::function task) { taskQueue.push_back(std::move(task)); } bool LinkerDriver::run() { ScopedTimer t(ctx.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. void LinkerDriver::parseOrderFile(StringRef arg) { // For some reason, the MSVC linker requires a filename to be // preceded by "@". if (!arg.starts_with("@")) { error("malformed /order option: '@' missing"); return; } // Get a list of all comdat sections for error checking. DenseSet set; for (Chunk *c : ctx.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, /*IsText=*/false, /*RequiresNullTerminator=*/false, /*IsVolatile=*/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 (StringRef arg : args::getLines(mb->getMemBufferRef())) { std::string s(arg); if (ctx.config.machine == I386 && !isDecorated(s)) s = "_" + s; if (set.count(s) == 0) { if (ctx.config.warnMissingOrderSymbol) warn("/order:" + arg + ": missing symbol: " + s + " [LNK4037]"); - } - else + } else ctx.config.order[s] = INT_MIN + ctx.config.order.size(); } // Include in /reproduce: output if applicable. ctx.driver.takeBuffer(std::move(mb)); } void LinkerDriver::parseCallGraphFile(StringRef path) { std::unique_ptr mb = CHECK(MemoryBuffer::getFile(path, /*IsText=*/false, /*RequiresNullTerminator=*/false, /*IsVolatile=*/true), "could not open " + path); // Build a map from symbol name to section. DenseMap map; for (ObjFile *file : ctx.objFileInstances) for (Symbol *sym : file->getSymbols()) if (sym) map[sym->getName()] = sym; auto findSection = [&](StringRef name) -> SectionChunk * { Symbol *sym = map.lookup(name); if (!sym) { if (ctx.config.warnMissingOrderSymbol) warn(path + ": no such symbol: " + name); return nullptr; } if (DefinedCOFF *dr = dyn_cast_or_null(sym)) return dyn_cast_or_null(dr->getChunk()); return nullptr; }; for (StringRef line : args::getLines(*mb)) { SmallVector fields; line.split(fields, ' '); uint64_t count; if (fields.size() != 3 || !to_integer(fields[2], count)) { error(path + ": parse error"); return; } if (SectionChunk *from = findSection(fields[0])) if (SectionChunk *to = findSection(fields[1])) ctx.config.callGraphProfile[{from, to}] += count; } // Include in /reproduce: output if applicable. ctx.driver.takeBuffer(std::move(mb)); } static void readCallGraphsFromObjectFiles(COFFLinkerContext &ctx) { for (ObjFile *obj : ctx.objFileInstances) { if (obj->callgraphSec) { ArrayRef contents; cantFail( obj->getCOFFObj()->getSectionContents(obj->callgraphSec, contents)); BinaryStreamReader reader(contents, support::little); while (!reader.empty()) { uint32_t fromIndex, toIndex; uint64_t count; if (Error err = reader.readInteger(fromIndex)) fatal(toString(obj) + ": Expected 32-bit integer"); if (Error err = reader.readInteger(toIndex)) fatal(toString(obj) + ": Expected 32-bit integer"); if (Error err = reader.readInteger(count)) fatal(toString(obj) + ": Expected 64-bit integer"); auto *fromSym = dyn_cast_or_null(obj->getSymbol(fromIndex)); auto *toSym = dyn_cast_or_null(obj->getSymbol(toIndex)); if (!fromSym || !toSym) continue; auto *from = dyn_cast_or_null(fromSym->getChunk()); auto *to = dyn_cast_or_null(toSym->getChunk()); if (from && to) ctx.config.callGraphProfile[{from, to}] += count; } } } } 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(COFFLinkerContext &ctx) { // Exported symbols could be address-significant in other executables or DSOs, // so we conservatively mark them as address-significant. for (Export &r : ctx.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 : ctx.objFileInstances) { 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. void LinkerDriver::parsePDBAltPath() { SmallString<128> buf; StringRef pdbBasename = sys::path::filename(ctx.config.pdbPath, sys::path::Style::windows); StringRef binaryExtension = sys::path::extension(ctx.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 < ctx.config.pdbAltPath.size()) { size_t firstMark, secondMark; if ((firstMark = ctx.config.pdbAltPath.find('%', cursor)) == StringRef::npos || (secondMark = ctx.config.pdbAltPath.find('%', firstMark + 1)) == StringRef::npos) { // Didn't find another full fragment, treat rest of string as literal. buf.append(ctx.config.pdbAltPath.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(ctx.config.pdbAltPath.substr(cursor, firstMark - cursor)); StringRef var = ctx.config.pdbAltPath.substr(firstMark, secondMark - firstMark + 1); if (var.equals_insensitive("%_pdb%")) buf.append(pdbBasename); else if (var.equals_insensitive("%_ext%")) buf.append(binaryExtension); else { - warn("only %_PDB% and %_EXT% supported in /pdbaltpath:, keeping " + - var + " as literal"); + warn("only %_PDB% and %_EXT% supported in /pdbaltpath:, keeping " + var + + " as literal"); buf.append(var); } cursor = secondMark + 1; } ctx.config.pdbAltPath = buf; } /// Convert resource files and potentially merge input resource object /// trees into one resource tree. /// Call after ObjFile::Instances is complete. void LinkerDriver::convertResources() { std::vector resourceObjFiles; for (ObjFile *f : ctx.objFileInstances) { if (f->isResourceObjFile()) resourceObjFiles.push_back(f); } if (!ctx.config.mingw && (resourceObjFiles.size() > 1 || (resourceObjFiles.size() == 1 && !resources.empty()))) { error((!resources.empty() ? "internal .obj file created from .res files" : toString(resourceObjFiles[1])) + ": more than one resource obj file not allowed, already got " + toString(resourceObjFiles.front())); return; } if (resources.empty() && resourceObjFiles.size() <= 1) { // No resources to convert, and max one resource object file in // the input. Keep that preconverted resource section as is. for (ObjFile *f : resourceObjFiles) f->includeResourceChunks(); return; } ObjFile *f = make(ctx, convertResToCOFF(resources, resourceObjFiles)); ctx.symtab.addFile(f); f->includeResourceChunks(); } // 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 (!args.hasArg(OPT_export_all_symbols)) { if (!ctx.config.dll) return; if (!ctx.config.exports.empty()) return; if (args.hasArg(OPT_exclude_all_symbols)) return; } AutoExporter exporter(ctx, excludedSymbols); for (auto *arg : args.filtered(OPT_wholearchive_file)) if (std::optional path = findFile(arg->getValue())) exporter.addWholeArchive(*path); for (auto *arg : args.filtered(OPT_exclude_symbols)) { SmallVector vec; StringRef(arg->getValue()).split(vec, ','); for (StringRef sym : vec) exporter.addExcludedSymbol(mangle(sym)); } ctx.symtab.forEachSymbol([&](Symbol *s) { auto *def = dyn_cast(s); if (!exporter.shouldExport(def)) return; if (!def->isGCRoot) { def->isGCRoot = true; ctx.config.gcroot.push_back(def); } Export e; e.name = def->getName(); e.sym = def; if (Chunk *c = def->getChunk()) if (!(c->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) e.data = true; s->isUsedInRegularObj = true; ctx.config.exports.push_back(e); }); } // lld has a feature to create a tar file containing all input files as well as // all command line options, so that other people can run lld again with exactly // the same inputs. This feature is accessible via /linkrepro and /reproduce. // // /linkrepro and /reproduce are very similar, but /linkrepro takes a directory // name while /reproduce takes a full path. We have /linkrepro for compatibility // with Microsoft link.exe. std::optional getReproduceFile(const opt::InputArgList &args) { if (auto *arg = args.getLastArg(OPT_reproduce)) return std::string(arg->getValue()); if (auto *arg = args.getLastArg(OPT_linkrepro)) { SmallString<64> path = StringRef(arg->getValue()); sys::path::append(path, "repro.tar"); return std::string(path); } // This is intentionally not guarded by OPT_lldignoreenv since writing // a repro tar file doesn't affect the main output. if (auto *path = getenv("LLD_REPRODUCE")) return std::string(path); return std::nullopt; } static std::unique_ptr getVFS(const opt::InputArgList &args) { using namespace llvm::vfs; const opt::Arg *arg = args.getLastArg(OPT_vfsoverlay); if (!arg) return nullptr; auto bufOrErr = llvm::MemoryBuffer::getFile(arg->getValue()); if (!bufOrErr) { checkError(errorCodeToError(bufOrErr.getError())); return nullptr; } - if (auto ret = vfs::getVFSFromYAML(std::move(*bufOrErr), /*DiagHandler*/ nullptr, - arg->getValue())) + if (auto ret = vfs::getVFSFromYAML(std::move(*bufOrErr), + /*DiagHandler*/ nullptr, arg->getValue())) return ret; error("Invalid vfs overlay"); return nullptr; } void LinkerDriver::linkerMain(ArrayRef argsArr) { ScopedTimer rootTimer(ctx.rootTimer); Configuration *config = &ctx.config; // 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_insensitive("/lib") || StringRef(argsArr[1]).equals_insensitive("-lib"))) { if (llvm::libDriverMain(argsArr.slice(1)) != 0) fatal("lib failed"); return; } // Parse command line options. ArgParser parser(ctx); opt::InputArgList args = parser.parse(argsArr); // Parse and evaluate -mllvm options. std::vector v; v.push_back("lld-link (LLVM option parsing)"); for (const auto *arg : args.filtered(OPT_mllvm)) { v.push_back(arg->getValue()); config->mllvmOpts.emplace_back(arg->getValue()); } cl::ResetAllOptionOccurrences(); 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; } config->vfs = getVFS(args); // Handle /help if (args.hasArg(OPT_help)) { printHelp(argsArr[0]); return; } // /threads: takes a positive integer and provides the default value for // /opt:lldltojobs=. if (auto *arg = args.getLastArg(OPT_threads)) { StringRef v(arg->getValue()); unsigned threads = 0; if (!llvm::to_integer(v, threads, 0) || threads == 0) error(arg->getSpelling() + ": expected a positive integer, but got '" + arg->getValue() + "'"); parallel::strategy = hardware_concurrency(threads); config->thinLTOJobs = v.str(); } if (args.hasArg(OPT_show_timing)) config->showTiming = true; config->showSummary = args.hasArg(OPT_summary); config->printSearchPaths = args.hasArg(OPT_print_search_paths); // 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)) { message(getLLDVersion()); return; } // Handle /lldmingw early, since it can potentially affect how other // options are handled. config->mingw = args.hasArg(OPT_lldmingw); if (config->mingw) ctx.e.errorLimitExceededMsg = "too many errors emitted, stopping now" " (use --error-limit=0 to see all errors)"; // Handle /linkrepro and /reproduce. if (std::optional path = getReproduceFile(args)) { Expected> errOrWriter = TarWriter::create(*path, sys::path::stem(*path)); if (errOrWriter) { tar = std::move(*errOrWriter); } else { error("/linkrepro: failed to open " + *path + ": " + toString(errOrWriter.takeError())); } } if (!args.hasArg(OPT_INPUT, OPT_wholearchive_file)) { if (args.hasArg(OPT_deffile)) config->noEntry = true; else fatal("no input files"); } // Construct search path list. searchPaths.emplace_back(""); + // Prefer the Clang provided builtins over the ones bundled with MSVC. + addClangLibSearchPaths(argsArr[0]); for (auto *arg : args.filtered(OPT_libpath)) searchPaths.push_back(arg->getValue()); detectWinSysRoot(args); if (!args.hasArg(OPT_lldignoreenv) && !args.hasArg(OPT_winsysroot)) addLibSearchPaths(); - addClangLibSearchPaths(argsArr[0]); // 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; else if (s == "longsections") config->warnLongSectionNames = 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 || debug == DebugKind::NoGHash) { config->debug = true; config->incremental = true; } // Handle /demangle config->demangle = args.hasFlag(OPT_demangle, OPT_demangle_no, true); // Handle /debugtype config->debugTypes = parseDebugTypes(args); // Handle /driver[:uponly|:wdm]. config->driverUponly = args.hasArg(OPT_driver_uponly) || args.hasArg(OPT_driver_uponly_wdm) || args.hasArg(OPT_driver_wdm_uponly); config->driverWdm = args.hasArg(OPT_driver_wdm) || args.hasArg(OPT_driver_uponly_wdm) || args.hasArg(OPT_driver_wdm_uponly); config->driver = config->driverUponly || config->driverWdm || args.hasArg(OPT_driver); // Handle /pdb bool shouldCreatePDB = (debug == DebugKind::Full || debug == DebugKind::GHash || debug == DebugKind::NoGHash); 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 (auto *arg = args.getLastArg(OPT_pdbpagesize)) parsePDBPageSize(arg->getValue()); if (args.hasArg(OPT_natvis)) config->natvisFiles = args.getAllArgValues(OPT_natvis); if (args.hasArg(OPT_pdbstream)) { for (const StringRef value : args.getAllArgValues(OPT_pdbstream)) { const std::pair nameFile = value.split("="); const StringRef name = nameFile.first; const std::string file = nameFile.second.str(); config->namedStreams[name] = file; } } if (auto *arg = args.getLastArg(OPT_pdb_source_path)) config->pdbSourcePath = arg->getValue(); } // Handle /pdbstripped if (args.hasArg(OPT_pdbstripped)) warn("ignoring /pdbstripped flag, it is not yet supported"); // 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()); addWinSysRootLibSearchPaths(); } // Handle /nodefaultlib: for (auto *arg : args.filtered(OPT_nodefaultlib)) config->noDefaultLibs.insert(findLib(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->majorSubsystemVersion, &config->minorSubsystemVersion); // Handle /osversion if (auto *arg = args.getLastArg(OPT_osversion)) { parseVersion(arg->getValue(), &config->majorOSVersion, &config->minorOSVersion); } else { config->majorOSVersion = config->majorSubsystemVersion; config->minorOSVersion = config->minorSubsystemVersion; } // 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(); config->noimplib = args.hasArg(OPT_noimplib); // Handle /opt. bool doGC = debug == DebugKind::None || args.hasArg(OPT_profile); std::optional icfLevel; if (args.hasArg(OPT_profile)) icfLevel = ICFLevel::None; unsigned tailMerge = 1; bool ltoDebugPM = false; 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.starts_with("icf=")) { icfLevel = ICFLevel::All; } else if (s == "safeicf") { icfLevel = ICFLevel::Safe; } else if (s == "noicf") { icfLevel = ICFLevel::None; } else if (s == "lldtailmerge") { tailMerge = 2; } else if (s == "nolldtailmerge") { tailMerge = 0; } else if (s == "ltodebugpassmanager") { ltoDebugPM = true; } else if (s == "noltodebugpassmanager") { ltoDebugPM = false; } else if (s.consume_front("lldlto=")) { if (s.getAsInteger(10, config->ltoo) || config->ltoo > 3) error("/opt:lldlto: invalid optimization level: " + s); } else if (s.consume_front("lldltocgo=")) { config->ltoCgo.emplace(); if (s.getAsInteger(10, *config->ltoCgo) || *config->ltoCgo > 3) error("/opt:lldltocgo: invalid codegen optimization level: " + s); } else if (s.consume_front("lldltojobs=")) { if (!get_threadpool_strategy(s)) error("/opt:lldltojobs: invalid job count: " + s); config->thinLTOJobs = s.str(); } else if (s.consume_front("lldltopartitions=")) { if (s.getAsInteger(10, config->ltoPartitions) || config->ltoPartitions == 0) error("/opt:lldltopartitions: invalid partition count: " + s); } else if (s != "lbr" && s != "nolbr") error("/opt: unknown option: " + s); } } if (!icfLevel) icfLevel = doGC ? ICFLevel::All : ICFLevel::None; config->doGC = doGC; config->doICF = *icfLevel; config->tailMerge = (tailMerge == 1 && config->doICF != ICFLevel::None) || tailMerge == 2; config->ltoDebugPassManager = ltoDebugPM; // 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 /align if (auto *arg = args.getLastArg(OPT_align)) { parseNumbers(arg->getValue(), &config->align); if (!isPowerOf2_64(config->align)) error("/align: not a power of two: " + StringRef(arg->getValue())); if (!args.hasArg(OPT_driver)) warn("/align specified without /driver; image may not run"); } // Handle /aligncomm for (auto *arg : args.filtered(OPT_aligncomm)) parseAligncomm(arg->getValue()); // Handle /manifestdependency. for (auto *arg : args.filtered(OPT_manifestdependency)) config->manifestDependencies.insert(arg->getValue()); // 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"); } // Handle /dwodir config->dwoDir = args.getLastArgValue(OPT_dwodir); 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); std::tie(config->thinLTOPrefixReplaceOld, config->thinLTOPrefixReplaceNew, config->thinLTOPrefixReplaceNativeObject) = getOldNewOptionsExtra(args, OPT_thinlto_prefix_replace); config->thinLTOObjectSuffixReplace = getOldNewOptions(args, OPT_thinlto_object_suffix_replace); config->ltoObjPath = args.getLastArgValue(OPT_lto_obj_path); config->ltoCSProfileGenerate = args.hasArg(OPT_lto_cs_profile_generate); config->ltoCSProfileFile = args.getLastArgValue(OPT_lto_cs_profile_file); // Handle miscellaneous boolean flags. config->ltoPGOWarnMismatch = args.hasFlag(OPT_lto_pgo_warn_mismatch, OPT_lto_pgo_warn_mismatch_no, true); 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 == ICFLevel::None && !args.hasArg(OPT_order) && !args.hasArg(OPT_profile)); config->integrityCheck = args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false); config->cetCompat = args.hasFlag(OPT_cetcompat, OPT_cetcompat_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 || debug == DebugKind::Full; config->debugSymtab = debug == DebugKind::Symtab; config->autoImport = args.hasFlag(OPT_auto_import, OPT_auto_import_no, config->mingw); config->pseudoRelocs = args.hasFlag( OPT_runtime_pseudo_reloc, OPT_runtime_pseudo_reloc_no, config->mingw); config->callGraphProfileSort = args.hasFlag( OPT_call_graph_profile_sort, OPT_call_graph_profile_sort_no, true); config->stdcallFixup = args.hasFlag(OPT_stdcall_fixup, OPT_stdcall_fixup_no, config->mingw); config->warnStdcallFixup = !args.hasArg(OPT_stdcall_fixup); if (args.hasFlag(OPT_inferasanlibs, OPT_inferasanlibs_no, false)) warn("ignoring '/inferasanlibs', this flag is not supported"); // Don't warn about long section names, such as .debug_info, for mingw or // when -debug:dwarf is requested. if (config->mingw || config->debugDwarf) config->warnLongSectionNames = false; 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 != ICFLevel::None) { 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 (std::optional path = findFile(arg->getValue())) if (std::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 (std::optional id = getUniqueID(path)) return wholeArchives.count(*id); return false; }; // Create a list of input files. These can be given as OPT_INPUT options // and OPT_wholearchive_file options, and we also need to track OPT_start_lib // and OPT_end_lib. bool inLib = false; for (auto *arg : args) { switch (arg->getOption().getID()) { case OPT_end_lib: if (!inLib) error("stray " + arg->getSpelling()); inLib = false; break; case OPT_start_lib: if (inLib) error("nested " + arg->getSpelling()); inLib = true; break; case OPT_wholearchive_file: if (std::optional path = findFileIfNew(arg->getValue())) enqueuePath(*path, true, inLib); break; case OPT_INPUT: if (std::optional path = findFileIfNew(arg->getValue())) enqueuePath(*path, isWholeArchive(*path), inLib); break; default: // Ignore other options. break; } } // 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; addWinSysRootLibSearchPaths(); } config->wordsize = config->is64() ? 8 : 4; if (config->printSearchPaths) { SmallString<256> buffer; raw_svector_ostream stream(buffer); stream << "Library search paths:\n"; - for (StringRef path : searchPaths) + for (StringRef path : searchPaths) { + if (path == "") + path = "(cwd)"; stream << " " << path << "\n"; + } message(buffer); } // Process files specified as /defaultlib. These must be processed after // addWinSysRootLibSearchPaths(), which is why they are in a separate loop. for (auto *arg : args.filtered(OPT_defaultlib)) if (std::optional path = findLibIfNew(arg->getValue())) enqueuePath(*path, false, false); run(); if (errorCount()) return; // Handle /RELEASE if (args.hasArg(OPT_release)) config->writeCheckSum = true; - + // Handle /safeseh, x86 only, on by default, except for mingw. if (config->machine == I386) { config->safeSEH = args.hasFlag(OPT_safeseh, OPT_safeseh_no, !config->mingw); config->noSEH = args.hasArg(OPT_noseh); } // Handle /functionpadmin for (auto *arg : args.filtered(OPT_functionpadmin, OPT_functionpadmin_opt)) parseFunctionPadMin(arg); 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, OPT_wholearchive_file)) { fixupExports(); if (!config->noimplib) 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 if (config->driverWdm) { // /driver:wdm implies /entry:_NtProcessStartup config->entry = addUndefined(mangle("_NtProcessStartup")); } 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, OPT_wholearchive_file).begin())->getValue(), config->dll, config->driver); } // 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; } config->lldmapFile = getMapFile(args, OPT_lldmap, OPT_lldmap_file); config->mapFile = getMapFile(args, OPT_map, OPT_map_file); if (config->mapFile != "" && args.hasArg(OPT_map_info)) { for (auto *arg : args.filtered(OPT_map_info)) { std::string s = StringRef(arg->getValue()).lower(); if (s == "exports") config->mapInfo = true; else error("unknown option: /mapinfo:" + s); } } if (config->lldmapFile != "" && config->lldmapFile == config->mapFile) { warn("/lldmap and /map have the same output file '" + config->mapFile + "'.\n>>> ignoring /lldmap"); config->lldmapFile.clear(); } 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 ctx.OutputFile is ready. parsePDBAltPath(); } } // Set default image base if /base is not given. if (config->imageBase == uint64_t(-1)) config->imageBase = getDefaultImageBase(); ctx.symtab.addSynthetic(mangle("__ImageBase"), nullptr); if (config->machine == I386) { ctx.symtab.addAbsolute("___safe_se_handler_table", 0); ctx.symtab.addAbsolute("___safe_se_handler_count", 0); } ctx.symtab.addAbsolute(mangle("__guard_fids_count"), 0); ctx.symtab.addAbsolute(mangle("__guard_fids_table"), 0); ctx.symtab.addAbsolute(mangle("__guard_flags"), 0); ctx.symtab.addAbsolute(mangle("__guard_iat_count"), 0); ctx.symtab.addAbsolute(mangle("__guard_iat_table"), 0); ctx.symtab.addAbsolute(mangle("__guard_longjmp_count"), 0); ctx.symtab.addAbsolute(mangle("__guard_longjmp_table"), 0); // Needed for MSVC 2017 15.5 CRT. ctx.symtab.addAbsolute(mangle("__enclave_config"), 0); // Needed for MSVC 2019 16.8 CRT. ctx.symtab.addAbsolute(mangle("__guard_eh_cont_count"), 0); ctx.symtab.addAbsolute(mangle("__guard_eh_cont_table"), 0); if (config->pseudoRelocs) { ctx.symtab.addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0); ctx.symtab.addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0); } if (config->mingw) { ctx.symtab.addAbsolute(mangle("__CTOR_LIST__"), 0); ctx.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.source != ExportSource::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 = ctx.symtab.find(from); if (!sym) continue; if (auto *u = dyn_cast(sym)) if (!u->weakAlias) u->weakAlias = ctx.symtab.addUndefined(to); } // If any inputs are bitcode files, the LTO code generator may create // references to library functions that are not explicit in the bitcode // file's symbol table. If any of those library functions are defined in a // bitcode file in an archive member, we need to arrange to use LTO to // compile those archive members by adding them to the link beforehand. if (!ctx.bitcodeFileInstances.empty()) for (auto *s : lto::LTO::getRuntimeLibcallSymbols()) ctx.symtab.addLibcall(s); // Windows specific -- if __load_config_used can be resolved, resolve it. if (ctx.symtab.findUnderscore("_load_config_used")) addUndefined(mangle("_load_config_used")); if (args.hasArg(OPT_include_optional)) { // Handle /includeoptional for (auto *arg : args.filtered(OPT_include_optional)) if (isa_and_nonnull(ctx.symtab.find(arg->getValue()))) addUndefined(arg->getValue()); } } while (run()); // Create wrapped symbols for -wrap option. std::vector wrapped = addWrappedSymbols(ctx, args); // Load more object files that might be needed for wrapped symbols. if (!wrapped.empty()) - while (run()); + while (run()) + ; if (config->autoImport || config->stdcallFixup) { // MinGW specific. // Load any further object files that might be needed for doing automatic // imports, and do stdcall fixups. // // 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. // // If stdcall fixups only are needed for loading import entries from // a DLL without import library, this also just needs running once. // If it ends up pulling in more object files from static libraries, // (and maybe doing more stdcall fixups along the way), this would need // to loop these two calls. ctx.symtab.loadMinGWSymbols(); run(); } // At this point, we should not have any symbols that cannot be resolved. // If we are going to do codegen for link-time optimization, check for // unresolvable symbols first, so we don't spend time generating code that // will fail to link anyway. if (!ctx.bitcodeFileInstances.empty() && !config->forceUnresolved) ctx.symtab.reportUnresolvable(); if (errorCount()) return; config->hadExplicitExports = !config->exports.empty(); if (config->mingw) { // In MinGW, all symbols are automatically exported if no symbols // are chosen to be exported. maybeExportMinGWSymbols(args); } // 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). ctx.symtab.compileBitcodeFiles(); // 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(); // Apply symbol renames for -wrap. if (!wrapped.empty()) wrapSymbols(ctx, wrapped); // Resolve remaining undefined symbols and warn about imported locals. ctx.symtab.resolveRemainingUndefines(); if (errorCount()) return; if (config->mingw) { // 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 = ctx.objFileInstances.begin(), e = ctx.objFileInstances.end(); i != e; i++) { ObjFile *file = *i; if (isCrtend(file->getName())) { ctx.objFileInstances.erase(i); ctx.objFileInstances.push_back(file); break; } } } // Windows specific -- when we are creating a .dll file, we also // need to create a .lib file. In MinGW mode, we only do that when the // -implib option is given explicitly, for compatibility with GNU ld. if (!config->exports.empty() || config->dll) { fixupExports(); if (!config->noimplib && (!config->mingw || !config->implib.empty())) createImportLibrary(/*asLib=*/false); assignExportOrdinals(); } // Handle /output-def (MinGW specific). if (auto *arg = args.getLastArg(OPT_output_def)) writeDefFile(arg->getValue(), config->exports); // Set extra alignment for .comm symbols for (auto pair : config->alignComm) { StringRef name = pair.first; uint32_t alignment = pair.second; Symbol *sym = ctx.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 an embedded or side-by-side manifest. // /manifestdependency: enables /manifest unless an explicit /manifest:no is // also passed. if (config->manifest == Configuration::Embed) addBuffer(createManifestRes(), false, false); else if (config->manifest == Configuration::SideBySide || (config->manifest == Configuration::Default && !config->manifestDependencies.empty())) 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)) { if (args.hasArg(OPT_call_graph_ordering_file)) error("/order and /call-graph-order-file may not be used together"); parseOrderFile(arg->getValue()); config->callGraphProfileSort = false; } // Handle /call-graph-ordering-file and /call-graph-profile-sort (default on). if (config->callGraphProfileSort) { if (auto *arg = args.getLastArg(OPT_call_graph_ordering_file)) { parseCallGraphFile(arg->getValue()); } readCallGraphsFromObjectFiles(ctx); } // Handle /print-symbol-order. if (auto *arg = args.getLastArg(OPT_print_symbol_order)) config->printSymbolOrder = arg->getValue(); // Identify unreferenced COMDAT sections. if (config->doGC) { if (config->mingw) { // markLive doesn't traverse .eh_frame, but the personality function is // only reached that way. The proper solution would be to parse and // traverse the .eh_frame section, like the ELF linker does. // For now, just manually try to retain the known possible personality // functions. This doesn't bring in more object files, but only marks // functions that already have been included to be retained. for (const char *n : {"__gxx_personality_v0", "__gcc_personality_v0", "rust_eh_personality"}) { Defined *d = dyn_cast_or_null(ctx.symtab.findUnderscore(n)); if (d && !d->isGCRoot) { d->isGCRoot = true; config->gcroot.push_back(d); } } } markLive(ctx); } // Needs to happen after the last call to addFile(). convertResources(); // Identify identical COMDAT sections to merge them. if (config->doICF != ICFLevel::None) { findKeepUniqueSections(ctx); doICF(ctx); } // Write the result. writeResult(ctx); // Stop early so we can print the results. rootTimer.stop(); if (config->showTiming) ctx.rootTimer.print(); } } // namespace lld::coff diff --git a/lld/Common/Filesystem.cpp b/lld/Common/Filesystem.cpp index 671b352a3f6b..c93353f2d292 100644 --- a/lld/Common/Filesystem.cpp +++ b/lld/Common/Filesystem.cpp @@ -1,129 +1,129 @@ //===- Filesystem.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 a few utility functions to handle files. // //===----------------------------------------------------------------------===// #include "lld/Common/Filesystem.h" #include "llvm/Config/llvm-config.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Parallel.h" #include "llvm/Support/Path.h" #if LLVM_ON_UNIX #include #endif #include using namespace llvm; using namespace lld; // Removes a given file asynchronously. This is a performance hack, // so remove this when operating systems are improved. // // On Linux (and probably on other Unix-like systems), unlink(2) is a // noticeably slow system call. As of 2016, unlink takes 250 // milliseconds to remove a 1 GB file on ext4 filesystem on my machine. // // To create a new result file, we first remove existing file. So, if // you repeatedly link a 1 GB program in a regular compile-link-debug // cycle, every cycle wastes 250 milliseconds only to remove a file. // Since LLD can link a 1 GB binary in about 5 seconds, that waste // actually counts. // // This function spawns a background thread to remove the file. // The calling thread returns almost immediately. void lld::unlinkAsync(StringRef path) { if (!sys::fs::exists(path) || !sys::fs::is_regular_file(path)) return; // Removing a file is async on windows. #if defined(_WIN32) // On Windows co-operative programs can be expected to open LLD's // output in FILE_SHARE_DELETE mode. This allows us to delete the // file (by moving it to a temporary filename and then deleting // it) so that we can link another output file that overwrites // the existing file, even if the current file is in use. // // This is done on a best effort basis - we do not error if the // operation fails. The consequence is merely that the user // experiences an inconvenient work-flow. // // The code here allows LLD to work on all versions of Windows. // However, at Windows 10 1903 it seems that the behavior of - // Windows has changed, so that we could simply delete the output + // Windows has changed, so that we could simply delete the output // file. This code should be simplified once support for older // versions of Windows is dropped. // // Warning: It seems that the WINVER and _WIN32_WINNT preprocessor // defines affect the behavior of the Windows versions of the calls // we are using here. If this code stops working this is worth // bearing in mind. SmallString<128> tmpName; if (!sys::fs::createUniqueFile(path + "%%%%%%%%.tmp", tmpName)) { if (!sys::fs::rename(path, tmpName)) path = tmpName; else sys::fs::remove(tmpName); } sys::fs::remove(path); #else if (parallel::strategy.ThreadsRequested == 1) return; // We cannot just remove path from a different thread because we are now going // to create path as a new file. // Instead we open the file and unlink it on this thread. The unlink is fast // since the open fd guarantees that it is not removing the last reference. int fd; std::error_code ec = sys::fs::openFileForRead(path, fd); sys::fs::remove(path); if (ec) return; // close and therefore remove TempPath in background. std::mutex m; std::condition_variable cv; bool started = false; std::thread([&, fd] { { std::lock_guard l(m); started = true; cv.notify_all(); } ::close(fd); }).detach(); // GLIBC 2.26 and earlier have race condition that crashes an entire process // if the main thread calls exit(2) while other thread is starting up. std::unique_lock l(m); cv.wait(l, [&] { return started; }); #endif } // Simulate file creation to see if Path is writable. // // Determining whether a file is writable or not is amazingly hard, // and after all the only reliable way of doing that is to actually // create a file. But we don't want to do that in this function // because LLD shouldn't update any file if it will end in a failure. // We also don't want to reimplement heuristics to determine if a // file is writable. So we'll let FileOutputBuffer do the work. // // FileOutputBuffer doesn't touch a destination file until commit() // is called. We use that class without calling commit() to predict // if the given file is writable. std::error_code lld::tryCreateFile(StringRef path) { if (path.empty()) return std::error_code(); if (path == "-") return std::error_code(); return errorToErrorCode(FileOutputBuffer::create(path, 1).takeError()); } diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index 55fb522554fa..4ffffd85ee53 100644 --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -1,2680 +1,2680 @@ //===- llvm/CodeGen/TargetLoweringObjectFileImpl.cpp - Object File Info ---===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements classes used to handle lowerings specific to common // object file formats. // //===----------------------------------------------------------------------===// #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/BinaryFormat/Wasm.h" #include "llvm/CodeGen/BasicBlockSectionUtils.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/IR/Comdat.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalObject.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/PseudoProbe.h" #include "llvm/IR/Type.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionGOFF.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCSectionWasm.h" #include "llvm/MC/MCSectionXCOFF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSymbolELF.h" #include "llvm/MC/MCValue.h" #include "llvm/MC/SectionKind.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Base64.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include "llvm/TargetParser/Triple.h" #include #include using namespace llvm; using namespace dwarf; static cl::opt JumpTableInFunctionSection( "jumptable-in-function-section", cl::Hidden, cl::init(false), cl::desc("Putting Jump Table in function section")); static void GetObjCImageInfo(Module &M, unsigned &Version, unsigned &Flags, StringRef &Section) { SmallVector ModuleFlags; M.getModuleFlagsMetadata(ModuleFlags); for (const auto &MFE: ModuleFlags) { // Ignore flags with 'Require' behaviour. if (MFE.Behavior == Module::Require) continue; StringRef Key = MFE.Key->getString(); if (Key == "Objective-C Image Info Version") { Version = mdconst::extract(MFE.Val)->getZExtValue(); } else if (Key == "Objective-C Garbage Collection" || Key == "Objective-C GC Only" || Key == "Objective-C Is Simulated" || Key == "Objective-C Class Properties" || Key == "Objective-C Image Swift Version") { Flags |= mdconst::extract(MFE.Val)->getZExtValue(); } else if (Key == "Objective-C Image Info Section") { Section = cast(MFE.Val)->getString(); } // Backend generates L_OBJC_IMAGE_INFO from Swift ABI version + major + minor + // "Objective-C Garbage Collection". else if (Key == "Swift ABI Version") { Flags |= (mdconst::extract(MFE.Val)->getZExtValue()) << 8; } else if (Key == "Swift Major Version") { Flags |= (mdconst::extract(MFE.Val)->getZExtValue()) << 24; } else if (Key == "Swift Minor Version") { Flags |= (mdconst::extract(MFE.Val)->getZExtValue()) << 16; } } } //===----------------------------------------------------------------------===// // ELF //===----------------------------------------------------------------------===// TargetLoweringObjectFileELF::TargetLoweringObjectFileELF() { SupportDSOLocalEquivalentLowering = true; } void TargetLoweringObjectFileELF::Initialize(MCContext &Ctx, const TargetMachine &TgtM) { TargetLoweringObjectFile::Initialize(Ctx, TgtM); CodeModel::Model CM = TgtM.getCodeModel(); InitializeELF(TgtM.Options.UseInitArray); switch (TgtM.getTargetTriple().getArch()) { case Triple::arm: case Triple::armeb: case Triple::thumb: case Triple::thumbeb: if (Ctx.getAsmInfo()->getExceptionHandlingType() == ExceptionHandling::ARM) break; // Fallthrough if not using EHABI [[fallthrough]]; case Triple::ppc: case Triple::ppcle: case Triple::x86: PersonalityEncoding = isPositionIndependent() ? dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4 : dwarf::DW_EH_PE_absptr; LSDAEncoding = isPositionIndependent() ? dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4 : dwarf::DW_EH_PE_absptr; TTypeEncoding = isPositionIndependent() ? dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4 : dwarf::DW_EH_PE_absptr; break; case Triple::x86_64: if (isPositionIndependent()) { PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | ((CM == CodeModel::Small || CM == CodeModel::Medium) ? dwarf::DW_EH_PE_sdata4 : dwarf::DW_EH_PE_sdata8); LSDAEncoding = dwarf::DW_EH_PE_pcrel | (CM == CodeModel::Small ? dwarf::DW_EH_PE_sdata4 : dwarf::DW_EH_PE_sdata8); TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | ((CM == CodeModel::Small || CM == CodeModel::Medium) ? dwarf::DW_EH_PE_sdata4 : dwarf::DW_EH_PE_sdata8); } else { PersonalityEncoding = (CM == CodeModel::Small || CM == CodeModel::Medium) ? dwarf::DW_EH_PE_udata4 : dwarf::DW_EH_PE_absptr; LSDAEncoding = (CM == CodeModel::Small) ? dwarf::DW_EH_PE_udata4 : dwarf::DW_EH_PE_absptr; TTypeEncoding = (CM == CodeModel::Small) ? dwarf::DW_EH_PE_udata4 : dwarf::DW_EH_PE_absptr; } break; case Triple::hexagon: PersonalityEncoding = dwarf::DW_EH_PE_absptr; LSDAEncoding = dwarf::DW_EH_PE_absptr; TTypeEncoding = dwarf::DW_EH_PE_absptr; if (isPositionIndependent()) { PersonalityEncoding |= dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel; LSDAEncoding |= dwarf::DW_EH_PE_pcrel; TTypeEncoding |= dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel; } break; case Triple::aarch64: case Triple::aarch64_be: case Triple::aarch64_32: // The small model guarantees static code/data size < 4GB, but not where it // will be in memory. Most of these could end up >2GB away so even a signed // pc-relative 32-bit address is insufficient, theoretically. // // Use DW_EH_PE_indirect even for -fno-pic to avoid copy relocations. LSDAEncoding = dwarf::DW_EH_PE_pcrel | (TgtM.getTargetTriple().getEnvironment() == Triple::GNUILP32 ? dwarf::DW_EH_PE_sdata4 : dwarf::DW_EH_PE_sdata8); PersonalityEncoding = LSDAEncoding | dwarf::DW_EH_PE_indirect; TTypeEncoding = LSDAEncoding | dwarf::DW_EH_PE_indirect; break; case Triple::lanai: LSDAEncoding = dwarf::DW_EH_PE_absptr; PersonalityEncoding = dwarf::DW_EH_PE_absptr; TTypeEncoding = dwarf::DW_EH_PE_absptr; break; case Triple::mips: case Triple::mipsel: case Triple::mips64: case Triple::mips64el: // MIPS uses indirect pointer to refer personality functions and types, so // that the eh_frame section can be read-only. DW.ref.personality will be // generated for relocation. PersonalityEncoding = dwarf::DW_EH_PE_indirect; // FIXME: The N64 ABI probably ought to use DW_EH_PE_sdata8 but we can't // identify N64 from just a triple. TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; // We don't support PC-relative LSDA references in GAS so we use the default // DW_EH_PE_absptr for those. // FreeBSD must be explicit about the data size and using pcrel since it's // assembler/linker won't do the automatic conversion that the Linux tools // do. if (TgtM.getTargetTriple().isOSFreeBSD()) { PersonalityEncoding |= dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; } break; case Triple::ppc64: case Triple::ppc64le: PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8; LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8; TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8; break; case Triple::sparcel: case Triple::sparc: if (isPositionIndependent()) { LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; } else { LSDAEncoding = dwarf::DW_EH_PE_absptr; PersonalityEncoding = dwarf::DW_EH_PE_absptr; TTypeEncoding = dwarf::DW_EH_PE_absptr; } CallSiteEncoding = dwarf::DW_EH_PE_udata4; break; case Triple::riscv32: case Triple::riscv64: LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; CallSiteEncoding = dwarf::DW_EH_PE_udata4; break; case Triple::sparcv9: LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; if (isPositionIndependent()) { PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; } else { PersonalityEncoding = dwarf::DW_EH_PE_absptr; TTypeEncoding = dwarf::DW_EH_PE_absptr; } break; case Triple::systemz: // All currently-defined code models guarantee that 4-byte PC-relative // values will be in range. if (isPositionIndependent()) { PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; } else { PersonalityEncoding = dwarf::DW_EH_PE_absptr; LSDAEncoding = dwarf::DW_EH_PE_absptr; TTypeEncoding = dwarf::DW_EH_PE_absptr; } break; case Triple::loongarch32: case Triple::loongarch64: LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; break; default: break; } } void TargetLoweringObjectFileELF::getModuleMetadata(Module &M) { SmallVector Vec; collectUsedGlobalVariables(M, Vec, false); for (GlobalValue *GV : Vec) if (auto *GO = dyn_cast(GV)) Used.insert(GO); } void TargetLoweringObjectFileELF::emitModuleMetadata(MCStreamer &Streamer, Module &M) const { auto &C = getContext(); if (NamedMDNode *LinkerOptions = M.getNamedMetadata("llvm.linker.options")) { auto *S = C.getELFSection(".linker-options", ELF::SHT_LLVM_LINKER_OPTIONS, ELF::SHF_EXCLUDE); Streamer.switchSection(S); for (const auto *Operand : LinkerOptions->operands()) { if (cast(Operand)->getNumOperands() != 2) report_fatal_error("invalid llvm.linker.options"); for (const auto &Option : cast(Operand)->operands()) { Streamer.emitBytes(cast(Option)->getString()); Streamer.emitInt8(0); } } } if (NamedMDNode *DependentLibraries = M.getNamedMetadata("llvm.dependent-libraries")) { auto *S = C.getELFSection(".deplibs", ELF::SHT_LLVM_DEPENDENT_LIBRARIES, ELF::SHF_MERGE | ELF::SHF_STRINGS, 1); Streamer.switchSection(S); for (const auto *Operand : DependentLibraries->operands()) { Streamer.emitBytes( cast(cast(Operand)->getOperand(0))->getString()); Streamer.emitInt8(0); } } if (NamedMDNode *FuncInfo = M.getNamedMetadata(PseudoProbeDescMetadataName)) { // Emit a descriptor for every function including functions that have an // available external linkage. We may not want this for imported functions // that has code in another thinLTO module but we don't have a good way to // tell them apart from inline functions defined in header files. Therefore // we put each descriptor in a separate comdat section and rely on the // linker to deduplicate. for (const auto *Operand : FuncInfo->operands()) { const auto *MD = cast(Operand); auto *GUID = mdconst::dyn_extract(MD->getOperand(0)); auto *Hash = mdconst::dyn_extract(MD->getOperand(1)); auto *Name = cast(MD->getOperand(2)); auto *S = C.getObjectFileInfo()->getPseudoProbeDescSection( TM->getFunctionSections() ? Name->getString() : StringRef()); Streamer.switchSection(S); Streamer.emitInt64(GUID->getZExtValue()); Streamer.emitInt64(Hash->getZExtValue()); Streamer.emitULEB128IntValue(Name->getString().size()); Streamer.emitBytes(Name->getString()); } } if (NamedMDNode *LLVMStats = M.getNamedMetadata("llvm.stats")) { // Emit the metadata for llvm statistics into .llvm_stats section, which is // formatted as a list of key/value pair, the value is base64 encoded. auto *S = C.getObjectFileInfo()->getLLVMStatsSection(); Streamer.switchSection(S); for (const auto *Operand : LLVMStats->operands()) { const auto *MD = cast(Operand); assert(MD->getNumOperands() % 2 == 0 && ("Operand num should be even for a list of key/value pair")); for (size_t I = 0; I < MD->getNumOperands(); I += 2) { // Encode the key string size. auto *Key = cast(MD->getOperand(I)); Streamer.emitULEB128IntValue(Key->getString().size()); Streamer.emitBytes(Key->getString()); // Encode the value into a Base64 string. std::string Value = encodeBase64( Twine(mdconst::dyn_extract(MD->getOperand(I + 1)) ->getZExtValue()) .str()); Streamer.emitULEB128IntValue(Value.size()); Streamer.emitBytes(Value); } } } unsigned Version = 0; unsigned Flags = 0; StringRef Section; GetObjCImageInfo(M, Version, Flags, Section); if (!Section.empty()) { auto *S = C.getELFSection(Section, ELF::SHT_PROGBITS, ELF::SHF_ALLOC); Streamer.switchSection(S); Streamer.emitLabel(C.getOrCreateSymbol(StringRef("OBJC_IMAGE_INFO"))); Streamer.emitInt32(Version); Streamer.emitInt32(Flags); Streamer.addBlankLine(); } emitCGProfileMetadata(Streamer, M); } MCSymbol *TargetLoweringObjectFileELF::getCFIPersonalitySymbol( const GlobalValue *GV, const TargetMachine &TM, MachineModuleInfo *MMI) const { unsigned Encoding = getPersonalityEncoding(); if ((Encoding & 0x80) == DW_EH_PE_indirect) return getContext().getOrCreateSymbol(StringRef("DW.ref.") + TM.getSymbol(GV)->getName()); if ((Encoding & 0x70) == DW_EH_PE_absptr) return TM.getSymbol(GV); report_fatal_error("We do not support this DWARF encoding yet!"); } void TargetLoweringObjectFileELF::emitPersonalityValue( MCStreamer &Streamer, const DataLayout &DL, const MCSymbol *Sym) const { SmallString<64> NameData("DW.ref."); NameData += Sym->getName(); MCSymbolELF *Label = cast(getContext().getOrCreateSymbol(NameData)); Streamer.emitSymbolAttribute(Label, MCSA_Hidden); Streamer.emitSymbolAttribute(Label, MCSA_Weak); unsigned Flags = ELF::SHF_ALLOC | ELF::SHF_WRITE | ELF::SHF_GROUP; MCSection *Sec = getContext().getELFNamedSection(".data", Label->getName(), ELF::SHT_PROGBITS, Flags, 0); unsigned Size = DL.getPointerSize(); Streamer.switchSection(Sec); Streamer.emitValueToAlignment(DL.getPointerABIAlignment(0)); Streamer.emitSymbolAttribute(Label, MCSA_ELF_TypeObject); const MCExpr *E = MCConstantExpr::create(Size, getContext()); Streamer.emitELFSize(Label, E); Streamer.emitLabel(Label); Streamer.emitSymbolValue(Sym, Size); } const MCExpr *TargetLoweringObjectFileELF::getTTypeGlobalReference( const GlobalValue *GV, unsigned Encoding, const TargetMachine &TM, MachineModuleInfo *MMI, MCStreamer &Streamer) const { if (Encoding & DW_EH_PE_indirect) { MachineModuleInfoELF &ELFMMI = MMI->getObjFileInfo(); MCSymbol *SSym = getSymbolWithGlobalValueBase(GV, ".DW.stub", TM); // Add information about the stub reference to ELFMMI so that the stub // gets emitted by the asmprinter. MachineModuleInfoImpl::StubValueTy &StubSym = ELFMMI.getGVStubEntry(SSym); if (!StubSym.getPointer()) { MCSymbol *Sym = TM.getSymbol(GV); StubSym = MachineModuleInfoImpl::StubValueTy(Sym, !GV->hasLocalLinkage()); } return TargetLoweringObjectFile:: getTTypeReference(MCSymbolRefExpr::create(SSym, getContext()), Encoding & ~DW_EH_PE_indirect, Streamer); } return TargetLoweringObjectFile::getTTypeGlobalReference(GV, Encoding, TM, MMI, Streamer); } static SectionKind getELFKindForNamedSection(StringRef Name, SectionKind K) { // N.B.: The defaults used in here are not the same ones used in MC. // We follow gcc, MC follows gas. For example, given ".section .eh_frame", // both gas and MC will produce a section with no flags. Given // section(".eh_frame") gcc will produce: // // .section .eh_frame,"a",@progbits if (Name == getInstrProfSectionName(IPSK_covmap, Triple::ELF, /*AddSegmentInfo=*/false) || Name == getInstrProfSectionName(IPSK_covfun, Triple::ELF, /*AddSegmentInfo=*/false) || Name == ".llvmbc" || Name == ".llvmcmd") return SectionKind::getMetadata(); if (Name.empty() || Name[0] != '.') return K; // Default implementation based on some magic section names. if (Name == ".bss" || Name.startswith(".bss.") || Name.startswith(".gnu.linkonce.b.") || Name.startswith(".llvm.linkonce.b.") || Name == ".sbss" || Name.startswith(".sbss.") || Name.startswith(".gnu.linkonce.sb.") || Name.startswith(".llvm.linkonce.sb.")) return SectionKind::getBSS(); if (Name == ".tdata" || Name.startswith(".tdata.") || Name.startswith(".gnu.linkonce.td.") || Name.startswith(".llvm.linkonce.td.")) return SectionKind::getThreadData(); if (Name == ".tbss" || Name.startswith(".tbss.") || Name.startswith(".gnu.linkonce.tb.") || Name.startswith(".llvm.linkonce.tb.")) return SectionKind::getThreadBSS(); return K; } static bool hasPrefix(StringRef SectionName, StringRef Prefix) { return SectionName.consume_front(Prefix) && (SectionName.empty() || SectionName[0] == '.'); } static unsigned getELFSectionType(StringRef Name, SectionKind K) { // Use SHT_NOTE for section whose name starts with ".note" to allow // emitting ELF notes from C variable declaration. // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77609 if (Name.startswith(".note")) return ELF::SHT_NOTE; if (hasPrefix(Name, ".init_array")) return ELF::SHT_INIT_ARRAY; if (hasPrefix(Name, ".fini_array")) return ELF::SHT_FINI_ARRAY; if (hasPrefix(Name, ".preinit_array")) return ELF::SHT_PREINIT_ARRAY; if (hasPrefix(Name, ".llvm.offloading")) return ELF::SHT_LLVM_OFFLOADING; if (K.isBSS() || K.isThreadBSS()) return ELF::SHT_NOBITS; return ELF::SHT_PROGBITS; } static unsigned getELFSectionFlags(SectionKind K) { unsigned Flags = 0; if (!K.isMetadata() && !K.isExclude()) Flags |= ELF::SHF_ALLOC; if (K.isExclude()) Flags |= ELF::SHF_EXCLUDE; if (K.isText()) Flags |= ELF::SHF_EXECINSTR; if (K.isExecuteOnly()) Flags |= ELF::SHF_ARM_PURECODE; if (K.isWriteable()) Flags |= ELF::SHF_WRITE; if (K.isThreadLocal()) Flags |= ELF::SHF_TLS; if (K.isMergeableCString() || K.isMergeableConst()) Flags |= ELF::SHF_MERGE; if (K.isMergeableCString()) Flags |= ELF::SHF_STRINGS; return Flags; } static const Comdat *getELFComdat(const GlobalValue *GV) { const Comdat *C = GV->getComdat(); if (!C) return nullptr; if (C->getSelectionKind() != Comdat::Any && C->getSelectionKind() != Comdat::NoDeduplicate) report_fatal_error("ELF COMDATs only support SelectionKind::Any and " "SelectionKind::NoDeduplicate, '" + C->getName() + "' cannot be lowered."); return C; } static const MCSymbolELF *getLinkedToSymbol(const GlobalObject *GO, const TargetMachine &TM) { MDNode *MD = GO->getMetadata(LLVMContext::MD_associated); if (!MD) return nullptr; auto *VM = cast(MD->getOperand(0).get()); auto *OtherGV = dyn_cast(VM->getValue()); return OtherGV ? dyn_cast(TM.getSymbol(OtherGV)) : nullptr; } static unsigned getEntrySizeForKind(SectionKind Kind) { if (Kind.isMergeable1ByteCString()) return 1; else if (Kind.isMergeable2ByteCString()) return 2; else if (Kind.isMergeable4ByteCString()) return 4; else if (Kind.isMergeableConst4()) return 4; else if (Kind.isMergeableConst8()) return 8; else if (Kind.isMergeableConst16()) return 16; else if (Kind.isMergeableConst32()) return 32; else { // We shouldn't have mergeable C strings or mergeable constants that we // didn't handle above. assert(!Kind.isMergeableCString() && "unknown string width"); assert(!Kind.isMergeableConst() && "unknown data width"); return 0; } } /// Return the section prefix name used by options FunctionsSections and /// DataSections. static StringRef getSectionPrefixForGlobal(SectionKind Kind, bool IsLarge) { if (Kind.isText()) return ".text"; if (Kind.isReadOnly()) return IsLarge ? ".lrodata" : ".rodata"; if (Kind.isBSS()) return IsLarge ? ".lbss" : ".bss"; if (Kind.isThreadData()) return ".tdata"; if (Kind.isThreadBSS()) return ".tbss"; if (Kind.isData()) return IsLarge ? ".ldata" : ".data"; if (Kind.isReadOnlyWithRel()) return IsLarge ? ".ldata.rel.ro" : ".data.rel.ro"; llvm_unreachable("Unknown section kind"); } static SmallString<128> getELFSectionNameForGlobal(const GlobalObject *GO, SectionKind Kind, Mangler &Mang, const TargetMachine &TM, unsigned EntrySize, bool UniqueSectionName) { SmallString<128> Name; if (Kind.isMergeableCString()) { // We also need alignment here. // FIXME: this is getting the alignment of the character, not the // alignment of the global! Align Alignment = GO->getParent()->getDataLayout().getPreferredAlign( cast(GO)); std::string SizeSpec = ".rodata.str" + utostr(EntrySize) + "."; Name = SizeSpec + utostr(Alignment.value()); } else if (Kind.isMergeableConst()) { Name = ".rodata.cst"; Name += utostr(EntrySize); } else { bool IsLarge = false; if (isa(GO)) IsLarge = TM.isLargeData(); Name = getSectionPrefixForGlobal(Kind, IsLarge); } bool HasPrefix = false; if (const auto *F = dyn_cast(GO)) { if (std::optional Prefix = F->getSectionPrefix()) { raw_svector_ostream(Name) << '.' << *Prefix; HasPrefix = true; } } if (UniqueSectionName) { Name.push_back('.'); TM.getNameWithPrefix(Name, GO, Mang, /*MayAlwaysUsePrivate*/true); } else if (HasPrefix) // For distinguishing between .text.${text-section-prefix}. (with trailing // dot) and .text.${function-name} Name.push_back('.'); return Name; } namespace { class LoweringDiagnosticInfo : public DiagnosticInfo { const Twine &Msg; public: LoweringDiagnosticInfo(const Twine &DiagMsg, DiagnosticSeverity Severity = DS_Error) : DiagnosticInfo(DK_Lowering, Severity), Msg(DiagMsg) {} void print(DiagnosticPrinter &DP) const override { DP << Msg; } }; } /// Calculate an appropriate unique ID for a section, and update Flags, /// EntrySize and NextUniqueID where appropriate. static unsigned calcUniqueIDUpdateFlagsAndSize(const GlobalObject *GO, StringRef SectionName, SectionKind Kind, const TargetMachine &TM, MCContext &Ctx, Mangler &Mang, unsigned &Flags, unsigned &EntrySize, unsigned &NextUniqueID, const bool Retain, const bool ForceUnique) { // Increment uniqueID if we are forced to emit a unique section. // This works perfectly fine with section attribute or pragma section as the // sections with the same name are grouped together by the assembler. if (ForceUnique) return NextUniqueID++; // A section can have at most one associated section. Put each global with // MD_associated in a unique section. const bool Associated = GO->getMetadata(LLVMContext::MD_associated); if (Associated) { Flags |= ELF::SHF_LINK_ORDER; return NextUniqueID++; } if (Retain) { if (TM.getTargetTriple().isOSSolaris()) Flags |= ELF::SHF_SUNW_NODISCARD; else if (Ctx.getAsmInfo()->useIntegratedAssembler() || Ctx.getAsmInfo()->binutilsIsAtLeast(2, 36)) Flags |= ELF::SHF_GNU_RETAIN; return NextUniqueID++; } // If two symbols with differing sizes end up in the same mergeable section // that section can be assigned an incorrect entry size. To avoid this we // usually put symbols of the same size into distinct mergeable sections with // the same name. Doing so relies on the ",unique ," assembly feature. This // feature is not avalible until bintuils version 2.35 // (https://sourceware.org/bugzilla/show_bug.cgi?id=25380). const bool SupportsUnique = Ctx.getAsmInfo()->useIntegratedAssembler() || Ctx.getAsmInfo()->binutilsIsAtLeast(2, 35); if (!SupportsUnique) { Flags &= ~ELF::SHF_MERGE; EntrySize = 0; return MCContext::GenericSectionID; } const bool SymbolMergeable = Flags & ELF::SHF_MERGE; const bool SeenSectionNameBefore = Ctx.isELFGenericMergeableSection(SectionName); // If this is the first ocurrence of this section name, treat it as the // generic section if (!SymbolMergeable && !SeenSectionNameBefore) return MCContext::GenericSectionID; // Symbols must be placed into sections with compatible entry sizes. Generate // unique sections for symbols that have not been assigned to compatible // sections. const auto PreviousID = Ctx.getELFUniqueIDForEntsize(SectionName, Flags, EntrySize); if (PreviousID) return *PreviousID; // If the user has specified the same section name as would be created // implicitly for this symbol e.g. .rodata.str1.1, then we don't need // to unique the section as the entry size for this symbol will be // compatible with implicitly created sections. SmallString<128> ImplicitSectionNameStem = getELFSectionNameForGlobal(GO, Kind, Mang, TM, EntrySize, false); if (SymbolMergeable && Ctx.isELFImplicitMergeableSectionNamePrefix(SectionName) && SectionName.startswith(ImplicitSectionNameStem)) return MCContext::GenericSectionID; // We have seen this section name before, but with different flags or entity // size. Create a new unique ID. return NextUniqueID++; } static MCSection *selectExplicitSectionGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM, MCContext &Ctx, Mangler &Mang, unsigned &NextUniqueID, bool Retain, bool ForceUnique) { StringRef SectionName = GO->getSection(); // Check if '#pragma clang section' name is applicable. // Note that pragma directive overrides -ffunction-section, -fdata-section // and so section name is exactly as user specified and not uniqued. const GlobalVariable *GV = dyn_cast(GO); if (GV && GV->hasImplicitSection()) { auto Attrs = GV->getAttributes(); if (Attrs.hasAttribute("bss-section") && Kind.isBSS()) { SectionName = Attrs.getAttribute("bss-section").getValueAsString(); } else if (Attrs.hasAttribute("rodata-section") && Kind.isReadOnly()) { SectionName = Attrs.getAttribute("rodata-section").getValueAsString(); } else if (Attrs.hasAttribute("relro-section") && Kind.isReadOnlyWithRel()) { SectionName = Attrs.getAttribute("relro-section").getValueAsString(); } else if (Attrs.hasAttribute("data-section") && Kind.isData()) { SectionName = Attrs.getAttribute("data-section").getValueAsString(); } } const Function *F = dyn_cast(GO); if (F && F->hasFnAttribute("implicit-section-name")) { SectionName = F->getFnAttribute("implicit-section-name").getValueAsString(); } // Infer section flags from the section name if we can. Kind = getELFKindForNamedSection(SectionName, Kind); StringRef Group = ""; bool IsComdat = false; unsigned Flags = getELFSectionFlags(Kind); if (const Comdat *C = getELFComdat(GO)) { Group = C->getName(); IsComdat = C->getSelectionKind() == Comdat::Any; Flags |= ELF::SHF_GROUP; } unsigned EntrySize = getEntrySizeForKind(Kind); const unsigned UniqueID = calcUniqueIDUpdateFlagsAndSize( GO, SectionName, Kind, TM, Ctx, Mang, Flags, EntrySize, NextUniqueID, Retain, ForceUnique); const MCSymbolELF *LinkedToSym = getLinkedToSymbol(GO, TM); MCSectionELF *Section = Ctx.getELFSection( SectionName, getELFSectionType(SectionName, Kind), Flags, EntrySize, Group, IsComdat, UniqueID, LinkedToSym); // Make sure that we did not get some other section with incompatible sh_link. // This should not be possible due to UniqueID code above. assert(Section->getLinkedToSymbol() == LinkedToSym && "Associated symbol mismatch between sections"); if (!(Ctx.getAsmInfo()->useIntegratedAssembler() || Ctx.getAsmInfo()->binutilsIsAtLeast(2, 35))) { // If we are using GNU as before 2.35, then this symbol might have // been placed in an incompatible mergeable section. Emit an error if this // is the case to avoid creating broken output. if ((Section->getFlags() & ELF::SHF_MERGE) && (Section->getEntrySize() != getEntrySizeForKind(Kind))) GO->getContext().diagnose(LoweringDiagnosticInfo( "Symbol '" + GO->getName() + "' from module '" + (GO->getParent() ? GO->getParent()->getSourceFileName() : "unknown") + "' required a section with entry-size=" + Twine(getEntrySizeForKind(Kind)) + " but was placed in section '" + SectionName + "' with entry-size=" + Twine(Section->getEntrySize()) + ": Explicit assignment by pragma or attribute of an incompatible " "symbol to this section?")); } return Section; } MCSection *TargetLoweringObjectFileELF::getExplicitSectionGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { return selectExplicitSectionGlobal(GO, Kind, TM, getContext(), getMangler(), NextUniqueID, Used.count(GO), /* ForceUnique = */false); } static MCSectionELF *selectELFSectionForGlobal( MCContext &Ctx, const GlobalObject *GO, SectionKind Kind, Mangler &Mang, const TargetMachine &TM, bool EmitUniqueSection, unsigned Flags, unsigned *NextUniqueID, const MCSymbolELF *AssociatedSymbol) { StringRef Group = ""; bool IsComdat = false; if (const Comdat *C = getELFComdat(GO)) { Flags |= ELF::SHF_GROUP; Group = C->getName(); IsComdat = C->getSelectionKind() == Comdat::Any; } - if (isa(GO)) { + if (isa(GO) && !cast(GO)->isThreadLocal()) { if (TM.isLargeData()) { assert(TM.getTargetTriple().getArch() == Triple::x86_64); Flags |= ELF::SHF_X86_64_LARGE; } } // Get the section entry size based on the kind. unsigned EntrySize = getEntrySizeForKind(Kind); bool UniqueSectionName = false; unsigned UniqueID = MCContext::GenericSectionID; if (EmitUniqueSection) { if (TM.getUniqueSectionNames()) { UniqueSectionName = true; } else { UniqueID = *NextUniqueID; (*NextUniqueID)++; } } SmallString<128> Name = getELFSectionNameForGlobal( GO, Kind, Mang, TM, EntrySize, UniqueSectionName); // Use 0 as the unique ID for execute-only text. if (Kind.isExecuteOnly()) UniqueID = 0; return Ctx.getELFSection(Name, getELFSectionType(Name, Kind), Flags, EntrySize, Group, IsComdat, UniqueID, AssociatedSymbol); } static MCSection *selectELFSectionForGlobal( MCContext &Ctx, const GlobalObject *GO, SectionKind Kind, Mangler &Mang, const TargetMachine &TM, bool Retain, bool EmitUniqueSection, unsigned Flags, unsigned *NextUniqueID) { const MCSymbolELF *LinkedToSym = getLinkedToSymbol(GO, TM); if (LinkedToSym) { EmitUniqueSection = true; Flags |= ELF::SHF_LINK_ORDER; } if (Retain) { if (TM.getTargetTriple().isOSSolaris()) { EmitUniqueSection = true; Flags |= ELF::SHF_SUNW_NODISCARD; } else if (Ctx.getAsmInfo()->useIntegratedAssembler() || Ctx.getAsmInfo()->binutilsIsAtLeast(2, 36)) { EmitUniqueSection = true; Flags |= ELF::SHF_GNU_RETAIN; } } MCSectionELF *Section = selectELFSectionForGlobal( Ctx, GO, Kind, Mang, TM, EmitUniqueSection, Flags, NextUniqueID, LinkedToSym); assert(Section->getLinkedToSymbol() == LinkedToSym); return Section; } MCSection *TargetLoweringObjectFileELF::SelectSectionForGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { unsigned Flags = getELFSectionFlags(Kind); // If we have -ffunction-section or -fdata-section then we should emit the // global value to a uniqued section specifically for it. bool EmitUniqueSection = false; if (!(Flags & ELF::SHF_MERGE) && !Kind.isCommon()) { if (Kind.isText()) EmitUniqueSection = TM.getFunctionSections(); else EmitUniqueSection = TM.getDataSections(); } EmitUniqueSection |= GO->hasComdat(); return selectELFSectionForGlobal(getContext(), GO, Kind, getMangler(), TM, Used.count(GO), EmitUniqueSection, Flags, &NextUniqueID); } MCSection *TargetLoweringObjectFileELF::getUniqueSectionForFunction( const Function &F, const TargetMachine &TM) const { SectionKind Kind = SectionKind::getText(); unsigned Flags = getELFSectionFlags(Kind); // If the function's section names is pre-determined via pragma or a // section attribute, call selectExplicitSectionGlobal. if (F.hasSection() || F.hasFnAttribute("implicit-section-name")) return selectExplicitSectionGlobal( &F, Kind, TM, getContext(), getMangler(), NextUniqueID, Used.count(&F), /* ForceUnique = */true); else return selectELFSectionForGlobal( getContext(), &F, Kind, getMangler(), TM, Used.count(&F), /*EmitUniqueSection=*/true, Flags, &NextUniqueID); } MCSection *TargetLoweringObjectFileELF::getSectionForJumpTable( const Function &F, const TargetMachine &TM) const { // If the function can be removed, produce a unique section so that // the table doesn't prevent the removal. const Comdat *C = F.getComdat(); bool EmitUniqueSection = TM.getFunctionSections() || C; if (!EmitUniqueSection) return ReadOnlySection; return selectELFSectionForGlobal(getContext(), &F, SectionKind::getReadOnly(), getMangler(), TM, EmitUniqueSection, ELF::SHF_ALLOC, &NextUniqueID, /* AssociatedSymbol */ nullptr); } MCSection *TargetLoweringObjectFileELF::getSectionForLSDA( const Function &F, const MCSymbol &FnSym, const TargetMachine &TM) const { // If neither COMDAT nor function sections, use the monolithic LSDA section. // Re-use this path if LSDASection is null as in the Arm EHABI. if (!LSDASection || (!F.hasComdat() && !TM.getFunctionSections())) return LSDASection; const auto *LSDA = cast(LSDASection); unsigned Flags = LSDA->getFlags(); const MCSymbolELF *LinkedToSym = nullptr; StringRef Group; bool IsComdat = false; if (const Comdat *C = getELFComdat(&F)) { Flags |= ELF::SHF_GROUP; Group = C->getName(); IsComdat = C->getSelectionKind() == Comdat::Any; } // Use SHF_LINK_ORDER to facilitate --gc-sections if we can use GNU ld>=2.36 // or LLD, which support mixed SHF_LINK_ORDER & non-SHF_LINK_ORDER. if (TM.getFunctionSections() && (getContext().getAsmInfo()->useIntegratedAssembler() && getContext().getAsmInfo()->binutilsIsAtLeast(2, 36))) { Flags |= ELF::SHF_LINK_ORDER; LinkedToSym = cast(&FnSym); } // Append the function name as the suffix like GCC, assuming // -funique-section-names applies to .gcc_except_table sections. return getContext().getELFSection( (TM.getUniqueSectionNames() ? LSDA->getName() + "." + F.getName() : LSDA->getName()), LSDA->getType(), Flags, 0, Group, IsComdat, MCSection::NonUniqueID, LinkedToSym); } bool TargetLoweringObjectFileELF::shouldPutJumpTableInFunctionSection( bool UsesLabelDifference, const Function &F) const { // We can always create relative relocations, so use another section // that can be marked non-executable. return false; } /// Given a mergeable constant with the specified size and relocation /// information, return a section that it should be placed in. MCSection *TargetLoweringObjectFileELF::getSectionForConstant( const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment) const { if (Kind.isMergeableConst4() && MergeableConst4Section) return MergeableConst4Section; if (Kind.isMergeableConst8() && MergeableConst8Section) return MergeableConst8Section; if (Kind.isMergeableConst16() && MergeableConst16Section) return MergeableConst16Section; if (Kind.isMergeableConst32() && MergeableConst32Section) return MergeableConst32Section; if (Kind.isReadOnly()) return ReadOnlySection; assert(Kind.isReadOnlyWithRel() && "Unknown section kind"); return DataRelROSection; } /// Returns a unique section for the given machine basic block. MCSection *TargetLoweringObjectFileELF::getSectionForMachineBasicBlock( const Function &F, const MachineBasicBlock &MBB, const TargetMachine &TM) const { assert(MBB.isBeginSection() && "Basic block does not start a section!"); unsigned UniqueID = MCContext::GenericSectionID; // For cold sections use the .text.split. prefix along with the parent // function name. All cold blocks for the same function go to the same // section. Similarly all exception blocks are grouped by symbol name // under the .text.eh prefix. For regular sections, we either use a unique // name, or a unique ID for the section. SmallString<128> Name; if (MBB.getSectionID() == MBBSectionID::ColdSectionID) { Name += BBSectionsColdTextPrefix; Name += MBB.getParent()->getName(); } else if (MBB.getSectionID() == MBBSectionID::ExceptionSectionID) { Name += ".text.eh."; Name += MBB.getParent()->getName(); } else { Name += MBB.getParent()->getSection()->getName(); if (TM.getUniqueBasicBlockSectionNames()) { if (!Name.endswith(".")) Name += "."; Name += MBB.getSymbol()->getName(); } else { UniqueID = NextUniqueID++; } } unsigned Flags = ELF::SHF_ALLOC | ELF::SHF_EXECINSTR; std::string GroupName; if (F.hasComdat()) { Flags |= ELF::SHF_GROUP; GroupName = F.getComdat()->getName().str(); } return getContext().getELFSection(Name, ELF::SHT_PROGBITS, Flags, 0 /* Entry Size */, GroupName, F.hasComdat(), UniqueID, nullptr); } static MCSectionELF *getStaticStructorSection(MCContext &Ctx, bool UseInitArray, bool IsCtor, unsigned Priority, const MCSymbol *KeySym) { std::string Name; unsigned Type; unsigned Flags = ELF::SHF_ALLOC | ELF::SHF_WRITE; StringRef Comdat = KeySym ? KeySym->getName() : ""; if (KeySym) Flags |= ELF::SHF_GROUP; if (UseInitArray) { if (IsCtor) { Type = ELF::SHT_INIT_ARRAY; Name = ".init_array"; } else { Type = ELF::SHT_FINI_ARRAY; Name = ".fini_array"; } if (Priority != 65535) { Name += '.'; Name += utostr(Priority); } } else { // The default scheme is .ctor / .dtor, so we have to invert the priority // numbering. if (IsCtor) Name = ".ctors"; else Name = ".dtors"; if (Priority != 65535) raw_string_ostream(Name) << format(".%05u", 65535 - Priority); Type = ELF::SHT_PROGBITS; } return Ctx.getELFSection(Name, Type, Flags, 0, Comdat, /*IsComdat=*/true); } MCSection *TargetLoweringObjectFileELF::getStaticCtorSection( unsigned Priority, const MCSymbol *KeySym) const { return getStaticStructorSection(getContext(), UseInitArray, true, Priority, KeySym); } MCSection *TargetLoweringObjectFileELF::getStaticDtorSection( unsigned Priority, const MCSymbol *KeySym) const { return getStaticStructorSection(getContext(), UseInitArray, false, Priority, KeySym); } const MCExpr *TargetLoweringObjectFileELF::lowerRelativeReference( const GlobalValue *LHS, const GlobalValue *RHS, const TargetMachine &TM) const { // We may only use a PLT-relative relocation to refer to unnamed_addr // functions. if (!LHS->hasGlobalUnnamedAddr() || !LHS->getValueType()->isFunctionTy()) return nullptr; // Basic correctness checks. if (LHS->getType()->getPointerAddressSpace() != 0 || RHS->getType()->getPointerAddressSpace() != 0 || LHS->isThreadLocal() || RHS->isThreadLocal()) return nullptr; return MCBinaryExpr::createSub( MCSymbolRefExpr::create(TM.getSymbol(LHS), PLTRelativeVariantKind, getContext()), MCSymbolRefExpr::create(TM.getSymbol(RHS), getContext()), getContext()); } const MCExpr *TargetLoweringObjectFileELF::lowerDSOLocalEquivalent( const DSOLocalEquivalent *Equiv, const TargetMachine &TM) const { assert(supportDSOLocalEquivalentLowering()); const auto *GV = Equiv->getGlobalValue(); // A PLT entry is not needed for dso_local globals. if (GV->isDSOLocal() || GV->isImplicitDSOLocal()) return MCSymbolRefExpr::create(TM.getSymbol(GV), getContext()); return MCSymbolRefExpr::create(TM.getSymbol(GV), PLTRelativeVariantKind, getContext()); } MCSection *TargetLoweringObjectFileELF::getSectionForCommandLines() const { // Use ".GCC.command.line" since this feature is to support clang's // -frecord-gcc-switches which in turn attempts to mimic GCC's switch of the // same name. return getContext().getELFSection(".GCC.command.line", ELF::SHT_PROGBITS, ELF::SHF_MERGE | ELF::SHF_STRINGS, 1); } void TargetLoweringObjectFileELF::InitializeELF(bool UseInitArray_) { UseInitArray = UseInitArray_; MCContext &Ctx = getContext(); if (!UseInitArray) { StaticCtorSection = Ctx.getELFSection(".ctors", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_WRITE); StaticDtorSection = Ctx.getELFSection(".dtors", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_WRITE); return; } StaticCtorSection = Ctx.getELFSection(".init_array", ELF::SHT_INIT_ARRAY, ELF::SHF_WRITE | ELF::SHF_ALLOC); StaticDtorSection = Ctx.getELFSection(".fini_array", ELF::SHT_FINI_ARRAY, ELF::SHF_WRITE | ELF::SHF_ALLOC); } //===----------------------------------------------------------------------===// // MachO //===----------------------------------------------------------------------===// TargetLoweringObjectFileMachO::TargetLoweringObjectFileMachO() { SupportIndirectSymViaGOTPCRel = true; } void TargetLoweringObjectFileMachO::Initialize(MCContext &Ctx, const TargetMachine &TM) { TargetLoweringObjectFile::Initialize(Ctx, TM); if (TM.getRelocationModel() == Reloc::Static) { StaticCtorSection = Ctx.getMachOSection("__TEXT", "__constructor", 0, SectionKind::getData()); StaticDtorSection = Ctx.getMachOSection("__TEXT", "__destructor", 0, SectionKind::getData()); } else { StaticCtorSection = Ctx.getMachOSection("__DATA", "__mod_init_func", MachO::S_MOD_INIT_FUNC_POINTERS, SectionKind::getData()); StaticDtorSection = Ctx.getMachOSection("__DATA", "__mod_term_func", MachO::S_MOD_TERM_FUNC_POINTERS, SectionKind::getData()); } PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; LSDAEncoding = dwarf::DW_EH_PE_pcrel; TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; } MCSection *TargetLoweringObjectFileMachO::getStaticDtorSection( unsigned Priority, const MCSymbol *KeySym) const { return StaticDtorSection; // In userspace, we lower global destructors via atexit(), but kernel/kext // environments do not provide this function so we still need to support the // legacy way here. // See the -disable-atexit-based-global-dtor-lowering CodeGen flag for more // context. } void TargetLoweringObjectFileMachO::emitModuleMetadata(MCStreamer &Streamer, Module &M) const { // Emit the linker options if present. if (auto *LinkerOptions = M.getNamedMetadata("llvm.linker.options")) { for (const auto *Option : LinkerOptions->operands()) { SmallVector StrOptions; for (const auto &Piece : cast(Option)->operands()) StrOptions.push_back(std::string(cast(Piece)->getString())); Streamer.emitLinkerOptions(StrOptions); } } unsigned VersionVal = 0; unsigned ImageInfoFlags = 0; StringRef SectionVal; GetObjCImageInfo(M, VersionVal, ImageInfoFlags, SectionVal); emitCGProfileMetadata(Streamer, M); // The section is mandatory. If we don't have it, then we don't have GC info. if (SectionVal.empty()) return; StringRef Segment, Section; unsigned TAA = 0, StubSize = 0; bool TAAParsed; if (Error E = MCSectionMachO::ParseSectionSpecifier( SectionVal, Segment, Section, TAA, TAAParsed, StubSize)) { // If invalid, report the error with report_fatal_error. report_fatal_error("Invalid section specifier '" + Section + "': " + toString(std::move(E)) + "."); } // Get the section. MCSectionMachO *S = getContext().getMachOSection( Segment, Section, TAA, StubSize, SectionKind::getData()); Streamer.switchSection(S); Streamer.emitLabel(getContext(). getOrCreateSymbol(StringRef("L_OBJC_IMAGE_INFO"))); Streamer.emitInt32(VersionVal); Streamer.emitInt32(ImageInfoFlags); Streamer.addBlankLine(); } static void checkMachOComdat(const GlobalValue *GV) { const Comdat *C = GV->getComdat(); if (!C) return; report_fatal_error("MachO doesn't support COMDATs, '" + C->getName() + "' cannot be lowered."); } MCSection *TargetLoweringObjectFileMachO::getExplicitSectionGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { StringRef SectionName = GO->getSection(); const GlobalVariable *GV = dyn_cast(GO); if (GV && GV->hasImplicitSection()) { auto Attrs = GV->getAttributes(); if (Attrs.hasAttribute("bss-section") && Kind.isBSS()) { SectionName = Attrs.getAttribute("bss-section").getValueAsString(); } else if (Attrs.hasAttribute("rodata-section") && Kind.isReadOnly()) { SectionName = Attrs.getAttribute("rodata-section").getValueAsString(); } else if (Attrs.hasAttribute("relro-section") && Kind.isReadOnlyWithRel()) { SectionName = Attrs.getAttribute("relro-section").getValueAsString(); } else if (Attrs.hasAttribute("data-section") && Kind.isData()) { SectionName = Attrs.getAttribute("data-section").getValueAsString(); } } const Function *F = dyn_cast(GO); if (F && F->hasFnAttribute("implicit-section-name")) { SectionName = F->getFnAttribute("implicit-section-name").getValueAsString(); } // Parse the section specifier and create it if valid. StringRef Segment, Section; unsigned TAA = 0, StubSize = 0; bool TAAParsed; checkMachOComdat(GO); if (Error E = MCSectionMachO::ParseSectionSpecifier( SectionName, Segment, Section, TAA, TAAParsed, StubSize)) { // If invalid, report the error with report_fatal_error. report_fatal_error("Global variable '" + GO->getName() + "' has an invalid section specifier '" + GO->getSection() + "': " + toString(std::move(E)) + "."); } // Get the section. MCSectionMachO *S = getContext().getMachOSection(Segment, Section, TAA, StubSize, Kind); // If TAA wasn't set by ParseSectionSpecifier() above, // use the value returned by getMachOSection() as a default. if (!TAAParsed) TAA = S->getTypeAndAttributes(); // Okay, now that we got the section, verify that the TAA & StubSize agree. // If the user declared multiple globals with different section flags, we need // to reject it here. if (S->getTypeAndAttributes() != TAA || S->getStubSize() != StubSize) { // If invalid, report the error with report_fatal_error. report_fatal_error("Global variable '" + GO->getName() + "' section type or attributes does not match previous" " section specifier"); } return S; } MCSection *TargetLoweringObjectFileMachO::SelectSectionForGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { checkMachOComdat(GO); // Handle thread local data. if (Kind.isThreadBSS()) return TLSBSSSection; if (Kind.isThreadData()) return TLSDataSection; if (Kind.isText()) return GO->isWeakForLinker() ? TextCoalSection : TextSection; // If this is weak/linkonce, put this in a coalescable section, either in text // or data depending on if it is writable. if (GO->isWeakForLinker()) { if (Kind.isReadOnly()) return ConstTextCoalSection; if (Kind.isReadOnlyWithRel()) return ConstDataCoalSection; return DataCoalSection; } // FIXME: Alignment check should be handled by section classifier. if (Kind.isMergeable1ByteCString() && GO->getParent()->getDataLayout().getPreferredAlign( cast(GO)) < Align(32)) return CStringSection; // Do not put 16-bit arrays in the UString section if they have an // externally visible label, this runs into issues with certain linker // versions. if (Kind.isMergeable2ByteCString() && !GO->hasExternalLinkage() && GO->getParent()->getDataLayout().getPreferredAlign( cast(GO)) < Align(32)) return UStringSection; // With MachO only variables whose corresponding symbol starts with 'l' or // 'L' can be merged, so we only try merging GVs with private linkage. if (GO->hasPrivateLinkage() && Kind.isMergeableConst()) { if (Kind.isMergeableConst4()) return FourByteConstantSection; if (Kind.isMergeableConst8()) return EightByteConstantSection; if (Kind.isMergeableConst16()) return SixteenByteConstantSection; } // Otherwise, if it is readonly, but not something we can specially optimize, // just drop it in .const. if (Kind.isReadOnly()) return ReadOnlySection; // If this is marked const, put it into a const section. But if the dynamic // linker needs to write to it, put it in the data segment. if (Kind.isReadOnlyWithRel()) return ConstDataSection; // Put zero initialized globals with strong external linkage in the // DATA, __common section with the .zerofill directive. if (Kind.isBSSExtern()) return DataCommonSection; // Put zero initialized globals with local linkage in __DATA,__bss directive // with the .zerofill directive (aka .lcomm). if (Kind.isBSSLocal()) return DataBSSSection; // Otherwise, just drop the variable in the normal data section. return DataSection; } MCSection *TargetLoweringObjectFileMachO::getSectionForConstant( const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment) const { // If this constant requires a relocation, we have to put it in the data // segment, not in the text segment. if (Kind.isData() || Kind.isReadOnlyWithRel()) return ConstDataSection; if (Kind.isMergeableConst4()) return FourByteConstantSection; if (Kind.isMergeableConst8()) return EightByteConstantSection; if (Kind.isMergeableConst16()) return SixteenByteConstantSection; return ReadOnlySection; // .const } MCSection *TargetLoweringObjectFileMachO::getSectionForCommandLines() const { return getContext().getMachOSection("__TEXT", "__command_line", 0, SectionKind::getReadOnly()); } const MCExpr *TargetLoweringObjectFileMachO::getTTypeGlobalReference( const GlobalValue *GV, unsigned Encoding, const TargetMachine &TM, MachineModuleInfo *MMI, MCStreamer &Streamer) const { // The mach-o version of this method defaults to returning a stub reference. if (Encoding & DW_EH_PE_indirect) { MachineModuleInfoMachO &MachOMMI = MMI->getObjFileInfo(); MCSymbol *SSym = getSymbolWithGlobalValueBase(GV, "$non_lazy_ptr", TM); // Add information about the stub reference to MachOMMI so that the stub // gets emitted by the asmprinter. MachineModuleInfoImpl::StubValueTy &StubSym = MachOMMI.getGVStubEntry(SSym); if (!StubSym.getPointer()) { MCSymbol *Sym = TM.getSymbol(GV); StubSym = MachineModuleInfoImpl::StubValueTy(Sym, !GV->hasLocalLinkage()); } return TargetLoweringObjectFile:: getTTypeReference(MCSymbolRefExpr::create(SSym, getContext()), Encoding & ~DW_EH_PE_indirect, Streamer); } return TargetLoweringObjectFile::getTTypeGlobalReference(GV, Encoding, TM, MMI, Streamer); } MCSymbol *TargetLoweringObjectFileMachO::getCFIPersonalitySymbol( const GlobalValue *GV, const TargetMachine &TM, MachineModuleInfo *MMI) const { // The mach-o version of this method defaults to returning a stub reference. MachineModuleInfoMachO &MachOMMI = MMI->getObjFileInfo(); MCSymbol *SSym = getSymbolWithGlobalValueBase(GV, "$non_lazy_ptr", TM); // Add information about the stub reference to MachOMMI so that the stub // gets emitted by the asmprinter. MachineModuleInfoImpl::StubValueTy &StubSym = MachOMMI.getGVStubEntry(SSym); if (!StubSym.getPointer()) { MCSymbol *Sym = TM.getSymbol(GV); StubSym = MachineModuleInfoImpl::StubValueTy(Sym, !GV->hasLocalLinkage()); } return SSym; } const MCExpr *TargetLoweringObjectFileMachO::getIndirectSymViaGOTPCRel( const GlobalValue *GV, const MCSymbol *Sym, const MCValue &MV, int64_t Offset, MachineModuleInfo *MMI, MCStreamer &Streamer) const { // Although MachO 32-bit targets do not explicitly have a GOTPCREL relocation // as 64-bit do, we replace the GOT equivalent by accessing the final symbol // through a non_lazy_ptr stub instead. One advantage is that it allows the // computation of deltas to final external symbols. Example: // // _extgotequiv: // .long _extfoo // // _delta: // .long _extgotequiv-_delta // // is transformed to: // // _delta: // .long L_extfoo$non_lazy_ptr-(_delta+0) // // .section __IMPORT,__pointers,non_lazy_symbol_pointers // L_extfoo$non_lazy_ptr: // .indirect_symbol _extfoo // .long 0 // // The indirect symbol table (and sections of non_lazy_symbol_pointers type) // may point to both local (same translation unit) and global (other // translation units) symbols. Example: // // .section __DATA,__pointers,non_lazy_symbol_pointers // L1: // .indirect_symbol _myGlobal // .long 0 // L2: // .indirect_symbol _myLocal // .long _myLocal // // If the symbol is local, instead of the symbol's index, the assembler // places the constant INDIRECT_SYMBOL_LOCAL into the indirect symbol table. // Then the linker will notice the constant in the table and will look at the // content of the symbol. MachineModuleInfoMachO &MachOMMI = MMI->getObjFileInfo(); MCContext &Ctx = getContext(); // The offset must consider the original displacement from the base symbol // since 32-bit targets don't have a GOTPCREL to fold the PC displacement. Offset = -MV.getConstant(); const MCSymbol *BaseSym = &MV.getSymB()->getSymbol(); // Access the final symbol via sym$non_lazy_ptr and generate the appropriated // non_lazy_ptr stubs. SmallString<128> Name; StringRef Suffix = "$non_lazy_ptr"; Name += MMI->getModule()->getDataLayout().getPrivateGlobalPrefix(); Name += Sym->getName(); Name += Suffix; MCSymbol *Stub = Ctx.getOrCreateSymbol(Name); MachineModuleInfoImpl::StubValueTy &StubSym = MachOMMI.getGVStubEntry(Stub); if (!StubSym.getPointer()) StubSym = MachineModuleInfoImpl::StubValueTy(const_cast(Sym), !GV->hasLocalLinkage()); const MCExpr *BSymExpr = MCSymbolRefExpr::create(BaseSym, MCSymbolRefExpr::VK_None, Ctx); const MCExpr *LHS = MCSymbolRefExpr::create(Stub, MCSymbolRefExpr::VK_None, Ctx); if (!Offset) return MCBinaryExpr::createSub(LHS, BSymExpr, Ctx); const MCExpr *RHS = MCBinaryExpr::createAdd(BSymExpr, MCConstantExpr::create(Offset, Ctx), Ctx); return MCBinaryExpr::createSub(LHS, RHS, Ctx); } static bool canUsePrivateLabel(const MCAsmInfo &AsmInfo, const MCSection &Section) { if (!AsmInfo.isSectionAtomizableBySymbols(Section)) return true; // FIXME: we should be able to use private labels for sections that can't be // dead-stripped (there's no issue with blocking atomization there), but `ld // -r` sometimes drops the no_dead_strip attribute from sections so for safety // we don't allow it. return false; } void TargetLoweringObjectFileMachO::getNameWithPrefix( SmallVectorImpl &OutName, const GlobalValue *GV, const TargetMachine &TM) const { bool CannotUsePrivateLabel = true; if (auto *GO = GV->getAliaseeObject()) { SectionKind GOKind = TargetLoweringObjectFile::getKindForGlobal(GO, TM); const MCSection *TheSection = SectionForGlobal(GO, GOKind, TM); CannotUsePrivateLabel = !canUsePrivateLabel(*TM.getMCAsmInfo(), *TheSection); } getMangler().getNameWithPrefix(OutName, GV, CannotUsePrivateLabel); } //===----------------------------------------------------------------------===// // COFF //===----------------------------------------------------------------------===// static unsigned getCOFFSectionFlags(SectionKind K, const TargetMachine &TM) { unsigned Flags = 0; bool isThumb = TM.getTargetTriple().getArch() == Triple::thumb; if (K.isMetadata()) Flags |= COFF::IMAGE_SCN_MEM_DISCARDABLE; else if (K.isExclude()) Flags |= COFF::IMAGE_SCN_LNK_REMOVE | COFF::IMAGE_SCN_MEM_DISCARDABLE; else if (K.isText()) Flags |= COFF::IMAGE_SCN_MEM_EXECUTE | COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_CNT_CODE | (isThumb ? COFF::IMAGE_SCN_MEM_16BIT : (COFF::SectionCharacteristics)0); else if (K.isBSS()) Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE; else if (K.isThreadLocal()) Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE; else if (K.isReadOnly() || K.isReadOnlyWithRel()) Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ; else if (K.isWriteable()) Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE; return Flags; } static const GlobalValue *getComdatGVForCOFF(const GlobalValue *GV) { const Comdat *C = GV->getComdat(); assert(C && "expected GV to have a Comdat!"); StringRef ComdatGVName = C->getName(); const GlobalValue *ComdatGV = GV->getParent()->getNamedValue(ComdatGVName); if (!ComdatGV) report_fatal_error("Associative COMDAT symbol '" + ComdatGVName + "' does not exist."); if (ComdatGV->getComdat() != C) report_fatal_error("Associative COMDAT symbol '" + ComdatGVName + "' is not a key for its COMDAT."); return ComdatGV; } static int getSelectionForCOFF(const GlobalValue *GV) { if (const Comdat *C = GV->getComdat()) { const GlobalValue *ComdatKey = getComdatGVForCOFF(GV); if (const auto *GA = dyn_cast(ComdatKey)) ComdatKey = GA->getAliaseeObject(); if (ComdatKey == GV) { switch (C->getSelectionKind()) { case Comdat::Any: return COFF::IMAGE_COMDAT_SELECT_ANY; case Comdat::ExactMatch: return COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH; case Comdat::Largest: return COFF::IMAGE_COMDAT_SELECT_LARGEST; case Comdat::NoDeduplicate: return COFF::IMAGE_COMDAT_SELECT_NODUPLICATES; case Comdat::SameSize: return COFF::IMAGE_COMDAT_SELECT_SAME_SIZE; } } else { return COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE; } } return 0; } MCSection *TargetLoweringObjectFileCOFF::getExplicitSectionGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { int Selection = 0; unsigned Characteristics = getCOFFSectionFlags(Kind, TM); StringRef Name = GO->getSection(); StringRef COMDATSymName = ""; if (GO->hasComdat()) { Selection = getSelectionForCOFF(GO); const GlobalValue *ComdatGV; if (Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) ComdatGV = getComdatGVForCOFF(GO); else ComdatGV = GO; if (!ComdatGV->hasPrivateLinkage()) { MCSymbol *Sym = TM.getSymbol(ComdatGV); COMDATSymName = Sym->getName(); Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT; } else { Selection = 0; } } return getContext().getCOFFSection(Name, Characteristics, Kind, COMDATSymName, Selection); } static StringRef getCOFFSectionNameForUniqueGlobal(SectionKind Kind) { if (Kind.isText()) return ".text"; if (Kind.isBSS()) return ".bss"; if (Kind.isThreadLocal()) return ".tls$"; if (Kind.isReadOnly() || Kind.isReadOnlyWithRel()) return ".rdata"; return ".data"; } MCSection *TargetLoweringObjectFileCOFF::SelectSectionForGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { // If we have -ffunction-sections then we should emit the global value to a // uniqued section specifically for it. bool EmitUniquedSection; if (Kind.isText()) EmitUniquedSection = TM.getFunctionSections(); else EmitUniquedSection = TM.getDataSections(); if ((EmitUniquedSection && !Kind.isCommon()) || GO->hasComdat()) { SmallString<256> Name = getCOFFSectionNameForUniqueGlobal(Kind); unsigned Characteristics = getCOFFSectionFlags(Kind, TM); Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT; int Selection = getSelectionForCOFF(GO); if (!Selection) Selection = COFF::IMAGE_COMDAT_SELECT_NODUPLICATES; const GlobalValue *ComdatGV; if (GO->hasComdat()) ComdatGV = getComdatGVForCOFF(GO); else ComdatGV = GO; unsigned UniqueID = MCContext::GenericSectionID; if (EmitUniquedSection) UniqueID = NextUniqueID++; if (!ComdatGV->hasPrivateLinkage()) { MCSymbol *Sym = TM.getSymbol(ComdatGV); StringRef COMDATSymName = Sym->getName(); if (const auto *F = dyn_cast(GO)) if (std::optional Prefix = F->getSectionPrefix()) raw_svector_ostream(Name) << '$' << *Prefix; // Append "$symbol" to the section name *before* IR-level mangling is // applied when targetting mingw. This is what GCC does, and the ld.bfd // COFF linker will not properly handle comdats otherwise. if (getContext().getTargetTriple().isWindowsGNUEnvironment()) raw_svector_ostream(Name) << '$' << ComdatGV->getName(); return getContext().getCOFFSection(Name, Characteristics, Kind, COMDATSymName, Selection, UniqueID); } else { SmallString<256> TmpData; getMangler().getNameWithPrefix(TmpData, GO, /*CannotUsePrivateLabel=*/true); return getContext().getCOFFSection(Name, Characteristics, Kind, TmpData, Selection, UniqueID); } } if (Kind.isText()) return TextSection; if (Kind.isThreadLocal()) return TLSDataSection; if (Kind.isReadOnly() || Kind.isReadOnlyWithRel()) return ReadOnlySection; // Note: we claim that common symbols are put in BSSSection, but they are // really emitted with the magic .comm directive, which creates a symbol table // entry but not a section. if (Kind.isBSS() || Kind.isCommon()) return BSSSection; return DataSection; } void TargetLoweringObjectFileCOFF::getNameWithPrefix( SmallVectorImpl &OutName, const GlobalValue *GV, const TargetMachine &TM) const { bool CannotUsePrivateLabel = false; if (GV->hasPrivateLinkage() && ((isa(GV) && TM.getFunctionSections()) || (isa(GV) && TM.getDataSections()))) CannotUsePrivateLabel = true; getMangler().getNameWithPrefix(OutName, GV, CannotUsePrivateLabel); } MCSection *TargetLoweringObjectFileCOFF::getSectionForJumpTable( const Function &F, const TargetMachine &TM) const { // If the function can be removed, produce a unique section so that // the table doesn't prevent the removal. const Comdat *C = F.getComdat(); bool EmitUniqueSection = TM.getFunctionSections() || C; if (!EmitUniqueSection) return ReadOnlySection; // FIXME: we should produce a symbol for F instead. if (F.hasPrivateLinkage()) return ReadOnlySection; MCSymbol *Sym = TM.getSymbol(&F); StringRef COMDATSymName = Sym->getName(); SectionKind Kind = SectionKind::getReadOnly(); StringRef SecName = getCOFFSectionNameForUniqueGlobal(Kind); unsigned Characteristics = getCOFFSectionFlags(Kind, TM); Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT; unsigned UniqueID = NextUniqueID++; return getContext().getCOFFSection( SecName, Characteristics, Kind, COMDATSymName, COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE, UniqueID); } bool TargetLoweringObjectFileCOFF::shouldPutJumpTableInFunctionSection( bool UsesLabelDifference, const Function &F) const { if (TM->getTargetTriple().getArch() == Triple::x86_64) { if (!JumpTableInFunctionSection) { // We can always create relative relocations, so use another section // that can be marked non-executable. return false; } } return TargetLoweringObjectFile::shouldPutJumpTableInFunctionSection( UsesLabelDifference, F); } void TargetLoweringObjectFileCOFF::emitModuleMetadata(MCStreamer &Streamer, Module &M) const { emitLinkerDirectives(Streamer, M); unsigned Version = 0; unsigned Flags = 0; StringRef Section; GetObjCImageInfo(M, Version, Flags, Section); if (!Section.empty()) { auto &C = getContext(); auto *S = C.getCOFFSection(Section, COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ, SectionKind::getReadOnly()); Streamer.switchSection(S); Streamer.emitLabel(C.getOrCreateSymbol(StringRef("OBJC_IMAGE_INFO"))); Streamer.emitInt32(Version); Streamer.emitInt32(Flags); Streamer.addBlankLine(); } emitCGProfileMetadata(Streamer, M); } void TargetLoweringObjectFileCOFF::emitLinkerDirectives( MCStreamer &Streamer, Module &M) const { if (NamedMDNode *LinkerOptions = M.getNamedMetadata("llvm.linker.options")) { // Emit the linker options to the linker .drectve section. According to the // spec, this section is a space-separated string containing flags for // linker. MCSection *Sec = getDrectveSection(); Streamer.switchSection(Sec); for (const auto *Option : LinkerOptions->operands()) { for (const auto &Piece : cast(Option)->operands()) { // Lead with a space for consistency with our dllexport implementation. std::string Directive(" "); Directive.append(std::string(cast(Piece)->getString())); Streamer.emitBytes(Directive); } } } // Emit /EXPORT: flags for each exported global as necessary. std::string Flags; for (const GlobalValue &GV : M.global_values()) { raw_string_ostream OS(Flags); emitLinkerFlagsForGlobalCOFF(OS, &GV, getContext().getTargetTriple(), getMangler()); OS.flush(); if (!Flags.empty()) { Streamer.switchSection(getDrectveSection()); Streamer.emitBytes(Flags); } Flags.clear(); } // Emit /INCLUDE: flags for each used global as necessary. if (const auto *LU = M.getNamedGlobal("llvm.used")) { assert(LU->hasInitializer() && "expected llvm.used to have an initializer"); assert(isa(LU->getValueType()) && "expected llvm.used to be an array type"); if (const auto *A = cast(LU->getInitializer())) { for (const Value *Op : A->operands()) { const auto *GV = cast(Op->stripPointerCasts()); // Global symbols with internal or private linkage are not visible to // the linker, and thus would cause an error when the linker tried to // preserve the symbol due to the `/include:` directive. if (GV->hasLocalLinkage()) continue; raw_string_ostream OS(Flags); emitLinkerFlagsForUsedCOFF(OS, GV, getContext().getTargetTriple(), getMangler()); OS.flush(); if (!Flags.empty()) { Streamer.switchSection(getDrectveSection()); Streamer.emitBytes(Flags); } Flags.clear(); } } } } void TargetLoweringObjectFileCOFF::Initialize(MCContext &Ctx, const TargetMachine &TM) { TargetLoweringObjectFile::Initialize(Ctx, TM); this->TM = &TM; const Triple &T = TM.getTargetTriple(); if (T.isWindowsMSVCEnvironment() || T.isWindowsItaniumEnvironment()) { StaticCtorSection = Ctx.getCOFFSection(".CRT$XCU", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ, SectionKind::getReadOnly()); StaticDtorSection = Ctx.getCOFFSection(".CRT$XTX", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ, SectionKind::getReadOnly()); } else { StaticCtorSection = Ctx.getCOFFSection( ".ctors", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE, SectionKind::getData()); StaticDtorSection = Ctx.getCOFFSection( ".dtors", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE, SectionKind::getData()); } } static MCSectionCOFF *getCOFFStaticStructorSection(MCContext &Ctx, const Triple &T, bool IsCtor, unsigned Priority, const MCSymbol *KeySym, MCSectionCOFF *Default) { if (T.isWindowsMSVCEnvironment() || T.isWindowsItaniumEnvironment()) { // If the priority is the default, use .CRT$XCU, possibly associative. if (Priority == 65535) return Ctx.getAssociativeCOFFSection(Default, KeySym, 0); // Otherwise, we need to compute a new section name. Low priorities should // run earlier. The linker will sort sections ASCII-betically, and we need a // string that sorts between .CRT$XCA and .CRT$XCU. In the general case, we // make a name like ".CRT$XCT12345", since that runs before .CRT$XCU. Really // low priorities need to sort before 'L', since the CRT uses that // internally, so we use ".CRT$XCA00001" for them. We have a contract with // the frontend that "init_seg(compiler)" corresponds to priority 200 and // "init_seg(lib)" corresponds to priority 400, and those respectively use // 'C' and 'L' without the priority suffix. Priorities between 200 and 400 // use 'C' with the priority as a suffix. SmallString<24> Name; char LastLetter = 'T'; bool AddPrioritySuffix = Priority != 200 && Priority != 400; if (Priority < 200) LastLetter = 'A'; else if (Priority < 400) LastLetter = 'C'; else if (Priority == 400) LastLetter = 'L'; raw_svector_ostream OS(Name); OS << ".CRT$X" << (IsCtor ? "C" : "T") << LastLetter; if (AddPrioritySuffix) OS << format("%05u", Priority); MCSectionCOFF *Sec = Ctx.getCOFFSection( Name, COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ, SectionKind::getReadOnly()); return Ctx.getAssociativeCOFFSection(Sec, KeySym, 0); } std::string Name = IsCtor ? ".ctors" : ".dtors"; if (Priority != 65535) raw_string_ostream(Name) << format(".%05u", 65535 - Priority); return Ctx.getAssociativeCOFFSection( Ctx.getCOFFSection(Name, COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE, SectionKind::getData()), KeySym, 0); } MCSection *TargetLoweringObjectFileCOFF::getStaticCtorSection( unsigned Priority, const MCSymbol *KeySym) const { return getCOFFStaticStructorSection( getContext(), getContext().getTargetTriple(), true, Priority, KeySym, cast(StaticCtorSection)); } MCSection *TargetLoweringObjectFileCOFF::getStaticDtorSection( unsigned Priority, const MCSymbol *KeySym) const { return getCOFFStaticStructorSection( getContext(), getContext().getTargetTriple(), false, Priority, KeySym, cast(StaticDtorSection)); } const MCExpr *TargetLoweringObjectFileCOFF::lowerRelativeReference( const GlobalValue *LHS, const GlobalValue *RHS, const TargetMachine &TM) const { const Triple &T = TM.getTargetTriple(); if (T.isOSCygMing()) return nullptr; // Our symbols should exist in address space zero, cowardly no-op if // otherwise. if (LHS->getType()->getPointerAddressSpace() != 0 || RHS->getType()->getPointerAddressSpace() != 0) return nullptr; // Both ptrtoint instructions must wrap global objects: // - Only global variables are eligible for image relative relocations. // - The subtrahend refers to the special symbol __ImageBase, a GlobalVariable. // We expect __ImageBase to be a global variable without a section, externally // defined. // // It should look something like this: @__ImageBase = external constant i8 if (!isa(LHS) || !isa(RHS) || LHS->isThreadLocal() || RHS->isThreadLocal() || RHS->getName() != "__ImageBase" || !RHS->hasExternalLinkage() || cast(RHS)->hasInitializer() || RHS->hasSection()) return nullptr; return MCSymbolRefExpr::create(TM.getSymbol(LHS), MCSymbolRefExpr::VK_COFF_IMGREL32, getContext()); } static std::string APIntToHexString(const APInt &AI) { unsigned Width = (AI.getBitWidth() / 8) * 2; std::string HexString = toString(AI, 16, /*Signed=*/false); llvm::transform(HexString, HexString.begin(), tolower); unsigned Size = HexString.size(); assert(Width >= Size && "hex string is too large!"); HexString.insert(HexString.begin(), Width - Size, '0'); return HexString; } static std::string scalarConstantToHexString(const Constant *C) { Type *Ty = C->getType(); if (isa(C)) { return APIntToHexString(APInt::getZero(Ty->getPrimitiveSizeInBits())); } else if (const auto *CFP = dyn_cast(C)) { return APIntToHexString(CFP->getValueAPF().bitcastToAPInt()); } else if (const auto *CI = dyn_cast(C)) { return APIntToHexString(CI->getValue()); } else { unsigned NumElements; if (auto *VTy = dyn_cast(Ty)) NumElements = cast(VTy)->getNumElements(); else NumElements = Ty->getArrayNumElements(); std::string HexString; for (int I = NumElements - 1, E = -1; I != E; --I) HexString += scalarConstantToHexString(C->getAggregateElement(I)); return HexString; } } MCSection *TargetLoweringObjectFileCOFF::getSectionForConstant( const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment) const { if (Kind.isMergeableConst() && C && getContext().getAsmInfo()->hasCOFFComdatConstants()) { // This creates comdat sections with the given symbol name, but unless // AsmPrinter::GetCPISymbol actually makes the symbol global, the symbol // will be created with a null storage class, which makes GNU binutils // error out. const unsigned Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_LNK_COMDAT; std::string COMDATSymName; if (Kind.isMergeableConst4()) { if (Alignment <= 4) { COMDATSymName = "__real@" + scalarConstantToHexString(C); Alignment = Align(4); } } else if (Kind.isMergeableConst8()) { if (Alignment <= 8) { COMDATSymName = "__real@" + scalarConstantToHexString(C); Alignment = Align(8); } } else if (Kind.isMergeableConst16()) { // FIXME: These may not be appropriate for non-x86 architectures. if (Alignment <= 16) { COMDATSymName = "__xmm@" + scalarConstantToHexString(C); Alignment = Align(16); } } else if (Kind.isMergeableConst32()) { if (Alignment <= 32) { COMDATSymName = "__ymm@" + scalarConstantToHexString(C); Alignment = Align(32); } } if (!COMDATSymName.empty()) return getContext().getCOFFSection(".rdata", Characteristics, Kind, COMDATSymName, COFF::IMAGE_COMDAT_SELECT_ANY); } return TargetLoweringObjectFile::getSectionForConstant(DL, Kind, C, Alignment); } //===----------------------------------------------------------------------===// // Wasm //===----------------------------------------------------------------------===// static const Comdat *getWasmComdat(const GlobalValue *GV) { const Comdat *C = GV->getComdat(); if (!C) return nullptr; if (C->getSelectionKind() != Comdat::Any) report_fatal_error("WebAssembly COMDATs only support " "SelectionKind::Any, '" + C->getName() + "' cannot be " "lowered."); return C; } static unsigned getWasmSectionFlags(SectionKind K) { unsigned Flags = 0; if (K.isThreadLocal()) Flags |= wasm::WASM_SEG_FLAG_TLS; if (K.isMergeableCString()) Flags |= wasm::WASM_SEG_FLAG_STRINGS; // TODO(sbc): Add suport for K.isMergeableConst() return Flags; } MCSection *TargetLoweringObjectFileWasm::getExplicitSectionGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { // We don't support explict section names for functions in the wasm object // format. Each function has to be in its own unique section. if (isa(GO)) { return SelectSectionForGlobal(GO, Kind, TM); } StringRef Name = GO->getSection(); // Certain data sections we treat as named custom sections rather than // segments within the data section. // This could be avoided if all data segements (the wasm sense) were // represented as their own sections (in the llvm sense). // TODO(sbc): https://github.com/WebAssembly/tool-conventions/issues/138 if (Name == ".llvmcmd" || Name == ".llvmbc") Kind = SectionKind::getMetadata(); StringRef Group = ""; if (const Comdat *C = getWasmComdat(GO)) { Group = C->getName(); } unsigned Flags = getWasmSectionFlags(Kind); MCSectionWasm *Section = getContext().getWasmSection( Name, Kind, Flags, Group, MCContext::GenericSectionID); return Section; } static MCSectionWasm *selectWasmSectionForGlobal( MCContext &Ctx, const GlobalObject *GO, SectionKind Kind, Mangler &Mang, const TargetMachine &TM, bool EmitUniqueSection, unsigned *NextUniqueID) { StringRef Group = ""; if (const Comdat *C = getWasmComdat(GO)) { Group = C->getName(); } bool UniqueSectionNames = TM.getUniqueSectionNames(); SmallString<128> Name = getSectionPrefixForGlobal(Kind, /*IsLarge=*/false); if (const auto *F = dyn_cast(GO)) { const auto &OptionalPrefix = F->getSectionPrefix(); if (OptionalPrefix) raw_svector_ostream(Name) << '.' << *OptionalPrefix; } if (EmitUniqueSection && UniqueSectionNames) { Name.push_back('.'); TM.getNameWithPrefix(Name, GO, Mang, true); } unsigned UniqueID = MCContext::GenericSectionID; if (EmitUniqueSection && !UniqueSectionNames) { UniqueID = *NextUniqueID; (*NextUniqueID)++; } unsigned Flags = getWasmSectionFlags(Kind); return Ctx.getWasmSection(Name, Kind, Flags, Group, UniqueID); } MCSection *TargetLoweringObjectFileWasm::SelectSectionForGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { if (Kind.isCommon()) report_fatal_error("mergable sections not supported yet on wasm"); // If we have -ffunction-section or -fdata-section then we should emit the // global value to a uniqued section specifically for it. bool EmitUniqueSection = false; if (Kind.isText()) EmitUniqueSection = TM.getFunctionSections(); else EmitUniqueSection = TM.getDataSections(); EmitUniqueSection |= GO->hasComdat(); return selectWasmSectionForGlobal(getContext(), GO, Kind, getMangler(), TM, EmitUniqueSection, &NextUniqueID); } bool TargetLoweringObjectFileWasm::shouldPutJumpTableInFunctionSection( bool UsesLabelDifference, const Function &F) const { // We can always create relative relocations, so use another section // that can be marked non-executable. return false; } const MCExpr *TargetLoweringObjectFileWasm::lowerRelativeReference( const GlobalValue *LHS, const GlobalValue *RHS, const TargetMachine &TM) const { // We may only use a PLT-relative relocation to refer to unnamed_addr // functions. if (!LHS->hasGlobalUnnamedAddr() || !LHS->getValueType()->isFunctionTy()) return nullptr; // Basic correctness checks. if (LHS->getType()->getPointerAddressSpace() != 0 || RHS->getType()->getPointerAddressSpace() != 0 || LHS->isThreadLocal() || RHS->isThreadLocal()) return nullptr; return MCBinaryExpr::createSub( MCSymbolRefExpr::create(TM.getSymbol(LHS), MCSymbolRefExpr::VK_None, getContext()), MCSymbolRefExpr::create(TM.getSymbol(RHS), getContext()), getContext()); } void TargetLoweringObjectFileWasm::InitializeWasm() { StaticCtorSection = getContext().getWasmSection(".init_array", SectionKind::getData()); // We don't use PersonalityEncoding and LSDAEncoding because we don't emit // .cfi directives. We use TTypeEncoding to encode typeinfo global variables. TTypeEncoding = dwarf::DW_EH_PE_absptr; } MCSection *TargetLoweringObjectFileWasm::getStaticCtorSection( unsigned Priority, const MCSymbol *KeySym) const { return Priority == UINT16_MAX ? StaticCtorSection : getContext().getWasmSection(".init_array." + utostr(Priority), SectionKind::getData()); } MCSection *TargetLoweringObjectFileWasm::getStaticDtorSection( unsigned Priority, const MCSymbol *KeySym) const { report_fatal_error("@llvm.global_dtors should have been lowered already"); } //===----------------------------------------------------------------------===// // XCOFF //===----------------------------------------------------------------------===// bool TargetLoweringObjectFileXCOFF::ShouldEmitEHBlock( const MachineFunction *MF) { if (!MF->getLandingPads().empty()) return true; const Function &F = MF->getFunction(); if (!F.hasPersonalityFn() || !F.needsUnwindTableEntry()) return false; const GlobalValue *Per = dyn_cast(F.getPersonalityFn()->stripPointerCasts()); assert(Per && "Personality routine is not a GlobalValue type."); if (isNoOpWithoutInvoke(classifyEHPersonality(Per))) return false; return true; } bool TargetLoweringObjectFileXCOFF::ShouldSetSSPCanaryBitInTB( const MachineFunction *MF) { const Function &F = MF->getFunction(); if (!F.hasStackProtectorFnAttr()) return false; // FIXME: check presence of canary word // There are cases that the stack protectors are not really inserted even if // the attributes are on. return true; } MCSymbol * TargetLoweringObjectFileXCOFF::getEHInfoTableSymbol(const MachineFunction *MF) { return MF->getMMI().getContext().getOrCreateSymbol( "__ehinfo." + Twine(MF->getFunctionNumber())); } MCSymbol * TargetLoweringObjectFileXCOFF::getTargetSymbol(const GlobalValue *GV, const TargetMachine &TM) const { // We always use a qualname symbol for a GV that represents // a declaration, a function descriptor, or a common symbol. // If a GV represents a GlobalVariable and -fdata-sections is enabled, we // also return a qualname so that a label symbol could be avoided. // It is inherently ambiguous when the GO represents the address of a // function, as the GO could either represent a function descriptor or a // function entry point. We choose to always return a function descriptor // here. if (const GlobalObject *GO = dyn_cast(GV)) { if (GO->isDeclarationForLinker()) return cast(getSectionForExternalReference(GO, TM)) ->getQualNameSymbol(); if (const GlobalVariable *GVar = dyn_cast(GV)) if (GVar->hasAttribute("toc-data")) return cast( SectionForGlobal(GVar, SectionKind::getData(), TM)) ->getQualNameSymbol(); SectionKind GOKind = getKindForGlobal(GO, TM); if (GOKind.isText()) return cast( getSectionForFunctionDescriptor(cast(GO), TM)) ->getQualNameSymbol(); if ((TM.getDataSections() && !GO->hasSection()) || GO->hasCommonLinkage() || GOKind.isBSSLocal() || GOKind.isThreadBSSLocal()) return cast(SectionForGlobal(GO, GOKind, TM)) ->getQualNameSymbol(); } // For all other cases, fall back to getSymbol to return the unqualified name. return nullptr; } MCSection *TargetLoweringObjectFileXCOFF::getExplicitSectionGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { if (!GO->hasSection()) report_fatal_error("#pragma clang section is not yet supported"); StringRef SectionName = GO->getSection(); // Handle the XCOFF::TD case first, then deal with the rest. if (const GlobalVariable *GVar = dyn_cast(GO)) if (GVar->hasAttribute("toc-data")) return getContext().getXCOFFSection( SectionName, Kind, XCOFF::CsectProperties(/*MappingClass*/ XCOFF::XMC_TD, XCOFF::XTY_SD), /* MultiSymbolsAllowed*/ true); XCOFF::StorageMappingClass MappingClass; if (Kind.isText()) MappingClass = XCOFF::XMC_PR; else if (Kind.isData() || Kind.isBSS()) MappingClass = XCOFF::XMC_RW; else if (Kind.isReadOnlyWithRel()) MappingClass = TM.Options.XCOFFReadOnlyPointers ? XCOFF::XMC_RO : XCOFF::XMC_RW; else if (Kind.isReadOnly()) MappingClass = XCOFF::XMC_RO; else report_fatal_error("XCOFF other section types not yet implemented."); return getContext().getXCOFFSection( SectionName, Kind, XCOFF::CsectProperties(MappingClass, XCOFF::XTY_SD), /* MultiSymbolsAllowed*/ true); } MCSection *TargetLoweringObjectFileXCOFF::getSectionForExternalReference( const GlobalObject *GO, const TargetMachine &TM) const { assert(GO->isDeclarationForLinker() && "Tried to get ER section for a defined global."); SmallString<128> Name; getNameWithPrefix(Name, GO, TM); XCOFF::StorageMappingClass SMC = isa(GO) ? XCOFF::XMC_DS : XCOFF::XMC_UA; if (GO->isThreadLocal()) SMC = XCOFF::XMC_UL; if (const GlobalVariable *GVar = dyn_cast(GO)) if (GVar->hasAttribute("toc-data")) SMC = XCOFF::XMC_TD; // Externals go into a csect of type ER. return getContext().getXCOFFSection( Name, SectionKind::getMetadata(), XCOFF::CsectProperties(SMC, XCOFF::XTY_ER)); } MCSection *TargetLoweringObjectFileXCOFF::SelectSectionForGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { // Handle the XCOFF::TD case first, then deal with the rest. if (const GlobalVariable *GVar = dyn_cast(GO)) if (GVar->hasAttribute("toc-data")) { SmallString<128> Name; getNameWithPrefix(Name, GO, TM); return getContext().getXCOFFSection( Name, Kind, XCOFF::CsectProperties(XCOFF::XMC_TD, XCOFF::XTY_SD), /* MultiSymbolsAllowed*/ true); } // Common symbols go into a csect with matching name which will get mapped // into the .bss section. // Zero-initialized local TLS symbols go into a csect with matching name which // will get mapped into the .tbss section. if (Kind.isBSSLocal() || GO->hasCommonLinkage() || Kind.isThreadBSSLocal()) { SmallString<128> Name; getNameWithPrefix(Name, GO, TM); XCOFF::StorageMappingClass SMC = Kind.isBSSLocal() ? XCOFF::XMC_BS : Kind.isCommon() ? XCOFF::XMC_RW : XCOFF::XMC_UL; return getContext().getXCOFFSection( Name, Kind, XCOFF::CsectProperties(SMC, XCOFF::XTY_CM)); } if (Kind.isText()) { if (TM.getFunctionSections()) { return cast(getFunctionEntryPointSymbol(GO, TM)) ->getRepresentedCsect(); } return TextSection; } if (TM.Options.XCOFFReadOnlyPointers && Kind.isReadOnlyWithRel()) { if (!TM.getDataSections()) report_fatal_error( "ReadOnlyPointers is supported only if data sections is turned on"); SmallString<128> Name; getNameWithPrefix(Name, GO, TM); return getContext().getXCOFFSection( Name, SectionKind::getReadOnly(), XCOFF::CsectProperties(XCOFF::XMC_RO, XCOFF::XTY_SD)); } // For BSS kind, zero initialized data must be emitted to the .data section // because external linkage control sections that get mapped to the .bss // section will be linked as tentative defintions, which is only appropriate // for SectionKind::Common. if (Kind.isData() || Kind.isReadOnlyWithRel() || Kind.isBSS()) { if (TM.getDataSections()) { SmallString<128> Name; getNameWithPrefix(Name, GO, TM); return getContext().getXCOFFSection( Name, SectionKind::getData(), XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD)); } return DataSection; } if (Kind.isReadOnly()) { if (TM.getDataSections()) { SmallString<128> Name; getNameWithPrefix(Name, GO, TM); return getContext().getXCOFFSection( Name, SectionKind::getReadOnly(), XCOFF::CsectProperties(XCOFF::XMC_RO, XCOFF::XTY_SD)); } return ReadOnlySection; } // External/weak TLS data and initialized local TLS data are not eligible // to be put into common csect. If data sections are enabled, thread // data are emitted into separate sections. Otherwise, thread data // are emitted into the .tdata section. if (Kind.isThreadLocal()) { if (TM.getDataSections()) { SmallString<128> Name; getNameWithPrefix(Name, GO, TM); return getContext().getXCOFFSection( Name, Kind, XCOFF::CsectProperties(XCOFF::XMC_TL, XCOFF::XTY_SD)); } return TLSDataSection; } report_fatal_error("XCOFF other section types not yet implemented."); } MCSection *TargetLoweringObjectFileXCOFF::getSectionForJumpTable( const Function &F, const TargetMachine &TM) const { assert (!F.getComdat() && "Comdat not supported on XCOFF."); if (!TM.getFunctionSections()) return ReadOnlySection; // If the function can be removed, produce a unique section so that // the table doesn't prevent the removal. SmallString<128> NameStr(".rodata.jmp.."); getNameWithPrefix(NameStr, &F, TM); return getContext().getXCOFFSection( NameStr, SectionKind::getReadOnly(), XCOFF::CsectProperties(XCOFF::XMC_RO, XCOFF::XTY_SD)); } bool TargetLoweringObjectFileXCOFF::shouldPutJumpTableInFunctionSection( bool UsesLabelDifference, const Function &F) const { return false; } /// Given a mergeable constant with the specified size and relocation /// information, return a section that it should be placed in. MCSection *TargetLoweringObjectFileXCOFF::getSectionForConstant( const DataLayout &DL, SectionKind Kind, const Constant *C, Align &Alignment) const { // TODO: Enable emiting constant pool to unique sections when we support it. if (Alignment > Align(16)) report_fatal_error("Alignments greater than 16 not yet supported."); if (Alignment == Align(8)) { assert(ReadOnly8Section && "Section should always be initialized."); return ReadOnly8Section; } if (Alignment == Align(16)) { assert(ReadOnly16Section && "Section should always be initialized."); return ReadOnly16Section; } return ReadOnlySection; } void TargetLoweringObjectFileXCOFF::Initialize(MCContext &Ctx, const TargetMachine &TgtM) { TargetLoweringObjectFile::Initialize(Ctx, TgtM); TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_datarel | (TgtM.getTargetTriple().isArch32Bit() ? dwarf::DW_EH_PE_sdata4 : dwarf::DW_EH_PE_sdata8); PersonalityEncoding = 0; LSDAEncoding = 0; CallSiteEncoding = dwarf::DW_EH_PE_udata4; // AIX debug for thread local location is not ready. And for integrated as // mode, the relocatable address for the thread local variable will cause // linker error. So disable the location attribute generation for thread local // variables for now. // FIXME: when TLS debug on AIX is ready, remove this setting. SupportDebugThreadLocalLocation = false; } MCSection *TargetLoweringObjectFileXCOFF::getStaticCtorSection( unsigned Priority, const MCSymbol *KeySym) const { report_fatal_error("no static constructor section on AIX"); } MCSection *TargetLoweringObjectFileXCOFF::getStaticDtorSection( unsigned Priority, const MCSymbol *KeySym) const { report_fatal_error("no static destructor section on AIX"); } const MCExpr *TargetLoweringObjectFileXCOFF::lowerRelativeReference( const GlobalValue *LHS, const GlobalValue *RHS, const TargetMachine &TM) const { /* Not implemented yet, but don't crash, return nullptr. */ return nullptr; } XCOFF::StorageClass TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(const GlobalValue *GV) { assert(!isa(GV) && "GlobalIFunc is not supported on AIX."); switch (GV->getLinkage()) { case GlobalValue::InternalLinkage: case GlobalValue::PrivateLinkage: return XCOFF::C_HIDEXT; case GlobalValue::ExternalLinkage: case GlobalValue::CommonLinkage: case GlobalValue::AvailableExternallyLinkage: return XCOFF::C_EXT; case GlobalValue::ExternalWeakLinkage: case GlobalValue::LinkOnceAnyLinkage: case GlobalValue::LinkOnceODRLinkage: case GlobalValue::WeakAnyLinkage: case GlobalValue::WeakODRLinkage: return XCOFF::C_WEAKEXT; case GlobalValue::AppendingLinkage: report_fatal_error( "There is no mapping that implements AppendingLinkage for XCOFF."); } llvm_unreachable("Unknown linkage type!"); } MCSymbol *TargetLoweringObjectFileXCOFF::getFunctionEntryPointSymbol( const GlobalValue *Func, const TargetMachine &TM) const { assert((isa(Func) || (isa(Func) && isa_and_nonnull( cast(Func)->getAliaseeObject()))) && "Func must be a function or an alias which has a function as base " "object."); SmallString<128> NameStr; NameStr.push_back('.'); getNameWithPrefix(NameStr, Func, TM); // When -function-sections is enabled and explicit section is not specified, // it's not necessary to emit function entry point label any more. We will use // function entry point csect instead. And for function delcarations, the // undefined symbols gets treated as csect with XTY_ER property. if (((TM.getFunctionSections() && !Func->hasSection()) || Func->isDeclarationForLinker()) && isa(Func)) { return getContext() .getXCOFFSection( NameStr, SectionKind::getText(), XCOFF::CsectProperties(XCOFF::XMC_PR, Func->isDeclarationForLinker() ? XCOFF::XTY_ER : XCOFF::XTY_SD)) ->getQualNameSymbol(); } return getContext().getOrCreateSymbol(NameStr); } MCSection *TargetLoweringObjectFileXCOFF::getSectionForFunctionDescriptor( const Function *F, const TargetMachine &TM) const { SmallString<128> NameStr; getNameWithPrefix(NameStr, F, TM); return getContext().getXCOFFSection( NameStr, SectionKind::getData(), XCOFF::CsectProperties(XCOFF::XMC_DS, XCOFF::XTY_SD)); } MCSection *TargetLoweringObjectFileXCOFF::getSectionForTOCEntry( const MCSymbol *Sym, const TargetMachine &TM) const { // Use TE storage-mapping class when large code model is enabled so that // the chance of needing -bbigtoc is decreased. return getContext().getXCOFFSection( cast(Sym)->getSymbolTableName(), SectionKind::getData(), XCOFF::CsectProperties( TM.getCodeModel() == CodeModel::Large ? XCOFF::XMC_TE : XCOFF::XMC_TC, XCOFF::XTY_SD)); } MCSection *TargetLoweringObjectFileXCOFF::getSectionForLSDA( const Function &F, const MCSymbol &FnSym, const TargetMachine &TM) const { auto *LSDA = cast(LSDASection); if (TM.getFunctionSections()) { // If option -ffunction-sections is on, append the function name to the // name of the LSDA csect so that each function has its own LSDA csect. // This helps the linker to garbage-collect EH info of unused functions. SmallString<128> NameStr = LSDA->getName(); raw_svector_ostream(NameStr) << '.' << F.getName(); LSDA = getContext().getXCOFFSection(NameStr, LSDA->getKind(), LSDA->getCsectProp()); } return LSDA; } //===----------------------------------------------------------------------===// // GOFF //===----------------------------------------------------------------------===// TargetLoweringObjectFileGOFF::TargetLoweringObjectFileGOFF() = default; MCSection *TargetLoweringObjectFileGOFF::getExplicitSectionGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { return SelectSectionForGlobal(GO, Kind, TM); } MCSection *TargetLoweringObjectFileGOFF::SelectSectionForGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { auto *Symbol = TM.getSymbol(GO); if (Kind.isBSS()) return getContext().getGOFFSection(Symbol->getName(), SectionKind::getBSS(), nullptr, nullptr); return getContext().getObjectFileInfo()->getTextSection(); }