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 { 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 break; 227 case llvm::Triple::riscv64: 228 CmdArgs.push_back("-m"); 229 CmdArgs.push_back("elf64lriscv"); 230 break; 231 default: 232 break; 233 } 234 235 if (Arg *A = Args.getLastArg(options::OPT_G)) { 236 if (ToolChain.getTriple().isMIPS()) { 237 StringRef v = A->getValue(); 238 CmdArgs.push_back(Args.MakeArgString("-G" + v)); 239 A->claim(); 240 } 241 } 242 243 if (Output.isFilename()) { 244 CmdArgs.push_back("-o"); 245 CmdArgs.push_back(Output.getFilename()); 246 } else { 247 assert(Output.isNothing() && "Invalid output."); 248 } 249 250 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, 251 options::OPT_r)) { 252 const char *crt1 = nullptr; 253 if (!Args.hasArg(options::OPT_shared)) { 254 if (Args.hasArg(options::OPT_pg)) 255 crt1 = "gcrt1.o"; 256 else if (IsPIE) 257 crt1 = "Scrt1.o"; 258 else 259 crt1 = "crt1.o"; 260 } 261 if (crt1) 262 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); 263 264 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); 265 266 const char *crtbegin = nullptr; 267 if (Args.hasArg(options::OPT_static)) 268 crtbegin = "crtbeginT.o"; 269 else if (Args.hasArg(options::OPT_shared) || IsPIE) 270 crtbegin = "crtbeginS.o"; 271 else 272 crtbegin = "crtbegin.o"; 273 274 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); 275 } 276 277 Args.AddAllArgs(CmdArgs, options::OPT_L); 278 ToolChain.AddFilePathLibArgs(Args, CmdArgs); 279 Args.AddAllArgs(CmdArgs, options::OPT_T_Group); 280 Args.AddAllArgs(CmdArgs, options::OPT_e); 281 Args.AddAllArgs(CmdArgs, options::OPT_s); 282 Args.AddAllArgs(CmdArgs, options::OPT_t); 283 Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); 284 Args.AddAllArgs(CmdArgs, options::OPT_r); 285 286 if (D.isUsingLTO()) { 287 assert(!Inputs.empty() && "Must have at least one input."); 288 addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0], 289 D.getLTOMode() == LTOK_Thin); 290 } 291 292 bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); 293 bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); 294 addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs); 295 AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); 296 297 unsigned Major = ToolChain.getTriple().getOSMajorVersion(); 298 bool Profiling = Args.hasArg(options::OPT_pg) && Major != 0 && Major < 14; 299 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, 300 options::OPT_r)) { 301 // Use the static OpenMP runtime with -static-openmp 302 bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && 303 !Args.hasArg(options::OPT_static); 304 addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); 305 306 if (D.CCCIsCXX()) { 307 if (ToolChain.ShouldLinkCXXStdlib(Args)) 308 ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); 309 if (Profiling) 310 CmdArgs.push_back("-lm_p"); 311 else 312 CmdArgs.push_back("-lm"); 313 } 314 if (NeedsSanitizerDeps) 315 linkSanitizerRuntimeDeps(ToolChain, CmdArgs); 316 if (NeedsXRayDeps) 317 linkXRayRuntimeDeps(ToolChain, CmdArgs); 318 // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding 319 // the default system libraries. Just mimic this for now. 320 if (Profiling) 321 CmdArgs.push_back("-lgcc_p"); 322 else 323 CmdArgs.push_back("-lgcc"); 324 if (Args.hasArg(options::OPT_static)) { 325 CmdArgs.push_back("-lgcc_eh"); 326 } else if (Profiling) { 327 CmdArgs.push_back("-lgcc_eh_p"); 328 } else { 329 CmdArgs.push_back("--as-needed"); 330 CmdArgs.push_back("-lgcc_s"); 331 CmdArgs.push_back("--no-as-needed"); 332 } 333 334 if (Args.hasArg(options::OPT_pthread)) { 335 if (Profiling) 336 CmdArgs.push_back("-lpthread_p"); 337 else 338 CmdArgs.push_back("-lpthread"); 339 } 340 341 if (Profiling) { 342 if (Args.hasArg(options::OPT_shared)) 343 CmdArgs.push_back("-lc"); 344 else 345 CmdArgs.push_back("-lc_p"); 346 CmdArgs.push_back("-lgcc_p"); 347 } else { 348 CmdArgs.push_back("-lc"); 349 CmdArgs.push_back("-lgcc"); 350 } 351 352 if (Args.hasArg(options::OPT_static)) { 353 CmdArgs.push_back("-lgcc_eh"); 354 } else if (Profiling) { 355 CmdArgs.push_back("-lgcc_eh_p"); 356 } else { 357 CmdArgs.push_back("--as-needed"); 358 CmdArgs.push_back("-lgcc_s"); 359 CmdArgs.push_back("--no-as-needed"); 360 } 361 } 362 363 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, 364 options::OPT_r)) { 365 if (Args.hasArg(options::OPT_shared) || IsPIE) 366 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); 367 else 368 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); 369 CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); 370 } 371 372 ToolChain.addProfileRTLibs(Args, CmdArgs); 373 374 const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); 375 C.addCommand(std::make_unique<Command>(JA, *this, 376 ResponseFileSupport::AtFileCurCP(), 377 Exec, CmdArgs, Inputs, Output)); 378 } 379 380 /// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly. 381 382 FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple, 383 const ArgList &Args) 384 : Generic_ELF(D, Triple, Args) { 385 386 // When targeting 32-bit platforms, look for '/usr/lib32/crt1.o' and fall 387 // back to '/usr/lib' if it doesn't exist. 388 if ((Triple.getArch() == llvm::Triple::x86 || Triple.isMIPS32() || 389 Triple.isPPC32()) && 390 D.getVFS().exists(getDriver().SysRoot + "/usr/lib32/crt1.o")) 391 getFilePaths().push_back(getDriver().SysRoot + "/usr/lib32"); 392 else 393 getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); 394 } 395 396 ToolChain::CXXStdlibType FreeBSD::GetDefaultCXXStdlibType() const { 397 unsigned Major = getTriple().getOSMajorVersion(); 398 if (Major >= 10 || Major == 0) 399 return ToolChain::CST_Libcxx; 400 return ToolChain::CST_Libstdcxx; 401 } 402 403 unsigned FreeBSD::GetDefaultDwarfVersion() const { 404 if (getTriple().getOSMajorVersion() < 12) 405 return 2; 406 return 4; 407 } 408 409 void FreeBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, 410 llvm::opt::ArgStringList &CC1Args) const { 411 addSystemInclude(DriverArgs, CC1Args, 412 getDriver().SysRoot + "/usr/include/c++/v1"); 413 } 414 415 void FreeBSD::addLibStdCxxIncludePaths( 416 const llvm::opt::ArgList &DriverArgs, 417 llvm::opt::ArgStringList &CC1Args) const { 418 addLibStdCXXIncludePaths(getDriver().SysRoot + "/usr/include/c++/4.2", "", "", 419 DriverArgs, CC1Args); 420 } 421 422 void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args, 423 ArgStringList &CmdArgs) const { 424 CXXStdlibType Type = GetCXXStdlibType(Args); 425 unsigned Major = getTriple().getOSMajorVersion(); 426 bool Profiling = Args.hasArg(options::OPT_pg) && Major != 0 && Major < 14; 427 428 switch (Type) { 429 case ToolChain::CST_Libcxx: 430 CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); 431 break; 432 433 case ToolChain::CST_Libstdcxx: 434 CmdArgs.push_back(Profiling ? "-lstdc++_p" : "-lstdc++"); 435 break; 436 } 437 } 438 439 void FreeBSD::AddCudaIncludeArgs(const ArgList &DriverArgs, 440 ArgStringList &CC1Args) const { 441 CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); 442 } 443 444 void FreeBSD::AddHIPIncludeArgs(const ArgList &DriverArgs, 445 ArgStringList &CC1Args) const { 446 RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args); 447 } 448 449 Tool *FreeBSD::buildAssembler() const { 450 return new tools::freebsd::Assembler(*this); 451 } 452 453 Tool *FreeBSD::buildLinker() const { return new tools::freebsd::Linker(*this); } 454 455 llvm::ExceptionHandling FreeBSD::GetExceptionModel(const ArgList &Args) const { 456 // FreeBSD uses SjLj exceptions on ARM oabi. 457 switch (getTriple().getEnvironment()) { 458 case llvm::Triple::GNUEABIHF: 459 case llvm::Triple::GNUEABI: 460 case llvm::Triple::EABI: 461 return llvm::ExceptionHandling::None; 462 default: 463 if (getTriple().getArch() == llvm::Triple::arm || 464 getTriple().getArch() == llvm::Triple::thumb) 465 return llvm::ExceptionHandling::SjLj; 466 return llvm::ExceptionHandling::None; 467 } 468 } 469 470 bool FreeBSD::HasNativeLLVMSupport() const { return true; } 471 472 bool FreeBSD::IsUnwindTablesDefault(const ArgList &Args) const { return true; } 473 474 bool FreeBSD::isPIEDefault(const llvm::opt::ArgList &Args) const { 475 return getSanitizerArgs(Args).requiresPIE(); 476 } 477 478 SanitizerMask FreeBSD::getSupportedSanitizers() const { 479 const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64; 480 const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; 481 const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; 482 const bool IsMIPS64 = getTriple().isMIPS64(); 483 SanitizerMask Res = ToolChain::getSupportedSanitizers(); 484 Res |= SanitizerKind::Address; 485 Res |= SanitizerKind::PointerCompare; 486 Res |= SanitizerKind::PointerSubtract; 487 Res |= SanitizerKind::Vptr; 488 if (IsX86_64 || IsMIPS64) { 489 Res |= SanitizerKind::Leak; 490 Res |= SanitizerKind::Thread; 491 } 492 if (IsX86 || IsX86_64) { 493 Res |= SanitizerKind::Function; 494 Res |= SanitizerKind::SafeStack; 495 Res |= SanitizerKind::Fuzzer; 496 Res |= SanitizerKind::FuzzerNoLink; 497 } 498 if (IsAArch64 || IsX86_64) { 499 Res |= SanitizerKind::KernelAddress; 500 Res |= SanitizerKind::KernelMemory; 501 } 502 if (IsX86_64) { 503 Res |= SanitizerKind::Memory; 504 } 505 return Res; 506 } 507 508 void FreeBSD::addClangTargetOptions(const ArgList &DriverArgs, 509 ArgStringList &CC1Args, 510 Action::OffloadKind) const { 511 if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, 512 options::OPT_fno_use_init_array, 513 getTriple().getOSMajorVersion() >= 12)) 514 CC1Args.push_back("-fno-use-init-array"); 515 } 516