Skip to content

Commit cfe59d0

Browse files
committed
Initial forward-edge CFI implementation
Give the user the option to start all basic blocks that are targets of indirect branches with the BTI instruction introduced by the Branch Target Identification extension to the Arm instruction set architecture. Copyright (c) 2022, Arm Limited.
1 parent 2f9d96c commit cfe59d0

File tree

27 files changed

+409
-80
lines changed

27 files changed

+409
-80
lines changed

cranelift/codegen/meta/src/isa/arm64.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,19 @@ use crate::shared::Definitions as SharedDefinitions;
55

66
fn define_settings(_shared: &SettingGroup) -> SettingGroup {
77
let mut setting = SettingGroupBuilder::new("arm64");
8-
let has_lse = setting.add_bool("has_lse", "Has Large System Extensions support.", "", false);
8+
let has_lse = setting.add_bool(
9+
"has_lse",
10+
"Has Large System Extensions (FEAT_LSE) support.",
11+
"",
12+
false,
13+
);
14+
15+
setting.add_bool(
16+
"use_bti",
17+
"Use Branch Target Identification (FEAT_BTI) instructions.",
18+
"",
19+
false,
20+
);
921

1022
setting.add_predicate("use_lse", predicate!(has_lse));
1123
setting.build()

cranelift/codegen/src/alias_analysis.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ impl<'a> AliasAnalysis<'a> {
236236
log::trace!("after inst{}: state is {:?}", inst.index(), state);
237237
}
238238

239-
visit_block_succs(self.func, block, |_inst, succ| {
239+
visit_block_succs(self.func, block, |_inst, succ, _from_table| {
240240
let succ_first_inst = self
241241
.func
242242
.layout

cranelift/codegen/src/inst_predicates.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,26 +130,32 @@ pub fn has_memory_fence_semantics(op: Opcode) -> bool {
130130
}
131131

132132
/// Visit all successors of a block with a given visitor closure.
133-
pub(crate) fn visit_block_succs<F: FnMut(Inst, Block)>(f: &Function, block: Block, mut visit: F) {
133+
pub(crate) fn visit_block_succs<F: FnMut(Inst, Block, bool)>(
134+
f: &Function,
135+
block: Block,
136+
mut visit: F,
137+
) {
134138
for inst in f.layout.block_likely_branches(block) {
135139
if f.dfg[inst].opcode().is_branch() {
136140
visit_branch_targets(f, inst, &mut visit);
137141
}
138142
}
139143
}
140144

141-
fn visit_branch_targets<F: FnMut(Inst, Block)>(f: &Function, inst: Inst, visit: &mut F) {
145+
fn visit_branch_targets<F: FnMut(Inst, Block, bool)>(f: &Function, inst: Inst, visit: &mut F) {
142146
match f.dfg[inst].analyze_branch(&f.dfg.value_lists) {
143147
BranchInfo::NotABranch => {}
144148
BranchInfo::SingleDest(dest, _) => {
145-
visit(inst, dest);
149+
visit(inst, dest, false);
146150
}
147151
BranchInfo::Table(table, maybe_dest) => {
148152
if let Some(dest) = maybe_dest {
149-
visit(inst, dest);
153+
// The default block is reached via a direct conditional branch,
154+
// so it is not part of the table.
155+
visit(inst, dest, false);
150156
}
151157
for &dest in f.jump_tables[table].as_slice() {
152-
visit(inst, dest);
158+
visit(inst, dest, true);
153159
}
154160
}
155161
}

cranelift/codegen/src/isa/aarch64/abi.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -622,10 +622,10 @@ impl ABIMachineSpec for AArch64MachineDeps {
622622
}
623623
}
624624

625-
fn gen_debug_frame_info(
625+
fn gen_prologue_start(
626626
call_conv: isa::CallConv,
627627
flags: &settings::Flags,
628-
_isa_flags: &Vec<settings::Value>,
628+
isa_flags: &Vec<settings::Value>,
629629
) -> SmallInstVec<Inst> {
630630
let mut insts = SmallVec::new();
631631
if flags.unwind_info() && call_conv.extends_apple_aarch64() {
@@ -635,6 +635,13 @@ impl ABIMachineSpec for AArch64MachineDeps {
635635
},
636636
});
637637
}
638+
639+
if has_bool_setting("use_bti", isa_flags) {
640+
insts.push(Inst::Bti {
641+
targets: BranchTargetType::C,
642+
});
643+
}
644+
638645
insts
639646
}
640647

cranelift/codegen/src/isa/aarch64/inst.isle

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,11 @@
732732
(rd WritableReg)
733733
(mem AMode))
734734

735+
;; Branch target identification; equivalent to a no-op if Branch Target
736+
;; Identification (FEAT_BTI) is not supported.
737+
(Bti
738+
(targets BranchTargetType))
739+
735740
;; Marker, no-op in generated code: SP "virtual offset" is adjusted. This
736741
;; controls how AMode::NominalSPOffset args are lowered.
737742
(VirtualSPOffsetAdj
@@ -1282,6 +1287,15 @@
12821287
(Xchg)
12831288
))
12841289

1290+
;; Branch target types
1291+
(type BranchTargetType
1292+
(enum
1293+
(None)
1294+
(C)
1295+
(J)
1296+
(JC)
1297+
))
1298+
12851299
;; Extractors for target features ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
12861300
(decl use_lse () Inst)
12871301
(extern extractor use_lse use_lse)

cranelift/codegen/src/isa/aarch64/inst/emit.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3044,6 +3044,16 @@ impl MachInstEmit for Inst {
30443044
add.emit(&[], sink, emit_info, state);
30453045
}
30463046
}
3047+
&Inst::Bti { targets } => {
3048+
let targets = match targets {
3049+
BranchTargetType::None => 0b00,
3050+
BranchTargetType::C => 0b01,
3051+
BranchTargetType::J => 0b10,
3052+
BranchTargetType::JC => 0b11,
3053+
};
3054+
3055+
sink.put4(0xd503241f | targets << 6);
3056+
}
30473057
&Inst::VirtualSPOffsetAdj { offset } => {
30483058
log::trace!(
30493059
"virtual sp offset adjusted by {} -> {}",

cranelift/codegen/src/isa/aarch64/inst/emit_tests.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ fn test_aarch64_binemit() {
3838
//
3939
// $ echo "mov x1, x2" | aarch64inst.sh
4040
insns.push((Inst::Ret { rets: vec![] }, "C0035FD6", "ret"));
41+
insns.push((
42+
Inst::Bti {
43+
targets: BranchTargetType::J,
44+
},
45+
"9F2403D5",
46+
"bti j",
47+
));
4148
insns.push((Inst::Nop0, "", "nop-zero-len"));
4249
insns.push((Inst::Nop4, "1F2003D5", "nop"));
4350
insns.push((

cranelift/codegen/src/isa/aarch64/inst/mod.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@ mod emit_tests;
3636
// Instructions (top level): definition
3737

3838
pub use crate::isa::aarch64::lower::isle::generated_code::{
39-
ALUOp, ALUOp3, AtomicRMWLoopOp, AtomicRMWOp, BitOp, FPUOp1, FPUOp2, FPUOp3, FpuRoundMode,
40-
FpuToIntOp, IntToFpuOp, MInst as Inst, MoveWideOp, VecALUOp, VecExtendOp, VecLanesOp, VecMisc2,
41-
VecPairOp, VecRRLongOp, VecRRNarrowOp, VecRRPairLongOp, VecRRRLongOp, VecShiftImmOp,
39+
ALUOp, ALUOp3, AtomicRMWLoopOp, AtomicRMWOp, BitOp, BranchTargetType, FPUOp1, FPUOp2, FPUOp3,
40+
FpuRoundMode, FpuToIntOp, IntToFpuOp, MInst as Inst, MoveWideOp, VecALUOp, VecExtendOp,
41+
VecLanesOp, VecMisc2, VecPairOp, VecRRLongOp, VecRRNarrowOp, VecRRPairLongOp, VecRRRLongOp,
42+
VecShiftImmOp,
4243
};
4344

4445
/// A floating-point unit (FPU) operation with two args, a register and an immediate.
@@ -1025,6 +1026,7 @@ fn aarch64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut Operan
10251026
collector.reg_def(rd);
10261027
memarg_operands(mem, collector);
10271028
}
1029+
&Inst::Bti { .. } => {}
10281030
&Inst::VirtualSPOffsetAdj { .. } => {}
10291031

10301032
&Inst::ElfTlsGetAddr { .. } => {
@@ -1224,6 +1226,19 @@ impl MachInst for Inst {
12241226
fn ref_type_regclass(_: &settings::Flags) -> RegClass {
12251227
RegClass::Int
12261228
}
1229+
1230+
fn gen_block_start(
1231+
is_indirect_branch_target: bool,
1232+
isa_flags: &Vec<settings::Value>,
1233+
) -> Option<Self> {
1234+
if is_indirect_branch_target && has_bool_setting("use_bti", isa_flags) {
1235+
Some(Inst::Bti {
1236+
targets: BranchTargetType::J,
1237+
})
1238+
} else {
1239+
None
1240+
}
1241+
}
12271242
}
12281243

12291244
//=============================================================================
@@ -2703,6 +2718,16 @@ impl Inst {
27032718
}
27042719
ret
27052720
}
2721+
&Inst::Bti { targets } => {
2722+
let targets = match targets {
2723+
BranchTargetType::None => "",
2724+
BranchTargetType::C => " c",
2725+
BranchTargetType::J => " j",
2726+
BranchTargetType::JC => " jc",
2727+
};
2728+
2729+
"bti".to_string() + targets
2730+
}
27062731
&Inst::VirtualSPOffsetAdj { offset } => {
27072732
state.virtual_sp_offset += offset;
27082733
format!("virtual_sp_offset_adjust {}", offset)
@@ -2896,3 +2921,10 @@ impl MachInstLabelUse for LabelUse {
28962921
}
28972922
}
28982923
}
2924+
2925+
pub fn has_bool_setting(name: &str, isa_flags: &Vec<settings::Value>) -> bool {
2926+
isa_flags
2927+
.iter()
2928+
.find(|&f| f.name == name)
2929+
.map_or(false, |f| f.as_bool().unwrap_or(false))
2930+
}

cranelift/codegen/src/machinst/abi.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ pub trait ABICallee {
3838
/// Get the settings controlling this function's compilation.
3939
fn flags(&self) -> &settings::Flags;
4040

41+
/// Get the ISA-specific flag values controlling this function's compilation.
42+
fn isa_flags(&self) -> &Vec<settings::Value>;
43+
4144
/// Get the calling convention implemented by this ABI object.
4245
fn call_conv(&self) -> CallConv;
4346

cranelift/codegen/src/machinst/abi_impl.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -403,9 +403,10 @@ pub trait ABIMachineSpec {
403403
/// Generate a meta-instruction that adjusts the nominal SP offset.
404404
fn gen_nominal_sp_adj(amount: i32) -> Self::I;
405405

406-
/// Generates extra unwind instructions for a new frame for this
407-
/// architecture, whether the frame has a prologue sequence or not.
408-
fn gen_debug_frame_info(
406+
/// Generates the mandatory part of the prologue, irrespective of whether
407+
/// the usual frame-setup sequence for this architecture is required or not,
408+
/// e.g. extra unwind instructions.
409+
fn gen_prologue_start(
409410
_call_conv: isa::CallConv,
410411
_flags: &settings::Flags,
411412
_isa_flags: &Vec<settings::Value>,
@@ -935,6 +936,10 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
935936
&self.flags
936937
}
937938

939+
fn isa_flags(&self) -> &Vec<settings::Value> {
940+
&self.isa_flags
941+
}
942+
938943
fn call_conv(&self) -> isa::CallConv {
939944
self.sig.call_conv
940945
}
@@ -1240,7 +1245,7 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
12401245
);
12411246

12421247
insts.extend(
1243-
M::gen_debug_frame_info(self.call_conv, &self.flags, &self.isa_flags).into_iter(),
1248+
M::gen_prologue_start(self.call_conv, &self.flags, &self.isa_flags).into_iter(),
12441249
);
12451250

12461251
if self.setup_frame {

0 commit comments

Comments
 (0)