1*dbc11c30SFrank Emrich use crate::{isa::x64::inst::regs, machinst::Reg};
2*dbc11c30SFrank Emrich
3*dbc11c30SFrank Emrich /// The `stack_switch` instruction loads information about the stack to switch
4*dbc11c30SFrank Emrich /// to and stores information about the current stack by receiving pointers to
5*dbc11c30SFrank Emrich /// memory laid out as in the struct `ControlContext` below.
6*dbc11c30SFrank Emrich ///
7*dbc11c30SFrank Emrich /// The instruction is only supported on x64 Linux at the moment.
8*dbc11c30SFrank Emrich ///
9*dbc11c30SFrank Emrich /// ```
10*dbc11c30SFrank Emrich /// #[repr(C)]
11*dbc11c30SFrank Emrich /// pub struct ControlContext {
12*dbc11c30SFrank Emrich /// pub stack_pointer: *mut u8,
13*dbc11c30SFrank Emrich /// pub frame_pointer: *mut u8,
14*dbc11c30SFrank Emrich /// pub instruction_pointer: *mut u8,
15*dbc11c30SFrank Emrich /// }
16*dbc11c30SFrank Emrich /// ```
17*dbc11c30SFrank Emrich ///
18*dbc11c30SFrank Emrich /// Note that this layout is deliberately chosen to make frame pointer walking
19*dbc11c30SFrank Emrich /// possible, if desired: The layout enables stack layouts where a
20*dbc11c30SFrank Emrich /// `ControlContext` is part of a frame pointer chain, putting the frame pointer
21*dbc11c30SFrank Emrich /// next to the corresponding IP.
22*dbc11c30SFrank Emrich ///
23*dbc11c30SFrank Emrich /// We never actually interact with values of that type in Cranelift, but are
24*dbc11c30SFrank Emrich /// only interested in its layout for the purposes of generating code.
25*dbc11c30SFrank Emrich pub struct ControlContextLayout {
26*dbc11c30SFrank Emrich pub stack_pointer_offset: usize,
27*dbc11c30SFrank Emrich pub frame_pointer_offset: usize,
28*dbc11c30SFrank Emrich pub ip_offset: usize,
29*dbc11c30SFrank Emrich }
30*dbc11c30SFrank Emrich
control_context_layout() -> ControlContextLayout31*dbc11c30SFrank Emrich pub fn control_context_layout() -> ControlContextLayout {
32*dbc11c30SFrank Emrich ControlContextLayout {
33*dbc11c30SFrank Emrich stack_pointer_offset: 0,
34*dbc11c30SFrank Emrich frame_pointer_offset: 8,
35*dbc11c30SFrank Emrich ip_offset: 16,
36*dbc11c30SFrank Emrich }
37*dbc11c30SFrank Emrich }
38*dbc11c30SFrank Emrich
39*dbc11c30SFrank Emrich /// The register used for handing over the payload when switching stacks.
40*dbc11c30SFrank Emrich ///
41*dbc11c30SFrank Emrich /// We must use a fixed register for sending and receiving the payload: When
42*dbc11c30SFrank Emrich /// switching from one stack to another using two matching``stack_switch``
43*dbc11c30SFrank Emrich /// instructions, they must agree on the register where the payload is, similar
44*dbc11c30SFrank Emrich /// to a calling convention. The same holds when `stack_switch`-ing to a newly
45*dbc11c30SFrank Emrich /// initialized stack, where the entry trampoline must know which register the
46*dbc11c30SFrank Emrich /// payload is in.
payload_register() -> Reg47*dbc11c30SFrank Emrich pub fn payload_register() -> Reg {
48*dbc11c30SFrank Emrich regs::rdi()
49*dbc11c30SFrank Emrich }
50