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 
25 using namespace clang::driver;
26 using namespace clang::driver::toolchains;
27 using namespace clang::driver::tools;
28 using namespace clang;
29 using namespace llvm::opt;
30 using namespace clang::driver::tools::arm;
31 
32 using tools::addMultilibFlag;
33 using tools::addPathIfExists;
34 
35 static 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 
60 static 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 
87 std::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 
117 std::string OHOS::getMultiarchTriple(const Driver &D,
118                                      const llvm::Triple &TargetTriple,
119                                      StringRef SysRoot) const {
120   return getMultiarchTriple(TargetTriple);
121 }
122 
123 static 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
131 OHOS::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 
174 ToolChain::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 
186 ToolChain::CXXStdlibType
187 OHOS::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 
198 void 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 
236 void 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 
259 void 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 
273 std::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 
285 ToolChain::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 
311 std::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 
340 std::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 
364 void 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 
380 SanitizerMask 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.
397 void 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 
407 ToolChain::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 
415 ToolChain::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