ADKaster created this revision.
Herald added a project: All.
ADKaster requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay.
Herald added a project: clang.

Adds support for the `$arch-pc-serenity` target to the Clang front end.
This makes the compiler look for libraries and headers in the right
places, and enables some security mitigations like stack-smashing
protection and position-independent code by default.

Depends on D154395 <https://reviews.llvm.org/D154395>


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D154396

Files:
  clang/lib/Basic/Targets.cpp
  clang/lib/Basic/Targets/OSTargets.h
  clang/lib/Driver/CMakeLists.txt
  clang/lib/Driver/Driver.cpp
  clang/lib/Driver/ToolChain.cpp
  clang/lib/Driver/ToolChains/Serenity.cpp
  clang/lib/Driver/ToolChains/Serenity.h

Index: clang/lib/Driver/ToolChains/Serenity.h
===================================================================
--- /dev/null
+++ clang/lib/Driver/ToolChains/Serenity.h
@@ -0,0 +1,100 @@
+//===---- Serenity.h - SerenityOS ToolChain Implementation ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SERENITY_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SERENITY_H
+
+#include "clang/Basic/LangOptions.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+namespace serenity {
+
+class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+public:
+  Linker(const ToolChain &TC) : Tool("serenity::Linker", "linker", TC) {}
+
+  bool hasIntegratedCPP() const override { return false; }
+  bool isLinkJob() const override { return true; }
+
+  void ConstructJob(Compilation &C, const JobAction &JA,
+                    const InputInfo &Output, const InputInfoList &Inputs,
+                    const llvm::opt::ArgList &TCArgs,
+                    const char *LinkingOutput) const override;
+};
+} // end namespace serenity
+} // end namespace tools
+
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY Serenity : public ToolChain {
+public:
+  Serenity(const Driver &D, const llvm::Triple &Triple,
+           const llvm::opt::ArgList &Args);
+
+  void
+  AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+                            llvm::opt::ArgStringList &CC1Args) const override;
+
+  void AddClangCXXStdlibIncludeArgs(
+      const llvm::opt::ArgList &DriverArgs,
+      llvm::opt::ArgStringList &CC1Args) const override;
+
+  RuntimeLibType GetDefaultRuntimeLibType() const override {
+    return ToolChain::RLT_CompilerRT;
+  }
+
+  CXXStdlibType GetDefaultCXXStdlibType() const override {
+    return ToolChain::CST_Libcxx;
+  }
+
+  UnwindLibType GetUnwindLibType(const llvm::opt::ArgList &Args) const override;
+
+  void
+  addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+                        llvm::opt::ArgStringList &CC1Args,
+                        Action::OffloadKind DeviceOffloadKind) const override;
+
+  const char *getDefaultLinker() const override { return "ld.lld"; }
+
+  bool HasNativeLLVMSupport() const override { return true; }
+
+  bool IsIntegratedAssemblerDefault() const override { return true; }
+
+  bool isPICDefault() const override { return true; }
+  bool isPIEDefault(const llvm::opt::ArgList &) const override { return false; }
+  bool isPICDefaultForced() const override { return false; }
+
+  bool IsMathErrnoDefault() const override { return false; }
+
+  UnwindTableLevel
+  getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override {
+    return UnwindTableLevel::Asynchronous;
+  }
+
+  bool useRelaxRelocations() const override { return true; }
+
+  LangOptions::StackProtectorMode
+  GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
+    return LangOptions::SSPStrong;
+  }
+
+  unsigned GetDefaultDwarfVersion() const override { return 5; }
+
+protected:
+  Tool *buildLinker() const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SERENITY_H
Index: clang/lib/Driver/ToolChains/Serenity.cpp
===================================================================
--- /dev/null
+++ clang/lib/Driver/ToolChains/Serenity.cpp
@@ -0,0 +1,336 @@
+//===---- Serenity.cpp - SerenityOS ToolChain Implementation ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Serenity.h"
+#include "CommonArgs.h"
+#include "clang/Config/config.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/SanitizerArgs.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include <string>
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace clang;
+using namespace llvm::opt;
+
+static bool getPIE(const ArgList &Args, const ToolChain &TC) {
+  if (Args.hasArg(options::OPT_static, options::OPT_shared,
+                  options::OPT_static_pie))
+    return false;
+  Arg *Last = Args.getLastArg(options::OPT_pie, options::OPT_no_pie,
+                              options::OPT_nopie);
+  return Last ? Last->getOption().matches(options::OPT_pie) : true;
+}
+
+void tools::serenity::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+                                           const InputInfo &Output,
+                                           const InputInfoList &Inputs,
+                                           const ArgList &Args,
+                                           const char *LinkingOutput) const {
+  const auto &TC = getToolChain();
+  const auto &D = TC.getDriver();
+  const bool IsShared = Args.hasArg(options::OPT_shared);
+  const bool IsStatic =
+      Args.hasArg(options::OPT_static) && !Args.hasArg(options::OPT_static_pie);
+  const bool IsRdynamic = Args.hasArg(options::OPT_rdynamic);
+  const bool IsStaticPIE = Args.hasArg(options::OPT_static_pie);
+  const bool IsPIE = getPIE(Args, TC);
+  ArgStringList CmdArgs;
+
+  if (!D.SysRoot.empty())
+    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+  if (IsPIE || IsStaticPIE)
+    CmdArgs.push_back("-pie");
+
+  if (IsShared)
+    CmdArgs.push_back("-shared");
+
+  if (IsStatic || IsStaticPIE)
+    CmdArgs.push_back("-static");
+
+  if (IsStaticPIE) {
+    CmdArgs.push_back("--no-dynamic-linker");
+    CmdArgs.push_back("-z");
+    CmdArgs.push_back("text");
+  }
+
+  if (!IsStatic && !IsStaticPIE) {
+    if (IsRdynamic)
+      CmdArgs.push_back("-export-dynamic");
+    CmdArgs.push_back("-dynamic-linker");
+    CmdArgs.push_back("/usr/lib/Loader.so");
+  }
+
+  if (!IsStatic || IsStaticPIE)
+    CmdArgs.push_back("--eh-frame-hdr");
+
+  if (Output.isFilename()) {
+    CmdArgs.push_back("-o");
+    CmdArgs.push_back(Output.getFilename());
+  }
+
+  const char *Exec = Args.MakeArgString(TC.GetLinkerPath());
+  auto linkerIs = [Exec](const char *name) {
+    return llvm::sys::path::filename(Exec).equals_insensitive(name) ||
+           llvm::sys::path::stem(Exec).equals_insensitive(name);
+  };
+
+  if (linkerIs("ld.lld") || linkerIs("ld.mold")) {
+    CmdArgs.push_back("--pack-dyn-relocs=relr");
+  } else {
+    CmdArgs.push_back("-z");
+    CmdArgs.push_back("pack-relative-relocs");
+  }
+
+  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+    CmdArgs.push_back(Args.MakeArgString(
+        TC.GetFilePath((IsShared) ? "crt0_shared.o" : "crt0.o")));
+    CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crti.o")));
+
+    std::string crtbegin_path;
+    if (TC.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT) {
+      std::string crtbegin =
+          TC.getCompilerRT(Args, "crtbegin", ToolChain::FT_Object);
+      if (TC.getVFS().exists(crtbegin))
+        crtbegin_path = crtbegin;
+    }
+    if (crtbegin_path.empty()) {
+      const char *crtbegin = (IsShared || IsPIE) ? "crtbeginS.o" : "crtbegin.o";
+      crtbegin_path = TC.GetFilePath(crtbegin);
+    }
+    CmdArgs.push_back(Args.MakeArgString(crtbegin_path));
+  }
+
+  Args.AddAllArgs(CmdArgs, options::OPT_L);
+  Args.AddAllArgs(CmdArgs, options::OPT_u);
+
+  TC.AddFilePathLibArgs(Args, CmdArgs);
+
+  if (D.isUsingLTO()) {
+    assert(!Inputs.empty() && "Must have at least one input.");
+    addLTOOptions(TC, Args, CmdArgs, Output, Inputs[0],
+                  D.getLTOMode() == LTOK_Thin);
+  }
+
+  Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
+  Args.AddAllArgs(CmdArgs, options::OPT_e);
+  Args.AddAllArgs(CmdArgs, options::OPT_s);
+  Args.AddAllArgs(CmdArgs, options::OPT_t);
+  Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
+  Args.AddAllArgs(CmdArgs, options::OPT_r);
+
+  addLinkerCompressDebugSectionsOption(TC, Args, CmdArgs);
+
+  AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
+
+  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+    AddRunTimeLibs(TC, D, CmdArgs, Args);
+
+    // We supply our own sanitizer runtimes
+    // FIXME: What if we want to use Clang-supplied ones as well?
+    const SanitizerArgs &Sanitize = TC.getSanitizerArgs(Args);
+    if (Sanitize.needsUbsanRt())
+      CmdArgs.push_back("-lubsan");
+  }
+
+  if (D.CCCIsCXX() && TC.ShouldLinkCXXStdlib(Args)) {
+    bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
+                               !Args.hasArg(options::OPT_static);
+    CmdArgs.push_back("--push-state");
+    CmdArgs.push_back("--as-needed");
+    if (OnlyLibstdcxxStatic)
+      CmdArgs.push_back("-Bstatic");
+    TC.AddCXXStdlibLibArgs(Args, CmdArgs);
+    if (OnlyLibstdcxxStatic)
+      CmdArgs.push_back("-Bdynamic");
+    CmdArgs.push_back("--pop-state");
+  }
+
+  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+    if (!Args.hasArg(options::OPT_nolibc))
+      CmdArgs.push_back("-lc");
+  }
+
+  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+    std::string crtend_path;
+    if (TC.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT) {
+      std::string crtend =
+          TC.getCompilerRT(Args, "crtend", ToolChain::FT_Object);
+      if (TC.getVFS().exists(crtend))
+        crtend_path = crtend;
+    }
+    if (crtend_path.empty()) {
+      const char *crtend = (IsShared || IsPIE) ? "crtendS.o" : "crtend.o";
+      crtend_path = TC.GetFilePath(crtend);
+    }
+    CmdArgs.push_back(Args.MakeArgString(crtend_path));
+
+    CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtn.o")));
+  }
+
+  Args.AddAllArgs(CmdArgs, options::OPT_T);
+
+  C.addCommand(std::make_unique<Command>(JA, *this,
+                                         ResponseFileSupport::AtFileCurCP(),
+                                         Exec, CmdArgs, Inputs, Output));
+}
+
+Serenity::Serenity(const Driver &D, const llvm::Triple &Triple,
+                   const ArgList &Args)
+    : ToolChain(D, Triple, Args) {
+  getProgramPaths().push_back(getDriver().getInstalledDir());
+  if (getDriver().getInstalledDir() != getDriver().Dir)
+    getProgramPaths().push_back(getDriver().Dir);
+  getFilePaths().push_back(getDriver().SysRoot + "/usr/local/lib");
+  getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
+}
+
+Tool *Serenity::buildLinker() const {
+  return new tools::serenity::Linker(*this);
+}
+
+void Serenity::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+                                         ArgStringList &CC1Args) const {
+  const Driver &D = getDriver();
+
+  if (DriverArgs.hasArg(options::OPT_nostdinc))
+    return;
+
+  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+    addSystemInclude(DriverArgs, CC1Args, D.ResourceDir + "/include");
+  }
+
+  if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+    return;
+
+  addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/local/include");
+  addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include");
+}
+
+static std::string getLibStdCXXVersion(const Driver &D, StringRef IncludePath) {
+  SmallString<128> Path(IncludePath);
+  llvm::sys::path::append(Path, "c++");
+
+  std::error_code EC;
+  std::tuple<int, int, int> Newest{0, 0, 0};
+  std::string Result;
+
+  for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(Path, EC), LE;
+       !EC && LI != LE; LI = LI.increment(EC)) {
+    StringRef VersionText = llvm::sys::path::filename(LI->path());
+
+    // This is libc++
+    if (VersionText[0] == 'v')
+      continue;
+
+    llvm::SmallVector<StringRef, 3> Parts;
+    VersionText.split(Parts, '.');
+
+    // SerenityOS always builds GCC with <major>.<minor>.<patch> versions
+    if (Parts.size() < 3)
+      continue;
+
+    std::tuple<int, int, int> Current;
+    if (!llvm::to_integer(Parts[0], std::get<0>(Current)))
+      continue;
+    if (!llvm::to_integer(Parts[1], std::get<1>(Current)))
+      continue;
+    if (!llvm::to_integer(Parts[2], std::get<2>(Current)))
+      continue;
+
+    if (Current > Newest) {
+      Newest = Current;
+      Result = VersionText.str();
+    }
+  }
+  return Result;
+}
+
+void Serenity::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+                                            ArgStringList &CC1Args) const {
+  if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdincxx,
+                        options::OPT_nostdlibinc))
+    return;
+
+  const auto StdLib = GetCXXStdlibType(DriverArgs);
+
+  const Driver &D = getDriver();
+  std::string SysRoot = computeSysRoot();
+  std::string Target = getTripleString();
+
+  auto AddIncludePath = [&](std::string Path) {
+    std::string Version = StdLib == CXXStdlibType::CST_Libstdcxx
+                              ? getLibStdCXXVersion(D, Path)
+                              : detectLibcxxVersion(Path);
+    if (Version.empty())
+      return false;
+
+    std::string TargetDir;
+    if (StdLib == CXXStdlibType::CST_Libstdcxx) {
+      TargetDir = Path + "/c++/" + Version + "/" + Target;
+    } else {
+      TargetDir = Path + "/" + Target + "/c++/" + Version;
+    }
+
+    if (D.getVFS().exists(TargetDir))
+      addSystemInclude(DriverArgs, CC1Args, TargetDir);
+
+    addSystemInclude(DriverArgs, CC1Args, Path + "/c++/" + Version);
+    return true;
+  };
+
+  if (AddIncludePath(getDriver().Dir + "/../include"))
+    return;
+  if (AddIncludePath(SysRoot + "/usr/local/include"))
+    return;
+  if (AddIncludePath(SysRoot + "/usr/include"))
+    return;
+}
+
+void Serenity::addClangTargetOptions(
+    const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
+    Action::OffloadKind DeviceOffloadKind) const {
+  if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,
+                          options::OPT_fno_use_init_array, true))
+    CC1Args.push_back("-fno-use-init-array");
+}
+
+ToolChain::UnwindLibType
+Serenity::GetUnwindLibType(const llvm::opt::ArgList &Args) const {
+
+  const Arg *A = Args.getLastArg(options::OPT_unwindlib_EQ);
+  StringRef LibName = A ? A->getValue() : CLANG_DEFAULT_UNWINDLIB;
+
+  if (LibName == "none") {
+    return ToolChain::UNW_None;
+  } else if (LibName == "platform" || LibName == "") {
+    ToolChain::RuntimeLibType RtLibType = GetRuntimeLibType(Args);
+    if (RtLibType == ToolChain::RLT_CompilerRT) {
+      return ToolChain::UNW_CompilerRT;
+    } else if (RtLibType == ToolChain::RLT_Libgcc)
+      return ToolChain::UNW_Libgcc;
+  } else if (LibName == "libunwind") {
+    if (GetRuntimeLibType(Args) == RLT_Libgcc)
+      getDriver().Diag(diag::err_drv_incompatible_unwindlib);
+    return ToolChain::UNW_CompilerRT;
+  } else if (LibName == "libgcc") {
+    return ToolChain::UNW_Libgcc;
+  }
+
+  if (A)
+    getDriver().Diag(diag::err_drv_invalid_unwindlib_name)
+        << A->getAsString(Args);
+
+  return ToolChain::UNW_None;
+}
Index: clang/lib/Driver/ToolChain.cpp
===================================================================
--- clang/lib/Driver/ToolChain.cpp
+++ clang/lib/Driver/ToolChain.cpp
@@ -582,6 +582,8 @@
     return "sunos";
   case llvm::Triple::AIX:
     return "aix";
