10b57cec5SDimitry Andric //===--- Solaris.cpp - Solaris ToolChain Implementations --------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "Solaris.h" 100b57cec5SDimitry Andric #include "CommonArgs.h" 11a7dea167SDimitry Andric #include "clang/Basic/LangStandard.h" 120b57cec5SDimitry Andric #include "clang/Config/config.h" 130b57cec5SDimitry Andric #include "clang/Driver/Compilation.h" 140b57cec5SDimitry Andric #include "clang/Driver/Driver.h" 150b57cec5SDimitry Andric #include "clang/Driver/DriverDiagnostic.h" 160b57cec5SDimitry Andric #include "clang/Driver/Options.h" 1781ad6265SDimitry Andric #include "clang/Driver/SanitizerArgs.h" 1881ad6265SDimitry Andric #include "clang/Driver/ToolChain.h" 190b57cec5SDimitry Andric #include "llvm/Option/ArgList.h" 200b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 210b57cec5SDimitry Andric #include "llvm/Support/Path.h" 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric using namespace clang::driver; 240b57cec5SDimitry Andric using namespace clang::driver::tools; 250b57cec5SDimitry Andric using namespace clang::driver::toolchains; 260b57cec5SDimitry Andric using namespace clang; 270b57cec5SDimitry Andric using namespace llvm::opt; 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric void solaris::Assembler::ConstructJob(Compilation &C, const JobAction &JA, 300b57cec5SDimitry Andric const InputInfo &Output, 310b57cec5SDimitry Andric const InputInfoList &Inputs, 320b57cec5SDimitry Andric const ArgList &Args, 330b57cec5SDimitry Andric const char *LinkingOutput) const { 340b57cec5SDimitry Andric claimNoWarnArgs(Args); 350b57cec5SDimitry Andric ArgStringList CmdArgs; 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric CmdArgs.push_back("-o"); 400b57cec5SDimitry Andric CmdArgs.push_back(Output.getFilename()); 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric for (const auto &II : Inputs) 430b57cec5SDimitry Andric CmdArgs.push_back(II.getFilename()); 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); 465ffd83dbSDimitry Andric C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), 47e8d8bef9SDimitry Andric Exec, CmdArgs, Inputs, Output)); 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, 510b57cec5SDimitry Andric const InputInfo &Output, 520b57cec5SDimitry Andric const InputInfoList &Inputs, 530b57cec5SDimitry Andric const ArgList &Args, 540b57cec5SDimitry Andric const char *LinkingOutput) const { 550b57cec5SDimitry Andric ArgStringList CmdArgs; 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric // Demangle C++ names in errors 580b57cec5SDimitry Andric CmdArgs.push_back("-C"); 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) { 610b57cec5SDimitry Andric CmdArgs.push_back("-e"); 620b57cec5SDimitry Andric CmdArgs.push_back("_start"); 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric if (Args.hasArg(options::OPT_static)) { 660b57cec5SDimitry Andric CmdArgs.push_back("-Bstatic"); 670b57cec5SDimitry Andric CmdArgs.push_back("-dn"); 680b57cec5SDimitry Andric } else { 690b57cec5SDimitry Andric CmdArgs.push_back("-Bdynamic"); 700b57cec5SDimitry Andric if (Args.hasArg(options::OPT_shared)) { 710b57cec5SDimitry Andric CmdArgs.push_back("-shared"); 720b57cec5SDimitry Andric } 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric // libpthread has been folded into libc since Solaris 10, no need to do 750b57cec5SDimitry Andric // anything for pthreads. Claim argument to avoid warning. 760b57cec5SDimitry Andric Args.ClaimAllArgs(options::OPT_pthread); 770b57cec5SDimitry Andric Args.ClaimAllArgs(options::OPT_pthreads); 780b57cec5SDimitry Andric } 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric if (Output.isFilename()) { 810b57cec5SDimitry Andric CmdArgs.push_back("-o"); 820b57cec5SDimitry Andric CmdArgs.push_back(Output.getFilename()); 830b57cec5SDimitry Andric } else { 840b57cec5SDimitry Andric assert(Output.isNothing() && "Invalid output."); 850b57cec5SDimitry Andric } 860b57cec5SDimitry Andric 872a66634dSDimitry Andric if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, 882a66634dSDimitry Andric options::OPT_r)) { 890b57cec5SDimitry Andric if (!Args.hasArg(options::OPT_shared)) 900b57cec5SDimitry Andric CmdArgs.push_back( 910b57cec5SDimitry Andric Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); 94a7dea167SDimitry Andric 95a7dea167SDimitry Andric const Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi); 96a7dea167SDimitry Andric bool HaveAnsi = false; 97a7dea167SDimitry Andric const LangStandard *LangStd = nullptr; 98a7dea167SDimitry Andric if (Std) { 99a7dea167SDimitry Andric HaveAnsi = Std->getOption().matches(options::OPT_ansi); 100a7dea167SDimitry Andric if (!HaveAnsi) 101a7dea167SDimitry Andric LangStd = LangStandard::getLangStandardForName(Std->getValue()); 102a7dea167SDimitry Andric } 103a7dea167SDimitry Andric 104a7dea167SDimitry Andric const char *values_X = "values-Xa.o"; 105a7dea167SDimitry Andric // Use values-Xc.o for -ansi, -std=c*, -std=iso9899:199409. 106a7dea167SDimitry Andric if (HaveAnsi || (LangStd && !LangStd->isGNUMode())) 107a7dea167SDimitry Andric values_X = "values-Xc.o"; 108a7dea167SDimitry Andric CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(values_X))); 109a7dea167SDimitry Andric 110a7dea167SDimitry Andric const char *values_xpg = "values-xpg6.o"; 111a7dea167SDimitry Andric // Use values-xpg4.o for -std=c90, -std=gnu90, -std=iso9899:199409. 112a7dea167SDimitry Andric if (LangStd && LangStd->getLanguage() == Language::C && !LangStd->isC99()) 113a7dea167SDimitry Andric values_xpg = "values-xpg4.o"; 1140b57cec5SDimitry Andric CmdArgs.push_back( 115a7dea167SDimitry Andric Args.MakeArgString(getToolChain().GetFilePath(values_xpg))); 1160b57cec5SDimitry Andric CmdArgs.push_back( 1170b57cec5SDimitry Andric Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); 118*bdd1243dSDimitry Andric // Add crtfastmath.o if available and fast math is enabled. 119*bdd1243dSDimitry Andric getToolChain().addFastMathRuntimeIfAvailable(Args, CmdArgs); 1200b57cec5SDimitry Andric } 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric getToolChain().AddFilePathLibArgs(Args, CmdArgs); 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, 1250b57cec5SDimitry Andric options::OPT_e, options::OPT_r}); 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric bool NeedsSanitizerDeps = addSanitizerRuntimes(getToolChain(), Args, CmdArgs); 1280b57cec5SDimitry Andric AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); 1290b57cec5SDimitry Andric 1302a66634dSDimitry Andric if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, 1312a66634dSDimitry Andric options::OPT_r)) { 1320b57cec5SDimitry Andric if (getToolChain().ShouldLinkCXXStdlib(Args)) 1330b57cec5SDimitry Andric getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); 1340b57cec5SDimitry Andric if (Args.hasArg(options::OPT_fstack_protector) || 1350b57cec5SDimitry Andric Args.hasArg(options::OPT_fstack_protector_strong) || 1360b57cec5SDimitry Andric Args.hasArg(options::OPT_fstack_protector_all)) { 1370b57cec5SDimitry Andric // Explicitly link ssp libraries, not folded into Solaris libc. 1380b57cec5SDimitry Andric CmdArgs.push_back("-lssp_nonshared"); 1390b57cec5SDimitry Andric CmdArgs.push_back("-lssp"); 1400b57cec5SDimitry Andric } 141d781ede6SDimitry Andric // LLVM support for atomics on 32-bit SPARC V8+ is incomplete, so 142d781ede6SDimitry Andric // forcibly link with libatomic as a workaround. 143d781ede6SDimitry Andric if (getToolChain().getTriple().getArch() == llvm::Triple::sparc) { 144d781ede6SDimitry Andric CmdArgs.push_back(getAsNeededOption(getToolChain(), true)); 145d781ede6SDimitry Andric CmdArgs.push_back("-latomic"); 146d781ede6SDimitry Andric CmdArgs.push_back(getAsNeededOption(getToolChain(), false)); 147d781ede6SDimitry Andric } 1480b57cec5SDimitry Andric CmdArgs.push_back("-lgcc_s"); 1490b57cec5SDimitry Andric CmdArgs.push_back("-lc"); 1500b57cec5SDimitry Andric if (!Args.hasArg(options::OPT_shared)) { 1510b57cec5SDimitry Andric CmdArgs.push_back("-lgcc"); 1520b57cec5SDimitry Andric CmdArgs.push_back("-lm"); 1530b57cec5SDimitry Andric } 15481ad6265SDimitry Andric if (NeedsSanitizerDeps) { 1550b57cec5SDimitry Andric linkSanitizerRuntimeDeps(getToolChain(), CmdArgs); 15681ad6265SDimitry Andric 15781ad6265SDimitry Andric // Work around Solaris/amd64 ld bug when calling __tls_get_addr directly. 15881ad6265SDimitry Andric // However, ld -z relax=transtls is available since Solaris 11.2, but not 15981ad6265SDimitry Andric // in Illumos. 16081ad6265SDimitry Andric const SanitizerArgs &SA = getToolChain().getSanitizerArgs(Args); 16181ad6265SDimitry Andric if (getToolChain().getTriple().getArch() == llvm::Triple::x86_64 && 16281ad6265SDimitry Andric (SA.needsAsanRt() || SA.needsStatsRt() || 16381ad6265SDimitry Andric (SA.needsUbsanRt() && !SA.requiresMinimalRuntime()))) 16481ad6265SDimitry Andric CmdArgs.push_back("-zrelax=transtls"); 16581ad6265SDimitry Andric } 1660b57cec5SDimitry Andric } 1670b57cec5SDimitry Andric 1682a66634dSDimitry Andric if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, 1692a66634dSDimitry Andric options::OPT_r)) { 1700b57cec5SDimitry Andric CmdArgs.push_back( 1710b57cec5SDimitry Andric Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); 1722a66634dSDimitry Andric CmdArgs.push_back( 1732a66634dSDimitry Andric Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric getToolChain().addProfileRTLibs(Args, CmdArgs); 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); 1795ffd83dbSDimitry Andric C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), 180e8d8bef9SDimitry Andric Exec, CmdArgs, Inputs, Output)); 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric static StringRef getSolarisLibSuffix(const llvm::Triple &Triple) { 1840b57cec5SDimitry Andric switch (Triple.getArch()) { 1850b57cec5SDimitry Andric case llvm::Triple::x86: 1860b57cec5SDimitry Andric case llvm::Triple::sparc: 1870b57cec5SDimitry Andric break; 1880b57cec5SDimitry Andric case llvm::Triple::x86_64: 1890b57cec5SDimitry Andric return "/amd64"; 1900b57cec5SDimitry Andric case llvm::Triple::sparcv9: 1910b57cec5SDimitry Andric return "/sparcv9"; 1920b57cec5SDimitry Andric default: 1930b57cec5SDimitry Andric llvm_unreachable("Unsupported architecture"); 1940b57cec5SDimitry Andric } 1950b57cec5SDimitry Andric return ""; 1960b57cec5SDimitry Andric } 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric /// Solaris - Solaris tool chain which can call as(1) and ld(1) directly. 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric Solaris::Solaris(const Driver &D, const llvm::Triple &Triple, 2010b57cec5SDimitry Andric const ArgList &Args) 2020b57cec5SDimitry Andric : Generic_ELF(D, Triple, Args) { 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric GCCInstallation.init(Triple, Args); 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric StringRef LibSuffix = getSolarisLibSuffix(Triple); 2070b57cec5SDimitry Andric path_list &Paths = getFilePaths(); 2080b57cec5SDimitry Andric if (GCCInstallation.isValid()) { 2090b57cec5SDimitry Andric // On Solaris gcc uses both an architecture-specific path with triple in it 2100b57cec5SDimitry Andric // as well as a more generic lib path (+arch suffix). 2110b57cec5SDimitry Andric addPathIfExists(D, 2120b57cec5SDimitry Andric GCCInstallation.getInstallPath() + 2130b57cec5SDimitry Andric GCCInstallation.getMultilib().gccSuffix(), 2140b57cec5SDimitry Andric Paths); 2150b57cec5SDimitry Andric addPathIfExists(D, GCCInstallation.getParentLibPath() + LibSuffix, Paths); 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric // If we are currently running Clang inside of the requested system root, 2190b57cec5SDimitry Andric // add its parent library path to those searched. 2200b57cec5SDimitry Andric if (StringRef(D.Dir).startswith(D.SysRoot)) 2210b57cec5SDimitry Andric addPathIfExists(D, D.Dir + "/../lib", Paths); 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric addPathIfExists(D, D.SysRoot + "/usr/lib" + LibSuffix, Paths); 2240b57cec5SDimitry Andric } 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric SanitizerMask Solaris::getSupportedSanitizers() const { 2270b57cec5SDimitry Andric const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; 228a7dea167SDimitry Andric const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; 2290b57cec5SDimitry Andric SanitizerMask Res = ToolChain::getSupportedSanitizers(); 2300b57cec5SDimitry Andric // FIXME: Omit X86_64 until 64-bit support is figured out. 2310b57cec5SDimitry Andric if (IsX86) { 2320b57cec5SDimitry Andric Res |= SanitizerKind::Address; 2330b57cec5SDimitry Andric Res |= SanitizerKind::PointerCompare; 2340b57cec5SDimitry Andric Res |= SanitizerKind::PointerSubtract; 2350b57cec5SDimitry Andric } 236a7dea167SDimitry Andric if (IsX86 || IsX86_64) 237a7dea167SDimitry Andric Res |= SanitizerKind::Function; 2380b57cec5SDimitry Andric Res |= SanitizerKind::Vptr; 2390b57cec5SDimitry Andric return Res; 2400b57cec5SDimitry Andric } 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric Tool *Solaris::buildAssembler() const { 2430b57cec5SDimitry Andric return new tools::solaris::Assembler(*this); 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric Tool *Solaris::buildLinker() const { return new tools::solaris::Linker(*this); } 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric void Solaris::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 2490b57cec5SDimitry Andric ArgStringList &CC1Args) const { 2500b57cec5SDimitry Andric const Driver &D = getDriver(); 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) 2530b57cec5SDimitry Andric return; 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) 2560b57cec5SDimitry Andric addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/local/include"); 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { 2590b57cec5SDimitry Andric SmallString<128> P(D.ResourceDir); 2600b57cec5SDimitry Andric llvm::sys::path::append(P, "include"); 2610b57cec5SDimitry Andric addSystemInclude(DriverArgs, CC1Args, P); 2620b57cec5SDimitry Andric } 2630b57cec5SDimitry Andric 2640b57cec5SDimitry Andric if (DriverArgs.hasArg(options::OPT_nostdlibinc)) 2650b57cec5SDimitry Andric return; 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric // Check for configure-time C include directories. 2680b57cec5SDimitry Andric StringRef CIncludeDirs(C_INCLUDE_DIRS); 2690b57cec5SDimitry Andric if (CIncludeDirs != "") { 2700b57cec5SDimitry Andric SmallVector<StringRef, 5> dirs; 2710b57cec5SDimitry Andric CIncludeDirs.split(dirs, ":"); 2720b57cec5SDimitry Andric for (StringRef dir : dirs) { 2730b57cec5SDimitry Andric StringRef Prefix = 2745ffd83dbSDimitry Andric llvm::sys::path::is_absolute(dir) ? "" : StringRef(D.SysRoot); 2750b57cec5SDimitry Andric addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); 2760b57cec5SDimitry Andric } 2770b57cec5SDimitry Andric return; 2780b57cec5SDimitry Andric } 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric // Add include directories specific to the selected multilib set and multilib. 2810b57cec5SDimitry Andric if (GCCInstallation.isValid()) { 2820b57cec5SDimitry Andric const MultilibSet::IncludeDirsFunc &Callback = 2830b57cec5SDimitry Andric Multilibs.includeDirsCallback(); 2840b57cec5SDimitry Andric if (Callback) { 2850b57cec5SDimitry Andric for (const auto &Path : Callback(GCCInstallation.getMultilib())) 2860b57cec5SDimitry Andric addExternCSystemIncludeIfExists( 2870b57cec5SDimitry Andric DriverArgs, CC1Args, GCCInstallation.getInstallPath() + Path); 2880b57cec5SDimitry Andric } 2890b57cec5SDimitry Andric } 2900b57cec5SDimitry Andric 2910b57cec5SDimitry Andric addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include"); 2920b57cec5SDimitry Andric } 2930b57cec5SDimitry Andric 2940b57cec5SDimitry Andric void Solaris::addLibStdCxxIncludePaths( 2950b57cec5SDimitry Andric const llvm::opt::ArgList &DriverArgs, 2960b57cec5SDimitry Andric llvm::opt::ArgStringList &CC1Args) const { 2970b57cec5SDimitry Andric // We need a detected GCC installation on Solaris (similar to Linux) 2980b57cec5SDimitry Andric // to provide libstdc++'s headers. 2990b57cec5SDimitry Andric if (!GCCInstallation.isValid()) 3000b57cec5SDimitry Andric return; 3010b57cec5SDimitry Andric 3020b57cec5SDimitry Andric // By default, look for the C++ headers in an include directory adjacent to 3030b57cec5SDimitry Andric // the lib directory of the GCC installation. 3040b57cec5SDimitry Andric // On Solaris this usually looks like /usr/gcc/X.Y/include/c++/X.Y.Z 3050b57cec5SDimitry Andric StringRef LibDir = GCCInstallation.getParentLibPath(); 3060b57cec5SDimitry Andric StringRef TripleStr = GCCInstallation.getTriple().str(); 3070b57cec5SDimitry Andric const Multilib &Multilib = GCCInstallation.getMultilib(); 3080b57cec5SDimitry Andric const GCCVersion &Version = GCCInstallation.getVersion(); 3090b57cec5SDimitry Andric 3100b57cec5SDimitry Andric // The primary search for libstdc++ supports multiarch variants. 311fe6060f1SDimitry Andric addLibStdCXXIncludePaths(LibDir.str() + "/../include/c++/" + Version.Text, 312fe6060f1SDimitry Andric TripleStr, Multilib.includeSuffix(), DriverArgs, 313fe6060f1SDimitry Andric CC1Args); 3140b57cec5SDimitry Andric } 315