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