Skip to content

Commit

Permalink
Extend X86 ABI to cover stack overflow checking on X86-32.
Browse files Browse the repository at this point in the history
In stark contrast with every reasonable architecture, X86-32 does not
pass any parameters in registers. Because of that we have to resort
to reading arguments from stack without being able to use the stack
slot machinery.

(This wouldn't have been avoidable even by pinning a register because
there is a trampoline in wasmtime with the C ABI that Cranelift needs
to be able to call.)
  • Loading branch information
whitequark authored and iximeow committed May 9, 2020
1 parent a1dbeee commit 2331403
Showing 1 changed file with 62 additions and 7 deletions.
69 changes: 62 additions & 7 deletions cranelift/codegen/src/isa/x86/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,14 @@ fn system_v_prologue_epilogue(func: &mut ir::Function, isa: &dyn TargetIsa) -> C

// Add CSRs to function signature
let reg_type = ir::Type::int(u16::from(pointer_width.bits())).unwrap();
if isa.pointer_bits() == 32 {
let sp_arg = ir::AbiParam::special_reg(
reg_type,
ir::ArgumentPurpose::CalleeSaved,
RU::rsp as RegUnit,
);
func.signature.params.push(sp_arg);
}
let fp_arg = ir::AbiParam::special_reg(
reg_type,
ir::ArgumentPurpose::FramePointer,
Expand Down Expand Up @@ -685,6 +693,17 @@ fn insert_common_prologue(
fpr_slot: Option<&StackSlot>,
isa: &dyn TargetIsa,
) {
// On X86-32 all parameters, including vmctx, are passed on stack, and we need
// to extract vmctx from the stack before we can save the frame pointer.
let sp = if isa.pointer_bits() == 32 {
let block = pos.current_block().expect("missing block under cursor");
let sp = pos.func.dfg.append_block_param(block, reg_type);
pos.func.locations[sp] = ir::ValueLoc::Reg(RU::rsp as RegUnit);
Some(sp)
} else {
None
};

// If this is a leaf function with zero stack, then there's no need to
// insert a stack check since it can't overflow anything and
// forward-progress is guarantee so long as loop are handled anyway.
Expand All @@ -707,7 +726,7 @@ fn insert_common_prologue(
None => pos
.func
.stack_limit
.map(|gv| interpret_gv(pos, gv, scratch)),
.map(|gv| interpret_gv(pos, gv, sp, scratch)),
};
if let Some(stack_limit_arg) = stack_limit_arg {
insert_stack_check(pos, stack_size, stack_limit_arg);
Expand Down Expand Up @@ -834,19 +853,55 @@ fn insert_common_prologue(
/// compared to the stack pointer, but currently it serves enough functionality
/// to get this implemented in `wasmtime` itself. This'll likely get expanded a
/// bit over time!
fn interpret_gv(pos: &mut EncCursor, gv: ir::GlobalValue, scratch: ir::ValueLoc) -> ir::Value {
fn interpret_gv(
pos: &mut EncCursor,
gv: ir::GlobalValue,
sp: Option<ir::Value>,
scratch: ir::ValueLoc,
) -> ir::Value {
match pos.func.global_values[gv] {
ir::GlobalValueData::VMContext => pos
.func
.special_param(ir::ArgumentPurpose::VMContext)
.expect("no vmcontext parameter found"),
ir::GlobalValueData::VMContext => {
let vmctx_index = pos
.func
.signature
.special_param_index(ir::ArgumentPurpose::VMContext)
.expect("no vmcontext parameter found");
match pos.func.signature.params[vmctx_index] {
AbiParam {
location: ArgumentLoc::Reg(_),
..
} => {
let entry = pos.func.layout.entry_block().unwrap();
pos.func.dfg.block_params(entry)[vmctx_index]
}
AbiParam {
location: ArgumentLoc::Stack(offset),
value_type,
..
} => {
let offset =
offset + i32::from(pos.isa.pointer_bytes() * (1 + vmctx_index as u8));
// The following access can be marked `trusted` because it is a load of an argument. We
// know it is safe because it was safe to write it in preparing this function call.
let ret =
pos.ins()
.load(value_type, ir::MemFlags::trusted(), sp.unwrap(), offset);
pos.func.locations[ret] = scratch;
return ret;
}
AbiParam {
location: ArgumentLoc::Unassigned,
..
} => unreachable!(),
}
}
ir::GlobalValueData::Load {
base,
offset,
global_type,
readonly: _,
} => {
let base = interpret_gv(pos, base, scratch);
let base = interpret_gv(pos, base, sp, scratch);
let ret = pos
.ins()
.load(global_type, ir::MemFlags::trusted(), base, offset);
Expand Down

0 comments on commit 2331403

Please sign in to comment.