+  case llvm::Triple::Serenity:
+    return "serenity";
   default:
     return getOS();
   }
Index: clang/lib/Driver/Driver.cpp
===================================================================
--- clang/lib/Driver/Driver.cpp
+++ clang/lib/Driver/Driver.cpp
@@ -48,6 +48,7 @@
 #include "ToolChains/PS4CPU.h"
 #include "ToolChains/RISCVToolchain.h"
 #include "ToolChains/SPIRV.h"
+#include "ToolChains/Serenity.h"
 #include "ToolChains/Solaris.h"
 #include "ToolChains/TCE.h"
 #include "ToolChains/VEToolchain.h"
@@ -6209,6 +6210,9 @@
     case llvm::Triple::Fuchsia:
       TC = std::make_unique<toolchains::Fuchsia>(*this, Target, Args);
       break;
+    case llvm::Triple::Serenity:
+      TC = std::make_unique<toolchains::Serenity>(*this, Target, Args);
+      break;
     case llvm::Triple::Solaris:
       TC = std::make_unique<toolchains::Solaris>(*this, Target, Args);
       break;
Index: clang/lib/Driver/CMakeLists.txt
===================================================================
--- clang/lib/Driver/CMakeLists.txt
+++ clang/lib/Driver/CMakeLists.txt
@@ -80,6 +80,7 @@
   ToolChains/OpenBSD.cpp
   ToolChains/PS4CPU.cpp
   ToolChains/RISCVToolchain.cpp
