1//===--- OHOS.cpp - OHOS ToolChain Implementations --------*- C++ -*-===//
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-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "OHOS.h"
10#include "Arch/ARM.h"
11#include "CommonArgs.h"
12#include "clang/Config/config.h"
13#include "clang/Driver/Compilation.h"
14#include "clang/Driver/Driver.h"
15#include "clang/Driver/DriverDiagnostic.h"
16#include "clang/Driver/Options.h"
17#include "clang/Driver/SanitizerArgs.h"
18#include "llvm/Option/ArgList.h"
19#include "llvm/ProfileData/InstrProf.h"
20#include "llvm/Support/FileSystem.h"
21#include "llvm/Support/Path.h"
22#include "llvm/Support/VirtualFileSystem.h"
23#include "llvm/Support/ScopedPrinter.h"
24
25using namespace clang::driver;
26using namespace clang::driver::toolchains;
27using namespace clang::driver::tools;
28using namespace clang;
29using namespace llvm::opt;
30using namespace clang::driver::tools::arm;
31
32using tools::addMultilibFlag;
33using tools::addPathIfExists;
34
35static bool findOHOSMuslMultilibs(const Multilib::flags_list &Flags,
36                                  DetectedMultilibs &Result) {
37  MultilibSet Multilibs;
38  Multilibs.push_back(Multilib());
39  // -mcpu=cortex-a7
40  // -mfloat-abi=soft -mfloat-abi=softfp -mfloat-abi=hard
41  // -mfpu=neon-vfpv4
42  Multilibs.push_back(
43      Multilib("/a7_soft", {}, {}, {"-mcpu=cortex-a7", "-mfloat-abi=soft"}));
44
45  Multilibs.push_back(
46      Multilib("/a7_softfp_neon-vfpv4", {}, {},
47               {"-mcpu=cortex-a7", "-mfloat-abi=softfp", "-mfpu=neon-vfpv4"}));
48
49  Multilibs.push_back(
50      Multilib("/a7_hard_neon-vfpv4", {}, {},
51               {"-mcpu=cortex-a7", "-mfloat-abi=hard", "-mfpu=neon-vfpv4"}));
52
53  if (Multilibs.select(Flags, Result.SelectedMultilibs)) {
54    Result.Multilibs = Multilibs;
55    return true;
56  }
57  return false;
58}
59
60static bool findOHOSMultilibs(const Driver &D,
61                                      const ToolChain &TC,
62                                      const llvm::Triple &TargetTriple,
63                                      StringRef Path, const ArgList &Args,
64                                      DetectedMultilibs &Result) {
65  Multilib::flags_list Flags;
66  bool IsA7 = false;
67  if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
68    IsA7 = A->getValue() == StringRef("cortex-a7");
69  addMultilibFlag(IsA7, "-mcpu=cortex-a7", Flags);
70
71  bool IsMFPU = false;
72  if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ))
73    IsMFPU = A->getValue() == StringRef("neon-vfpv4");
74  addMultilibFlag(IsMFPU, "-mfpu=neon-vfpv4", Flags);
75
76  tools::arm::FloatABI ARMFloatABI = getARMFloatABI(D, TargetTriple, Args);
77  addMultilibFlag((ARMFloatABI == tools::arm::FloatABI::Soft),
78                  "-mfloat-abi=soft", Flags);
79  addMultilibFlag((ARMFloatABI == tools::arm::FloatABI::SoftFP),
80                  "-mfloat-abi=softfp", Flags);
81  addMultilibFlag((ARMFloatABI == tools::arm::FloatABI::Hard),
82                  "-mfloat-abi=hard", Flags);
83
84  return findOHOSMuslMultilibs(Flags, Result);
85}
86
87std::string OHOS::getMultiarchTriple(const llvm::Triple &T) const {
88  // For most architectures, just use whatever we have rather than trying to be
89  // clever.
90  switch (T.getArch()) {
91  default:
92    break;
93
94  // We use the existence of '/lib/<triple>' as a directory to detect some
95  // common linux triples that don't quite match the Clang triple for both
96  // 32-bit and 64-bit targets. Multiarch fixes its install triples to these
97  // regardless of what the actual target triple is.
98  case llvm::Triple::arm:
99  case llvm::Triple::thumb:
100    return T.isOSLiteOS() ? "arm-liteos-ohos" : "arm-linux-ohos";
101  case llvm::Triple::riscv32:
102    return "riscv32-linux-ohos";
103  case llvm::Triple::riscv64:
104    return "riscv64-linux-ohos";
105  case llvm::Triple::mipsel:
106    return "mipsel-linux-ohos";
107  case llvm::Triple::x86:
108    return "i686-linux-ohos";
109  case llvm::Triple::x86_64:
110    return "x86_64-linux-ohos";
111  case llvm::Triple::aarch64:
112    return "aarch64-linux-ohos";
113  }
114  return T.str();
115}
116
117std::string OHOS::getMultiarchTriple(const Driver &D,
118                                     const llvm::Triple &TargetTriple,
119                                     StringRef SysRoot) const {
120  return getMultiarchTriple(TargetTriple);
121}
122
123static std::string makePath(const std::initializer_list<std::string> &IL) {
124  SmallString<128> P;
125  for (const auto &S : IL)
126    llvm::sys::path::append(P, S);
127  return static_cast<std::string>(P.str());
128}
129
130/// OHOS Toolchain
131OHOS::OHOS(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
132    : Generic_ELF(D, Triple, Args) {
133  std::string SysRoot = computeSysRoot();
134
135  // Select the correct multilib according to the given arguments.
136  DetectedMultilibs Result;
137  findOHOSMultilibs(D, *this, Triple, "", Args, Result);
138  Multilibs = Result.Multilibs;
139  SelectedMultilibs = Result.SelectedMultilibs;
140  if (!SelectedMultilibs.empty()) {
141    SelectedMultilib = SelectedMultilibs.back();
142  }
143
144  getFilePaths().clear();
145  for (const auto &CandidateLibPath : getArchSpecificLibPaths())
146    if (getVFS().exists(CandidateLibPath))
147      getFilePaths().push_back(CandidateLibPath);
148
149  getLibraryPaths().clear();
150  for (auto &Path : getRuntimePaths())
151    if (getVFS().exists(Path))
152      getLibraryPaths().push_back(Path);
153
154  // OHOS sysroots contain a library directory for each supported OS
155  // version as well as some unversioned libraries in the usual multiarch
156  // directory. Support --target=aarch64-linux-ohosX.Y.Z or
157  // --target=aarch64-linux-ohosX.Y or --target=aarch64-linux-ohosX
158  path_list &Paths = getFilePaths();
159  std::string SysRootLibPath = makePath({SysRoot, "usr", "lib"});
160  std::string MultiarchTriple = getMultiarchTriple(getTriple());
161  addPathIfExists(D, makePath({SysRootLibPath, SelectedMultilib.gccSuffix()}),
162                  Paths);
163  addPathIfExists(D,
164                  makePath({D.Dir, "..", "lib", MultiarchTriple,
165                            SelectedMultilib.gccSuffix()}),
166                  Paths);
167
168  addPathIfExists(
169      D,
170      makePath({SysRootLibPath, MultiarchTriple, SelectedMultilib.gccSuffix()}),
171      Paths);
172}
173
174ToolChain::RuntimeLibType OHOS::GetRuntimeLibType(
175    const ArgList &Args) const {
176  if (Arg *A = Args.getLastArg(clang::driver::options::OPT_rtlib_EQ)) {
177    StringRef Value = A->getValue();
178    if (Value != "compiler-rt")
179      getDriver().Diag(clang::diag::err_drv_invalid_rtlib_name)
180          << A->getAsString(Args);
181  }
182
183  return ToolChain::RLT_CompilerRT;
184}
185
186ToolChain::CXXStdlibType
187OHOS::GetCXXStdlibType(const ArgList &Args) const {
188  if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
189    StringRef Value = A->getValue();
190    if (Value != "libc++")
191      getDriver().Diag(diag::err_drv_invalid_stdlib_name)
192        << A->getAsString(Args);
193  }
194
195  return ToolChain::CST_Libcxx;
196}
197
198void OHOS::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
199                                        ArgStringList &CC1Args) const {
200  const Driver &D = getDriver();
201  const llvm::Triple &Triple = getTriple();
202  std::string SysRoot = computeSysRoot();
203
204  if (DriverArgs.hasArg(options::OPT_nostdinc))
205    return;
206
207  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
208    SmallString<128> P(D.ResourceDir);
209    llvm::sys::path::append(P, "include");
210    addSystemInclude(DriverArgs, CC1Args, P);
211  }
212
213  if (DriverArgs.hasArg(options::OPT_nostdlibinc))
214    return;
215
216  // Check for configure-time C include directories.
217  StringRef CIncludeDirs(C_INCLUDE_DIRS);
218  if (CIncludeDirs != "") {
219    SmallVector<StringRef, 5> dirs;
220    CIncludeDirs.split(dirs, ":");
221    for (StringRef dir : dirs) {
222      StringRef Prefix =
223          llvm::sys::path::is_absolute(dir) ? StringRef(SysRoot) : "";
224      addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
225    }
226    return;
227  }
228
229  addExternCSystemInclude(DriverArgs, CC1Args,
230                          SysRoot + "/usr/include/" +
231                              getMultiarchTriple(Triple));
232  addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include");
233  addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
234}
235
236void OHOS::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
237                                        ArgStringList &CC1Args) const {
238  if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
239      DriverArgs.hasArg(options::OPT_nostdincxx))
240    return;
241
242  switch (GetCXXStdlibType(DriverArgs)) {
243  case ToolChain::CST_Libcxx: {
244    std::string IncPath = makePath({getDriver().Dir, "..", "include"});
245    std::string IncTargetPath =
246        makePath({IncPath, getMultiarchTriple(getTriple()), "c++", "v1"});
247    if (getVFS().exists(IncTargetPath)) {
248      addSystemInclude(DriverArgs, CC1Args, makePath({IncPath, "c++", "v1"}));
249      addSystemInclude(DriverArgs, CC1Args, IncTargetPath);
250    }
251    break;
252  }
253
254  default:
255    llvm_unreachable("invalid stdlib name");
256  }
257}
258
259void OHOS::AddCXXStdlibLibArgs(const ArgList &Args,
260                                  ArgStringList &CmdArgs) const {
261  switch (GetCXXStdlibType(Args)) {
262  case ToolChain::CST_Libcxx:
263    CmdArgs.push_back("-lc++");
264    CmdArgs.push_back("-lc++abi");
265    CmdArgs.push_back("-lunwind");
266    break;
267
268  case ToolChain::CST_Libstdcxx:
269    llvm_unreachable("invalid stdlib name");
270  }
271}
272
273std::string OHOS::computeSysRoot() const {
274  std::string SysRoot =
275      !getDriver().SysRoot.empty()
276          ? getDriver().SysRoot
277          : makePath({getDriver().getInstalledDir(), "..", "..", "sysroot"});
278  if (!llvm::sys::fs::exists(SysRoot))
279    return std::string();
280
281  std::string ArchRoot = makePath({SysRoot, getMultiarchTriple(getTriple())});
282  return llvm::sys::fs::exists(ArchRoot) ? ArchRoot : SysRoot;
283}
284
285ToolChain::path_list OHOS::getRuntimePaths() const {
286  SmallString<128> P;
287  path_list Paths;
288  const Driver &D = getDriver();
289  const llvm::Triple &Triple = getTriple();
290
291  // First try the triple passed to driver as --target=<triple>.
292  P.assign(D.ResourceDir);
293  llvm::sys::path::append(P, "lib", D.getTargetTriple(), SelectedMultilib.gccSuffix());
294  Paths.push_back(P.c_str());
295
296  // Second try the normalized triple.
297  P.assign(D.ResourceDir);
298  llvm::sys::path::append(P, "lib", Triple.str(), SelectedMultilib.gccSuffix());
299  Paths.push_back(P.c_str());
300
301  // Third try the effective triple.
302  P.assign(D.ResourceDir);
303  std::string SysRoot = computeSysRoot();
304  llvm::sys::path::append(P, "lib", getMultiarchTriple(Triple),
305                          SelectedMultilib.gccSuffix());
306  Paths.push_back(P.c_str());
307
308  return Paths;
309}
310
311std::string OHOS::getDynamicLinker(const ArgList &Args) const {
312  const llvm::Triple &Triple = getTriple();
313  const llvm::Triple::ArchType Arch = getArch();
314
315  assert(Triple.isMusl());
316  std::string ArchName;
317  bool IsArm = false;
318
319  switch (Arch) {
320  case llvm::Triple::arm:
321  case llvm::Triple::thumb:
322    ArchName = "arm";
323    IsArm = true;
324    break;
325  case llvm::Triple::armeb:
326  case llvm::Triple::thumbeb:
327    ArchName = "armeb";
328    IsArm = true;
329    break;
330  default:
331    ArchName = Triple.getArchName().str();
332  }
333  if (IsArm &&
334      (tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard))
335    ArchName += "hf";
336
337  return "/lib/ld-musl-" + ArchName + ".so.1";
338}
339
340std::string OHOS::getCompilerRT(const ArgList &Args, StringRef Component,
341                                FileType Type) const {
342  SmallString<128> Path(getDriver().ResourceDir);
343  llvm::sys::path::append(Path, "lib", getMultiarchTriple(getTriple()),
344                          SelectedMultilib.gccSuffix());
345  const char *Prefix =
346      Type == ToolChain::FT_Object ? "" : "lib";
347  const char *Suffix;
348  switch (Type) {
349  case ToolChain::FT_Object:
350    Suffix = ".o";
351    break;
352  case ToolChain::FT_Static:
353    Suffix = ".a";
354    break;
355  case ToolChain::FT_Shared:
356    Suffix = ".so";
357    break;
358  }
359  llvm::sys::path::append(
360      Path, Prefix + Twine("clang_rt.") + Component + Suffix);
361  return static_cast<std::string>(Path.str());
362}
363
364void OHOS::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const {
365  CmdArgs.push_back("-z");
366  CmdArgs.push_back("now");
367  CmdArgs.push_back("-z");
368  CmdArgs.push_back("relro");
369  CmdArgs.push_back("-z");
370  CmdArgs.push_back("max-page-size=4096");
371  // .gnu.hash section is not compatible with the MIPS target
372  if (getArch() != llvm::Triple::mipsel)
373    CmdArgs.push_back("--hash-style=both");
374#ifdef ENABLE_LINKER_BUILD_ID
375  CmdArgs.push_back("--build-id");
376#endif
377  CmdArgs.push_back("--enable-new-dtags");
378}
379
380SanitizerMask OHOS::getSupportedSanitizers() const {
381  SanitizerMask Res = ToolChain::getSupportedSanitizers();
382  Res |= SanitizerKind::Address;
383  Res |= SanitizerKind::PointerCompare;
384  Res |= SanitizerKind::PointerSubtract;
385  Res |= SanitizerKind::Fuzzer;
386  Res |= SanitizerKind::FuzzerNoLink;
387  Res |= SanitizerKind::Memory;
388  Res |= SanitizerKind::Vptr;
389  Res |= SanitizerKind::SafeStack;
390  Res |= SanitizerKind::Scudo;
391  // TODO: kASAN for liteos ??
392  // TODO: Support TSAN and HWASAN and update mask.
393  return Res;
394}
395
396// TODO: Make a base class for Linux and OHOS and move this there.
397void OHOS::addProfileRTLibs(const llvm::opt::ArgList &Args,
398                             llvm::opt::ArgStringList &CmdArgs) const {
399  // Add linker option -u__llvm_profile_runtime to cause runtime
400  // initialization module to be linked in.
401  if (needsProfileRT(Args))
402    CmdArgs.push_back(Args.MakeArgString(
403        Twine("-u", llvm::getInstrProfRuntimeHookVarName())));
404  ToolChain::addProfileRTLibs(Args, CmdArgs);
405}
406
407ToolChain::path_list OHOS::getArchSpecificLibPaths() const {
408  ToolChain::path_list Paths;
409  llvm::Triple Triple = getTriple();
410  Paths.push_back(
411      makePath({getDriver().ResourceDir, "lib", getMultiarchTriple(Triple)}));
412  return Paths;
413}
414
415ToolChain::UnwindLibType OHOS::GetUnwindLibType(const llvm::opt::ArgList &Args) const {
416  if (Args.getLastArg(options::OPT_unwindlib_EQ))
417    return Generic_ELF::GetUnwindLibType(Args);
418  return GetDefaultUnwindLibType();
419}
420