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(M: Multilib());
39 // -mcpu=cortex-a7
40 // -mfloat-abi=soft -mfloat-abi=softfp -mfloat-abi=hard
41 // -mfpu=neon-vfpv4
42 Multilibs.push_back(
43 M: Multilib("/a7_soft", {}, {}, {"-mcpu=cortex-a7", "-mfloat-abi=soft"}));
44
45 Multilibs.push_back(
46 M: Multilib("/a7_softfp_neon-vfpv4", {}, {},
47 {"-mcpu=cortex-a7", "-mfloat-abi=softfp", "-mfpu=neon-vfpv4"}));
48
49 Multilibs.push_back(
50 M: 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(Ids: options::OPT_mcpu_EQ))
68 IsA7 = A->getValue() == StringRef("cortex-a7");
69 addMultilibFlag(Enabled: IsA7, Flag: "-mcpu=cortex-a7", Flags);
70
71 bool IsMFPU = false;
72 if (const Arg *A = Args.getLastArg(Ids: options::OPT_mfpu_EQ))
73 IsMFPU = A->getValue() == StringRef("neon-vfpv4");
74 addMultilibFlag(Enabled: IsMFPU, Flag: "-mfpu=neon-vfpv4", Flags);
75
76 tools::arm::FloatABI ARMFloatABI = getARMFloatABI(D, Triple: TargetTriple, Args);
77 addMultilibFlag(Enabled: (ARMFloatABI == tools::arm::FloatABI::Soft),
78 Flag: "-mfloat-abi=soft", Flags);
79 addMultilibFlag(Enabled: (ARMFloatABI == tools::arm::FloatABI::SoftFP),
80 Flag: "-mfloat-abi=softfp", Flags);
81 addMultilibFlag(Enabled: (ARMFloatABI == tools::arm::FloatABI::Hard),
82 Flag: "-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(T: 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(path&: P, a: 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, TC: *this, TargetTriple: Triple, Path: "", 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(Path: CandidateLibPath))
147 getFilePaths().push_back(Elt: CandidateLibPath);
148
149 getLibraryPaths().clear();
150 for (auto &Path : getRuntimePaths())
151 if (getVFS().exists(Path))
152 getLibraryPaths().push_back(Elt: 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(IL: {SysRoot, "usr", "lib"});
160 std::string MultiarchTriple = getMultiarchTriple(T: getTriple());
161 addPathIfExists(D, Path: makePath(IL: {SysRootLibPath, SelectedMultilib.gccSuffix()}),
162 Paths);
163 addPathIfExists(D,
164 Path: makePath(IL: {D.Dir, "..", "lib", MultiarchTriple,
165 SelectedMultilib.gccSuffix()}),
166 Paths);
167
168 addPathIfExists(
169 D,
170 Path: makePath(IL: {SysRootLibPath, MultiarchTriple, SelectedMultilib.gccSuffix()}),
171 Paths);
172}
173
174ToolChain::RuntimeLibType OHOS::GetRuntimeLibType(
175 const ArgList &Args) const {
176 if (Arg *A = Args.getLastArg(Ids: clang::driver::options::OPT_rtlib_EQ)) {
177 StringRef Value = A->getValue();
178 if (Value != "compiler-rt")
179 getDriver().Diag(DiagID: 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(Ids: options::OPT_stdlib_EQ)) {
189 StringRef Value = A->getValue();
190 if (Value != "libc++")
191 getDriver().Diag(DiagID: 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(Ids: options::OPT_nostdinc))
205 return;
206
207 if (!DriverArgs.hasArg(Ids: options::OPT_nobuiltininc)) {
208 SmallString<128> P(D.ResourceDir);
209 llvm::sys::path::append(path&: P, a: "include");
210 addSystemInclude(DriverArgs, CC1Args, Path: P);
211 }
212
213 if (DriverArgs.hasArg(Ids: 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(A&: dirs, Separator: ":");
221 for (StringRef dir : dirs) {
222 StringRef Prefix =
223 llvm::sys::path::is_absolute(path: dir) ? StringRef(SysRoot) : "";
224 addExternCSystemInclude(DriverArgs, CC1Args, Path: Prefix + dir);
225 }
226 return;
227 }
228
229 addExternCSystemInclude(DriverArgs, CC1Args,
230 Path: SysRoot + "/usr/include/" +
231 getMultiarchTriple(T: Triple));
232 addExternCSystemInclude(DriverArgs, CC1Args, Path: SysRoot + "/include");
233 addExternCSystemInclude(DriverArgs, CC1Args, Path: SysRoot + "/usr/include");
234}
235
236void OHOS::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
237 ArgStringList &CC1Args) const {
238 if (DriverArgs.hasArg(Ids: options::OPT_nostdlibinc) ||
239 DriverArgs.hasArg(Ids: options::OPT_nostdincxx))
240 return;
241
242 switch (GetCXXStdlibType(Args: DriverArgs)) {
243 case ToolChain::CST_Libcxx: {
244 std::string IncPath = makePath(IL: {getDriver().Dir, "..", "include"});
245 std::string IncTargetPath =
246 makePath(IL: {IncPath, getMultiarchTriple(T: getTriple()), "c++", "v1"});
247 if (getVFS().exists(Path: IncTargetPath)) {
248 addSystemInclude(DriverArgs, CC1Args, Path: makePath(IL: {IncPath, "c++", "v1"}));
249 addSystemInclude(DriverArgs, CC1Args, Path: 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(Elt: "-lc++");
264 CmdArgs.push_back(Elt: "-lc++abi");
265 CmdArgs.push_back(Elt: "-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(IL: {getDriver().Dir, "..", "..", "sysroot"});
278 if (!llvm::sys::fs::exists(Path: SysRoot))
279 return std::string();
280
281 std::string ArchRoot = makePath(IL: {SysRoot, getMultiarchTriple(T: getTriple())});
282 return llvm::sys::fs::exists(Path: 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(RHS: D.ResourceDir);
293 llvm::sys::path::append(path&: P, a: "lib", b: D.getTargetTriple(), c: SelectedMultilib.gccSuffix());
294 Paths.push_back(Elt: P.c_str());
295
296 // Second try the normalized triple.
297 P.assign(RHS: D.ResourceDir);
298 llvm::sys::path::append(path&: P, a: "lib", b: Triple.str(), c: SelectedMultilib.gccSuffix());
299 Paths.push_back(Elt: P.c_str());
300
301 // Third try the effective triple.
302 P.assign(RHS: D.ResourceDir);
303 std::string SysRoot = computeSysRoot();
304 llvm::sys::path::append(path&: P, a: "lib", b: getMultiarchTriple(T: Triple),
305 c: SelectedMultilib.gccSuffix());
306 Paths.push_back(Elt: 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(TC: *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&: Path, a: "lib", b: getMultiarchTriple(T: getTriple()),
344 c: 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&: Path, a: 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(Elt: "-z");
366 CmdArgs.push_back(Elt: "now");
367 CmdArgs.push_back(Elt: "-z");
368 CmdArgs.push_back(Elt: "relro");
369 CmdArgs.push_back(Elt: "-z");
370 CmdArgs.push_back(Elt: "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(Elt: "--hash-style=both");
374#ifdef ENABLE_LINKER_BUILD_ID
375 CmdArgs.push_back("--build-id");
376#endif
377 CmdArgs.push_back(Elt: "--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(Elt: Args.MakeArgString(
403 Str: 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 Elt: makePath(IL: {getDriver().ResourceDir, "lib", getMultiarchTriple(T: Triple)}));
412 return Paths;
413}
414
415ToolChain::UnwindLibType OHOS::GetUnwindLibType(const llvm::opt::ArgList &Args) const {
416 if (Args.getLastArg(Ids: options::OPT_unwindlib_EQ))
417 return Generic_ELF::GetUnwindLibType(Args);
418 return GetDefaultUnwindLibType();
419}
420