diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.h b/clang/lib/Driver/ToolChains/Arch/ARM.h --- a/clang/lib/Driver/ToolChains/Arch/ARM.h +++ b/clang/lib/Driver/ToolChains/Arch/ARM.h @@ -11,6 +11,7 @@ #include "clang/Driver/ToolChain.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" #include "llvm/TargetParser/ARMTargetParser.h" #include "llvm/TargetParser/Triple.h" @@ -73,6 +74,7 @@ int getARMSubArchVersionNumber(const llvm::Triple &Triple); bool isARMMProfile(const llvm::Triple &Triple); bool isARMAProfile(const llvm::Triple &Triple); +bool isARMBigEndian(const llvm::Triple &Triple, const llvm::opt::ArgList &Args); } // end namespace arm } // end namespace tools diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp --- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -32,6 +32,20 @@ return llvm::ARM::parseArchProfile(Arch) == llvm::ARM::ProfileKind::M; } +// On Arm the endianness of the output file is determined by the target and +// can be overridden by the pseudo-target flags '-mlittle-endian'/'-EL' and +// '-mbig-endian'/'-EB'. Unlike other targets the flag does not result in a +// normalized triple so we must handle the flag here. +bool arm::isARMBigEndian(const llvm::Triple &Triple, const ArgList &Args) { + if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, + options::OPT_mbig_endian)) { + return !A->getOption().matches(options::OPT_mlittle_endian); + } + + return Triple.getArch() == llvm::Triple::armeb || + Triple.getArch() == llvm::Triple::thumbeb; +} + // True if A-profile. bool arm::isARMAProfile(const llvm::Triple &Triple) { llvm::StringRef Arch = Triple.getArchName(); diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp --- a/clang/lib/Driver/ToolChains/BareMetal.cpp +++ b/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -12,6 +12,7 @@ #include "Gnu.h" #include "clang/Driver/InputInfo.h" +#include "Arch/ARM.h" #include "Arch/RISCV.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" @@ -115,10 +116,12 @@ } } -/// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ? +/// Is the triple {arm,armeb,thumb,thumbeb}-none-none-{eabi,eabihf} ? static bool isARMBareMetal(const llvm::Triple &Triple) { if (Triple.getArch() != llvm::Triple::arm && - Triple.getArch() != llvm::Triple::thumb) + Triple.getArch() != llvm::Triple::thumb && + Triple.getArch() != llvm::Triple::armeb && + Triple.getArch() != llvm::Triple::thumbeb) return false; if (Triple.getVendor() != llvm::Triple::UnknownVendor) @@ -134,9 +137,10 @@ return true; } -/// Is the triple aarch64-none-elf? +/// Is the triple {aarch64.aarch64_be}-none-elf? static bool isAArch64BareMetal(const llvm::Triple &Triple) { - if (Triple.getArch() != llvm::Triple::aarch64) + if (Triple.getArch() != llvm::Triple::aarch64 && + Triple.getArch() != llvm::Triple::aarch64_be) return false; if (Triple.getVendor() != llvm::Triple::UnknownVendor) @@ -432,11 +436,21 @@ ArgStringList CmdArgs; auto &TC = static_cast(getToolChain()); + const llvm::Triple::ArchType Arch = TC.getArch(); + const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); CmdArgs.push_back("-Bstatic"); + if (Triple.isARM() || Triple.isThumb() || Triple.isAArch64()) { + bool IsBigEndian = arm::isARMBigEndian(Triple, Args); + if (IsBigEndian) + arm::appendBE8LinkFlag(Args, CmdArgs, Triple); + IsBigEndian = IsBigEndian || Arch == llvm::Triple::aarch64_be; + CmdArgs.push_back(IsBigEndian ? "-EB" : "-EL"); + } + Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, options::OPT_s, options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -220,30 +220,6 @@ // The types are (hopefully) good enough. } -// On Arm the endianness of the output file is determined by the target and -// can be overridden by the pseudo-target flags '-mlittle-endian'/'-EL' and -// '-mbig-endian'/'-EB'. Unlike other targets the flag does not result in a -// normalized triple so we must handle the flag here. -static bool isArmBigEndian(const llvm::Triple &Triple, - const ArgList &Args) { - bool IsBigEndian = false; - switch (Triple.getArch()) { - case llvm::Triple::armeb: - case llvm::Triple::thumbeb: - IsBigEndian = true; - [[fallthrough]]; - case llvm::Triple::arm: - case llvm::Triple::thumb: - if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian, - options::OPT_mbig_endian)) - IsBigEndian = !A->getOption().matches(options::OPT_mlittle_endian); - break; - default: - break; - } - return IsBigEndian; -} - static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { switch (T.getArch()) { case llvm::Triple::x86: @@ -258,7 +234,8 @@ case llvm::Triple::thumb: case llvm::Triple::armeb: case llvm::Triple::thumbeb: - return isArmBigEndian(T, Args) ? "armelfb_linux_eabi" : "armelf_linux_eabi"; + return tools::arm::isARMBigEndian(T, Args) ? "armelfb_linux_eabi" + : "armelf_linux_eabi"; case llvm::Triple::m68k: return "m68kelf"; case llvm::Triple::ppc: @@ -448,7 +425,7 @@ CmdArgs.push_back("-s"); if (Triple.isARM() || Triple.isThumb() || Triple.isAArch64()) { - bool IsBigEndian = isArmBigEndian(Triple, Args); + bool IsBigEndian = arm::isARMBigEndian(Triple, Args); if (IsBigEndian) arm::appendBE8LinkFlag(Args, CmdArgs, Triple); IsBigEndian = IsBigEndian || Arch == llvm::Triple::aarch64_be; @@ -820,7 +797,7 @@ case llvm::Triple::thumb: case llvm::Triple::thumbeb: { const llvm::Triple &Triple2 = getToolChain().getTriple(); - CmdArgs.push_back(isArmBigEndian(Triple2, Args) ? "-EB" : "-EL"); + CmdArgs.push_back(arm::isARMBigEndian(Triple2, Args) ? "-EB" : "-EL"); switch (Triple2.getSubArch()) { case llvm::Triple::ARMSubArch_v7: CmdArgs.push_back("-mfpu=neon"); diff --git a/clang/test/Driver/baremetal.cpp b/clang/test/Driver/baremetal.cpp --- a/clang/test/Driver/baremetal.cpp +++ b/clang/test/Driver/baremetal.cpp @@ -15,7 +15,7 @@ // CHECK-V6M-C-SAME: "-internal-isystem" "[[SYSROOT]]{{[/\\]+}}include{{[/\\]+}}c++{{[/\\]+}}v1" // CHECk-V6M-C-SAME: "-internal-isystem" "[[SYSROOT]]{{[/\\]+}}include" // CHECK-V6M-C-SAME: "-x" "c++" "{{.*}}baremetal.cpp" -// CHECK-V6M-C-NEXT: ld{{(.exe)?}}" "{{.*}}.o" "-Bstatic" +// CHECK-V6M-C-NEXT: ld{{(.exe)?}}" "{{.*}}.o" "-Bstatic" "-EL" // CHECK-V6M-C-SAME: "-T" "semihosted.lds" "-Lsome{{[/\\]+}}directory{{[/\\]+}}user{{[/\\]+}}asked{{[/\\]+}}for" // CHECK-V6M-C-SAME: "-L[[SYSROOT:[^"]+]]{{[/\\]+}}lib" // CHECK-V6M-C-SAME: "-L[[RESOURCE_DIR:[^"]+]]{{[/\\]+}}lib{{[/\\]+}}baremetal" @@ -34,7 +34,7 @@ // CHECK-ARMV7M-PER-TARGET: "-resource-dir" "[[RESOURCE_DIR:[^"]+]]" // CHECK-ARMV7M-PER-TARGET: "-isysroot" "[[SYSROOT:[^"]*]]" // CHECK-ARMV7M-PER-TARGET: "-x" "c++" "{{.*}}baremetal.cpp" -// CHECK-ARMV7M-PER-TARGET: ld{{(.exe)?}}" "{{.*}}.o" "-Bstatic" +// CHECK-ARMV7M-PER-TARGET: ld{{(.exe)?}}" "{{.*}}.o" "-Bstatic" "-EL" // CHECK-ARMV7M-PER-TARGET: "-L[[SYSROOT:[^"]+]]{{[/\\]+}}lib" // CHECK-ARMV7M-PER-TARGET: "-L[[RESOURCE_DIR:[^"]+]]{{[/\\]+}}lib{{[/\\]+}}armv7m-vendor-none-eabi // CHECK-ARMV7M-PER-TARGET: "-lc" "-lm" "-lclang_rt.builtins" @@ -42,7 +42,7 @@ // RUN: %clangxx %s -### --target=armv6m-none-eabi 2>&1 \ // RUN: --sysroot=%S/Inputs/baremetal_arm | FileCheck --check-prefix=CHECK-V6M-DEFAULTCXX %s // CHECK-V6M-DEFAULTCXX: "-resource-dir" "[[RESOURCE_DIR:[^"]+]]" -// CHECK-V6M-DEFAULTCXX: ld{{(.exe)?}}" "{{.*}}.o" "-Bstatic" +// CHECK-V6M-DEFAULTCXX: ld{{(.exe)?}}" "{{.*}}.o" "-Bstatic" "-EL" // CHECK-V6M-DEFAULTCXX-SAME: "-L{{[^"]*}}{{[/\\]+}}Inputs{{[/\\]+}}baremetal_arm{{[/\\]+}}lib" // CHECK-V6M-DEFAULTCXX-SAME: "-L[[RESOURCE_DIR]]{{[/\\]+}}lib{{[/\\]+}}baremetal" // CHECK-V6M-DEFAULTCXX-SAME: "-lc++" "-lc++abi" "-lunwind" @@ -53,7 +53,7 @@ // CHECK-V6M-LIBCXX: "-resource-dir" "[[RESOURCE_DIR:[^"]+]]" // CHECK-V6M-LIBCXX-NOT: "-internal-isystem" "{{[^"]+}}{{[/\\]+}}include{{[/\\]+}}c++{{[/\\]+}}{{[^v].*}}" // CHECK-V6M-LIBCXX-SAME: "-internal-isystem" "{{[^"]+}}{{[/\\]+}}include{{[/\\]+}}c++{{[/\\]+}}v1" -// CHECK-V6M-LIBCXX: ld{{(.exe)?}}" "{{.*}}.o" "-Bstatic" +// CHECK-V6M-LIBCXX: ld{{(.exe)?}}" "{{.*}}.o" "-Bstatic" "-EL" // CHECK-V6M-LIBCXX-SAME: "-L{{[^"]*}}{{[/\\]+}}Inputs{{[/\\]+}}baremetal_arm{{[/\\]+}}lib" // CHECK-V6M-LIBCXX-SAME: "-L[[RESOURCE_DIR]]{{[/\\]+}}lib{{[/\\]+}}baremetal" // CHECK-V6M-LIBCXX-SAME: "-lc++" "-lc++abi" "-lunwind" @@ -66,7 +66,7 @@ // CHECK-V6M-LIBSTDCXX: "-resource-dir" "[[RESOURCE_DIR:[^"]+]]" // CHECK-V6M-LIBSTDCXX-NOT: "-internal-isystem" "{{[^"]+}}{{[/\\]+}}include{{[/\\]+}}c++{{[/\\]+}}v1" // CHECK-V6M-LIBSTDCXX-SAME: "-internal-isystem" "{{[^"]+}}{{[/\\]+}}include{{[/\\]+}}c++{{[/\\]+}}6.0.0" -// CHECK-V6M-LIBSTDCXX: ld{{(.exe)?}}" "{{.*}}.o" "-Bstatic" +// CHECK-V6M-LIBSTDCXX: ld{{(.exe)?}}" "{{.*}}.o" "-Bstatic" "-EL" // CHECK-V6M-LIBSTDCXX-SAME: "-L{{[^"]*}}{{[/\\]+}}Inputs{{[/\\]+}}baremetal_arm{{[/\\]+}}lib" // CHECK-V6M-LIBSTDCXX-SAME: "-L[[RESOURCE_DIR]]{{[/\\]+}}lib{{[/\\]+}}baremetal" // CHECK-V6M-LIBSTDCXX-SAME: "-lstdc++" "-lsupc++" "-lunwind" @@ -77,7 +77,7 @@ // RUN: -nodefaultlibs \ // RUN: | FileCheck --check-prefix=CHECK-V6M-NDL %s // CHECK-V6M-NDL: "-resource-dir" "[[RESOURCE_DIR:[^"]+]]" -// CHECK-V6M-NDL: ld{{(.exe)?}}" "{{.*}}.o" "-Bstatic" +// CHECK-V6M-NDL: ld{{(.exe)?}}" "{{.*}}.o" "-Bstatic" "-EL" // CHECK-V6M-NDL-SAME: "-L{{[^"]*}}{{[/\\]+}}Inputs{{[/\\]+}}baremetal_arm{{[/\\]+}}lib" // CHECK-V6M-NDL-SAME: "-L[[RESOURCE_DIR]]{{[/\\]+}}lib{{[/\\]+}}baremetal" @@ -117,6 +117,46 @@ // RUN: | FileCheck %s --check-prefix=CHECK-SYSROOT-INC // CHECK-SYSROOT-INC-NOT: "-internal-isystem" "include" +// RUN: %clang -### %s --target=armebv7-none-eabi --sysroot=%S/Inputs/baremetal_arm 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-ARMV7EB %s +// CHECK-ARMV7EB: "{{.*}}ld{{(.exe)?}}" "{{.*}}.o" "-Bstatic" "--be8" "-EB" + +// RUN: %clang -### %s --target=armv7-none-eabi -mbig-endian --sysroot=%S/Inputs/baremetal_arm 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-ARMV7EB %s + +// RUN: %clang -### %s --target=armebv7-none-eabi -mbig-endian --sysroot=%S/Inputs/baremetal_arm 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-ARMV7EB %s + +// RUN: %clang -### %s --target=armv7-none-eabi --sysroot=%S/Inputs/baremetal_arm 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-ARMV7EL %s +// CHECK-ARMV7EL: "{{.*}}ld{{(.exe)?}}" "{{.*}}.o" "-Bstatic" "-EL" +// CHECK-ARMV7EL-NOT: "--be8" + +// RUN: %clang -### %s --target=armebv7-none-eabi -mlittle-endian --sysroot=%S/Inputs/baremetal_arm 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-ARMV7EL %s + +// RUN: %clang -### %s --target=armv7-none-eabi -mlittle-endian --sysroot=%S/Inputs/baremetal_arm 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-ARMV7EL %s + +// RUN: %clang -### %s --target=aarch64_be-none-elf --sysroot=%S/Inputs/baremetal_arm 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-AARCH64BE %s +// CHECK-AARCH64BE: "{{.*}}ld{{(.exe)?}}" "{{.*}}.o" "-Bstatic" "-EB" +// CHECK-AARCH64BE-NOT: "--be8" + +// RUN: %clang -### %s --target=aarch64-none-elf -mbig-endian --sysroot=%S/Inputs/baremetal_arm 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-AARCH64BE %s + +// RUN: %clang -### %s --target=aarch64_be-none-elf -mbig-endian --sysroot=%S/Inputs/baremetal_arm 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-AARCH64BE %s + +// RUN: %clang -### %s --target=aarch64-none-elf --sysroot=%S/Inputs/baremetal_arm 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-AARCH64LE %s +// CHECK-AARCH64LE: "{{.*}}ld{{(.exe)?}}" "{{.*}}.o" "-Bstatic" "-EL" +// CHECK-AARCH64LE-NOT: "--be8" + +// RUN: %clang -### %s --target=aarch64_be-none-elf -mlittle-endian --sysroot=%S/Inputs/baremetal_arm 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-AARCH64LE %s + // RUN: %clang -no-canonical-prefixes %s -### --target=aarch64-none-elf 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-AARCH64-NO-HOST-INC %s // Verify that the bare metal driver does not include any host system paths: