Reworked as suggested.
  Somehow missed your comments. Thanks, Alexey.

Hi kcc, samsonov,

http://llvm-reviews.chandlerc.com/D2644

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D2644?vs=7166&id=7178#toc

Files:
  lib/Driver/SanitizerArgs.cpp
  lib/Driver/Tools.cpp
  test/Driver/freebsd-sanitizers.c
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 IsLinuxOrFreeBSD = 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 (!(IsLinuxOrFreeBSD && IsX86_64)) {
     filterUnsupportedMask(TC, Kinds, Thread | Memory | DataFlow, Args, A,
                           DiagnoseErrors, DiagnosedKinds);
   }
-  if (!(IsLinux && (IsX86 || IsX86_64))) {
+  if (!(IsLinuxOrFreeBSD && (IsX86 || IsX86_64))) {
     filterUnsupportedMask(TC, Kinds, Function, Args, A, DiagnoseErrors,
                           DiagnosedKinds);
   }
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -224,8 +224,23 @@
   // the link line. We cannot do the same thing because unlike gcov there is a
   // libprofile_rt.so. We used to use the -l:libprofile_rt.a syntax, but that is
   // not supported by old linkers.
-  std::string ProfileRT =
-    std::string(TC.getDriver().Dir) + "/../lib/libprofile_rt.a";
+  SmallString<128> ProfileRT;
+  if (Triple.getOS() == llvm::Triple::FreeBSD) {
+    // The profile runtime is located in the freebsd library directory and has
+    // name "libclang_rt.profile-<ArchName>.a".
+    llvm::sys::path::append(ProfileRT,
+                            TC.getDriver().ResourceDir,
+                            "lib",
+                            "freebsd",
+                            Twine("libclang_rt.profile-") +
+                              TC.getArchName() + ".a");
+  } else {
+    llvm::sys::path::append(ProfileRT,
+                            TC.getDriver().Dir,
+                            "..",
+                            "lib",
+                            "libprofile_rt.a");
+  }
 
   CmdArgs.push_back(Args.MakeArgString(ProfileRT));
 }
@@ -1794,15 +1809,18 @@
   CmdArgs.push_back(Args.MakeArgString(LibProfile));
 }
 
-static void addSanitizerRTLinkFlagsLinux(
+static void addSanitizerRTLinkFlagsLinuxOrFreeBSD(
     const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs,
     const StringRef Sanitizer, bool BeforeLibStdCXX,
     bool ExportSymbols = true) {
-  // Sanitizer runtime is located in the Linux library directory and
+  const bool IsFreeBSD = (TC.getTriple().getOS() == llvm::Triple::FreeBSD);
+
+  // Sanitizer runtime is located in the Linux or FreeBSD library directory and
   // has name "libclang_rt.<Sanitizer>-<ArchName>.a".
   SmallString<128> LibSanitizer(TC.getDriver().ResourceDir);
   llvm::sys::path::append(
-      LibSanitizer, "lib", "linux",
+      LibSanitizer, "lib",
+      IsFreeBSD ? "freebsd" : "linux",
       (Twine("libclang_rt.") + Sanitizer + "-" +
           getArchNameForCompilerRTLib(TC) + ".a"));
 
@@ -1820,19 +1838,25 @@
   CmdArgs.insert(BeforeLibStdCXX ? CmdArgs.begin() : CmdArgs.end(),
                  LibSanitizerArgs.begin(), LibSanitizerArgs.end());
 
-  CmdArgs.push_back("-lpthread");
-  CmdArgs.push_back("-lrt");
-  CmdArgs.push_back("-ldl");
-  CmdArgs.push_back("-lm");
+  if (!IsFreeBSD) {
+    CmdArgs.push_back("-lpthread");
+    CmdArgs.push_back("-lrt");
+    CmdArgs.push_back("-ldl");
+    CmdArgs.push_back("-lm");
+  }
 
   // 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.
   if (ExportSymbols) {
-    if (llvm::sys::fs::exists(LibSanitizer + ".syms"))
+    if (llvm::sys::fs::exists(LibSanitizer + ".syms")) {
       CmdArgs.push_back(
           Args.MakeArgString("--dynamic-list=" + LibSanitizer + ".syms"));
-    else
+    } else if (IsFreeBSD) {
+      if (!Args.hasArg(options::OPT_rdynamic) &&
+          !Args.hasArg(options::OPT_static))
+      CmdArgs.push_back("--export-dynamic");
+    } else
       CmdArgs.push_back("-export-dynamic");
   }
 }
@@ -1849,32 +1873,32 @@
     CmdArgs.insert(CmdArgs.begin(), Args.MakeArgString(LibAsan));
   } else {
     if (!Args.hasArg(options::OPT_shared))
-      addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "asan", true);
+      addSanitizerRTLinkFlagsLinuxOrFreeBSD(TC, Args, CmdArgs, "asan", true);
   }
 }
 
 /// If ThreadSanitizer is enabled, add appropriate linker flags (Linux).
 /// This needs to be called before we add the C run-time (malloc, etc).
 static void addTsanRTLinux(const ToolChain &TC, const ArgList &Args,
                            ArgStringList &CmdArgs) {
   if (!Args.hasArg(options::OPT_shared))
-    addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "tsan", true);
+    addSanitizerRTLinkFlagsLinuxOrFreeBSD(TC, Args, CmdArgs, "tsan", true);
 }
 
 /// If MemorySanitizer is enabled, add appropriate linker flags (Linux).
 /// This needs to be called before we add the C run-time (malloc, etc).
 static void addMsanRTLinux(const ToolChain &TC, const ArgList &Args,
                            ArgStringList &CmdArgs) {
   if (!Args.hasArg(options::OPT_shared))
-    addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "msan", true);
+    addSanitizerRTLinkFlagsLinuxOrFreeBSD(TC, Args, CmdArgs, "msan", true);
 }
 
 /// If LeakSanitizer is enabled, add appropriate linker flags (Linux).
 /// This needs to be called before we add the C run-time (malloc, etc).
 static void addLsanRTLinux(const ToolChain &TC, const ArgList &Args,
                            ArgStringList &CmdArgs) {
   if (!Args.hasArg(options::OPT_shared))
-    addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "lsan", true);
+    addSanitizerRTLinkFlagsLinuxOrFreeBSD(TC, Args, CmdArgs, "lsan", true);
 }
 
 /// If UndefinedBehaviorSanitizer is enabled, add appropriate linker flags
