Skip to content

Commit acd2093

Browse files
committed
[clang][RISCV] Introduce command line options for Zicfilp-backed forward-edge CFI
This patch enables the following command line flags for RISC-V targets: + `-fcf-protection=branch` turns on forward-edge control-flow integrity conditioning on RISC-V targets with Zicfilp extension + `-mcf-branch-label-scheme=unlabeled|func-sig` selects the label scheme used in the forward-edge CFI conditioning
1 parent ea902d1 commit acd2093

File tree

12 files changed

+151
-0
lines changed

12 files changed

+151
-0
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//===--- CFProtectionOptions.h ----------------------------------*- 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+
// This file defines constants for -fcf-protection and other related flags.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_CLANG_BASIC_CFPROTECTIONOPTIONS_H
14+
#define LLVM_CLANG_BASIC_CFPROTECTIONOPTIONS_H
15+
16+
namespace clang {
17+
18+
enum class CFBranchLabelSchemeKind { Default, Unlabeled, FuncSig };
19+
20+
} // namespace clang
21+
22+
#endif // #ifndef LLVM_CLANG_BASIC_CFPROTECTIONOPTIONS_H

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ CODEGENOPT(CFProtectionReturn , 1, 0) ///< if -fcf-protection is
110110
///< set to full or return.
111111
CODEGENOPT(CFProtectionBranch , 1, 0) ///< if -fcf-protection is
112112
///< set to full or branch.
113+
ENUM_CODEGENOPT(CFBranchLabelScheme, CFBranchLabelSchemeKind, 2,
114+
CFBranchLabelSchemeKind::Default) ///< if -mcf-branch-label-scheme is set.
113115
CODEGENOPT(FunctionReturnThunks, 1, 0) ///< -mfunction-return={keep|thunk-extern}
114116
CODEGENOPT(IndirectBranchCSPrefix, 1, 0) ///< if -mindirect-branch-cs-prefix
115117
///< is set.

clang/include/clang/Basic/CodeGenOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef LLVM_CLANG_BASIC_CODEGENOPTIONS_H
1414
#define LLVM_CLANG_BASIC_CODEGENOPTIONS_H
1515

16+
#include "clang/Basic/CFProtectionOptions.h"
1617
#include "clang/Basic/PointerAuthOptions.h"
1718
#include "clang/Basic/Sanitizers.h"
1819
#include "clang/Basic/XRayInstr.h"

