From c45a5196d44b4cee469d0a366ff8489227e2566f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 14 Jul 2025 13:55:19 +0100 Subject: [PATCH 1/4] [Clang][Driver] Expose relocation model as multilib flags If a multilib collection contains libraries built for different methods of accessing global data (via absolute address, or via a GOT in -fPIC style, or as an offset from a fixed register in Arm -frwpi style), then `multilib.yaml` will need to know which relocation model an application is using in order to select the right library. Even if a multilib collection only supports one relocation model, it's still useful for `multilib.yaml` to be able to tell if the user has selected the right one, so as to give a useful error message if they haven't, instead of silently selecting a library that won't work. In this commit we determine the PIC / ROPI / RWPI status using the existing logic in `ParsePICArgs`, and translate it back into a canonical set of multilib selection flags. --- clang/lib/Driver/ToolChain.cpp | 37 +++++++++++++++++++ .../test/Driver/print-multi-selection-flags.c | 19 ++++++++++ 2 files changed, 56 insertions(+) diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 3f9b808b2722e..5738c0aa9b1d2 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -343,6 +343,7 @@ ToolChain::getMultilibFlags(const llvm::opt::ArgList &Args) const { std::vector Result; const llvm::Triple Triple(ComputeEffectiveClangTriple(Args)); Result.push_back("--target=" + Triple.str()); + bool IsARM = false; switch (Triple.getArch()) { case llvm::Triple::aarch64: @@ -355,6 +356,7 @@ ToolChain::getMultilibFlags(const llvm::opt::ArgList &Args) const { case llvm::Triple::thumb: case llvm::Triple::thumbeb: getARMMultilibFlags(D, Triple, Args, Result); + IsARM = true; // for ROPI/RWPI below break; case llvm::Triple::riscv32: case llvm::Triple::riscv64: @@ -376,6 +378,41 @@ ToolChain::getMultilibFlags(const llvm::opt::ArgList &Args) const { else Result.push_back("-fexceptions"); + // A difference of relocation model (absolutely addressed data, PIC, Arm + // ROPI/RWPI) is likely to change whether a particular multilib variant is + // compatible with a given link. Determine the relocation model of the + // current link, and add appropriate + { + RegisterEffectiveTriple TripleRAII( + *this, llvm::Triple(ComputeEffectiveClangTriple(Args))); + + auto [RelocationModel, PICLevel, IsPIE] = tools::ParsePICArgs(*this, Args); + + // ROPI and RWPI are only meaningful on Arm, so for other architectures, we + // expect never to find out they're enabled. But it seems confusing to add + // -fno-ropi and -fno-rwpi unconditionally to every other architecture's + // multilib flags, so instead we leave them out completely. + if (IsARM) { + if (RelocationModel == llvm::Reloc::ROPI || + RelocationModel == llvm::Reloc::ROPI_RWPI) + Result.push_back("-fropi"); + else + Result.push_back("-fno-ropi"); + + if (RelocationModel == llvm::Reloc::RWPI || + RelocationModel == llvm::Reloc::ROPI_RWPI) + Result.push_back("-frwpi"); + else + Result.push_back("-fno-rwpi"); + } + + if (RelocationModel == llvm::Reloc::PIC_) + Result.push_back(IsPIE ? (PICLevel > 1 ? "-fPIE" : "-fpie") + : (PICLevel > 1 ? "-fPIC" : "-fpic")); + else + Result.push_back("-fno-pic"); + } + // Sort and remove duplicates. std::sort(Result.begin(), Result.end()); Result.erase(llvm::unique(Result), Result.end()); diff --git a/clang/test/Driver/print-multi-selection-flags.c b/clang/test/Driver/print-multi-selection-flags.c index 5f9383fbed8f4..1d794091970d3 100644 --- a/clang/test/Driver/print-multi-selection-flags.c +++ b/clang/test/Driver/print-multi-selection-flags.c @@ -107,3 +107,22 @@ // CHECK-AARCH64-MULTILIB-CUSTOM-FLAG: --target=aarch64-unknown-none-eabi // CHECK-MULTILIB-CUSTOM-FLAG-DAG: -fmultilib-flag=foo // CHECK-MULTILIB-CUSTOM-FLAG-DAG: -fmultilib-flag=bar + +// RUN: %clang -multi-lib-config=%S/Inputs/multilib/empty.yaml -print-multi-flags-experimental --target=arm-none-eabi -march=armv7a -fropi | FileCheck --check-prefixes=CHECK-ROPI,CHECK-NO-RWPI,CHECK-NO-PIC %s +// RUN: %clang -multi-lib-config=%S/Inputs/multilib/empty.yaml -print-multi-flags-experimental --target=arm-none-eabi -march=armv7a -frwpi | FileCheck --check-prefixes=CHECK-RWPI,CHECK-NO-ROPI,CHECK-NO-PIC %s +// RUN: %clang -multi-lib-config=%S/Inputs/multilib/empty.yaml -print-multi-flags-experimental --target=arm-none-eabi -march=armv7a -fropi -frwpi | FileCheck --check-prefixes=CHECK-ROPI,CHECK-RWPI,CHECK-NO-PIC %s +// RUN: %clang -multi-lib-config=%S/Inputs/multilib/empty.yaml -print-multi-flags-experimental --target=arm-none-eabi -march=armv7a -fno-ropi -fno-rwpi | FileCheck --check-prefixes=CHECK-NO-ROPI,CHECK-NO-RWPI,CHECK-NO-PIC %s +// RUN: %clang -multi-lib-config=%S/Inputs/multilib/empty.yaml -print-multi-flags-experimental --target=arm-none-eabi -march=armv7a | FileCheck --check-prefixes=CHECK-NO-ROPI,CHECK-NO-RWPI,CHECK-NO-PIC %s +// RUN: %clang -multi-lib-config=%S/Inputs/multilib/empty.yaml -print-multi-flags-experimental --target=arm-none-eabi -march=armv7a -fpic | FileCheck --check-prefixes=CHECK-NO-ROPI,CHECK-NO-RWPI,CHECK-PIC1 %s +// RUN: %clang -multi-lib-config=%S/Inputs/multilib/empty.yaml -print-multi-flags-experimental --target=arm-none-eabi -march=armv7a -fPIC | FileCheck --check-prefixes=CHECK-NO-ROPI,CHECK-NO-RWPI,CHECK-PIC2 %s +// RUN: %clang -multi-lib-config=%S/Inputs/multilib/empty.yaml -print-multi-flags-experimental --target=arm-none-eabi -march=armv7a -fpie | FileCheck --check-prefixes=CHECK-NO-ROPI,CHECK-NO-RWPI,CHECK-PIE1 %s +// RUN: %clang -multi-lib-config=%S/Inputs/multilib/empty.yaml -print-multi-flags-experimental --target=arm-none-eabi -march=armv7a -fPIE | FileCheck --check-prefixes=CHECK-NO-ROPI,CHECK-NO-RWPI,CHECK-PIE2 %s +// CHECK-ROPI: -fropi +// CHECK-NO-ROPI: -fno-ropi +// CHECK-RWPI: -frwpi +// CHECK-NO-RWPI: -fno-rwpi +// CHECK-PIC1: -fpic +// CHECK-PIC2: -fPIC +// CHECK-PIE1: -fpie +// CHECK-PIE2: -fPIE +// CHECK-NO-PIC: -fno-pic From 02eada87bcc21bd0e1503cb41361b666cc460d82 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 16 Jul 2025 17:20:10 +0100 Subject: [PATCH 2/4] Add missing end of sentence in comment (Thanks to clang-format for pointing out the trailing space on that line, which was there because I meant to type a word after it!) --- clang/lib/Driver/ToolChain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 5738c0aa9b1d2..72056bdd222eb 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -381,7 +381,7 @@ ToolChain::getMultilibFlags(const llvm::opt::ArgList &Args) const { // A difference of relocation model (absolutely addressed data, PIC, Arm // ROPI/RWPI) is likely to change whether a particular multilib variant is // compatible with a given link. Determine the relocation model of the - // current link, and add appropriate + // current link, and add appropriate multilib flags. { RegisterEffectiveTriple TripleRAII( *this, llvm::Triple(ComputeEffectiveClangTriple(Args))); From 877d7330d52ceed0b4ee2515878001fceef859d6 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 17 Jul 2025 12:43:59 +0100 Subject: [PATCH 3/4] Move ROPI/RWPI into the Arm-specific function --- clang/lib/Driver/ToolChain.cpp | 75 +++++++++++++++------------------- 1 file changed, 34 insertions(+), 41 deletions(-) diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 72056bdd222eb..481f575518b93 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -258,10 +258,10 @@ static void getAArch64MultilibFlags(const Driver &D, processMultilibCustomFlags(Result, Args); } -static void getARMMultilibFlags(const Driver &D, - const llvm::Triple &Triple, - const llvm::opt::ArgList &Args, - Multilib::flags_list &Result) { +static void getARMMultilibFlags(const Driver &D, const llvm::Triple &Triple, + llvm::Reloc::Model RelocationModel, + const llvm::opt::ArgList &Args, + Multilib::flags_list &Result) { std::vector Features; llvm::ARM::FPUKind FPUKind = tools::arm::getARMTargetFeatures( D, Triple, Args, Features, false /*ForAs*/, true /*ForMultilib*/); @@ -304,6 +304,18 @@ static void getARMMultilibFlags(const Driver &D, llvm_unreachable("Invalid float ABI"); } + if (RelocationModel == llvm::Reloc::ROPI || + RelocationModel == llvm::Reloc::ROPI_RWPI) + Result.push_back("-fropi"); + else + Result.push_back("-fno-ropi"); + + if (RelocationModel == llvm::Reloc::RWPI || + RelocationModel == llvm::Reloc::ROPI_RWPI) + Result.push_back("-frwpi"); + else + Result.push_back("-fno-rwpi"); + const Arg *BranchProtectionArg = Args.getLastArgNoClaim(options::OPT_mbranch_protection_EQ); if (BranchProtectionArg) { @@ -343,7 +355,18 @@ ToolChain::getMultilibFlags(const llvm::opt::ArgList &Args) const { std::vector Result; const llvm::Triple Triple(ComputeEffectiveClangTriple(Args)); Result.push_back("--target=" + Triple.str()); - bool IsARM = false; + + // A difference of relocation model (absolutely addressed data, PIC, Arm + // ROPI/RWPI) is likely to change whether a particular multilib variant is + // compatible with a given link. Determine the relocation model of the + // current link, so as to add appropriate multilib flags. + llvm::Reloc::Model RelocationModel; + unsigned PICLevel; + bool IsPIE; + { + RegisterEffectiveTriple TripleRAII(*this, Triple); + std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(*this, Args); + } switch (Triple.getArch()) { case llvm::Triple::aarch64: @@ -355,8 +378,7 @@ ToolChain::getMultilibFlags(const llvm::opt::ArgList &Args) const { case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: - getARMMultilibFlags(D, Triple, Args, Result); - IsARM = true; // for ROPI/RWPI below + getARMMultilibFlags(D, Triple, RelocationModel, Args, Result); break; case llvm::Triple::riscv32: case llvm::Triple::riscv64: @@ -378,40 +400,11 @@ ToolChain::getMultilibFlags(const llvm::opt::ArgList &Args) const { else Result.push_back("-fexceptions"); - // A difference of relocation model (absolutely addressed data, PIC, Arm - // ROPI/RWPI) is likely to change whether a particular multilib variant is - // compatible with a given link. Determine the relocation model of the - // current link, and add appropriate multilib flags. - { - RegisterEffectiveTriple TripleRAII( - *this, llvm::Triple(ComputeEffectiveClangTriple(Args))); - - auto [RelocationModel, PICLevel, IsPIE] = tools::ParsePICArgs(*this, Args); - - // ROPI and RWPI are only meaningful on Arm, so for other architectures, we - // expect never to find out they're enabled. But it seems confusing to add - // -fno-ropi and -fno-rwpi unconditionally to every other architecture's - // multilib flags, so instead we leave them out completely. - if (IsARM) { - if (RelocationModel == llvm::Reloc::ROPI || - RelocationModel == llvm::Reloc::ROPI_RWPI) - Result.push_back("-fropi"); - else - Result.push_back("-fno-ropi"); - - if (RelocationModel == llvm::Reloc::RWPI || - RelocationModel == llvm::Reloc::ROPI_RWPI) - Result.push_back("-frwpi"); - else - Result.push_back("-fno-rwpi"); - } - - if (RelocationModel == llvm::Reloc::PIC_) - Result.push_back(IsPIE ? (PICLevel > 1 ? "-fPIE" : "-fpie") - : (PICLevel > 1 ? "-fPIC" : "-fpic")); - else - Result.push_back("-fno-pic"); - } + if (RelocationModel == llvm::Reloc::PIC_) + Result.push_back(IsPIE ? (PICLevel > 1 ? "-fPIE" : "-fpie") + : (PICLevel > 1 ? "-fPIC" : "-fpic")); + else + Result.push_back("-fno-pic"); // Sort and remove duplicates. std::sort(Result.begin(), Result.end()); From 2568c65829ec2ef3f7b4b8855b204838032e3633 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 17 Jul 2025 13:51:45 +0100 Subject: [PATCH 4/4] Fix the test All the CHECK lines are checked in a single run of FileCheck, so the options they mention must appear in the same order that the flags are shown in the -print-multi-flags output, which is ASCII sorting order. --- clang/test/Driver/print-multi-selection-flags.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/test/Driver/print-multi-selection-flags.c b/clang/test/Driver/print-multi-selection-flags.c index 1d794091970d3..8cf8f04bb6b48 100644 --- a/clang/test/Driver/print-multi-selection-flags.c +++ b/clang/test/Driver/print-multi-selection-flags.c @@ -109,7 +109,7 @@ // CHECK-MULTILIB-CUSTOM-FLAG-DAG: -fmultilib-flag=bar // RUN: %clang -multi-lib-config=%S/Inputs/multilib/empty.yaml -print-multi-flags-experimental --target=arm-none-eabi -march=armv7a -fropi | FileCheck --check-prefixes=CHECK-ROPI,CHECK-NO-RWPI,CHECK-NO-PIC %s -// RUN: %clang -multi-lib-config=%S/Inputs/multilib/empty.yaml -print-multi-flags-experimental --target=arm-none-eabi -march=armv7a -frwpi | FileCheck --check-prefixes=CHECK-RWPI,CHECK-NO-ROPI,CHECK-NO-PIC %s +// RUN: %clang -multi-lib-config=%S/Inputs/multilib/empty.yaml -print-multi-flags-experimental --target=arm-none-eabi -march=armv7a -frwpi | FileCheck --check-prefixes=CHECK-NO-ROPI,CHECK-RWPI,CHECK-NO-PIC %s // RUN: %clang -multi-lib-config=%S/Inputs/multilib/empty.yaml -print-multi-flags-experimental --target=arm-none-eabi -march=armv7a -fropi -frwpi | FileCheck --check-prefixes=CHECK-ROPI,CHECK-RWPI,CHECK-NO-PIC %s // RUN: %clang -multi-lib-config=%S/Inputs/multilib/empty.yaml -print-multi-flags-experimental --target=arm-none-eabi -march=armv7a -fno-ropi -fno-rwpi | FileCheck --check-prefixes=CHECK-NO-ROPI,CHECK-NO-RWPI,CHECK-NO-PIC %s // RUN: %clang -multi-lib-config=%S/Inputs/multilib/empty.yaml -print-multi-flags-experimental --target=arm-none-eabi -march=armv7a | FileCheck --check-prefixes=CHECK-NO-ROPI,CHECK-NO-RWPI,CHECK-NO-PIC %s @@ -117,12 +117,12 @@ // RUN: %clang -multi-lib-config=%S/Inputs/multilib/empty.yaml -print-multi-flags-experimental --target=arm-none-eabi -march=armv7a -fPIC | FileCheck --check-prefixes=CHECK-NO-ROPI,CHECK-NO-RWPI,CHECK-PIC2 %s // RUN: %clang -multi-lib-config=%S/Inputs/multilib/empty.yaml -print-multi-flags-experimental --target=arm-none-eabi -march=armv7a -fpie | FileCheck --check-prefixes=CHECK-NO-ROPI,CHECK-NO-RWPI,CHECK-PIE1 %s // RUN: %clang -multi-lib-config=%S/Inputs/multilib/empty.yaml -print-multi-flags-experimental --target=arm-none-eabi -march=armv7a -fPIE | FileCheck --check-prefixes=CHECK-NO-ROPI,CHECK-NO-RWPI,CHECK-PIE2 %s -// CHECK-ROPI: -fropi +// CHECK-PIC2: -fPIC +// CHECK-PIE2: -fPIE +// CHECK-NO-PIC: -fno-pic // CHECK-NO-ROPI: -fno-ropi -// CHECK-RWPI: -frwpi // CHECK-NO-RWPI: -fno-rwpi // CHECK-PIC1: -fpic -// CHECK-PIC2: -fPIC // CHECK-PIE1: -fpie -// CHECK-PIE2: -fPIE -// CHECK-NO-PIC: -fno-pic +// CHECK-ROPI: -fropi +// CHECK-RWPI: -frwpi