Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/isa/x64/inst/unwind/systemv.rs
1693 views
1
//! Unwind information for System V ABI (x86-64).
2
3
use crate::isa::unwind::systemv::RegisterMappingError;
4
use crate::machinst::{Reg, RegClass};
5
use gimli::{Encoding, Format, Register, X86_64, write::CommonInformationEntry};
6
7
/// Creates a new x86-64 common information entry (CIE).
8
pub fn create_cie() -> CommonInformationEntry {
9
use gimli::write::CallFrameInstruction;
10
11
let mut entry = CommonInformationEntry::new(
12
Encoding {
13
address_size: 8,
14
format: Format::Dwarf32,
15
version: 1,
16
},
17
1, // Code alignment factor
18
-8, // Data alignment factor
19
X86_64::RA,
20
);
21
22
// Every frame will start with the call frame address (CFA) at RSP+8
23
// It is +8 to account for the push of the return address by the call instruction
24
entry.add_instruction(CallFrameInstruction::Cfa(X86_64::RSP, 8));
25
26
// Every frame will start with the return address at RSP (CFA-8 = RSP+8-8 = RSP)
27
entry.add_instruction(CallFrameInstruction::Offset(X86_64::RA, -8));
28
29
entry
30
}
31
32
/// Map Cranelift registers to their corresponding Gimli registers.
33
pub fn map_reg(reg: Reg) -> Result<Register, RegisterMappingError> {
34
// Mapping from https://github.com/bytecodealliance/cranelift/pull/902 by @iximeow
35
const X86_GP_REG_MAP: [gimli::Register; 16] = [
36
X86_64::RAX,
37
X86_64::RCX,
38
X86_64::RDX,
39
X86_64::RBX,
40
X86_64::RSP,
41
X86_64::RBP,
42
X86_64::RSI,
43
X86_64::RDI,
44
X86_64::R8,
45
X86_64::R9,
46
X86_64::R10,
47
X86_64::R11,
48
X86_64::R12,
49
X86_64::R13,
50
X86_64::R14,
51
X86_64::R15,
52
];
53
const X86_XMM_REG_MAP: [gimli::Register; 16] = [
54
X86_64::XMM0,
55
X86_64::XMM1,
56
X86_64::XMM2,
57
X86_64::XMM3,
58
X86_64::XMM4,
59
X86_64::XMM5,
60
X86_64::XMM6,
61
X86_64::XMM7,
62
X86_64::XMM8,
63
X86_64::XMM9,
64
X86_64::XMM10,
65
X86_64::XMM11,
66
X86_64::XMM12,
67
X86_64::XMM13,
68
X86_64::XMM14,
69
X86_64::XMM15,
70
];
71
72
match reg.class() {
73
RegClass::Int => {
74
// x86 GP registers have a weird mapping to DWARF registers, so we use a
75
// lookup table.
76
Ok(X86_GP_REG_MAP[reg.to_real_reg().unwrap().hw_enc() as usize])
77
}
78
RegClass::Float => Ok(X86_XMM_REG_MAP[reg.to_real_reg().unwrap().hw_enc() as usize]),
79
RegClass::Vector => unreachable!(),
80
}
81
}
82
83
pub(crate) struct RegisterMapper;
84
85
impl crate::isa::unwind::systemv::RegisterMapper<Reg> for RegisterMapper {
86
fn map(&self, reg: Reg) -> Result<u16, RegisterMappingError> {
87
Ok(map_reg(reg)?.0)
88
}
89
fn fp(&self) -> Option<u16> {
90
Some(X86_64::RBP.0)
91
}
92
}
93
94
#[cfg(test)]
95
mod tests {
96
use crate::Context;
97
use crate::cursor::{Cursor, FuncCursor};
98
use crate::ir::{
99
AbiParam, Function, InstBuilder, Signature, StackSlotData, StackSlotKind, types,
100
};
101
use crate::isa::{CallConv, lookup};
102
use crate::settings::{Flags, builder};
103
use gimli::write::Address;
104
use target_lexicon::triple;
105
106
#[test]
107
fn test_simple_func() {
108
let isa = lookup(triple!("x86_64"))
109
.expect("expect x86 ISA")
110
.finish(Flags::new(builder()))
111
.expect("expect backend creation to succeed");
112
113
let mut context = Context::for_function(create_function(
114
CallConv::SystemV,
115
Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64, 0)),
116
));
117
118
let code = context
119
.compile(&*isa, &mut Default::default())
120
.expect("expected compilation");
121
122
let fde = match code
123
.create_unwind_info(isa.as_ref())
124
.expect("can create unwind info")
125
{
126
Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => {
127
info.to_fde(Address::Constant(1234))
128
}
129
_ => panic!("expected unwind information"),
130
};
131
132
assert_eq!(
133
format!("{fde:?}"),
134
"FrameDescriptionEntry { address: Constant(1234), length: 17, lsda: None, instructions: [(1, CfaOffset(16)), (1, Offset(Register(6), -16)), (4, CfaRegister(Register(6)))] }"
135
);
136
}
137
138
fn create_function(call_conv: CallConv, stack_slot: Option<StackSlotData>) -> Function {
139
let mut func = Function::with_name_signature(Default::default(), Signature::new(call_conv));
140
141
let block0 = func.dfg.make_block();
142
let mut pos = FuncCursor::new(&mut func);
143
pos.insert_block(block0);
144
pos.ins().return_(&[]);
145
146
if let Some(stack_slot) = stack_slot {
147
func.sized_stack_slots.push(stack_slot);
148
}
149
150
func
151
}
152
153
#[test]
154
fn test_multi_return_func() {
155
let isa = lookup(triple!("x86_64"))
156
.expect("expect x86 ISA")
157
.finish(Flags::new(builder()))
158
.expect("expect backend creation to succeed");
159
160
let mut context = Context::for_function(create_multi_return_function(CallConv::SystemV));
161
162
let code = context
163
.compile(&*isa, &mut Default::default())
164
.expect("expected compilation");
165
166
let fde = match code
167
.create_unwind_info(isa.as_ref())
168
.expect("can create unwind info")
169
{
170
Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => {
171
info.to_fde(Address::Constant(4321))
172
}
173
_ => panic!("expected unwind information"),
174
};
175
176
assert_eq!(
177
format!("{fde:?}"),
178
"FrameDescriptionEntry { address: Constant(4321), length: 22, lsda: None, instructions: [(1, CfaOffset(16)), (1, Offset(Register(6), -16)), (4, CfaRegister(Register(6)))] }"
179
);
180
}
181
182
fn create_multi_return_function(call_conv: CallConv) -> Function {
183
let mut sig = Signature::new(call_conv);
184
sig.params.push(AbiParam::new(types::I32));
185
let mut func = Function::with_name_signature(Default::default(), sig);
186
187
let block0 = func.dfg.make_block();
188
let v0 = func.dfg.append_block_param(block0, types::I32);
189
let block1 = func.dfg.make_block();
190
let block2 = func.dfg.make_block();
191
192
let mut pos = FuncCursor::new(&mut func);
193
pos.insert_block(block0);
194
pos.ins().brif(v0, block2, &[], block1, &[]);
195
196
pos.insert_block(block1);
197
pos.ins().return_(&[]);
198
199
pos.insert_block(block2);
200
pos.ins().return_(&[]);
201
202
func
203
}
204
}
205
206