+  ToolChains/Serenity.cpp
   ToolChains/Solaris.cpp
   ToolChains/SPIRV.cpp
   ToolChains/TCE.cpp
Index: clang/lib/Basic/Targets/OSTargets.h
===================================================================
--- clang/lib/Basic/Targets/OSTargets.h
+++ clang/lib/Basic/Targets/OSTargets.h
@@ -1035,6 +1035,24 @@
   }
 };
 
+// SerenityOS target
+template <typename Target>
+class LLVM_LIBRARY_VISIBILITY SerenityTargetInfo : public OSTargetInfo<Target> {
+protected:
+  void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+                    MacroBuilder &Builder) const override {
+    Builder.defineMacro("__serenity__");
+    DefineStd(Builder, "unix", Opts);
+    Builder.defineMacro("__ELF__");
+  }
+
+public:
+  SerenityTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+      : OSTargetInfo<Target>(Triple, Opts) {
+    this->WIntType = TargetInfo::UnsignedInt;
+  }
+};
+
 } // namespace targets
 } // namespace clang
 #endif // LLVM_CLANG_LIB_BASIC_TARGETS_OSTARGETS_H
Index: clang/lib/Basic/Targets.cpp
===================================================================
--- clang/lib/Basic/Targets.cpp
+++ clang/lib/Basic/Targets.cpp
@@ -166,6 +166,9 @@
     case llvm::Triple::OpenBSD:
       return std::make_unique<OpenBSDTargetInfo<AArch64leTargetInfo>>(Triple,
                                                                       Opts);