@@ -1885,20 +1909,23 @@
   // Need a copy of sanitizer_common. This could come from another sanitizer
   // runtime; if we're not including one, include our own copy.
   if (!HasOtherSanitizerRt)
-    addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "san", true, false);
+    addSanitizerRTLinkFlagsLinuxOrFreeBSD(TC, Args, CmdArgs,
+                                          "san", true, false);
 
-  addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "ubsan", false);
+  addSanitizerRTLinkFlagsLinuxOrFreeBSD(TC, Args, CmdArgs, "ubsan", false);
 
   // Only include the bits of the runtime which need a C++ ABI library if
   // we're linking in C++ mode.
   if (IsCXX)
-    addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "ubsan_cxx", false);
+    addSanitizerRTLinkFlagsLinuxOrFreeBSD(TC, Args, CmdArgs,
+                                          "ubsan_cxx", false);
 }
 
 static void addDfsanRTLinux(const ToolChain &TC, const ArgList &Args,
                             ArgStringList &CmdArgs) {
   if (!Args.hasArg(options::OPT_shared))
-    addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "dfsan", true);
+    addSanitizerRTLinkFlagsLinuxOrFreeBSD(TC, Args, CmdArgs,
+                                          "dfsan", true);
 }
 
 static bool shouldUseFramePointerForTarget(const ArgList &Args,
@@ -5960,9 +5987,28 @@
                                  const InputInfoList &Inputs,
                                  const ArgList &Args,
                                  const char *LinkingOutput) const {
-  const toolchains::FreeBSD& ToolChain = 
+  const toolchains::FreeBSD &ToolChain =
     static_cast<const toolchains::FreeBSD&>(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"
@@ -5976,7 +6022,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)) {
@@ -6020,13 +6066,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";
@@ -6039,7 +6084,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";
@@ -6064,10 +6109,58 @@
 
   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) {
+    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)
+        addSanitizerRTLinkFlagsLinuxOrFreeBSD(ToolChain, Args, CmdArgs,
+                                              "san", false);
+      addSanitizerRTLinkFlagsLinuxOrFreeBSD(ToolChain, Args, CmdArgs,
+                                            "ubsan", false);
+    }
+    if (Sanitize.needsAsanRt())
+      addSanitizerRTLinkFlagsLinuxOrFreeBSD(ToolChain, Args, CmdArgs,
+                                            "asan", false);
+    if (Sanitize.needsTsanRt())
+      addSanitizerRTLinkFlagsLinuxOrFreeBSD(ToolChain, Args, CmdArgs,
+                                            "tsan", false);
+    if (Sanitize.needsMsanRt())
+      addSanitizerRTLinkFlagsLinuxOrFreeBSD(ToolChain, Args, CmdArgs,
+                                            "msan", false);
+    if (Sanitize.needsLsanRt())
+      addSanitizerRTLinkFlagsLinuxOrFreeBSD(ToolChain, Args, CmdArgs,
+                                            "lsan", false);
+    if (Sanitize.needsDfsanRt())
+      addSanitizerRTLinkFlagsLinuxOrFreeBSD(ToolChain, Args, CmdArgs,
+                                            "dfsan", false);
+
+    if (NeedsDefaultLibs)
+      CmdArgs.push_back("-lrt");
+  }
+
+  // The profile runtime also needs access to system libraries.
+  addProfileRT(ToolChain, Args, CmdArgs, ToolChain.getTriple());
+
+  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.
+    addSanitizerRTLinkFlagsLinuxOrFreeBSD(ToolChain, Args, CmdArgs,
+                                          "ubsan_cxx", false);
+  }
+
+  if (NeedsDefaultLibs) {
     if (D.CCCIsCXX()) {
-      ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
       if (Args.hasArg(options::OPT_pg))
         CmdArgs.push_back("-lm_p");
       else
@@ -6089,7 +6182,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
@@ -6118,19 +6211,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));
 }
 
