1 //===--- FreeBSD.cpp - FreeBSD 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 "FreeBSD.h" 10 #include "Arch/ARM.h" 11 #include "Arch/Mips.h" 12 #include "Arch/Sparc.h" 13 #include "CommonArgs.h" 14 #include "clang/Driver/Compilation.h" 15 #include "clang/Driver/DriverDiagnostic.h" 16 #include "clang/Driver/Options.h" 17 #include "clang/Driver/SanitizerArgs.h" 18 #include "llvm/Option/ArgList.h" 19 #include "llvm/Support/VirtualFileSystem.h" 20 21 using namespace clang::driver; 22 using namespace clang::driver::tools; 23 using namespace clang::driver::toolchains; 24 using namespace clang; 25 using namespace llvm::opt; 26 27 void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, 28 const InputInfo &Output, 29 const InputInfoList &Inputs, 30 const ArgList &Args, 31 const char *LinkingOutput) const { 32 claimNoWarnArgs(Args); 33 ArgStringList CmdArgs; 34 const auto &D = getToolChain().getDriver(); 35 36 // When building 32-bit code on FreeBSD/amd64, we have to explicitly 37 // instruct as in the base system to assemble 32-bit code. 38 switch (getToolChain().getArch()) { 39 default: 40 break; 41 case llvm::Triple::x86: 42 CmdArgs.push_back("--32"); 43 break; 44 case llvm::Triple::ppc: 45 case llvm::Triple::ppcle: 46 CmdArgs.push_back("-a32"); 47 break; 48 case llvm::Triple::mips: 49 case llvm::Triple::mipsel: 50 case llvm::Triple::mips64: 51 case llvm::Triple::mips64el: { 52 StringRef CPUName; 53 StringRef ABIName; 54 mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); 55 56 CmdArgs.push_back("-march"); 57 CmdArgs.push_back(CPUName.data()); 58 59 CmdArgs.push_back("-mabi"); 60 CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); 61 62 if (getToolChain().getTriple().isLittleEndian()) 63 CmdArgs.push_back("-EL"); 64 else 65 CmdArgs.push_back("-EB"); 66 67 if (Arg *A = Args.getLastArg(options::OPT_G)) { 68 StringRef v = A->getValue(); 69 CmdArgs.push_back(Args.MakeArgString("-G" + v)); 70 A->claim(); 71 } 72 73 AddAssemblerKPIC(getToolChain(), Args, CmdArgs); 74 break; 75 } 76 case llvm::Triple::arm: 77 case llvm::Triple::armeb: 78 case llvm::Triple::thumb: 79 case llvm::Triple::thumbeb: { 80 arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args); 81 82 if (ABI == arm::FloatABI::Hard) 83 CmdArgs.push_back("-mfpu=vfp"); 84 else 85 CmdArgs.push_back("-mfpu=softvfp"); 86 87 switch (getToolChain().getTriple().getEnvironment()) { 88 case llvm::Triple::GNUEABIHF: 89 case llvm::Triple::GNUEABI: 90 case llvm::Triple::EABI: 91 CmdArgs.push_back("-meabi=5"); 92 break; 93 94 default: 95 CmdArgs.push_back("-matpcs"); 96 } 97 break; 98 } 99 case llvm::Triple::sparc: 100 case llvm::Triple::sparcel: 101 case llvm::Triple::sparcv9: { 102 std::string CPU = getCPUName(D, Args, getToolChain().getTriple()); 103 CmdArgs.push_back( 104 sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); 105 AddAssemblerKPIC(getToolChain(), Args, CmdArgs); 106 break; 107 } 108 } 109 110 for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, 111 options::OPT_fdebug_prefix_map_EQ)) { 112 StringRef Map = A->getValue(); 113 if (!Map.contains('=')) 114 D.Diag(diag::err_drv_invalid_argument_to_option) 115 << Map << A->getOption().getName(); 116 else { 117 CmdArgs.push_back(Args.MakeArgString("--debug-prefix-map")); 118 CmdArgs.push_back(Args.MakeArgString(Map)); 119 } 120 A->claim(); 121 } 122 123 Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); 124 125 CmdArgs.push_back("-o"); 126 CmdArgs.push_back(Output.getFilename()); 127 128 for (const auto &II : Inputs) 129 CmdArgs.push_back(II.getFilename()); 130 131 const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); 132 C.addCommand(std::make_unique<Command>(JA, *this, 133 ResponseFileSupport::AtFileCurCP(), 134 Exec, CmdArgs, Inputs, Output)); 135 } 136 137 void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, 138 const InputInfo &Output, 139 const InputInfoList &Inputs, 140 const ArgList &Args, 141 const char *LinkingOutput) const { 142 const toolchains::FreeBSD &ToolChain = 143 static_cast<const toolchains::FreeBSD &>(getToolChain()); 144 const Driver &D = ToolChain.getDriver(); 145 const llvm::Triple::ArchType Arch = ToolChain.getArch(); 146 const bool IsPIE = 147 !Args.hasArg(options::OPT_shared) && 148 (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault(Args)); 149 ArgStringList CmdArgs; 150 151 // Silence warning for "clang -g foo.o -o foo" 152 Args.ClaimAllArgs(options::OPT_g_Group); 153 // and "clang -emit-llvm foo.o -o foo" 154 Args.ClaimAllArgs(options::OPT_emit_llvm); 155 // and for "clang -w foo.o -o foo". Other warning options are already 156 // handled somewhere else. 157 Args.ClaimAllArgs(options::OPT_w); 158 159 if (!D.SysRoot.empty()) 160 CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); 161 162 if (IsPIE) 163 CmdArgs.push_back("-pie"); 164 165 CmdArgs.push_back("--eh-frame-hdr"); 166 if (Args.hasArg(options::OPT_static)) { 167 CmdArgs.push_back("-Bstatic"); 168 } else { 169 if (Args.hasArg(options::OPT_rdynamic)) 170 CmdArgs.push_back("-export-dynamic"); 171 if (Args.hasArg(options::OPT_shared)) { 172 CmdArgs.push_back("-Bshareable"); 173 } else if (!Args.hasArg(options::OPT_r)) { 174 CmdArgs.push_back("-dynamic-linker"); 175 CmdArgs.push_back("/libexec/ld-elf.so.1"); 176 } 177 const llvm::Triple &T = ToolChain.getTriple(); 178 if (T.getOSMajorVersion() >= 9) { 179 if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc || T.isX86()) 180 CmdArgs.push_back("--hash-style=both"); 181 } 182 CmdArgs.push_back("--enable-new-dtags"); 183 } 184 185 // Explicitly set the linker emulation for platforms that might not 186 // be the default emulation for the linker. 187 switch (Arch) { 188 case llvm::Triple::x86: 189 CmdArgs.push_back("-m"); 190 CmdArgs.push_back("elf_i386_fbsd"); 191 break; 192 case llvm::Triple::ppc: 193 CmdArgs.push_back("-m"); 194 CmdArgs.push_back("elf32ppc_fbsd"); 195 break; 196 case llvm::Triple::ppcle: 197 CmdArgs.push_back("-m"); 198 // Use generic -- only usage is for freestanding. 199 CmdArgs.push_back("elf32lppc"); 200 break; 201 case llvm::Triple::mips: 202 CmdArgs.push_back("-m"); 203 CmdArgs.push_back("elf32btsmip_fbsd"); 204 break; 205 case llvm::Triple::mipsel: 206 CmdArgs.push_back("-m"); 207 CmdArgs.push_back("elf32ltsmip_fbsd"); 208 break; 209 case llvm::Triple::mips64: 210 CmdArgs.push_back("-m"); 211 if (tools::mips::hasMipsAbiArg(Args, "n32")) 212 CmdArgs.push_back("elf32btsmipn32_fbsd"); 213 else 214 CmdArgs.push_back("elf64btsmip_fbsd"); 215 break; 216 case llvm::Triple::mips64el: 217 CmdArgs.push_back("-m"); 218 if (tools::mips::hasMipsAbiArg(Args, "n32")) 219 CmdArgs.push_back("elf32ltsmipn32_fbsd"); 220 else 221 CmdArgs.push_back("elf64ltsmip_fbsd"); 222 break; 223 case llvm::Triple::riscv32: 224 CmdArgs.push_back("-m"); 225 CmdArgs.push_back("elf32lriscv"); 226 CmdArgs.push_back("-X"); 227 break; 228 case llvm::Triple::riscv64: 229 CmdArgs.push_back("-m"); 230 CmdArgs.push_back("elf64lriscv"); 231 CmdArgs.push_back("-X"); 232 break; 233 default: 234 break; 235 } 236 237 if (Arg *A = Args.getLastArg(options::OPT_G)) { 238 if (ToolChain.getTriple().isMIPS()) { 239 StringRef v = A->getValue(); 240 CmdArgs.push_back(Args.MakeArgString("-G" + v)); 241 A->claim(); 242 } 243 } 244 245 if (Output.isFilename()) { 246 CmdArgs.push_back("-o"); 247 CmdArgs.push_back(Output.getFilename()); 248 } else { 249 assert(Output.isNothing() && "Invalid output."); 250 } 251 252 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, 253 options::OPT_r)) { 254 const char *crt1 = nullptr; 255 if (!Args.hasArg(options::OPT_shared)) { 256 if (Args.hasArg(options::OPT_pg)) 257 crt1 = "gcrt1.o"; 258 else if (IsPIE) 259 crt1 = "Scrt1.o"; 260 else 261 crt1 = "crt1.o"; 262 } 263 if (crt1) 264 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); 265 266 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); 267 268 const char *crtbegin = nullptr; 269 if (Args.hasArg(options::OPT_static)) 270 crtbegin = "crtbeginT.o"; 271 else if (Args.hasArg(options::OPT_shared) || IsPIE) 272 crtbegin = "crtbeginS.o"; 273 else 274 crtbegin = "crtbegin.o"; 275 276 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); 277 } 278 279 Args.AddAllArgs(CmdArgs, options::OPT_L); 280 ToolChain.AddFilePathLibArgs(Args, CmdArgs); 281 Args.AddAllArgs(CmdArgs, options::OPT_T_Group); 282 Args.AddAllArgs(CmdArgs, options::OPT_e); 283 Args.AddAllArgs(CmdArgs, options::OPT_s); 284 Args.AddAllArgs(CmdArgs, options::OPT_t); 285 Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); 286 Args.AddAllArgs(CmdArgs, options::OPT_r); 287 288 if (D.isUsingLTO()) { 289 assert(!Inputs.empty() && "Must have at least one input."); 290 addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0], 291 D.getLTOMode() == LTOK_Thin); 292 } 293 294 bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); 295 bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); 296 addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs); 297 AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); 298 299 unsigned Major = ToolChain.getTriple().getOSMajorVersion(); 300 bool Profiling = Args.hasArg(options::OPT_pg) && Major != 0 && Major < 14; 301 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, 302 options::OPT_r)) { 303 // Use the static OpenMP runtime with -static-openmp 304 bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && 305 !Args.hasArg(options::OPT_static); 306 addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); 307 308 if (D.CCCIsCXX()) { 309 if (ToolChain.ShouldLinkCXXStdlib(Args)) 310 ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); 311 if (Profiling) 312 CmdArgs.push_back("-lm_p"); 313 else 314 CmdArgs.push_back("-lm"); 315 } 316 if (NeedsSanitizerDeps) 317 linkSanitizerRuntimeDeps(ToolChain, CmdArgs); 318 if (NeedsXRayDeps) 319 linkXRayRuntimeDeps(ToolChain, CmdArgs); 320 // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding 321 // the default system libraries. Just mimic this for now. 322 if (Profiling) 323 CmdArgs.push_back("-lgcc_p"); 324 else 325 CmdArgs.push_back("-lgcc"); 326 if (Args.hasArg(options::OPT_static)) { 327 CmdArgs.push_back("-lgcc_eh"); 328 } else if (Profiling) { 329 CmdArgs.push_back("-lgcc_eh_p"); 330 } else { 331 CmdArgs.push_back("--as-needed"); 332 CmdArgs.push_back("-lgcc_s"); 333 CmdArgs.push_back("--no-as-needed"); 334 } 335 336 if (Args.hasArg(options::OPT_pthread)) { 337 if (Profiling) 338 CmdArgs.push_back("-lpthread_p"); 339 else 340 CmdArgs.push_back("-lpthread"); 341 } 342 343 if (Profiling) { 344 if (Args.hasArg(options::OPT_shared)) 345 CmdArgs.push_back("-lc"); 346 else 347 CmdArgs.push_back("-lc_p"); 348 CmdArgs.push_back("-lgcc_p"); 349 } else { 350 CmdArgs.push_back("-lc"); 351 CmdArgs.push_back("-lgcc"); 352 } 353 354 if (Args.hasArg(options::OPT_static)) { 355 CmdArgs.push_back("-lgcc_eh"); 356 } else if (Profiling) { 357 CmdArgs.push_back("-lgcc_eh_p"); 358 } else { 359 CmdArgs.push_back("--as-needed"); 360 CmdArgs.push_back("-lgcc_s"); 361 CmdArgs.push_back("--no-as-needed"); 362 } 363 } 364 365 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, 366 options::OPT_r)) { 367 if (Args.hasArg(options::OPT_shared) || IsPIE) 368 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); 369 else 370 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); 371 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); 372 } 373 374 ToolChain.addProfileRTLibs(Args, CmdArgs); 375 376 const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); 377 C.addCommand(std::make_unique<Command>(JA, *this, 378 ResponseFileSupport::AtFileCurCP(), 379 Exec, CmdArgs, Inputs, Output)); 380 } 381 382 /// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly. 383 384 FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple, 385 const ArgList &Args) 386 : Generic_ELF(D, Triple, Args) { 387 388 // When targeting 32-bit platforms, look for '/usr/lib32/crt1.o' and fall 389 // back to '/usr/lib' if it doesn't exist. 390 if ((Triple.getArch() == llvm::Triple::x86 || Triple.isMIPS32() || 391 Triple.isPPC32()) && 392 D.getVFS().exists(concat(getDriver().SysRoot, "/usr/lib32/crt1.o"))) 393 getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib32")); 394 else 395 getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib")); 396 } 397 398 ToolChain::CXXStdlibType FreeBSD::GetDefaultCXXStdlibType() const { 399 unsigned Major = getTriple().getOSMajorVersion(); 400 if (Major >= 10 || Major == 0) 401 return ToolChain::CST_Libcxx; 402 return ToolChain::CST_Libstdcxx; 403 } 404 405 unsigned FreeBSD::GetDefaultDwarfVersion() const { 406 if (getTriple().getOSMajorVersion() < 12) 407 return 2; 408 return 4; 409 } 410 411 void FreeBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, 412 llvm::opt::ArgStringList &CC1Args) const { 413 addSystemInclude(DriverArgs, CC1Args, 414 concat(getDriver().SysRoot, "/usr/include/c++/v1")); 415 } 416 417 void FreeBSD::addLibStdCxxIncludePaths( 418 const llvm::opt::ArgList &DriverArgs, 419 llvm::opt::ArgStringList &CC1Args) const { 420 addLibStdCXXIncludePaths(concat(getDriver().SysRoot, "/usr/include/c++/4.2"), 421 "", "", DriverArgs, CC1Args); 422 } 423 424 void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args, 425 ArgStringList &CmdArgs) const { 426 CXXStdlibType Type = GetCXXStdlibType(Args); 427 unsigned Major = getTriple().getOSMajorVersion(); 428 bool Profiling = Args.hasArg(options::OPT_pg) && Major != 0 && Major < 14; 429 430 switch (Type) { 431 case ToolChain::CST_Libcxx: 432 CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); 433 if (Args.hasArg(options::OPT_fexperimental_library)) 434 CmdArgs.push_back("-lc++experimental"); 435 break; 436 437 case ToolChain::CST_Libstdcxx: 438 CmdArgs.push_back(Profiling ? "-lstdc++_p" : "-lstdc++"); 439 break; 440 } 441 } 442 443 void FreeBSD::AddCudaIncludeArgs(const ArgList &DriverArgs, 444 ArgStringList &CC1Args) const { 445 CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); 446 } 447 448 void FreeBSD::AddHIPIncludeArgs(const ArgList &DriverArgs, 449 ArgStringList &CC1Args) const { 450 RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); 451 } 452 453 Tool *FreeBSD::buildAssembler() const { 454 return new tools::freebsd::Assembler(*this); 455 } 456 457 Tool *FreeBSD::buildLinker() const { return new tools::freebsd::Linker(*this); } 458 459 llvm::ExceptionHandling FreeBSD::GetExceptionModel(const ArgList &Args) const { 460 // FreeBSD uses SjLj exceptions on ARM oabi. 461 switch (getTriple().getEnvironment()) { 462 case llvm::Triple::GNUEABIHF: 463 case llvm::Triple::GNUEABI: 464 case llvm::Triple::EABI: 465 return llvm::ExceptionHandling::None; 466 default: 467 if (getTriple().getArch() == llvm::Triple::arm || 468 getTriple().getArch() == llvm::Triple::thumb) 469 return llvm::ExceptionHandling::SjLj; 470 return llvm::ExceptionHandling::None; 471 } 472 } 473 474 bool FreeBSD::HasNativeLLVMSupport() const { return true; } 475 476 bool FreeBSD::IsUnwindTablesDefault(const ArgList &Args) const { return true; } 477 478 bool FreeBSD::isPIEDefault(const llvm::opt::ArgList &Args) const { 479 return getSanitizerArgs(Args).requiresPIE(); 480 } 481 482 SanitizerMask FreeBSD::getSupportedSanitizers() const { 483 const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64; 484 const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; 485 const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; 486 const bool IsMIPS64 = getTriple().isMIPS64(); 487 SanitizerMask Res = ToolChain::getSupportedSanitizers(); 488 Res |= SanitizerKind::Address; 489 Res |= SanitizerKind::PointerCompare; 490 Res |= SanitizerKind::PointerSubtract; 491 Res |= SanitizerKind::Vptr; 492 if (IsAArch64 || IsX86_64 || IsMIPS64) { 493 Res |= SanitizerKind::Leak; 494 Res |= SanitizerKind::Thread; 495 } 496 if (IsX86 || IsX86_64) { 497 Res |= SanitizerKind::Function; 498 } 499 if (IsAArch64 || IsX86 || IsX86_64) { 500 Res |= SanitizerKind::SafeStack; 501 Res |= SanitizerKind::Fuzzer; 502 Res |= SanitizerKind::FuzzerNoLink; 503 } 504 if (IsAArch64 || IsX86_64) { 505 Res |= SanitizerKind::KernelAddress; 506 Res |= SanitizerKind::KernelMemory; 507 Res |= SanitizerKind::Memory; 508 } 509 return Res; 510 } 511 512 void FreeBSD::addClangTargetOptions(const ArgList &DriverArgs, 513 ArgStringList &CC1Args, 514 Action::OffloadKind) const { 515 if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, 516 options::OPT_fno_use_init_array, 517 getTriple().getOSMajorVersion() >= 12)) 518 CC1Args.push_back("-fno-use-init-array"); 519 } 520