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