Index: test/Driver/freebsd-sanitizers.c
===================================================================
--- test/Driver/freebsd-sanitizers.c
+++ test/Driver/freebsd-sanitizers.c
@@ -0,0 +1,32 @@
+
+// RUN: %clang -no-canonical-prefixes -target i386-pc-freebsd \
+// RUN:     -fsanitize=address %s -### 2>&1 | \
+// RUN:   FileCheck --check-prefix=CHECK-ASAN-I386 %s
+// CHECK-ASAN-I386: "-whole-archive" "{{.*}}/lib/freebsd/libclang_rt.asan-i386.a"
+// CHECK-ASAN-I386: "--export-dynamic" "-lrt" "-lgcc"
+
+// RUN: %clang -no-canonical-prefixes -target x86_64-pc-freebsd \
+// RUN:     -fsanitize=address %s -### 2>&1 | \
+// RUN:   FileCheck --check-prefix=CHECK-ASAN-X86_64 %s
+// CHECK-ASAN-X86_64: "-whole-archive" "{{.*}}/lib/freebsd/libclang_rt.asan-x86_64.a"
+// CHECK-ASAN-X86_64: "-lrt" "-lgcc"
+
+// RUN: %clang -no-canonical-prefixes -target i386-pc-freebsd \
+// RUN:     -fsanitize=undefined %s -### 2>&1 | \
+// RUN:   FileCheck --check-prefix=CHECK-UBSAN-I386 %s
+// CHECK-UBSAN-I386: "-whole-archive" "{{.*}}/freebsd/libclang_rt.san-i386.a" "{{.*}}/freebsd/libclang_rt.ubsan-i386.a"
+// CHECK-UBSAN-I386: "-lrt" "-lstdc++"
+
+// RUN: %clang -no-canonical-prefixes -target x86_64-pc-freebsd \
+// RUN:     -fsanitize=undefined %s -### 2>&1 | \
+// RUN:   FileCheck --check-prefix=CHECK-UBSAN-X86_64 %s
+// CHECK-UBSAN-X86_64: "-whole-archive" "{{.*}}/freebsd/libclang_rt.san-x86_64.a" "{{.*}}/freebsd/libclang_rt.ubsan-x86_64.a"
+// CHECK-UBSAN-X86_64: "-lrt" "-lstdc++"
+// CHECK-UBSAN-X86_64-NOT: libclang_rt.ubsan_cxx
+
+// RUN: %clangxx -no-canonical-prefixes -target x86_64-pc-freebsd \
+// RUN:     -fsanitize=undefined %s -### 2>&1 | \
+// RUN:   FileCheck --check-prefix=CHECK-UBSAN-CXX %s
+// CHECK-UBSAN-CXX: "-whole-archive" "{{.*}}/freebsd/libclang_rt.san-x86_64.a" "{{.*}}/freebsd/libclang_rt.ubsan-x86_64.a"
+// CHECK-UBSAN-CXX: "-lrt" "-lstdc++"
+// CHECK-UBSAN-CXX: "-whole-archive" "{{.*}}/freebsd/libclang_rt.ubsan_cxx-x86_64.a"
_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to