bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, const ArgList &Args, bool IsOffloadingHost, bool GompNeedsRT) { if (!Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, options::OPT_fno_openmp, false)) return false; switch (TC.getDriver().getOpenMPRuntime(Args)) { case Driver::OMPRT_OMP: CmdArgs.push_back("-lomp"); break; case Driver::OMPRT_GOMP: CmdArgs.push_back("-lgomp"); if (GompNeedsRT) CmdArgs.push_back("-lrt"); break; case Driver::OMPRT_IOMP5: CmdArgs.push_back("-liomp5"); break; case Driver::OMPRT_Unknown: // Already diagnosed. return false; } if (IsOffloadingHost) CmdArgs.push_back("-lomptarget"); addArchSpecificRPath(TC, Args, CmdArgs); return true; }
void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, const ArgList &Args, ArgStringList &CmdArgs, const JobAction &JA) { const Driver &D = TC.getDriver(); // Add extra linker input arguments which are not treated as inputs // (constructed via -Xarch_). Args.AddAllArgValues(CmdArgs, options::OPT_Zlinker_input); for (const auto &II : Inputs) { // If the current tool chain refers to an OpenMP offloading host, we should // ignore inputs that refer to OpenMP offloading devices - they will be // embedded according to a proper linker script. if (auto *IA = II.getAction()) if (JA.isHostOffloading(Action::OFK_OpenMP) && IA->isDeviceOffloading(Action::OFK_OpenMP)) continue; if (!TC.HasNativeLLVMSupport() && types::isLLVMIR(II.getType())) // Don't try to pass LLVM inputs unless we have native support. D.Diag(diag::err_drv_no_linker_llvm_support) << TC.getTripleString(); // Add filenames immediately. if (II.isFilename()) { CmdArgs.push_back(II.getFilename()); continue; } // Otherwise, this is a linker input argument. const Arg &A = II.getInputArg(); // Handle reserved library options. if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx)) TC.AddCXXStdlibLibArgs(Args, CmdArgs); else if (A.getOption().matches(options::OPT_Z_reserved_lib_cckext)) TC.AddCCKextLibArgs(Args, CmdArgs); else if (A.getOption().matches(options::OPT_z)) { // Pass -z prefix for gcc linker compatibility. A.claim(); A.render(Args, CmdArgs); } else { A.renderAsInput(Args, CmdArgs); } } // LIBRARY_PATH - included following the user specified library paths. // and only supported on native toolchains. if (!TC.isCrossCompiling()) { addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH"); } }
/// Get the runtime library link path, which is platform-specific and found /// relative to the compiler. static void getRuntimeLibraryPath(SmallVectorImpl<char> &runtimeLibPath, const llvm::opt::ArgList &args, const ToolChain &TC) { // FIXME: Duplicated from CompilerInvocation, but in theory the runtime // library link path and the standard library module import path don't // need to be the same. if (const Arg *A = args.getLastArg(options::OPT_resource_dir)) { StringRef value = A->getValue(); runtimeLibPath.append(value.begin(), value.end()); } else { auto programPath = TC.getDriver().getSwiftProgramPath(); runtimeLibPath.append(programPath.begin(), programPath.end()); llvm::sys::path::remove_filename(runtimeLibPath); // remove /swift llvm::sys::path::remove_filename(runtimeLibPath); // remove /bin llvm::sys::path::append(runtimeLibPath, "lib", "swift"); } llvm::sys::path::append(runtimeLibPath, getPlatformNameForTriple(TC.getTriple())); }
void SanitizerArgs::filterUnsupportedMask(const ToolChain &TC, unsigned &Kinds, unsigned Mask, const llvm::opt::ArgList &Args, const llvm::opt::Arg *A, bool DiagnoseErrors, unsigned &DiagnosedKinds) { unsigned MaskedKinds = Kinds & Mask; if (!MaskedKinds) return; Kinds &= ~Mask; // Do we have new kinds to diagnose? if (DiagnoseErrors && (DiagnosedKinds & MaskedKinds) != MaskedKinds) { // Only diagnose the new kinds. std::string Desc = describeSanitizeArg(Args, A, MaskedKinds & ~DiagnosedKinds); TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) << Desc << TC.getTriple().str(); DiagnosedKinds |= MaskedKinds; } }
void tools::AddRunTimeLibs(const ToolChain &TC, const Driver &D, ArgStringList &CmdArgs, const ArgList &Args) { // Make use of compiler-rt if --rtlib option is used ToolChain::RuntimeLibType RLT = TC.GetRuntimeLibType(Args); switch (RLT) { case ToolChain::RLT_CompilerRT: CmdArgs.push_back(TC.getCompilerRTArgString(Args, "builtins")); break; case ToolChain::RLT_Libgcc: // Make sure libgcc is not used under MSVC environment by default if (TC.getTriple().isKnownWindowsMSVCEnvironment()) { // Issue error diagnostic if libgcc is explicitly specified // through command line as --rtlib option argument. if (Args.hasArg(options::OPT_rtlib_EQ)) { TC.getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform) << Args.getLastArg(options::OPT_rtlib_EQ)->getValue() << "MSVC"; } } else AddLibgcc(TC.getTriple(), D, CmdArgs, Args); break; } }
void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { if (!Kind) return; const Driver &D = TC.getDriver(); SmallString<256> SanitizeOpt("-fsanitize="); #define SANITIZER(NAME, ID) \ if (Kind & ID) \ SanitizeOpt += NAME ","; #include "clang/Basic/Sanitizers.def" SanitizeOpt.pop_back(); CmdArgs.push_back(Args.MakeArgString(SanitizeOpt)); if (!BlacklistFile.empty()) { SmallString<64> BlacklistOpt("-fsanitize-blacklist="); BlacklistOpt += BlacklistFile; CmdArgs.push_back(Args.MakeArgString(BlacklistOpt)); } if (MsanTrackOrigins) CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins")); if (needsAsanRt()) { if (hasAsanZeroBaseShadow(TC)) { CmdArgs.push_back( Args.MakeArgString("-fsanitize-address-zero-base-shadow")); } else if (TC.getTriple().getEnvironment() == llvm::Triple::Android) { // Zero-base shadow is a requirement on Android. D.Diag(diag::err_drv_argument_not_allowed_with) << "-fno-sanitize-address-zero-base-shadow" << lastArgumentForKind(D, Args, Address); } } // Workaround for PR16386. if (needsMsanRt()) CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new")); }
SanitizerArgs::SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args) { clear(); unsigned AllAdd = 0; // All kinds of sanitizers that were turned on // at least once (possibly, disabled further). unsigned AllRemove = 0; // During the loop below, the accumulated set of // sanitizers disabled by the current sanitizer // argument or any argument after it. unsigned DiagnosedKinds = 0; // All Kinds we have diagnosed up to now. // Used to deduplicate diagnostics. const Driver &D = TC.getDriver(); for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); I != E; ++I) { unsigned Add, Remove; if (!parse(D, Args, *I, Add, Remove, true)) continue; (*I)->claim(); AllAdd |= expandGroups(Add); AllRemove |= expandGroups(Remove); // Avoid diagnosing any sanitizer which is disabled later. Add &= ~AllRemove; // At this point we have not expanded groups, so any unsupported sanitizers // in Add are those which have been explicitly enabled. Diagnose them. Add = filterUnsupportedKinds(TC, Add, Args, *I, /*DiagnoseErrors=*/true, DiagnosedKinds); Add = expandGroups(Add); // Group expansion may have enabled a sanitizer which is disabled later. Add &= ~AllRemove; // Silently discard any unsupported sanitizers implicitly enabled through // group expansion. Add = filterUnsupportedKinds(TC, Add, Args, *I, /*DiagnoseErrors=*/false, DiagnosedKinds); Kind |= Add; } UbsanTrapOnError = Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error, options::OPT_fno_sanitize_undefined_trap_on_error, false); // Warn about undefined sanitizer options that require runtime support. if (UbsanTrapOnError && notAllowedWithTrap()) { D.Diag(diag::err_drv_argument_not_allowed_with) << lastArgumentForKind(D, Args, NotAllowedWithTrap) << "-fsanitize-undefined-trap-on-error"; } // Only one runtime library can be used at once. bool NeedsAsan = needsAsanRt(); bool NeedsTsan = needsTsanRt(); bool NeedsMsan = needsMsanRt(); bool NeedsLsan = needsLeakDetection(); if (NeedsAsan && NeedsTsan) D.Diag(diag::err_drv_argument_not_allowed_with) << lastArgumentForKind(D, Args, NeedsAsanRt) << lastArgumentForKind(D, Args, NeedsTsanRt); if (NeedsAsan && NeedsMsan) D.Diag(diag::err_drv_argument_not_allowed_with) << lastArgumentForKind(D, Args, NeedsAsanRt) << lastArgumentForKind(D, Args, NeedsMsanRt); if (NeedsTsan && NeedsMsan) D.Diag(diag::err_drv_argument_not_allowed_with) << lastArgumentForKind(D, Args, NeedsTsanRt) << lastArgumentForKind(D, Args, NeedsMsanRt); if (NeedsLsan && NeedsTsan) D.Diag(diag::err_drv_argument_not_allowed_with) << lastArgumentForKind(D, Args, NeedsLeakDetection) << lastArgumentForKind(D, Args, NeedsTsanRt); if (NeedsLsan && NeedsMsan) D.Diag(diag::err_drv_argument_not_allowed_with) << lastArgumentForKind(D, Args, NeedsLeakDetection) << lastArgumentForKind(D, Args, NeedsMsanRt); // FIXME: Currently -fsanitize=leak is silently ignored in the presence of // -fsanitize=address. Perhaps it should print an error, or perhaps // -f(-no)sanitize=leak should change whether leak detection is enabled by // default in ASan? // Parse -f(no-)sanitize-blacklist options. if (Arg *BLArg = Args.getLastArg(options::OPT_fsanitize_blacklist, options::OPT_fno_sanitize_blacklist)) { if (BLArg->getOption().matches(options::OPT_fsanitize_blacklist)) { std::string BLPath = BLArg->getValue(); if (llvm::sys::fs::exists(BLPath)) { // Validate the blacklist format. std::string BLError; std::unique_ptr<llvm::SpecialCaseList> SCL( llvm::SpecialCaseList::create(BLPath, BLError)); if (!SCL.get()) D.Diag(diag::err_drv_malformed_sanitizer_blacklist) << BLError; else BlacklistFile = BLPath; } else { D.Diag(diag::err_drv_no_such_file) << BLPath; } } } else { // If no -fsanitize-blacklist option is specified, try to look up for // blacklist in the resource directory. std::string BLPath; if (getDefaultBlacklistForKind(D, Kind, BLPath) && llvm::sys::fs::exists(BLPath)) BlacklistFile = BLPath; } // Parse -f[no-]sanitize-memory-track-origins[=level] options. if (NeedsMsan) { if (Arg *A = Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ, options::OPT_fsanitize_memory_track_origins, options::OPT_fno_sanitize_memory_track_origins)) { if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) { MsanTrackOrigins = 1; } else if (A->getOption().matches( options::OPT_fno_sanitize_memory_track_origins)) { MsanTrackOrigins = 0; } else { StringRef S = A->getValue(); if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 || MsanTrackOrigins > 2) { D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << S; } } } } if (NeedsAsan) { AsanSharedRuntime = Args.hasArg(options::OPT_shared_libasan) || (TC.getTriple().getEnvironment() == llvm::Triple::Android); AsanZeroBaseShadow = (TC.getTriple().getEnvironment() == llvm::Triple::Android); } }
SanitizerArgs::SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args) { clear(); SanitizerMask AllRemove = 0; // During the loop below, the accumulated set of // sanitizers disabled by the current sanitizer // argument or any argument after it. SanitizerMask AllAddedKinds = 0; // Mask of all sanitizers ever enabled by // -fsanitize= flags (directly or via group // expansion), some of which may be disabled // later. Used to carefully prune // unused-argument diagnostics. SanitizerMask DiagnosedKinds = 0; // All Kinds we have diagnosed up to now. // Used to deduplicate diagnostics. SanitizerMask Kinds = 0; const SanitizerMask Supported = setGroupBits(TC.getSupportedSanitizers()); ToolChain::RTTIMode RTTIMode = TC.getRTTIMode(); const Driver &D = TC.getDriver(); SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args); SanitizerMask InvalidTrappingKinds = TrappingKinds & NotAllowedWithTrap; for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); I != E; ++I) { const auto *Arg = *I; if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) { Arg->claim(); SanitizerMask Add = parseArgValues(D, Arg, true); AllAddedKinds |= expandSanitizerGroups(Add); // Avoid diagnosing any sanitizer which is disabled later. Add &= ~AllRemove; // At this point we have not expanded groups, so any unsupported // sanitizers in Add are those which have been explicitly enabled. // Diagnose them. if (SanitizerMask KindsToDiagnose = Add & InvalidTrappingKinds & ~DiagnosedKinds) { std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); D.Diag(diag::err_drv_argument_not_allowed_with) << Desc << "-fsanitize-trap=undefined"; DiagnosedKinds |= KindsToDiagnose; } Add &= ~InvalidTrappingKinds; if (SanitizerMask KindsToDiagnose = Add & ~Supported & ~DiagnosedKinds) { std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); D.Diag(diag::err_drv_unsupported_opt_for_target) << Desc << TC.getTriple().str(); DiagnosedKinds |= KindsToDiagnose; } Add &= Supported; // Test for -fno-rtti + explicit -fsanitizer=vptr before expanding groups // so we don't error out if -fno-rtti and -fsanitize=undefined were // passed. if (Add & Vptr && (RTTIMode == ToolChain::RM_DisabledImplicitly || RTTIMode == ToolChain::RM_DisabledExplicitly)) { if (RTTIMode == ToolChain::RM_DisabledImplicitly) // Warn about not having rtti enabled if the vptr sanitizer is // explicitly enabled D.Diag(diag::warn_drv_disabling_vptr_no_rtti_default); else { const llvm::opt::Arg *NoRTTIArg = TC.getRTTIArg(); assert(NoRTTIArg && "RTTI disabled explicitly but we have no argument!"); D.Diag(diag::err_drv_argument_not_allowed_with) << "-fsanitize=vptr" << NoRTTIArg->getAsString(Args); } // Take out the Vptr sanitizer from the enabled sanitizers AllRemove |= Vptr; } Add = expandSanitizerGroups(Add); // Group expansion may have enabled a sanitizer which is disabled later. Add &= ~AllRemove; // Silently discard any unsupported sanitizers implicitly enabled through // group expansion. Add &= ~InvalidTrappingKinds; Add &= Supported; Kinds |= Add; } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) { Arg->claim(); SanitizerMask Remove = parseArgValues(D, Arg, true); AllRemove |= expandSanitizerGroups(Remove); } } // We disable the vptr sanitizer if it was enabled by group expansion but RTTI // is disabled. if ((Kinds & Vptr) && (RTTIMode == ToolChain::RM_DisabledImplicitly || RTTIMode == ToolChain::RM_DisabledExplicitly)) { Kinds &= ~Vptr; } // Check that LTO is enabled if we need it. if ((Kinds & NeedsLTO) && !D.isUsingLTO()) { D.Diag(diag::err_drv_argument_only_allowed_with) << lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto"; } // Report error if there are non-trapping sanitizers that require // c++abi-specific parts of UBSan runtime, and they are not provided by the // toolchain. We don't have a good way to check the latter, so we just // check if the toolchan supports vptr. if (~Supported & Vptr) { SanitizerMask KindsToDiagnose = Kinds & ~TrappingKinds & NeedsUbsanCxxRt; // The runtime library supports the Microsoft C++ ABI, but only well enough // for CFI. FIXME: Remove this once we support vptr on Windows. if (TC.getTriple().isOSWindows()) KindsToDiagnose &= ~CFI; if (KindsToDiagnose) { SanitizerSet S; S.Mask = KindsToDiagnose; D.Diag(diag::err_drv_unsupported_opt_for_target) << ("-fno-sanitize-trap=" + toString(S)) << TC.getTriple().str(); Kinds &= ~KindsToDiagnose; } } // Warn about incompatible groups of sanitizers. std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = { std::make_pair(Address, Thread), std::make_pair(Address, Memory), std::make_pair(Thread, Memory), std::make_pair(Leak, Thread), std::make_pair(Leak, Memory), std::make_pair(KernelAddress, Address), std::make_pair(KernelAddress, Leak), std::make_pair(KernelAddress, Thread), std::make_pair(KernelAddress, Memory)}; for (auto G : IncompatibleGroups) { SanitizerMask Group = G.first; if (Kinds & Group) { if (SanitizerMask Incompatible = Kinds & G.second) { D.Diag(clang::diag::err_drv_argument_not_allowed_with) << lastArgumentForMask(D, Args, Group) << lastArgumentForMask(D, Args, Incompatible); Kinds &= ~Incompatible; } } } // FIXME: Currently -fsanitize=leak is silently ignored in the presence of // -fsanitize=address. Perhaps it should print an error, or perhaps // -f(-no)sanitize=leak should change whether leak detection is enabled by // default in ASan? // Parse -f(no-)?sanitize-recover flags. SanitizerMask RecoverableKinds = RecoverableByDefault; SanitizerMask DiagnosedUnrecoverableKinds = 0; for (const auto *Arg : Args) { const char *DeprecatedReplacement = nullptr; if (Arg->getOption().matches(options::OPT_fsanitize_recover)) { DeprecatedReplacement = "-fsanitize-recover=undefined,integer"; RecoverableKinds |= expandSanitizerGroups(LegacyFsanitizeRecoverMask); Arg->claim(); } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover)) { DeprecatedReplacement = "-fno-sanitize-recover=undefined,integer"; RecoverableKinds &= ~expandSanitizerGroups(LegacyFsanitizeRecoverMask); Arg->claim(); } else if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) { SanitizerMask Add = parseArgValues(D, Arg, true); // Report error if user explicitly tries to recover from unrecoverable // sanitizer. if (SanitizerMask KindsToDiagnose = Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) { SanitizerSet SetToDiagnose; SetToDiagnose.Mask |= KindsToDiagnose; D.Diag(diag::err_drv_unsupported_option_argument) << Arg->getOption().getName() << toString(SetToDiagnose); DiagnosedUnrecoverableKinds |= KindsToDiagnose; } RecoverableKinds |= expandSanitizerGroups(Add); Arg->claim(); } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) { RecoverableKinds &= ~expandSanitizerGroups(parseArgValues(D, Arg, true)); Arg->claim(); } if (DeprecatedReplacement) { D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args) << DeprecatedReplacement; } } RecoverableKinds &= Kinds; RecoverableKinds &= ~Unrecoverable; TrappingKinds &= Kinds; // Setup blacklist files. // Add default blacklist from resource directory. { std::string BLPath; if (getDefaultBlacklist(D, Kinds, BLPath) && llvm::sys::fs::exists(BLPath)) BlacklistFiles.push_back(BLPath); } // Parse -f(no-)sanitize-blacklist options. for (const auto *Arg : Args) { if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) { Arg->claim(); std::string BLPath = Arg->getValue(); if (llvm::sys::fs::exists(BLPath)) { BlacklistFiles.push_back(BLPath); ExtraDeps.push_back(BLPath); } else D.Diag(clang::diag::err_drv_no_such_file) << BLPath; } else if (Arg->getOption().matches(options::OPT_fno_sanitize_blacklist)) { Arg->claim(); BlacklistFiles.clear(); ExtraDeps.clear(); } } // Validate blacklists format. { std::string BLError; std::unique_ptr<llvm::SpecialCaseList> SCL( llvm::SpecialCaseList::create(BlacklistFiles, BLError)); if (!SCL.get()) D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError; } // Parse -f[no-]sanitize-memory-track-origins[=level] options. if (AllAddedKinds & Memory) { if (Arg *A = Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ, options::OPT_fsanitize_memory_track_origins, options::OPT_fno_sanitize_memory_track_origins)) { if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) { MsanTrackOrigins = 2; } else if (A->getOption().matches( options::OPT_fno_sanitize_memory_track_origins)) { MsanTrackOrigins = 0; } else { StringRef S = A->getValue(); if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 || MsanTrackOrigins > 2) { D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; } } } MsanUseAfterDtor = Args.hasArg(options::OPT_fsanitize_memory_use_after_dtor); NeedPIE |= !(TC.getTriple().isOSLinux() && TC.getTriple().getArch() == llvm::Triple::x86_64); } // Parse -f(no-)?sanitize-coverage flags if coverage is supported by the // enabled sanitizers. if (AllAddedKinds & SupportsCoverage) { for (const auto *Arg : Args) { if (Arg->getOption().matches(options::OPT_fsanitize_coverage)) { Arg->claim(); int LegacySanitizeCoverage; if (Arg->getNumValues() == 1 && !StringRef(Arg->getValue(0)) .getAsInteger(0, LegacySanitizeCoverage) && LegacySanitizeCoverage >= 0 && LegacySanitizeCoverage <= 4) { // TODO: Add deprecation notice for this form. switch (LegacySanitizeCoverage) { case 0: CoverageFeatures = 0; break; case 1: CoverageFeatures = CoverageFunc; break; case 2: CoverageFeatures = CoverageBB; break; case 3: CoverageFeatures = CoverageEdge; break; case 4: CoverageFeatures = CoverageEdge | CoverageIndirCall; break; } continue; } CoverageFeatures |= parseCoverageFeatures(D, Arg); } else if (Arg->getOption().matches(options::OPT_fno_sanitize_coverage)) { Arg->claim(); CoverageFeatures &= ~parseCoverageFeatures(D, Arg); } } } // Choose at most one coverage type: function, bb, or edge. if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageBB)) D.Diag(clang::diag::err_drv_argument_not_allowed_with) << "-fsanitize-coverage=func" << "-fsanitize-coverage=bb"; if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageEdge)) D.Diag(clang::diag::err_drv_argument_not_allowed_with) << "-fsanitize-coverage=func" << "-fsanitize-coverage=edge"; if ((CoverageFeatures & CoverageBB) && (CoverageFeatures & CoverageEdge)) D.Diag(clang::diag::err_drv_argument_not_allowed_with) << "-fsanitize-coverage=bb" << "-fsanitize-coverage=edge"; // Basic block tracing and 8-bit counters require some type of coverage // enabled. int CoverageTypes = CoverageFunc | CoverageBB | CoverageEdge; if ((CoverageFeatures & CoverageTraceBB) && !(CoverageFeatures & CoverageTypes)) D.Diag(clang::diag::err_drv_argument_only_allowed_with) << "-fsanitize-coverage=trace-bb" << "-fsanitize-coverage=(func|bb|edge)"; if ((CoverageFeatures & Coverage8bitCounters) && !(CoverageFeatures & CoverageTypes)) D.Diag(clang::diag::err_drv_argument_only_allowed_with) << "-fsanitize-coverage=8bit-counters" << "-fsanitize-coverage=(func|bb|edge)"; if (AllAddedKinds & Address) { AsanSharedRuntime = Args.hasArg(options::OPT_shared_libasan) || TC.getTriple().isAndroid(); NeedPIE |= TC.getTriple().isAndroid(); if (Arg *A = Args.getLastArg(options::OPT_fsanitize_address_field_padding)) { StringRef S = A->getValue(); // Legal values are 0 and 1, 2, but in future we may add more levels. if (S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 || AsanFieldPadding > 2) { D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; } } if (Arg *WindowsDebugRTArg = Args.getLastArg(options::OPT__SLASH_MTd, options::OPT__SLASH_MT, options::OPT__SLASH_MDd, options::OPT__SLASH_MD, options::OPT__SLASH_LDd, options::OPT__SLASH_LD)) { switch (WindowsDebugRTArg->getOption().getID()) { case options::OPT__SLASH_MTd: case options::OPT__SLASH_MDd: case options::OPT__SLASH_LDd: D.Diag(clang::diag::err_drv_argument_not_allowed_with) << WindowsDebugRTArg->getAsString(Args) << lastArgumentForMask(D, Args, Address); D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime); } } } // Parse -link-cxx-sanitizer flag. LinkCXXRuntimes = Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX(); // Finally, initialize the set of available and recoverable sanitizers. Sanitizers.Mask |= Kinds; RecoverableSanitizers.Mask |= RecoverableKinds; TrapSanitizers.Mask |= TrappingKinds; }
void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, types::ID InputType) const { // Translate available CoverageFeatures to corresponding clang-cc1 flags. // Do it even if Sanitizers.empty() since some forms of coverage don't require // sanitizers. std::pair<int, const char *> CoverageFlags[] = { std::make_pair(CoverageFunc, "-fsanitize-coverage-type=1"), std::make_pair(CoverageBB, "-fsanitize-coverage-type=2"), std::make_pair(CoverageEdge, "-fsanitize-coverage-type=3"), std::make_pair(CoverageIndirCall, "-fsanitize-coverage-indirect-calls"), std::make_pair(CoverageTraceBB, "-fsanitize-coverage-trace-bb"), std::make_pair(CoverageTraceCmp, "-fsanitize-coverage-trace-cmp"), std::make_pair(CoverageTraceDiv, "-fsanitize-coverage-trace-div"), std::make_pair(CoverageTraceGep, "-fsanitize-coverage-trace-gep"), std::make_pair(Coverage8bitCounters, "-fsanitize-coverage-8bit-counters"), std::make_pair(CoverageTracePC, "-fsanitize-coverage-trace-pc")}; for (auto F : CoverageFlags) { if (CoverageFeatures & F.first) CmdArgs.push_back(Args.MakeArgString(F.second)); } if (TC.getTriple().isOSWindows() && needsUbsanRt()) { // Instruct the code generator to embed linker directives in the object file // that cause the required runtime libraries to be linked. CmdArgs.push_back(Args.MakeArgString( "--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone"))); if (types::isCXX(InputType)) CmdArgs.push_back(Args.MakeArgString( "--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone_cxx"))); } if (TC.getTriple().isOSWindows() && needsStatsRt()) { CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" + TC.getCompilerRT(Args, "stats_client"))); // The main executable must export the stats runtime. // FIXME: Only exporting from the main executable (e.g. based on whether the // translation unit defines main()) would save a little space, but having // multiple copies of the runtime shouldn't hurt. CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" + TC.getCompilerRT(Args, "stats"))); addIncludeLinkerOption(TC, Args, CmdArgs, "__sanitizer_stats_register"); } if (Sanitizers.empty()) return; CmdArgs.push_back(Args.MakeArgString("-fsanitize=" + toString(Sanitizers))); if (!RecoverableSanitizers.empty()) CmdArgs.push_back(Args.MakeArgString("-fsanitize-recover=" + toString(RecoverableSanitizers))); if (!TrapSanitizers.empty()) CmdArgs.push_back( Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers))); for (const auto &BLPath : BlacklistFiles) { SmallString<64> BlacklistOpt("-fsanitize-blacklist="); BlacklistOpt += BLPath; CmdArgs.push_back(Args.MakeArgString(BlacklistOpt)); } for (const auto &Dep : ExtraDeps) { SmallString<64> ExtraDepOpt("-fdepfile-entry="); ExtraDepOpt += Dep; CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt)); } if (MsanTrackOrigins) CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" + llvm::utostr(MsanTrackOrigins))); if (MsanUseAfterDtor) CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-use-after-dtor")); if (CfiCrossDso) CmdArgs.push_back(Args.MakeArgString("-fsanitize-cfi-cross-dso")); if (Stats) CmdArgs.push_back(Args.MakeArgString("-fsanitize-stats")); if (AsanFieldPadding) CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" + llvm::utostr(AsanFieldPadding))); if (AsanUseAfterScope) CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-use-after-scope")); // MSan: Workaround for PR16386. // ASan: This is mainly to help LSan with cases such as // https://code.google.com/p/address-sanitizer/issues/detail?id=373 // We can't make this conditional on -fsanitize=leak, as that flag shouldn't // affect compilation. if (Sanitizers.has(Memory) || Sanitizers.has(Address)) CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new")); // Require -fvisibility= flag on non-Windows when compiling if vptr CFI is // enabled. if (Sanitizers.hasOneOf(CFIClasses) && !TC.getTriple().isOSWindows() && !Args.hasArg(options::OPT_fvisibility_EQ)) { TC.getDriver().Diag(clang::diag::err_drv_argument_only_allowed_with) << lastArgumentForMask(TC.getDriver(), Args, Sanitizers.Mask & CFIClasses) << "-fvisibility="; } }
/// Parses the various -fpic/-fPIC/-fpie/-fPIE arguments. Then, /// smooshes them together with platform defaults, to decide whether /// this compile should be using PIC mode or not. Returns a tuple of /// (RelocationModel, PICLevel, IsPIE). std::tuple<llvm::Reloc::Model, unsigned, bool> tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) { const llvm::Triple &EffectiveTriple = ToolChain.getEffectiveTriple(); const llvm::Triple &Triple = ToolChain.getTriple(); bool PIE = ToolChain.isPIEDefault(); bool PIC = PIE || ToolChain.isPICDefault(); // The Darwin/MachO default to use PIC does not apply when using -static. if (Triple.isOSBinFormatMachO() && Args.hasArg(options::OPT_static)) PIE = PIC = false; bool IsPICLevelTwo = PIC; bool KernelOrKext = Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); // Android-specific defaults for PIC/PIE if (Triple.isAndroid()) { switch (Triple.getArch()) { case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: case llvm::Triple::aarch64: case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: PIC = true; // "-fpic" break; case llvm::Triple::x86: case llvm::Triple::x86_64: PIC = true; // "-fPIC" IsPICLevelTwo = true; break; default: break; } } // OpenBSD-specific defaults for PIE if (Triple.getOS() == llvm::Triple::OpenBSD) { switch (ToolChain.getArch()) { case llvm::Triple::arm: case llvm::Triple::aarch64: case llvm::Triple::mips64: case llvm::Triple::mips64el: case llvm::Triple::x86: case llvm::Triple::x86_64: IsPICLevelTwo = false; // "-fpie" break; case llvm::Triple::ppc: case llvm::Triple::sparc: case llvm::Triple::sparcel: case llvm::Triple::sparcv9: IsPICLevelTwo = true; // "-fPIE" break; default: break; } } // The last argument relating to either PIC or PIE wins, and no // other argument is used. If the last argument is any flavor of the // '-fno-...' arguments, both PIC and PIE are disabled. Any PIE // option implicitly enables PIC at the same level. Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, options::OPT_fpic, options::OPT_fno_pic, options::OPT_fPIE, options::OPT_fno_PIE, options::OPT_fpie, options::OPT_fno_pie); if (Triple.isOSWindows() && LastPICArg && LastPICArg == Args.getLastArg(options::OPT_fPIC, options::OPT_fpic, options::OPT_fPIE, options::OPT_fpie)) { ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) << LastPICArg->getSpelling() << Triple.str(); if (Triple.getArch() == llvm::Triple::x86_64) return std::make_tuple(llvm::Reloc::PIC_, 2U, false); return std::make_tuple(llvm::Reloc::Static, 0U, false); } // Check whether the tool chain trumps the PIC-ness decision. If the PIC-ness // is forced, then neither PIC nor PIE flags will have no effect. if (!ToolChain.isPICDefaultForced()) { if (LastPICArg) { Option O = LastPICArg->getOption(); if (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) || O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) { PIE = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie); PIC = PIE || O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic); IsPICLevelTwo = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fPIC); } else { PIE = PIC = false; if (EffectiveTriple.isPS4CPU()) { Arg *ModelArg = Args.getLastArg(options::OPT_mcmodel_EQ); StringRef Model = ModelArg ? ModelArg->getValue() : ""; if (Model != "kernel") { PIC = true; ToolChain.getDriver().Diag(diag::warn_drv_ps4_force_pic) << LastPICArg->getSpelling(); } } } } } // Introduce a Darwin and PS4-specific hack. If the default is PIC, but the // PIC level would've been set to level 1, force it back to level 2 PIC // instead. if (PIC && (Triple.isOSDarwin() || EffectiveTriple.isPS4CPU())) IsPICLevelTwo |= ToolChain.isPICDefault(); // This kernel flags are a trump-card: they will disable PIC/PIE // generation, independent of the argument order. if (KernelOrKext && ((!EffectiveTriple.isiOS() || EffectiveTriple.isOSVersionLT(6)) && !EffectiveTriple.isWatchOS())) PIC = PIE = false; if (Arg *A = Args.getLastArg(options::OPT_mdynamic_no_pic)) { // This is a very special mode. It trumps the other modes, almost no one // uses it, and it isn't even valid on any OS but Darwin. if (!Triple.isOSDarwin()) ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) << A->getSpelling() << Triple.str(); // FIXME: Warn when this flag trumps some other PIC or PIE flag. // Only a forced PIC mode can cause the actual compile to have PIC defines // etc., no flags are sufficient. This behavior was selected to closely // match that of llvm-gcc and Apple GCC before that. PIC = ToolChain.isPICDefault() && ToolChain.isPICDefaultForced(); return std::make_tuple(llvm::Reloc::DynamicNoPIC, PIC ? 2U : 0U, false); } bool EmbeddedPISupported; switch (Triple.getArch()) { case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: EmbeddedPISupported = true; break; default: EmbeddedPISupported = false; break; } bool ROPI = false, RWPI = false; Arg* LastROPIArg = Args.getLastArg(options::OPT_fropi, options::OPT_fno_ropi); if (LastROPIArg && LastROPIArg->getOption().matches(options::OPT_fropi)) { if (!EmbeddedPISupported) ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) << LastROPIArg->getSpelling() << Triple.str(); ROPI = true; } Arg *LastRWPIArg = Args.getLastArg(options::OPT_frwpi, options::OPT_fno_rwpi); if (LastRWPIArg && LastRWPIArg->getOption().matches(options::OPT_frwpi)) { if (!EmbeddedPISupported) ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) << LastRWPIArg->getSpelling() << Triple.str(); RWPI = true; } // ROPI and RWPI are not comaptible with PIC or PIE. if ((ROPI || RWPI) && (PIC || PIE)) ToolChain.getDriver().Diag(diag::err_drv_ropi_rwpi_incompatible_with_pic); // When targettng MIPS64 with N64, the default is PIC, unless -mno-abicalls is // used. if ((Triple.getArch() == llvm::Triple::mips64 || Triple.getArch() == llvm::Triple::mips64el) && Args.hasArg(options::OPT_mno_abicalls)) return std::make_tuple(llvm::Reloc::Static, 0U, false); if (PIC) return std::make_tuple(llvm::Reloc::PIC_, IsPICLevelTwo ? 2U : 1U, PIE); llvm::Reloc::Model RelocM = llvm::Reloc::Static; if (ROPI && RWPI) RelocM = llvm::Reloc::ROPI_RWPI; else if (ROPI) RelocM = llvm::Reloc::ROPI; else if (RWPI) RelocM = llvm::Reloc::RWPI; return std::make_tuple(RelocM, 0U, false); }
void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, ArgStringList &CmdArgs, bool IsThinLTO, const Driver &D) { // Tell the linker to load the plugin. This has to come before AddLinkerInputs // as gold requires -plugin to come before any -plugin-opt that -Wl might // forward. CmdArgs.push_back("-plugin"); #if defined(LLVM_ON_WIN32) const char *Suffix = ".dll"; #elif defined(__APPLE__) const char *Suffix = ".dylib"; #else const char *Suffix = ".so"; #endif SmallString<1024> Plugin; llvm::sys::path::native(Twine(ToolChain.getDriver().Dir) + "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold" + Suffix, Plugin); CmdArgs.push_back(Args.MakeArgString(Plugin)); // Try to pass driver level flags relevant to LTO code generation down to // the plugin. // Handle flags for selecting CPU variants. std::string CPU = getCPUName(Args, ToolChain.getTriple()); if (!CPU.empty()) CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU)); if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { StringRef OOpt; if (A->getOption().matches(options::OPT_O4) || A->getOption().matches(options::OPT_Ofast)) OOpt = "3"; else if (A->getOption().matches(options::OPT_O)) OOpt = A->getValue(); else if (A->getOption().matches(options::OPT_O0)) OOpt = "0"; if (!OOpt.empty()) CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=O") + OOpt)); } if (IsThinLTO) CmdArgs.push_back("-plugin-opt=thinlto"); if (unsigned Parallelism = getLTOParallelism(Args, D)) CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=jobs=") + llvm::to_string(Parallelism))); // If an explicit debugger tuning argument appeared, pass it along. if (Arg *A = Args.getLastArg(options::OPT_gTune_Group, options::OPT_ggdbN_Group)) { if (A->getOption().matches(options::OPT_glldb)) CmdArgs.push_back("-plugin-opt=-debugger-tune=lldb"); else if (A->getOption().matches(options::OPT_gsce)) CmdArgs.push_back("-plugin-opt=-debugger-tune=sce"); else CmdArgs.push_back("-plugin-opt=-debugger-tune=gdb"); } bool UseSeparateSections = isUseSeparateSections(ToolChain.getEffectiveTriple()); if (Args.hasFlag(options::OPT_ffunction_sections, options::OPT_fno_function_sections, UseSeparateSections)) { CmdArgs.push_back("-plugin-opt=-function-sections"); } if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections, UseSeparateSections)) { CmdArgs.push_back("-plugin-opt=-data-sections"); } if (Arg *A = getLastProfileSampleUseArg(Args)) { StringRef FName = A->getValue(); if (!llvm::sys::fs::exists(FName)) D.Diag(diag::err_drv_no_such_file) << FName; else CmdArgs.push_back( Args.MakeArgString(Twine("-plugin-opt=sample-profile=") + FName)); } // Need this flag to turn on new pass manager via Gold plugin. if (Args.hasFlag(options::OPT_fexperimental_new_pass_manager, options::OPT_fno_experimental_new_pass_manager, /* Default */ false)) { CmdArgs.push_back("-plugin-opt=new-pass-manager"); } }
SanitizerArgs::SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args) { SanitizerMask AllRemove = 0; // During the loop below, the accumulated set of // sanitizers disabled by the current sanitizer // argument or any argument after it. SanitizerMask AllAddedKinds = 0; // Mask of all sanitizers ever enabled by // -fsanitize= flags (directly or via group // expansion), some of which may be disabled // later. Used to carefully prune // unused-argument diagnostics. SanitizerMask DiagnosedKinds = 0; // All Kinds we have diagnosed up to now. // Used to deduplicate diagnostics. SanitizerMask Kinds = 0; const SanitizerMask Supported = setGroupBits(TC.getSupportedSanitizers()); ToolChain::RTTIMode RTTIMode = TC.getRTTIMode(); const Driver &D = TC.getDriver(); SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args); SanitizerMask InvalidTrappingKinds = TrappingKinds & NotAllowedWithTrap; MinimalRuntime = Args.hasFlag(options::OPT_fsanitize_minimal_runtime, options::OPT_fno_sanitize_minimal_runtime, MinimalRuntime); // The object size sanitizer should not be enabled at -O0. Arg *OptLevel = Args.getLastArg(options::OPT_O_Group); bool RemoveObjectSizeAtO0 = !OptLevel || OptLevel->getOption().matches(options::OPT_O0); for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); I != E; ++I) { const auto *Arg = *I; if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) { Arg->claim(); SanitizerMask Add = parseArgValues(D, Arg, /*AllowGroups=*/true); if (RemoveObjectSizeAtO0) { AllRemove |= SanitizerKind::ObjectSize; // The user explicitly enabled the object size sanitizer. Warn that // that this does nothing at -O0. if (Add & SanitizerKind::ObjectSize) D.Diag(diag::warn_drv_object_size_disabled_O0) << Arg->getAsString(Args); } AllAddedKinds |= expandSanitizerGroups(Add); // Avoid diagnosing any sanitizer which is disabled later. Add &= ~AllRemove; // At this point we have not expanded groups, so any unsupported // sanitizers in Add are those which have been explicitly enabled. // Diagnose them. if (SanitizerMask KindsToDiagnose = Add & InvalidTrappingKinds & ~DiagnosedKinds) { std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); D.Diag(diag::err_drv_argument_not_allowed_with) << Desc << "-fsanitize-trap=undefined"; DiagnosedKinds |= KindsToDiagnose; } Add &= ~InvalidTrappingKinds; if (MinimalRuntime) { if (SanitizerMask KindsToDiagnose = Add & NotAllowedWithMinimalRuntime & ~DiagnosedKinds) { std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); D.Diag(diag::err_drv_argument_not_allowed_with) << Desc << "-fsanitize-minimal-runtime"; DiagnosedKinds |= KindsToDiagnose; } Add &= ~NotAllowedWithMinimalRuntime; } if (SanitizerMask KindsToDiagnose = Add & ~Supported & ~DiagnosedKinds) { std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); D.Diag(diag::err_drv_unsupported_opt_for_target) << Desc << TC.getTriple().str(); DiagnosedKinds |= KindsToDiagnose; } Add &= Supported; // Test for -fno-rtti + explicit -fsanitizer=vptr before expanding groups // so we don't error out if -fno-rtti and -fsanitize=undefined were // passed. if (Add & Vptr && (RTTIMode == ToolChain::RM_DisabledImplicitly || RTTIMode == ToolChain::RM_DisabledExplicitly)) { if (RTTIMode == ToolChain::RM_DisabledImplicitly) // Warn about not having rtti enabled if the vptr sanitizer is // explicitly enabled D.Diag(diag::warn_drv_disabling_vptr_no_rtti_default); else { const llvm::opt::Arg *NoRTTIArg = TC.getRTTIArg(); assert(NoRTTIArg && "RTTI disabled explicitly but we have no argument!"); D.Diag(diag::err_drv_argument_not_allowed_with) << "-fsanitize=vptr" << NoRTTIArg->getAsString(Args); } // Take out the Vptr sanitizer from the enabled sanitizers AllRemove |= Vptr; } Add = expandSanitizerGroups(Add); // Group expansion may have enabled a sanitizer which is disabled later. Add &= ~AllRemove; // Silently discard any unsupported sanitizers implicitly enabled through // group expansion. Add &= ~InvalidTrappingKinds; if (MinimalRuntime) { Add &= ~NotAllowedWithMinimalRuntime; } Add &= Supported; if (Add & Fuzzer) Add |= FuzzerNoLink; // Enable coverage if the fuzzing flag is set. if (Add & FuzzerNoLink) { CoverageFeatures |= CoverageInline8bitCounters | CoverageIndirCall | CoverageTraceCmp | CoveragePCTable; // Due to TLS differences, stack depth tracking is only enabled on Linux if (TC.getTriple().isOSLinux()) CoverageFeatures |= CoverageStackDepth; } Kinds |= Add; } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) { Arg->claim(); SanitizerMask Remove = parseArgValues(D, Arg, true); AllRemove |= expandSanitizerGroups(Remove); } } // Enable toolchain specific default sanitizers if not explicitly disabled. Kinds |= TC.getDefaultSanitizers() & ~AllRemove; // We disable the vptr sanitizer if it was enabled by group expansion but RTTI // is disabled. if ((Kinds & Vptr) && (RTTIMode == ToolChain::RM_DisabledImplicitly || RTTIMode == ToolChain::RM_DisabledExplicitly)) { Kinds &= ~Vptr; } // Check that LTO is enabled if we need it. if ((Kinds & NeedsLTO) && !D.isUsingLTO()) { D.Diag(diag::err_drv_argument_only_allowed_with) << lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto"; } // Report error if there are non-trapping sanitizers that require // c++abi-specific parts of UBSan runtime, and they are not provided by the // toolchain. We don't have a good way to check the latter, so we just // check if the toolchan supports vptr. if (~Supported & Vptr) { SanitizerMask KindsToDiagnose = Kinds & ~TrappingKinds & NeedsUbsanCxxRt; // The runtime library supports the Microsoft C++ ABI, but only well enough // for CFI. FIXME: Remove this once we support vptr on Windows. if (TC.getTriple().isOSWindows()) KindsToDiagnose &= ~CFI; if (KindsToDiagnose) { SanitizerSet S; S.Mask = KindsToDiagnose; D.Diag(diag::err_drv_unsupported_opt_for_target) << ("-fno-sanitize-trap=" + toString(S)) << TC.getTriple().str(); Kinds &= ~KindsToDiagnose; } } // Warn about incompatible groups of sanitizers. std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = { std::make_pair(Address, Thread), std::make_pair(Address, Memory), std::make_pair(Thread, Memory), std::make_pair(Leak, Thread), std::make_pair(Leak, Memory), std::make_pair(KernelAddress, Address), std::make_pair(KernelAddress, Leak), std::make_pair(KernelAddress, Thread), std::make_pair(KernelAddress, Memory), std::make_pair(Efficiency, Address), std::make_pair(Efficiency, Leak), std::make_pair(Efficiency, Thread), std::make_pair(Efficiency, Memory), std::make_pair(Efficiency, KernelAddress)}; for (auto G : IncompatibleGroups) { SanitizerMask Group = G.first; if (Kinds & Group) { if (SanitizerMask Incompatible = Kinds & G.second) { D.Diag(clang::diag::err_drv_argument_not_allowed_with) << lastArgumentForMask(D, Args, Group) << lastArgumentForMask(D, Args, Incompatible); Kinds &= ~Incompatible; } } } // FIXME: Currently -fsanitize=leak is silently ignored in the presence of // -fsanitize=address. Perhaps it should print an error, or perhaps // -f(-no)sanitize=leak should change whether leak detection is enabled by // default in ASan? // Parse -f(no-)?sanitize-recover flags. SanitizerMask RecoverableKinds = RecoverableByDefault; SanitizerMask DiagnosedUnrecoverableKinds = 0; for (const auto *Arg : Args) { const char *DeprecatedReplacement = nullptr; if (Arg->getOption().matches(options::OPT_fsanitize_recover)) { DeprecatedReplacement = "-fsanitize-recover=undefined,integer' or '-fsanitize-recover=all"; RecoverableKinds |= expandSanitizerGroups(LegacyFsanitizeRecoverMask); Arg->claim(); } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover)) { DeprecatedReplacement = "-fno-sanitize-recover=undefined,integer' or " "'-fno-sanitize-recover=all"; RecoverableKinds &= ~expandSanitizerGroups(LegacyFsanitizeRecoverMask); Arg->claim(); } else if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) { SanitizerMask Add = parseArgValues(D, Arg, true); // Report error if user explicitly tries to recover from unrecoverable // sanitizer. if (SanitizerMask KindsToDiagnose = Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) { SanitizerSet SetToDiagnose; SetToDiagnose.Mask |= KindsToDiagnose; D.Diag(diag::err_drv_unsupported_option_argument) << Arg->getOption().getName() << toString(SetToDiagnose); DiagnosedUnrecoverableKinds |= KindsToDiagnose; } RecoverableKinds |= expandSanitizerGroups(Add); Arg->claim(); } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) { RecoverableKinds &= ~expandSanitizerGroups(parseArgValues(D, Arg, true)); Arg->claim(); } if (DeprecatedReplacement) { D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args) << DeprecatedReplacement; } } RecoverableKinds &= Kinds; RecoverableKinds &= ~Unrecoverable; TrappingKinds &= Kinds; // Setup blacklist files. // Add default blacklist from resource directory. { std::string BLPath; if (getDefaultBlacklist(D, Kinds, BLPath) && llvm::sys::fs::exists(BLPath)) BlacklistFiles.push_back(BLPath); } // Parse -f(no-)sanitize-blacklist options. for (const auto *Arg : Args) { if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) { Arg->claim(); std::string BLPath = Arg->getValue(); if (llvm::sys::fs::exists(BLPath)) { BlacklistFiles.push_back(BLPath); ExtraDeps.push_back(BLPath); } else D.Diag(clang::diag::err_drv_no_such_file) << BLPath; } else if (Arg->getOption().matches(options::OPT_fno_sanitize_blacklist)) { Arg->claim(); BlacklistFiles.clear(); ExtraDeps.clear(); } } // Validate blacklists format. { std::string BLError; std::unique_ptr<llvm::SpecialCaseList> SCL( llvm::SpecialCaseList::create(BlacklistFiles, BLError)); if (!SCL.get()) D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError; } // Parse -f[no-]sanitize-memory-track-origins[=level] options. if (AllAddedKinds & Memory) { if (Arg *A = Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ, options::OPT_fsanitize_memory_track_origins, options::OPT_fno_sanitize_memory_track_origins)) { if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) { MsanTrackOrigins = 2; } else if (A->getOption().matches( options::OPT_fno_sanitize_memory_track_origins)) { MsanTrackOrigins = 0; } else { StringRef S = A->getValue(); if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 || MsanTrackOrigins > 2) { D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; } } } MsanUseAfterDtor = Args.hasFlag(options::OPT_fsanitize_memory_use_after_dtor, options::OPT_fno_sanitize_memory_use_after_dtor, MsanUseAfterDtor); NeedPIE |= !(TC.getTriple().isOSLinux() && TC.getTriple().getArch() == llvm::Triple::x86_64); } else { MsanUseAfterDtor = false; } if (AllAddedKinds & Thread) { TsanMemoryAccess = Args.hasFlag(options::OPT_fsanitize_thread_memory_access, options::OPT_fno_sanitize_thread_memory_access, TsanMemoryAccess); TsanFuncEntryExit = Args.hasFlag(options::OPT_fsanitize_thread_func_entry_exit, options::OPT_fno_sanitize_thread_func_entry_exit, TsanFuncEntryExit); TsanAtomics = Args.hasFlag(options::OPT_fsanitize_thread_atomics, options::OPT_fno_sanitize_thread_atomics, TsanAtomics); } if (AllAddedKinds & CFI) { CfiCrossDso = Args.hasFlag(options::OPT_fsanitize_cfi_cross_dso, options::OPT_fno_sanitize_cfi_cross_dso, false); // Without PIE, external function address may resolve to a PLT record, which // can not be verified by the target module. NeedPIE |= CfiCrossDso; } Stats = Args.hasFlag(options::OPT_fsanitize_stats, options::OPT_fno_sanitize_stats, false); if (MinimalRuntime) { SanitizerMask IncompatibleMask = Kinds & ~setGroupBits(CompatibleWithMinimalRuntime); if (IncompatibleMask) D.Diag(clang::diag::err_drv_argument_not_allowed_with) << "-fsanitize-minimal-runtime" << lastArgumentForMask(D, Args, IncompatibleMask); SanitizerMask NonTrappingCfi = Kinds & CFI & ~TrappingKinds; if (NonTrappingCfi) D.Diag(clang::diag::err_drv_argument_only_allowed_with) << "fsanitize-minimal-runtime" << "fsanitize-trap=cfi"; } // Parse -f(no-)?sanitize-coverage flags if coverage is supported by the // enabled sanitizers. for (const auto *Arg : Args) { if (Arg->getOption().matches(options::OPT_fsanitize_coverage)) { int LegacySanitizeCoverage; if (Arg->getNumValues() == 1 && !StringRef(Arg->getValue(0)) .getAsInteger(0, LegacySanitizeCoverage)) { CoverageFeatures = 0; Arg->claim(); if (LegacySanitizeCoverage != 0) { D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args) << "-fsanitize-coverage=trace-pc-guard"; } continue; } CoverageFeatures |= parseCoverageFeatures(D, Arg); // Disable coverage and not claim the flags if there is at least one // non-supporting sanitizer. if (!(AllAddedKinds & ~AllRemove & ~setGroupBits(SupportsCoverage))) { Arg->claim(); } else { CoverageFeatures = 0; } } else if (Arg->getOption().matches(options::OPT_fno_sanitize_coverage)) { Arg->claim(); CoverageFeatures &= ~parseCoverageFeatures(D, Arg); } } // Choose at most one coverage type: function, bb, or edge. if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageBB)) D.Diag(clang::diag::err_drv_argument_not_allowed_with) << "-fsanitize-coverage=func" << "-fsanitize-coverage=bb"; if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageEdge)) D.Diag(clang::diag::err_drv_argument_not_allowed_with) << "-fsanitize-coverage=func" << "-fsanitize-coverage=edge"; if ((CoverageFeatures & CoverageBB) && (CoverageFeatures & CoverageEdge)) D.Diag(clang::diag::err_drv_argument_not_allowed_with) << "-fsanitize-coverage=bb" << "-fsanitize-coverage=edge"; // Basic block tracing and 8-bit counters require some type of coverage // enabled. if (CoverageFeatures & CoverageTraceBB) D.Diag(clang::diag::warn_drv_deprecated_arg) << "-fsanitize-coverage=trace-bb" << "-fsanitize-coverage=trace-pc-guard"; if (CoverageFeatures & Coverage8bitCounters) D.Diag(clang::diag::warn_drv_deprecated_arg) << "-fsanitize-coverage=8bit-counters" << "-fsanitize-coverage=trace-pc-guard"; int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge; int InstrumentationTypes = CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters; if ((CoverageFeatures & InsertionPointTypes) && !(CoverageFeatures & InstrumentationTypes)) { D.Diag(clang::diag::warn_drv_deprecated_arg) << "-fsanitize-coverage=[func|bb|edge]" << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]"; } // trace-pc w/o func/bb/edge implies edge. if (!(CoverageFeatures & InsertionPointTypes)) { if (CoverageFeatures & (CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters)) CoverageFeatures |= CoverageEdge; if (CoverageFeatures & CoverageStackDepth) CoverageFeatures |= CoverageFunc; } if (AllAddedKinds & Address) { AsanSharedRuntime = Args.hasArg(options::OPT_shared_libasan) || TC.getTriple().isAndroid() || TC.getTriple().isOSFuchsia(); NeedPIE |= TC.getTriple().isAndroid() || TC.getTriple().isOSFuchsia(); if (Arg *A = Args.getLastArg(options::OPT_fsanitize_address_field_padding)) { StringRef S = A->getValue(); // Legal values are 0 and 1, 2, but in future we may add more levels. if (S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 || AsanFieldPadding > 2) { D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; } } if (Arg *WindowsDebugRTArg = Args.getLastArg(options::OPT__SLASH_MTd, options::OPT__SLASH_MT, options::OPT__SLASH_MDd, options::OPT__SLASH_MD, options::OPT__SLASH_LDd, options::OPT__SLASH_LD)) { switch (WindowsDebugRTArg->getOption().getID()) { case options::OPT__SLASH_MTd: case options::OPT__SLASH_MDd: case options::OPT__SLASH_LDd: D.Diag(clang::diag::err_drv_argument_not_allowed_with) << WindowsDebugRTArg->getAsString(Args) << lastArgumentForMask(D, Args, Address); D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime); } } AsanUseAfterScope = Args.hasFlag( options::OPT_fsanitize_address_use_after_scope, options::OPT_fno_sanitize_address_use_after_scope, AsanUseAfterScope); // As a workaround for a bug in gold 2.26 and earlier, dead stripping of // globals in ASan is disabled by default on ELF targets. // See https://sourceware.org/bugzilla/show_bug.cgi?id=19002 AsanGlobalsDeadStripping = !TC.getTriple().isOSBinFormatELF() || TC.getTriple().isOSFuchsia() || Args.hasArg(options::OPT_fsanitize_address_globals_dead_stripping); } else { AsanUseAfterScope = false; } if (AllAddedKinds & SafeStack) { // SafeStack runtime is built into the system on Fuchsia. SafeStackRuntime = !TC.getTriple().isOSFuchsia(); } // Parse -link-cxx-sanitizer flag. LinkCXXRuntimes = Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX(); // Finally, initialize the set of available and recoverable sanitizers. Sanitizers.Mask |= Kinds; RecoverableSanitizers.Mask |= RecoverableKinds; TrapSanitizers.Mask |= TrappingKinds; }
XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { const Driver &D = TC.getDriver(); const llvm::Triple &Triple = TC.getTriple(); if (Args.hasFlag(options::OPT_fxray_instrument, options::OPT_fnoxray_instrument, false)) { if (Triple.getOS() == llvm::Triple::Linux) { switch (Triple.getArch()) { case llvm::Triple::x86_64: case llvm::Triple::arm: case llvm::Triple::aarch64: case llvm::Triple::ppc64le: case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: break; default: D.Diag(diag::err_drv_clang_unsupported) << (std::string(XRayInstrumentOption) + " on " + Triple.str()); } } else if (Triple.getOS() == llvm::Triple::FreeBSD || Triple.getOS() == llvm::Triple::OpenBSD || Triple.getOS() == llvm::Triple::NetBSD) { if (Triple.getArch() != llvm::Triple::x86_64) { D.Diag(diag::err_drv_clang_unsupported) << (std::string(XRayInstrumentOption) + " on " + Triple.str()); } } else { D.Diag(diag::err_drv_clang_unsupported) << (std::string(XRayInstrumentOption) + " on " + Triple.str()); } XRayInstrument = true; if (const Arg *A = Args.getLastArg(options::OPT_fxray_instruction_threshold_, options::OPT_fxray_instruction_threshold_EQ)) { StringRef S = A->getValue(); if (S.getAsInteger(0, InstructionThreshold) || InstructionThreshold < 0) D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; } // By default, the back-end will not emit the lowering for XRay customevent // calls if the function is not instrumented. In the future we will change // this default to be the reverse, but in the meantime we're going to // introduce the new functionality behind a flag. if (Args.hasFlag(options::OPT_fxray_always_emit_customevents, options::OPT_fnoxray_always_emit_customevents, false)) XRayAlwaysEmitCustomEvents = true; if (Args.hasFlag(options::OPT_fxray_always_emit_typedevents, options::OPT_fnoxray_always_emit_typedevents, false)) XRayAlwaysEmitTypedEvents = true; if (!Args.hasFlag(options::OPT_fxray_link_deps, options::OPT_fnoxray_link_deps, true)) XRayRT = false; auto Bundles = Args.getAllArgValues(options::OPT_fxray_instrumentation_bundle); if (Bundles.empty()) InstrumentationBundle.Mask = XRayInstrKind::All; else for (const auto &B : Bundles) { llvm::SmallVector<StringRef, 2> BundleParts; llvm::SplitString(B, BundleParts, ","); for (const auto &P : BundleParts) { // TODO: Automate the generation of the string case table. auto Valid = llvm::StringSwitch<bool>(P) .Cases("none", "all", "function", "custom", true) .Default(false); if (!Valid) { D.Diag(clang::diag::err_drv_invalid_value) << "-fxray-instrumentation-bundle=" << P; continue; } auto Mask = parseXRayInstrValue(P); if (Mask == XRayInstrKind::None) { InstrumentationBundle.clear(); break; } InstrumentationBundle.Mask |= Mask; } } // Validate the always/never attribute files. We also make sure that they // are treated as actual dependencies. for (const auto &Filename : Args.getAllArgValues(options::OPT_fxray_always_instrument)) { if (llvm::sys::fs::exists(Filename)) { AlwaysInstrumentFiles.push_back(Filename); ExtraDeps.push_back(Filename); } else D.Diag(clang::diag::err_drv_no_such_file) << Filename; } for (const auto &Filename : Args.getAllArgValues(options::OPT_fxray_never_instrument)) { if (llvm::sys::fs::exists(Filename)) { NeverInstrumentFiles.push_back(Filename); ExtraDeps.push_back(Filename); } else D.Diag(clang::diag::err_drv_no_such_file) << Filename; } for (const auto &Filename : Args.getAllArgValues(options::OPT_fxray_attr_list)) { if (llvm::sys::fs::exists(Filename)) { AttrListFiles.push_back(Filename); ExtraDeps.push_back(Filename); } else D.Diag(clang::diag::err_drv_no_such_file) << Filename; } // Get the list of modes we want to support. auto SpecifiedModes = Args.getAllArgValues(options::OPT_fxray_modes); if (SpecifiedModes.empty()) llvm::copy(XRaySupportedModes, std::back_inserter(Modes)); else for (const auto &Arg : SpecifiedModes) { // Parse CSV values for -fxray-modes=... llvm::SmallVector<StringRef, 2> ModeParts; llvm::SplitString(Arg, ModeParts, ","); for (const auto &M : ModeParts) if (M == "none") Modes.clear(); else if (M == "all") llvm::copy(XRaySupportedModes, std::back_inserter(Modes)); else Modes.push_back(M); } // Then we want to sort and unique the modes we've collected. llvm::sort(Modes.begin(), Modes.end()); Modes.erase(std::unique(Modes.begin(), Modes.end()), Modes.end()); } }
void arm::getARMTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, const ArgList &Args, ArgStringList &CmdArgs, std::vector<StringRef> &Features, bool ForAS) { const Driver &D = TC.getDriver(); bool KernelOrKext = Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); arm::FloatABI ABI = arm::getARMFloatABI(TC, Args); const Arg *WaCPU = nullptr, *WaFPU = nullptr; const Arg *WaHDiv = nullptr, *WaArch = nullptr; if (!ForAS) { // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these // yet (it uses the -mfloat-abi and -msoft-float options), and it is // stripped out by the ARM target. We should probably pass this a new // -target-option, which is handled by the -cc1/-cc1as invocation. // // FIXME2: For consistency, it would be ideal if we set up the target // machine state the same when using the frontend or the assembler. We don't // currently do that for the assembler, we pass the options directly to the // backend and never even instantiate the frontend TargetInfo. If we did, // and used its handleTargetFeatures hook, then we could ensure the // assembler and the frontend behave the same. // Use software floating point operations? if (ABI == arm::FloatABI::Soft) Features.push_back("+soft-float"); // Use software floating point argument passing? if (ABI != arm::FloatABI::Hard) Features.push_back("+soft-float-abi"); } else { // Here, we make sure that -Wa,-mfpu/cpu/arch/hwdiv will be passed down // to the assembler correctly. for (const Arg *A : Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { StringRef Value = A->getValue(); if (Value.startswith("-mfpu=")) { WaFPU = A; } else if (Value.startswith("-mcpu=")) { WaCPU = A; } else if (Value.startswith("-mhwdiv=")) { WaHDiv = A; } else if (Value.startswith("-march=")) { WaArch = A; } } } // Check -march. ClangAs gives preference to -Wa,-march=. const Arg *ArchArg = Args.getLastArg(options::OPT_march_EQ); StringRef ArchName; if (WaArch) { if (ArchArg) D.Diag(clang::diag::warn_drv_unused_argument) << ArchArg->getAsString(Args); ArchName = StringRef(WaArch->getValue()).substr(7); checkARMArchName(D, WaArch, Args, ArchName, Features, Triple); // FIXME: Set Arch. D.Diag(clang::diag::warn_drv_unused_argument) << WaArch->getAsString(Args); } else if (ArchArg) { ArchName = ArchArg->getValue(); checkARMArchName(D, ArchArg, Args, ArchName, Features, Triple); } // Check -mcpu. ClangAs gives preference to -Wa,-mcpu=. const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ); StringRef CPUName; if (WaCPU) { if (CPUArg) D.Diag(clang::diag::warn_drv_unused_argument) << CPUArg->getAsString(Args); CPUName = StringRef(WaCPU->getValue()).substr(6); checkARMCPUName(D, WaCPU, Args, CPUName, ArchName, Features, Triple); } else if (CPUArg) { CPUName = CPUArg->getValue(); checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, Features, Triple); } // Add CPU features for generic CPUs if (CPUName == "native") { llvm::StringMap<bool> HostFeatures; if (llvm::sys::getHostCPUFeatures(HostFeatures)) for (auto &F : HostFeatures) Features.push_back( Args.MakeArgString((F.second ? "+" : "-") + F.first())); } else if (!CPUName.empty()) { DecodeARMFeaturesFromCPU(D, CPUName, Features); } // Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=. const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ); if (WaFPU) { if (FPUArg) D.Diag(clang::diag::warn_drv_unused_argument) << FPUArg->getAsString(Args); getARMFPUFeatures(D, WaFPU, Args, StringRef(WaFPU->getValue()).substr(6), Features); } else if (FPUArg) { getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features); } // Honor -mhwdiv=. ClangAs gives preference to -Wa,-mhwdiv=. const Arg *HDivArg = Args.getLastArg(options::OPT_mhwdiv_EQ); if (WaHDiv) { if (HDivArg) D.Diag(clang::diag::warn_drv_unused_argument) << HDivArg->getAsString(Args); getARMHWDivFeatures(D, WaHDiv, Args, StringRef(WaHDiv->getValue()).substr(8), Features); } else if (HDivArg) getARMHWDivFeatures(D, HDivArg, Args, HDivArg->getValue(), Features); // Setting -msoft-float effectively disables NEON because of the GCC // implementation, although the same isn't true of VFP or VFP3. if (ABI == arm::FloatABI::Soft) { Features.push_back("-neon"); // Also need to explicitly disable features which imply NEON. Features.push_back("-crypto"); } // En/disable crc code generation. if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) { if (A->getOption().matches(options::OPT_mcrc)) Features.push_back("+crc"); else Features.push_back("-crc"); } // Look for the last occurrence of -mlong-calls or -mno-long-calls. If // neither options are specified, see if we are compiling for kernel/kext and // decide whether to pass "+long-calls" based on the OS and its version. if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, options::OPT_mno_long_calls)) { if (A->getOption().matches(options::OPT_mlong_calls)) Features.push_back("+long-calls"); } else if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(6)) && !Triple.isWatchOS()) { Features.push_back("+long-calls"); } // Generate execute-only output (no data access to code sections). // This only makes sense for the compiler, not for the assembler. if (!ForAS) { // Supported only on ARMv6T2 and ARMv7 and above. // Cannot be combined with -mno-movt or -mlong-calls if (Arg *A = Args.getLastArg(options::OPT_mexecute_only, options::OPT_mno_execute_only)) { if (A->getOption().matches(options::OPT_mexecute_only)) { if (getARMSubArchVersionNumber(Triple) < 7 && llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6T2) D.Diag(diag::err_target_unsupported_execute_only) << Triple.getArchName(); else if (Arg *B = Args.getLastArg(options::OPT_mno_movt)) D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args); // Long calls create constant pool entries and have not yet been fixed up // to play nicely with execute-only. Hence, they cannot be used in // execute-only code for now else if (Arg *B = Args.getLastArg(options::OPT_mlong_calls, options::OPT_mno_long_calls)) { if (B->getOption().matches(options::OPT_mlong_calls)) D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args); } Features.push_back("+execute-only"); } } } // Kernel code has more strict alignment requirements. if (KernelOrKext) Features.push_back("+strict-align"); else if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, options::OPT_munaligned_access)) { if (A->getOption().matches(options::OPT_munaligned_access)) { // No v6M core supports unaligned memory access (v6M ARM ARM A3.2). if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) D.Diag(diag::err_target_unsupported_unaligned) << "v6m"; // v8M Baseline follows on from v6M, so doesn't support unaligned memory // access either. else if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8m_baseline) D.Diag(diag::err_target_unsupported_unaligned) << "v8m.base"; } else Features.push_back("+strict-align"); } else { // Assume pre-ARMv6 doesn't support unaligned accesses. // // ARMv6 may or may not support unaligned accesses depending on the // SCTLR.U bit, which is architecture-specific. We assume ARMv6 // Darwin and NetBSD targets support unaligned accesses, and others don't. // // ARMv7 always has SCTLR.U set to 1, but it has a new SCTLR.A bit // which raises an alignment fault on unaligned accesses. Linux // defaults this bit to 0 and handles it as a system-wide (not // per-process) setting. It is therefore safe to assume that ARMv7+ // Linux targets support unaligned accesses. The same goes for NaCl. // // The above behavior is consistent with GCC. int VersionNum = getARMSubArchVersionNumber(Triple); if (Triple.isOSDarwin() || Triple.isOSNetBSD()) { if (VersionNum < 6 || Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) Features.push_back("+strict-align"); } else if (Triple.isOSLinux() || Triple.isOSNaCl()) { if (VersionNum < 7) Features.push_back("+strict-align"); } else Features.push_back("+strict-align"); } // llvm does not support reserving registers in general. There is support // for reserving r9 on ARM though (defined as a platform-specific register // in ARM EABI). if (Args.hasArg(options::OPT_ffixed_r9)) Features.push_back("+reserve-r9"); // The kext linker doesn't know how to deal with movw/movt. if (KernelOrKext || Args.hasArg(options::OPT_mno_movt)) Features.push_back("+no-movt"); if (Args.hasArg(options::OPT_mno_neg_immediates)) Features.push_back("+no-neg-immediates"); }
// Select the float ABI as determined by -msoft-float, -mhard-float, and // -mfloat-abi=. arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) { const Driver &D = TC.getDriver(); const llvm::Triple &Triple = TC.getEffectiveTriple(); auto SubArch = getARMSubArchVersionNumber(Triple); arm::FloatABI ABI = FloatABI::Invalid; if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, options::OPT_mfloat_abi_EQ)) { if (A->getOption().matches(options::OPT_msoft_float)) { ABI = FloatABI::Soft; } else if (A->getOption().matches(options::OPT_mhard_float)) { ABI = FloatABI::Hard; } else { ABI = llvm::StringSwitch<arm::FloatABI>(A->getValue()) .Case("soft", FloatABI::Soft) .Case("softfp", FloatABI::SoftFP) .Case("hard", FloatABI::Hard) .Default(FloatABI::Invalid); if (ABI == FloatABI::Invalid && !StringRef(A->getValue()).empty()) { D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); ABI = FloatABI::Soft; } } // It is incorrect to select hard float ABI on MachO platforms if the ABI is // "apcs-gnu". if (Triple.isOSBinFormatMachO() && !useAAPCSForMachO(Triple) && ABI == FloatABI::Hard) { D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << Triple.getArchName(); } } // If unspecified, choose the default based on the platform. if (ABI == FloatABI::Invalid) { switch (Triple.getOS()) { case llvm::Triple::Darwin: case llvm::Triple::MacOSX: case llvm::Triple::IOS: case llvm::Triple::TvOS: { // Darwin defaults to "softfp" for v6 and v7. ABI = (SubArch == 6 || SubArch == 7) ? FloatABI::SoftFP : FloatABI::Soft; ABI = Triple.isWatchABI() ? FloatABI::Hard : ABI; break; } case llvm::Triple::WatchOS: ABI = FloatABI::Hard; break; // FIXME: this is invalid for WindowsCE case llvm::Triple::Win32: ABI = FloatABI::Hard; break; case llvm::Triple::NetBSD: switch (Triple.getEnvironment()) { case llvm::Triple::EABIHF: case llvm::Triple::GNUEABIHF: ABI = FloatABI::Hard; break; default: ABI = FloatABI::Soft; break; } break; case llvm::Triple::FreeBSD: switch (Triple.getEnvironment()) { case llvm::Triple::GNUEABIHF: ABI = FloatABI::Hard; break; default: // FreeBSD defaults to soft float ABI = FloatABI::Soft; break; } break; case llvm::Triple::OpenBSD: ABI = FloatABI::Soft; break; default: switch (Triple.getEnvironment()) { case llvm::Triple::GNUEABIHF: case llvm::Triple::MuslEABIHF: case llvm::Triple::EABIHF: ABI = FloatABI::Hard; break; case llvm::Triple::GNUEABI: case llvm::Triple::MuslEABI: case llvm::Triple::EABI: // EABI is always AAPCS, and if it was not marked 'hard', it's softfp ABI = FloatABI::SoftFP; break; case llvm::Triple::Android: ABI = (SubArch == 7) ? FloatABI::SoftFP : FloatABI::Soft; break; default: // Assume "soft", but warn the user we are guessing. if (Triple.isOSBinFormatMachO() && Triple.getSubArch() == llvm::Triple::ARMSubArch_v7em) ABI = FloatABI::Hard; else ABI = FloatABI::Soft; if (Triple.getOS() != llvm::Triple::UnknownOS || !Triple.isOSBinFormatMachO()) D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft"; break; } } } assert(ABI != FloatABI::Invalid && "must select an ABI"); return ABI; }