Index: lib/Driver/SanitizerArgs.cpp =================================================================== --- lib/Driver/SanitizerArgs.cpp +++ lib/Driver/SanitizerArgs.cpp @@ -246,14 +246,15 @@ const llvm::opt::Arg *A, bool DiagnoseErrors, unsigned &DiagnosedKinds) { - bool IsLinux = TC.getTriple().getOS() == llvm::Triple::Linux; + bool IsPosix = TC.getTriple().getOS() == llvm::Triple::Linux || + TC.getTriple().getOS() == llvm::Triple::FreeBSD; bool IsX86 = TC.getTriple().getArch() == llvm::Triple::x86; bool IsX86_64 = TC.getTriple().getArch() == llvm::Triple::x86_64; - if (!(IsLinux && IsX86_64)) { + if (!(IsPosix && IsX86_64)) { filterUnsupportedMask(TC, Kinds, Thread | Memory | DataFlow, Args, A, DiagnoseErrors, DiagnosedKinds); } - if (!(IsLinux && (IsX86 || IsX86_64))) { + if (!(IsPosix && (IsX86 || IsX86_64))) { filterUnsupportedMask(TC, Kinds, Function, Args, A, DiagnoseErrors, DiagnosedKinds); } Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -1864,6 +1864,53 @@ addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "dfsan", true); } +static void addProfileRTFreeBSD( + const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { + if (!(Args.hasArg(options::OPT_fprofile_arcs) || + Args.hasArg(options::OPT_fprofile_generate) || + Args.hasArg(options::OPT_fcreate_profile) || + Args.hasArg(options::OPT_coverage))) + return; + + // The profile runtime is located in the freebsd library directory and has + // name "libclang_rt.profile-.a". + SmallString<128> LibProfile(TC.getDriver().ResourceDir); + llvm::sys::path::append( + LibProfile, "lib", "freebsd", + Twine("libclang_rt.profile-") + TC.getArchName() + ".a"); + + CmdArgs.push_back(Args.MakeArgString(LibProfile)); +} + +// Append a name of a appropriate Sanitizer library into a list +// of the linker arguments. +// This function returns true if an appropriate .syms file for +// the specified Sanitizer library does exist and has been added into the linker +// argument list to export the proper dynamic symbols; +// otherwise this function returns false. +static bool addSanitizerRTLinkFlagFreeBSD( + const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, + const StringRef Sanitizer) { + // Sanitizer runtime is located in the freebsd library directory and + // has name "libclang_rt.-.a". + SmallString<128> LibSanitizer(TC.getDriver().ResourceDir); + llvm::sys::path::append( + LibSanitizer, "lib", "freebsd", + (Twine("libclang_rt.") + Sanitizer + "-" + TC.getArchName() + ".a")); + + CmdArgs.push_back(Args.MakeArgString(LibSanitizer)); + + // If possible, use a dynamic symbols file to export the symbols from the + // runtime library. If we can't do so, use --export-dynamic instead to export + // all symbols from the binary. + const bool syms = llvm::sys::fs::exists(LibSanitizer + ".syms"); + if (syms) + CmdArgs.push_back( + Args.MakeArgString("--dynamic-list=" + LibSanitizer + ".syms")); + + return syms; +} + static bool shouldUseFramePointerForTarget(const ArgList &Args, const llvm::Triple &Triple) { switch (Triple.getArch()) { @@ -5867,9 +5914,28 @@ const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const toolchains::FreeBSD& ToolChain = + const toolchains::FreeBSD &ToolChain = static_cast(getToolChain()); const Driver &D = ToolChain.getDriver(); + const SanitizerArgs &Sanitize = ToolChain.getSanitizerArgs(); + const bool IsPIE = + !Args.hasArg(options::OPT_shared) && + (Args.hasArg(options::OPT_pie) || Sanitize.hasZeroBaseShadow()); + const bool NeedsDefaultLibs = + !Args.hasArg(options::OPT_nostdlib) && + !Args.hasArg(options::OPT_nodefaultlibs); + const bool NeedsCXXSanRt = + !Args.hasArg(options::OPT_shared) && + (Sanitize.needsAsanRt() || + Sanitize.needsTsanRt() || + Sanitize.needsMsanRt() || + Sanitize.needsLsanRt()); + const bool NeedsUbsanRt = Sanitize.needsUbsanRt(); + const bool NeedsSanRt = NeedsCXXSanRt || Sanitize.needsDfsanRt(); + const bool NeedsCXXStdlib = + NeedsDefaultLibs && + (D.CCCIsCXX() || NeedsUbsanRt); + ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" @@ -5883,7 +5949,7 @@ if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - if (Args.hasArg(options::OPT_pie)) + if (IsPIE) CmdArgs.push_back("-pie"); if (Args.hasArg(options::OPT_static)) { @@ -5927,13 +5993,12 @@ assert(Output.isNothing() && "Invalid output."); } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { + if (NeedsDefaultLibs) { const char *crt1 = NULL; if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) crt1 = "gcrt1.o"; - else if (Args.hasArg(options::OPT_pie)) + else if (IsPIE) crt1 = "Scrt1.o"; else crt1 = "crt1.o"; @@ -5946,7 +6011,7 @@ const char *crtbegin = NULL; if (Args.hasArg(options::OPT_static)) crtbegin = "crtbeginT.o"; - else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) + else if (Args.hasArg(options::OPT_shared) || IsPIE) crtbegin = "crtbeginS.o"; else crtbegin = "crtbegin.o"; @@ -5971,10 +6036,62 @@ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs)) { + // Call these before we add the C++ ABI library. + // Sanitizer runtime may need to come before -lstdc++ (or -lc++, libstdc++.a, + // etc.) so that the linker picks custom versions of the global 'operator + // new' and 'operator delete' symbols. We take the extreme (but simple) + // strategy of inserting it at the front of the link command. It also + // needs to be forced to end up in the executable, so wrap it in + // whole-archive. + if (NeedsSanRt || NeedsUbsanRt) { + CmdArgs.push_back("-whole-archive"); + if (NeedsUbsanRt) { + // Need a copy of sanitizer_common. This could come from another + // sanitizer runtime; if we're not including one, include our own copy. + if (!NeedsSanRt) + addSanitizerRTLinkFlagFreeBSD(ToolChain, Args, CmdArgs, "san"); + addSanitizerRTLinkFlagFreeBSD(ToolChain, Args, CmdArgs, "ubsan"); + } + bool NeedsExportDynamicOpt = false; + NeedsExportDynamicOpt |= (Sanitize.needsAsanRt() && + !addSanitizerRTLinkFlagFreeBSD(ToolChain, Args, CmdArgs, "asan")); + NeedsExportDynamicOpt |= (Sanitize.needsTsanRt() && + !addSanitizerRTLinkFlagFreeBSD(ToolChain, Args, CmdArgs, "tsan")); + NeedsExportDynamicOpt |= (Sanitize.needsMsanRt() && + !addSanitizerRTLinkFlagFreeBSD(ToolChain, Args, CmdArgs, "msan")); + NeedsExportDynamicOpt |= (Sanitize.needsLsanRt() && + !addSanitizerRTLinkFlagFreeBSD(ToolChain, Args, CmdArgs, "lsan")); + NeedsExportDynamicOpt |= (Sanitize.needsDfsanRt() && + !addSanitizerRTLinkFlagFreeBSD(ToolChain, Args, CmdArgs, "dfsan")); + + CmdArgs.push_back("-no-whole-archive"); + + // Force exporting of the dynamic symbols if it was not done before. + if (NeedsExportDynamicOpt && + (!Args.hasArg(options::OPT_rdynamic) && + !Args.hasArg(options::OPT_static))) + CmdArgs.push_back("--export-dynamic"); + + if (NeedsDefaultLibs) + CmdArgs.push_back("-lrt"); + } + + // The profile runtime also needs access to system libraries. + addProfileRTFreeBSD(ToolChain, Args, CmdArgs); + + if (NeedsCXXStdlib) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + + if (NeedsUbsanRt && D.CCCIsCXX()) { + // Only include the bits of the runtime which need a C++ ABI library if + // we're linking in C++ mode. + CmdArgs.push_back("-whole-archive"); + addSanitizerRTLinkFlagFreeBSD(ToolChain, Args, CmdArgs, "ubsan_cxx"); + CmdArgs.push_back("-no-whole-archive"); + } + + if (NeedsDefaultLibs) { if (D.CCCIsCXX()) { - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lm_p"); else @@ -5996,7 +6113,7 @@ CmdArgs.push_back("--no-as-needed"); } - if (Args.hasArg(options::OPT_pthread)) { + if (Args.hasArg(options::OPT_pthread) || NeedsSanRt || NeedsUbsanRt) { if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lpthread_p"); else @@ -6025,19 +6142,15 @@ } } - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nostartfiles)) { - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) + if (NeedsDefaultLibs) { + if (Args.hasArg(options::OPT_shared) || IsPIE) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); else CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } - addProfileRT(ToolChain, Args, CmdArgs, ToolChain.getTriple()); - - const char *Exec = - Args.MakeArgString(ToolChain.GetProgramPath("ld")); + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); }