clang/include/clang/Basic/LangOptions.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,8 @@ BENIGN_LANGOPT(CompatibilityQualifiedIdBlockParamTypeChecking, 1, 0,
364364
LANGOPT(ObjCDisableDirectMethodsForTesting, 1, 0,
365365
"Disable recognition of objc_direct methods")
366366
LANGOPT(CFProtectionBranch , 1, 0, "Control-Flow Branch Protection enabled")
367+
ENUM_LANGOPT(CFBranchLabelScheme, CFBranchLabelSchemeKind, 2, CFBranchLabelSchemeKind::Default,
368+
"Control-Flow Branch Protection Label Scheme")
367369
LANGOPT(FakeAddressSpaceMap , 1, 0, "OpenCL fake address space map")
368370
ENUM_LANGOPT(AddressSpaceMapMangling , AddrSpaceMapMangling, 2, ASMM_Target, "OpenCL address space map mangling mode")
369371
LANGOPT(IncludeDefaultHeader, 1, 0, "Include default header file for OpenCL")

clang/include/clang/Basic/LangOptions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#ifndef LLVM_CLANG_BASIC_LANGOPTIONS_H
1515
#define LLVM_CLANG_BASIC_LANGOPTIONS_H
1616

17+
#include "clang/Basic/CFProtectionOptions.h"
1718
#include "clang/Basic/CommentOptions.h"
1819
#include "clang/Basic/LLVM.h"
1920
#include "clang/Basic/LangStandard.h"
@@ -73,6 +74,7 @@ class LangOptionsBase {
7374
public:
7475
using Visibility = clang::Visibility;
7576
using RoundingMode = llvm::RoundingMode;
77+
using CFBranchLabelSchemeKind = clang::CFBranchLabelSchemeKind;
7678

7779
enum GCMode { NonGC, GCOnly, HybridGC };
7880
enum StackProtectorMode { SSPOff, SSPOn, SSPStrong, SSPReq };

clang/include/clang/Basic/TargetInfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "clang/Basic/AddressSpaces.h"
1818
#include "clang/Basic/BitmaskEnum.h"
19+
#include "clang/Basic/CFProtectionOptions.h"
1920
#include "clang/Basic/CodeGenOptions.h"
2021
#include "clang/Basic/LLVM.h"
2122
#include "clang/Basic/LangOptions.h"
@@ -1727,6 +1728,9 @@ class TargetInfo : public TransferrableTargetInfo,
17271728
virtual bool
17281729
checkCFProtectionBranchSupported(DiagnosticsEngine &Diags) const;
17291730

1731+
/// Get the target default CFBranchLabelScheme scheme
1732+
virtual CFBranchLabelSchemeKind getDefaultCFBranchLabelScheme() const;
1733+
17301734
/// Check if the target supports CFProtection return.
17311735
virtual bool
17321736
checkCFProtectionReturnSupported(DiagnosticsEngine &Diags) const;

clang/include/clang/Driver/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2841,6 +2841,10 @@ def fcf_protection : Flag<["-"], "fcf-protection">, Group<f_Group>,
28412841
Visibility<[ClangOption, CLOption, CC1Option]>,
28422842
Alias<fcf_protection_EQ>, AliasArgs<["full"]>,
28432843
HelpText<"Enable cf-protection in 'full' mode">;
2844+
def mcf_branch_label_scheme_EQ : Joined<["-"], "mcf-branch-label-scheme=">,
2845+
Visibility<[ClangOption, CC1Option]>, Group<m_Group>,
2846+
HelpText<"Select label scheme for branch control-flow architecture protection">,
2847+
Values<"unlabeled,func-sig">;
28442848
def mfunction_return_EQ : Joined<["-"], "mfunction-return=">,
28452849
Group<m_Group>, Visibility<[ClangOption, CLOption, CC1Option]>,
28462850
HelpText<"Replace returns with jumps to ``__x86_return_thunk`` (x86 only, error otherwise)">,

clang/lib/Basic/TargetInfo.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ void TargetInfo::resetDataLayout(StringRef DL, const char *ULP) {
192192
UserLabelPrefix = ULP;
193193
}
194194

195+
CFBranchLabelSchemeKind TargetInfo::getDefaultCFBranchLabelScheme() const {
196+
// if this hook is called, the target should override it
197+
llvm::report_fatal_error("not implemented");
198+
}
199+
195200
bool
196201
TargetInfo::checkCFProtectionBranchSupported(DiagnosticsEngine &Diags) const {
197202
Diags.Report(diag::err_opt_not_valid_on_target) << "cf-protection=branch";

clang/lib/Basic/Targets/RISCV.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,17 @@ class RISCVTargetInfo : public TargetInfo {
134134

135135
bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize,
136136
bool &HasSizeMismatch) const override;
137+
138+
bool
139+
checkCFProtectionBranchSupported(DiagnosticsEngine &Diags) const override {
140+
if (ISAInfo->hasExtension("zicfilp"))
141+
return true;
142+
return TargetInfo::checkCFProtectionBranchSupported(Diags);
143+
}
144+
145+
CFBranchLabelSchemeKind getDefaultCFBranchLabelScheme() const override {
146+
return CFBranchLabelSchemeKind::FuncSig;
147+
}
137148
};
138149
class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo {
139150
public:

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7012,6 +7012,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
70127012
if (Arg *A = Args.getLastArg(options::OPT_fcf_protection_EQ)) {
70137013
CmdArgs.push_back(
70147014
Args.MakeArgString(Twine("-fcf-protection=") + A->getValue()));
7015+
7016+
if (Arg *SA = Args.getLastArg(options::OPT_mcf_branch_label_scheme_EQ))
7017+
CmdArgs.push_back(Args.MakeArgString(Twine("-mcf-branch-label-scheme=") +
7018+
SA->getValue()));
70157019
}
70167020

70177021
if (Arg *A = Args.getLastArg(options::OPT_mfunction_return_EQ))

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,6 +1688,19 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
16881688
else if (Opts.CFProtectionBranch)
16891689
GenerateArg(Consumer, OPT_fcf_protection_EQ, "branch");
16901690

1691+
if (Opts.CFProtectionBranch) {
1692+
switch (Opts.getCFBranchLabelScheme()) {
1693+
case CFBranchLabelSchemeKind::Default:
1694+
break;
1695+
case CFBranchLabelSchemeKind::Unlabeled:
1696+
GenerateArg(Consumer, OPT_mcf_branch_label_scheme_EQ, "unlabeled");
1697+
break;
1698+
case CFBranchLabelSchemeKind::FuncSig:
1699+
GenerateArg(Consumer, OPT_mcf_branch_label_scheme_EQ, "func-sig");
1700+
break;
1701+
}
1702+
}
1703+
16911704
if (Opts.FunctionReturnThunks)
16921705
GenerateArg(Consumer, OPT_mfunction_return_EQ, "thunk-extern");
16931706

@@ -2022,6 +2035,19 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
20222035
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
20232036
}
20242037

2038+
if (Opts.CFProtectionBranch && T.isRISCV()) {
2039+
if (const Arg *A = Args.getLastArg(OPT_mcf_branch_label_scheme_EQ)) {
2040+
const StringRef Scheme = A->getValue();
2041+
if (Scheme == "unlabeled")
2042+
Opts.setCFBranchLabelScheme(CFBranchLabelSchemeKind::Unlabeled);
2043+
else if (Scheme == "func-sig")
2044+
Opts.setCFBranchLabelScheme(CFBranchLabelSchemeKind::FuncSig);
2045+
else
2046+
Diags.Report(diag::err_drv_invalid_value)
2047+
<< A->getAsString(Args) << Scheme;
2048+
}
2049+
}
2050+
20252051
if (const Arg *A = Args.getLastArg(OPT_mfunction_return_EQ)) {
20262052
auto Val = llvm::StringSwitch<llvm::FunctionReturnThunksKind>(A->getValue())
20272053
.Case("keep", llvm::FunctionReturnThunksKind::Keep)
@@ -3952,6 +3978,16 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
39523978
}
39533979
}
39543980

3981+
if (const Arg *A = Args.getLastArg(OPT_mcf_branch_label_scheme_EQ)) {
3982+
if (Opts.CFProtectionBranch) {
3983+
const StringRef Scheme = A->getValue();
3984+
if (Scheme == "unlabeled")
3985+
Opts.setCFBranchLabelScheme(CFBranchLabelSchemeKind::Unlabeled);
3986+
else if (Scheme == "func-sig")
3987+
Opts.setCFBranchLabelScheme(CFBranchLabelSchemeKind::FuncSig);
3988+
}
3989+
}
3990+
39553991
if ((Args.hasArg(OPT_fsycl_is_device) || Args.hasArg(OPT_fsycl_is_host)) &&
39563992
!Args.hasArg(OPT_sycl_std_EQ)) {
39573993
// If the user supplied -fsycl-is-device or -fsycl-is-host, but failed to
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// RUN: %clang --target=riscv32 -menable-experimental-extensions \
2+
// RUN: -march=rv32i_zicfilp1p0 -mcf-branch-label-scheme=unlabeled -c %s \
3+
// RUN: -o /dev/null 2>&1 \
4+
// RUN: | FileCheck --check-prefix=CHECK-UNLABELED-SCHEME-UNUSED %s
5+
6+
// RUN: %clang --target=riscv32 -menable-experimental-extensions \
7+
// RUN: -march=rv32i_zicfilp1p0 -mcf-branch-label-scheme=func-sig -c %s \
8+
// RUN: -o /dev/null 2>&1 \
9+
// RUN: | FileCheck --check-prefix=CHECK-FUNC-SIG-SCHEME-UNUSED %s
10+
11+
// RUN: not %clang --target=riscv32 -fcf-protection=branch \
12+
// RUN: -mcf-branch-label-scheme=unlabeled -c %s -o /dev/null 2>&1 \
13+
// RUN: | FileCheck --check-prefix=CHECK-BRANCH-PROT-INVALID %s
14+
15+
// RUN: not %clang --target=riscv32 -fcf-protection=branch \
16+
// RUN: -mcf-branch-label-scheme=func-sig -c %s -o /dev/null 2>&1 \
17+
// RUN: | FileCheck --check-prefix=CHECK-BRANCH-PROT-INVALID %s
18+
19+
// RUN: %clang --target=riscv32 -mcf-branch-label-scheme=unlabeled -c %s \
20+
// RUN: -o /dev/null 2>&1 \
21+
// RUN: | FileCheck --check-prefix=CHECK-UNLABELED-SCHEME-UNUSED %s
22+
23+
// RUN: %clang --target=riscv32 -mcf-branch-label-scheme=func-sig -c %s \
24+
// RUN: -o /dev/null 2>&1 \
25+
// RUN: | FileCheck --check-prefix=CHECK-FUNC-SIG-SCHEME-UNUSED %s
26+
27+
// RUN: %clang --target=riscv64 -menable-experimental-extensions \
28+
// RUN: -march=rv64i_zicfilp1p0 -mcf-branch-label-scheme=unlabeled -c %s \
29+
// RUN: -o /dev/null 2>&1 \
30+
// RUN: | FileCheck --check-prefix=CHECK-UNLABELED-SCHEME-UNUSED %s
31+
32+
// RUN: %clang --target=riscv64 -menable-experimental-extensions \
33+
// RUN: -march=rv64i_zicfilp1p0 -mcf-branch-label-scheme=func-sig -c %s \
34+
// RUN: -o /dev/null 2>&1 \
35+
// RUN: | FileCheck --check-prefix=CHECK-FUNC-SIG-SCHEME-UNUSED %s
36+
37+
// RUN: not %clang --target=riscv64 -fcf-protection=branch \
38+
// RUN: -mcf-branch-label-scheme=unlabeled -c %s -o /dev/null 2>&1 \
39+
// RUN: | FileCheck --check-prefix=CHECK-BRANCH-PROT-INVALID %s
40+
41+
// RUN: not %clang --target=riscv64 -fcf-protection=branch \
42+
// RUN: -mcf-branch-label-scheme=func-sig -c %s -o /dev/null 2>&1 \
43+
// RUN: | FileCheck --check-prefix=CHECK-BRANCH-PROT-INVALID %s
44+
45+
// RUN: %clang --target=riscv64 -mcf-branch-label-scheme=unlabeled -c %s \
46+
// RUN: -o /dev/null 2>&1 \
47+
// RUN: | FileCheck --check-prefix=CHECK-UNLABELED-SCHEME-UNUSED %s
48+
49+
// RUN: %clang --target=riscv64 -mcf-branch-label-scheme=func-sig -c %s \
50+
// RUN: -o /dev/null 2>&1 \
51+
// RUN: | FileCheck --check-prefix=CHECK-FUNC-SIG-SCHEME-UNUSED %s
52+
53+
// CHECK-BRANCH-PROT-INVALID: error: option 'cf-protection=branch' cannot be
54+
// CHECK-BRANCH-PROT-INVALID-SAME: specified on this target
55+
// CHECK-UNLABELED-SCHEME-UNUSED: warning: argument unused during compilation:
56+
// CHECK-UNLABELED-SCHEME-UNUSED-SAME: '-mcf-branch-label-scheme=unlabeled'
57+
// CHECK-FUNC-SIG-SCHEME-UNUSED: warning: argument unused during compilation:
58+
// CHECK-FUNC-SIG-SCHEME-UNUSED-SAME: '-mcf-branch-label-scheme=func-sig'

0 commit comments

Comments
 (0)