216 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Managarm.h"10#include "Arch/RISCV.h"11#include "clang/Config/config.h"12#include "clang/Driver/CommonArgs.h"13#include "clang/Driver/Driver.h"14#include "clang/Driver/SanitizerArgs.h"15#include "clang/Options/Options.h"16#include "llvm/Option/ArgList.h"17#include "llvm/Support/Path.h"18 19using namespace clang::driver;20using namespace clang::driver::toolchains;21using namespace clang;22using namespace llvm::opt;23 24using tools::addPathIfExists;25 26std::string Managarm::getMultiarchTriple(const Driver &D,27 const llvm::Triple &TargetTriple,28 StringRef SysRoot) const {29 switch (TargetTriple.getArch()) {30 default:31 return TargetTriple.str();32 case llvm::Triple::x86_64:33 return "x86_64-managarm-" + TargetTriple.getEnvironmentName().str();34 case llvm::Triple::aarch64:35 return "aarch64-managarm-" + TargetTriple.getEnvironmentName().str();36 case llvm::Triple::riscv64:37 return "riscv64-managarm-" + TargetTriple.getEnvironmentName().str();38 }39}40 41static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) {42 // It happens that only x86, PPC and SPARC use the 'lib32' variant of43 // oslibdir, and using that variant while targeting other architectures causes44 // problems because the libraries are laid out in shared system roots that45 // can't cope with a 'lib32' library search path being considered. So we only46 // enable them when we know we may need it.47 //48 // FIXME: This is a bit of a hack. We should really unify this code for49 // reasoning about oslibdir spellings with the lib dir spellings in the50 // GCCInstallationDetector, but that is a more significant refactoring.51 if (Triple.getArch() == llvm::Triple::x86 || Triple.isPPC32() ||52 Triple.getArch() == llvm::Triple::sparc)53 return "lib32";54 55 if (Triple.getArch() == llvm::Triple::x86_64 && Triple.isX32())56 return "libx32";57 58 if (Triple.getArch() == llvm::Triple::riscv32)59 return "lib32";60 61 return Triple.isArch32Bit() ? "lib" : "lib64";62}63 64Managarm::Managarm(const Driver &D, const llvm::Triple &Triple,65 const ArgList &Args)66 : Generic_ELF(D, Triple, Args) {67 GCCInstallation.init(Triple, Args);68 Multilibs = GCCInstallation.getMultilibs();69 SelectedMultilibs.assign({GCCInstallation.getMultilib()});70 std::string SysRoot = computeSysRoot();71 72 ToolChain::path_list &PPaths = getProgramPaths();73 74 Generic_GCC::PushPPaths(PPaths);75 76#ifdef ENABLE_LINKER_BUILD_ID77 ExtraOpts.push_back("--build-id");78#endif79 80 // The selection of paths to try here is designed to match the patterns which81 // the GCC driver itself uses, as this is part of the GCC-compatible driver.82 // This was determined by running GCC in a fake filesystem, creating all83 // possible permutations of these directories, and seeing which ones it added84 // to the link paths.85 path_list &Paths = getFilePaths();86 87 const std::string OSLibDir = std::string(getOSLibDir(Triple, Args));88 const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot);89 90 Generic_GCC::AddMultilibPaths(D, SysRoot, OSLibDir, MultiarchTriple, Paths);91 92 addPathIfExists(D, concat(SysRoot, "/lib", MultiarchTriple), Paths);93 addPathIfExists(D, concat(SysRoot, "/lib/..", OSLibDir), Paths);94 addPathIfExists(D, concat(SysRoot, "/usr/lib", MultiarchTriple), Paths);95 addPathIfExists(D, concat(SysRoot, "/usr", OSLibDir), Paths);96 97 Generic_GCC::AddMultiarchPaths(D, SysRoot, OSLibDir, Paths);98 99 addPathIfExists(D, concat(SysRoot, "/lib"), Paths);100 addPathIfExists(D, concat(SysRoot, "/usr/lib"), Paths);101}102 103bool Managarm::HasNativeLLVMSupport() const { return true; }104 105Tool *Managarm::buildLinker() const {106 return new tools::gnutools::Linker(*this);107}108 109Tool *Managarm::buildAssembler() const {110 return new tools::gnutools::Assembler(*this);111}112 113std::string Managarm::computeSysRoot() const {114 if (!getDriver().SysRoot.empty())115 return getDriver().SysRoot;116 return std::string();117}118 119std::string Managarm::getDynamicLinker(const ArgList &Args) const {120 switch (getTriple().getArch()) {121 case llvm::Triple::aarch64:122 return "/lib/aarch64-managarm/ld.so";123 case llvm::Triple::riscv64: {124 StringRef ABIName = tools::riscv::getRISCVABI(Args, getTriple());125 return ("/lib/riscv64-managarm/ld-riscv64-" + ABIName + ".so").str();126 }127 case llvm::Triple::x86_64:128 return "/lib/x86_64-managarm/ld.so";129 default:130 llvm_unreachable("unsupported architecture");131 }132}133 134void Managarm::AddClangSystemIncludeArgs(const ArgList &DriverArgs,135 ArgStringList &CC1Args) const {136 const Driver &D = getDriver();137 std::string SysRoot = computeSysRoot();138 139 if (DriverArgs.hasArg(options::OPT_nostdinc))140 return;141 142 if (!DriverArgs.hasArg(options::OPT_nostdlibinc))143 addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include");144 145 // Add 'include' in the resource directory, which is similar to146 // GCC_INCLUDE_DIR (private headers) in GCC.147 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {148 SmallString<128> ResourceDirInclude(D.ResourceDir);149 llvm::sys::path::append(ResourceDirInclude, "include");150 addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);151 }152 153 if (DriverArgs.hasArg(options::OPT_nostdlibinc))154 return;155 156 // TOOL_INCLUDE_DIR157 AddMultilibIncludeArgs(DriverArgs, CC1Args);158 159 // Check for configure-time C include directories.160 StringRef CIncludeDirs(C_INCLUDE_DIRS);161 if (CIncludeDirs != "") {162 SmallVector<StringRef, 5> dirs;163 CIncludeDirs.split(dirs, ":");164 for (StringRef dir : dirs) {165 StringRef Prefix =166 llvm::sys::path::is_absolute(dir) ? StringRef(SysRoot) : "";167 addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);168 }169 return;170 }171 172 // On systems using multiarch, add /usr/include/$triple before173 // /usr/include.174 std::string MultiarchIncludeDir = getMultiarchTriple(D, getTriple(), SysRoot);175 if (!MultiarchIncludeDir.empty())176 addExternCSystemInclude(177 DriverArgs, CC1Args,178 concat(SysRoot, "/usr/include", MultiarchIncludeDir));179 180 // Add an include of '/include' directly. This isn't provided by default by181 // system GCCs, but is often used with cross-compiling GCCs, and harmless to182 // add even when Clang is acting as-if it were a system compiler.183 addExternCSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/include"));184 185 addExternCSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/usr/include"));186}187 188void Managarm::addLibStdCxxIncludePaths(189 const llvm::opt::ArgList &DriverArgs,190 llvm::opt::ArgStringList &CC1Args) const {191 // We need a detected GCC installation on Managarm to provide libstdc++'s192 // headers.193 if (!GCCInstallation.isValid())194 return;195 196 // Try generic GCC detection.197 addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args);198}199 200SanitizerMask Managarm::getSupportedSanitizers() const {201 const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;202 SanitizerMask Res = ToolChain::getSupportedSanitizers();203 Res |= SanitizerKind::PointerCompare;204 Res |= SanitizerKind::PointerSubtract;205 Res |= SanitizerKind::KernelAddress;206 Res |= SanitizerKind::Vptr;207 if (IsX86_64)208 Res |= SanitizerKind::KernelMemory;209 return Res;210}211 212void Managarm::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const {213 for (const auto &Opt : ExtraOpts)214 CmdArgs.push_back(Opt.c_str());215}216