1 //===--- Fuchsia.cpp - Fuchsia ToolChain Implementations --------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "Fuchsia.h" 10 #include "CommonArgs.h" 11 #include "clang/Config/config.h" 12 #include "clang/Driver/Compilation.h" 13 #include "clang/Driver/Driver.h" 14 #include "clang/Driver/DriverDiagnostic.h" 15 #include "clang/Driver/Options.h" 16 #include "clang/Driver/SanitizerArgs.h" 17 #include "llvm/Option/ArgList.h" 18 #include "llvm/Support/FileSystem.h" 19 #include "llvm/Support/Path.h" 20 #include "llvm/Support/VirtualFileSystem.h" 21 22 using namespace clang::driver; 23 using namespace clang::driver::toolchains; 24 using namespace clang::driver::tools; 25 using namespace clang; 26 using namespace llvm::opt; 27 28 using tools::addMultilibFlag; 29 30 void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, 31 const InputInfo &Output, 32 const InputInfoList &Inputs, 33 const ArgList &Args, 34 const char *LinkingOutput) const { 35 const toolchains::Fuchsia &ToolChain = 36 static_cast<const toolchains::Fuchsia &>(getToolChain()); 37 const Driver &D = ToolChain.getDriver(); 38 39 ArgStringList CmdArgs; 40 41 // Silence warning for "clang -g foo.o -o foo" 42 Args.ClaimAllArgs(options::OPT_g_Group); 43 // and "clang -emit-llvm foo.o -o foo" 44 Args.ClaimAllArgs(options::OPT_emit_llvm); 45 // and for "clang -w foo.o -o foo". Other warning options are already 46 // handled somewhere else. 47 Args.ClaimAllArgs(options::OPT_w); 48 49 const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); 50 if (llvm::sys::path::filename(Exec).equals_lower("ld.lld") || 51 llvm::sys::path::stem(Exec).equals_lower("ld.lld")) { 52 CmdArgs.push_back("-z"); 53 CmdArgs.push_back("rodynamic"); 54 } 55 56 if (!D.SysRoot.empty()) 57 CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); 58 59 if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_r)) 60 CmdArgs.push_back("-pie"); 61 62 if (Args.hasArg(options::OPT_rdynamic)) 63 CmdArgs.push_back("-export-dynamic"); 64 65 if (Args.hasArg(options::OPT_s)) 66 CmdArgs.push_back("-s"); 67 68 if (Args.hasArg(options::OPT_r)) { 69 CmdArgs.push_back("-r"); 70 } else { 71 CmdArgs.push_back("--build-id"); 72 CmdArgs.push_back("--hash-style=gnu"); 73 } 74 75 CmdArgs.push_back("--eh-frame-hdr"); 76 77 if (Args.hasArg(options::OPT_static)) 78 CmdArgs.push_back("-Bstatic"); 79 else if (Args.hasArg(options::OPT_shared)) 80 CmdArgs.push_back("-shared"); 81 82 const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(); 83 84 if (!Args.hasArg(options::OPT_shared)) { 85 std::string Dyld = D.DyldPrefix; 86 if (SanArgs.needsAsanRt() && SanArgs.needsSharedRt()) 87 Dyld += "asan/"; 88 Dyld += "ld.so.1"; 89 CmdArgs.push_back("-dynamic-linker"); 90 CmdArgs.push_back(Args.MakeArgString(Dyld)); 91 } 92 93 CmdArgs.push_back("-o"); 94 CmdArgs.push_back(Output.getFilename()); 95 96 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { 97 if (!Args.hasArg(options::OPT_shared)) { 98 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o"))); 99 } 100 } 101 102 Args.AddAllArgs(CmdArgs, options::OPT_L); 103 Args.AddAllArgs(CmdArgs, options::OPT_u); 104 105 ToolChain.AddFilePathLibArgs(Args, CmdArgs); 106 107 if (D.isUsingLTO()) { 108 assert(!Inputs.empty() && "Must have at least one input."); 109 AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], 110 D.getLTOMode() == LTOK_Thin); 111 } 112 113 bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); 114 bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); 115 AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); 116 ToolChain.addProfileRTLibs(Args, CmdArgs); 117 118 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { 119 if (Args.hasArg(options::OPT_static)) 120 CmdArgs.push_back("-Bdynamic"); 121 122 if (D.CCCIsCXX()) { 123 if (ToolChain.ShouldLinkCXXStdlib(Args)) { 124 bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && 125 !Args.hasArg(options::OPT_static); 126 CmdArgs.push_back("--push-state"); 127 CmdArgs.push_back("--as-needed"); 128 if (OnlyLibstdcxxStatic) 129 CmdArgs.push_back("-Bstatic"); 130 ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); 131 if (OnlyLibstdcxxStatic) 132 CmdArgs.push_back("-Bdynamic"); 133 CmdArgs.push_back("-lm"); 134 CmdArgs.push_back("--pop-state"); 135 } 136 } 137 138 if (NeedsSanitizerDeps) 139 linkSanitizerRuntimeDeps(ToolChain, CmdArgs); 140 141 if (NeedsXRayDeps) 142 linkXRayRuntimeDeps(ToolChain, CmdArgs); 143 144 AddRunTimeLibs(ToolChain, D, CmdArgs, Args); 145 146 if (Args.hasArg(options::OPT_pthread) || 147 Args.hasArg(options::OPT_pthreads)) 148 CmdArgs.push_back("-lpthread"); 149 150 if (Args.hasArg(options::OPT_fsplit_stack)) 151 CmdArgs.push_back("--wrap=pthread_create"); 152 153 if (!Args.hasArg(options::OPT_nolibc)) 154 CmdArgs.push_back("-lc"); 155 } 156 157 C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); 158 } 159 160 /// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly. 161 162 Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple, 163 const ArgList &Args) 164 : ToolChain(D, Triple, Args) { 165 getProgramPaths().push_back(getDriver().getInstalledDir()); 166 if (getDriver().getInstalledDir() != D.Dir) 167 getProgramPaths().push_back(D.Dir); 168 169 if (!D.SysRoot.empty()) { 170 SmallString<128> P(D.SysRoot); 171 llvm::sys::path::append(P, "lib"); 172 getFilePaths().push_back(P.str()); 173 } 174 175 auto FilePaths = [&](const Multilib &M) -> std::vector<std::string> { 176 std::vector<std::string> FP; 177 if (D.CCCIsCXX()) { 178 if (auto CXXStdlibPath = getCXXStdlibPath()) { 179 SmallString<128> P(*CXXStdlibPath); 180 llvm::sys::path::append(P, M.gccSuffix()); 181 FP.push_back(P.str()); 182 } 183 } 184 return FP; 185 }; 186 187 Multilibs.push_back(Multilib()); 188 // Use the noexcept variant with -fno-exceptions to avoid the extra overhead. 189 Multilibs.push_back(Multilib("noexcept", {}, {}, 1) 190 .flag("-fexceptions") 191 .flag("+fno-exceptions")); 192 // ASan has higher priority because we always want the instrumentated version. 193 Multilibs.push_back(Multilib("asan", {}, {}, 2) 194 .flag("+fsanitize=address")); 195 // Use the asan+noexcept variant with ASan and -fno-exceptions. 196 Multilibs.push_back(Multilib("asan+noexcept", {}, {}, 3) 197 .flag("+fsanitize=address") 198 .flag("-fexceptions") 199 .flag("+fno-exceptions")); 200 Multilibs.FilterOut([&](const Multilib &M) { 201 std::vector<std::string> RD = FilePaths(M); 202 return std::all_of(RD.begin(), RD.end(), [&](std::string P) { 203 return !getVFS().exists(P); 204 }); 205 }); 206 207 Multilib::flags_list Flags; 208 addMultilibFlag( 209 Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true), 210 "fexceptions", Flags); 211 addMultilibFlag(getSanitizerArgs().needsAsanRt(), "fsanitize=address", Flags); 212 Multilibs.setFilePathsCallback(FilePaths); 213 214 if (Multilibs.select(Flags, SelectedMultilib)) 215 if (!SelectedMultilib.isDefault()) 216 if (const auto &PathsCallback = Multilibs.filePathsCallback()) 217 for (const auto &Path : PathsCallback(SelectedMultilib)) 218 // Prepend the multilib path to ensure it takes the precedence. 219 getFilePaths().insert(getFilePaths().begin(), Path); 220 } 221 222 std::string Fuchsia::ComputeEffectiveClangTriple(const ArgList &Args, 223 types::ID InputType) const { 224 llvm::Triple Triple(ComputeLLVMTriple(Args, InputType)); 225 return (Triple.getArchName() + "-" + Triple.getOSName()).str(); 226 } 227 228 Tool *Fuchsia::buildLinker() const { 229 return new tools::fuchsia::Linker(*this); 230 } 231 232 ToolChain::RuntimeLibType Fuchsia::GetRuntimeLibType( 233 const ArgList &Args) const { 234 if (Arg *A = Args.getLastArg(clang::driver::options::OPT_rtlib_EQ)) { 235 StringRef Value = A->getValue(); 236 if (Value != "compiler-rt") 237 getDriver().Diag(clang::diag::err_drv_invalid_rtlib_name) 238 << A->getAsString(Args); 239 } 240 241 return ToolChain::RLT_CompilerRT; 242 } 243 244 ToolChain::CXXStdlibType 245 Fuchsia::GetCXXStdlibType(const ArgList &Args) const { 246 if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { 247 StringRef Value = A->getValue(); 248 if (Value != "libc++") 249 getDriver().Diag(diag::err_drv_invalid_stdlib_name) 250 << A->getAsString(Args); 251 } 252 253 return ToolChain::CST_Libcxx; 254 } 255 256 void Fuchsia::addClangTargetOptions(const ArgList &DriverArgs, 257 ArgStringList &CC1Args, 258 Action::OffloadKind) const { 259 if (DriverArgs.hasFlag(options::OPT_fuse_init_array, 260 options::OPT_fno_use_init_array, true)) 261 CC1Args.push_back("-fuse-init-array"); 262 } 263 264 void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs, 265 ArgStringList &CC1Args) const { 266 const Driver &D = getDriver(); 267 268 if (DriverArgs.hasArg(options::OPT_nostdinc)) 269 return; 270 271 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { 272 SmallString<128> P(D.ResourceDir); 273 llvm::sys::path::append(P, "include"); 274 addSystemInclude(DriverArgs, CC1Args, P); 275 } 276 277 if (DriverArgs.hasArg(options::OPT_nostdlibinc)) 278 return; 279 280 // Check for configure-time C include directories. 281 StringRef CIncludeDirs(C_INCLUDE_DIRS); 282 if (CIncludeDirs != "") { 283 SmallVector<StringRef, 5> dirs; 284 CIncludeDirs.split(dirs, ":"); 285 for (StringRef dir : dirs) { 286 StringRef Prefix = 287 llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; 288 addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); 289 } 290 return; 291 } 292 293 if (!D.SysRoot.empty()) { 294 SmallString<128> P(D.SysRoot); 295 llvm::sys::path::append(P, "include"); 296 addExternCSystemInclude(DriverArgs, CC1Args, P.str()); 297 } 298 } 299 300 void Fuchsia::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, 301 ArgStringList &CC1Args) const { 302 if (DriverArgs.hasArg(options::OPT_nostdlibinc) || 303 DriverArgs.hasArg(options::OPT_nostdincxx)) 304 return; 305 306 switch (GetCXXStdlibType(DriverArgs)) { 307 case ToolChain::CST_Libcxx: { 308 SmallString<128> P(getDriver().Dir); 309 llvm::sys::path::append(P, "..", "include", "c++", "v1"); 310 addSystemInclude(DriverArgs, CC1Args, P.str()); 311 break; 312 } 313 314 default: 315 llvm_unreachable("invalid stdlib name"); 316 } 317 } 318 319 void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args, 320 ArgStringList &CmdArgs) const { 321 switch (GetCXXStdlibType(Args)) { 322 case ToolChain::CST_Libcxx: 323 CmdArgs.push_back("-lc++"); 324 break; 325 326 case ToolChain::CST_Libstdcxx: 327 llvm_unreachable("invalid stdlib name"); 328 } 329 } 330 331 SanitizerMask Fuchsia::getSupportedSanitizers() const { 332 SanitizerMask Res = ToolChain::getSupportedSanitizers(); 333 Res |= SanitizerKind::Address; 334 Res |= SanitizerKind::PointerCompare; 335 Res |= SanitizerKind::PointerSubtract; 336 Res |= SanitizerKind::Fuzzer; 337 Res |= SanitizerKind::FuzzerNoLink; 338 Res |= SanitizerKind::SafeStack; 339 Res |= SanitizerKind::Scudo; 340 return Res; 341 } 342 343 SanitizerMask Fuchsia::getDefaultSanitizers() const { 344 return SanitizerKind::SafeStack; 345 } 346