+    case llvm::Triple::Serenity:
+      return std::make_unique<SerenityTargetInfo<AArch64leTargetInfo>>(Triple,
+                                                                       Opts);
     case llvm::Triple::Win32:
       switch (Triple.getEnvironment()) {
       case llvm::Triple::GNU:
@@ -598,6 +601,9 @@
       return std::make_unique<MCUX86_32TargetInfo>(Triple, Opts);
     case llvm::Triple::Hurd:
       return std::make_unique<HurdTargetInfo<X86_32TargetInfo>>(Triple, Opts);
+    case llvm::Triple::Serenity:
+      return std::make_unique<SerenityTargetInfo<X86_32TargetInfo>>(Triple,
+                                                                    Opts);
     default:
       return std::make_unique<X86_32TargetInfo>(Triple, Opts);
     }
@@ -661,6 +667,9 @@
       return std::make_unique<PS4OSTargetInfo<X86_64TargetInfo>>(Triple, Opts);
     case llvm::Triple::PS5:
       return std::make_unique<PS5OSTargetInfo<X86_64TargetInfo>>(Triple, Opts);
+    case llvm::Triple::Serenity:
+      return std::make_unique<SerenityTargetInfo<X86_64TargetInfo>>(Triple,
+                                                                    Opts);
     default:
       return std::make_unique<X86_64TargetInfo>(Triple, Opts);
     }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to