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