Skip to content

Commit

Permalink
Initial forward-edge CFI implementation
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
akirilov-arm committed May 10, 2022
1 parent 71fc16b commit f5f2375
Show file tree
Hide file tree
Showing 24 changed files with 522 additions and 217 deletions.
14 changes: 13 additions & 1 deletion cranelift/codegen/meta/src/isa/arm64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,19 @@ use crate::shared::Definitions as SharedDefinitions;

fn define_settings(_shared: &SettingGroup) -> SettingGroup {
let mut setting = SettingGroupBuilder::new("arm64");
let has_lse = setting.add_bool("has_lse", "Has Large System Extensions support.", "", false);
let has_lse = setting.add_bool(
"has_lse",
"Has Large System Extensions (FEAT_LSE) support.",
"",
false,
);

setting.add_bool(
"use_bti",
"Use Branch Target Identification (FEAT_BTI) instructions.",
"",
false,
);

setting.add_predicate("use_lse", predicate!(has_lse));
setting.build()
Expand Down
18 changes: 16 additions & 2 deletions cranelift/codegen/src/isa/aarch64/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -622,9 +622,9 @@ impl ABIMachineSpec for AArch64MachineDeps {
}
}

fn gen_debug_frame_info(
fn gen_prologue_start(
flags: &settings::Flags,
_isa_flags: &Vec<settings::Value>,
isa_flags: &Vec<settings::Value>,
) -> SmallInstVec<Inst> {
let mut insts = SmallVec::new();
if flags.unwind_info() {
Expand All @@ -634,6 +634,13 @@ impl ABIMachineSpec for AArch64MachineDeps {
},
});
}

if has_bool_setting("use_bti", isa_flags) {
insts.push(Inst::Bti {
targets: BranchTargetType::C,
});
}

insts
}

Expand Down Expand Up @@ -1323,3 +1330,10 @@ fn is_reg_clobbered_by_call(call_conv_of_callee: isa::CallConv, r: RealReg) -> b
}
}
}

fn has_bool_setting(name: &str, isa_flags: &Vec<settings::Value>) -> bool {
isa_flags
.iter()
.find(|&f| f.name == name)
.map_or(false, |f| f.as_bool().unwrap_or(false))
}
14 changes: 14 additions & 0 deletions cranelift/codegen/src/isa/aarch64/inst.isle
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,11 @@
(rd WritableReg)
(mem AMode))

;; Branch target identification; equivalent to a no-op if Branch Target
;; Identification (FEAT_BTI) is not supported.
(Bti
(targets BranchTargetType))

;; Marker, no-op in generated code: SP "virtual offset" is adjusted. This
;; controls how AMode::NominalSPOffset args are lowered.
(VirtualSPOffsetAdj
Expand Down Expand Up @@ -1278,6 +1283,15 @@
(Xchg)
))

;; Branch target types
(type BranchTargetType
(enum
(None)
(C)
(J)
(JC)
))

;; Extractors for target features ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(decl use_lse () Inst)
(extern extractor use_lse use_lse)
Expand Down
10 changes: 10 additions & 0 deletions cranelift/codegen/src/isa/aarch64/inst/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3048,6 +3048,16 @@ impl MachInstEmit for Inst {
add.emit(&[], sink, emit_info, state);
}
}
&Inst::Bti { targets } => {
let targets = match targets {
BranchTargetType::None => 0b00,
BranchTargetType::C => 0b01,
BranchTargetType::J => 0b10,
BranchTargetType::JC => 0b11,
};

sink.put4(0xd503241f | targets << 6);
}
&Inst::VirtualSPOffsetAdj { offset } => {
log::trace!(
"virtual sp offset adjusted by {} -> {}",
Expand Down
7 changes: 7 additions & 0 deletions cranelift/codegen/src/isa/aarch64/inst/emit_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ fn test_aarch64_binemit() {
//
// $ echo "mov x1, x2" | aarch64inst.sh
insns.push((Inst::Ret { rets: vec![] }, "C0035FD6", "ret"));
insns.push((
Inst::Bti {
targets: BranchTargetType::J,
},
"9F2403D5",
"bti j",
));
insns.push((Inst::Nop0, "", "nop-zero-len"));
insns.push((Inst::Nop4, "1F2003D5", "nop"));
insns.push((
Expand Down
18 changes: 15 additions & 3 deletions cranelift/codegen/src/isa/aarch64/inst/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ mod emit_tests;
// Instructions (top level): definition

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

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

&Inst::ElfTlsGetAddr { .. } => {
Expand Down Expand Up @@ -2703,6 +2705,16 @@ impl Inst {
}
ret
}
&Inst::Bti { targets } => {
let targets = match targets {
BranchTargetType::None => "",
BranchTargetType::C => " c",
BranchTargetType::J => " j",
BranchTargetType::JC => " jc",
};

"bti".to_string() + targets
}
&Inst::VirtualSPOffsetAdj { offset } => {
state.virtual_sp_offset += offset;
format!("virtual_sp_offset_adjust {}", offset)
Expand Down
14 changes: 14 additions & 0 deletions cranelift/codegen/src/isa/aarch64/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1559,4 +1559,18 @@ impl LowerBackend for AArch64Backend {
fn maybe_pinned_reg(&self) -> Option<Reg> {
Some(xreg(PINNED_REG))
}

fn start_block<C: LowerCtx<I = Inst>>(
&self,
is_indirect_branch_target: bool,
ctx: &mut C,
) -> CodegenResult<()> {
if self.isa_flags.use_bti() && is_indirect_branch_target {
ctx.emit(Inst::Bti {
targets: BranchTargetType::J,
});
}

Ok(())
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
src/clif.isle 443b34b797fc8ace
src/prelude.isle 97c4b6eebbab9f05
src/isa/aarch64/inst.isle 21a43af20be377d2
src/isa/aarch64/inst.isle 542264a10347b8f1
src/isa/aarch64/lower.isle 75ad8450963e3829
Loading

0 comments on commit f5f2375

Please sign in to comment.