1use cranelift_codegen::binemit::{Addend, CodeOffset, Reloc};
4use cranelift_codegen::entity::PrimaryMap;
5use cranelift_codegen::ir;
6use std::borrow::ToOwned;
7use std::boxed::Box;
8use std::string::String;
9use std::vec::Vec;
10
11use crate::module::ModuleReloc;
12use crate::ModuleRelocTarget;
13
14#[derive(Clone, PartialEq, Eq, Debug)]
16#[cfg_attr(
17 feature = "enable-serde",
18 derive(serde_derive::Serialize, serde_derive::Deserialize)
19)]
20pub enum Init {
21 Uninitialized,
23 Zeros {
25 size: usize,
27 },
28 Bytes {
30 contents: Box<[u8]>,
32 },
33}
34
35impl Init {
36 pub fn size(&self) -> usize {
38 match *self {
39 Self::Uninitialized => panic!("data size not initialized yet"),
40 Self::Zeros { size } => size,
41 Self::Bytes { ref contents } => contents.len(),
42 }
43 }
44}
45
46#[derive(Clone, Debug)]
48#[cfg_attr(
49 feature = "enable-serde",
50 derive(serde_derive::Serialize, serde_derive::Deserialize)
51)]
52pub struct DataDescription {
53 pub init: Init,
55 pub function_decls: PrimaryMap<ir::FuncRef, ModuleRelocTarget>,
57 pub data_decls: PrimaryMap<ir::GlobalValue, ModuleRelocTarget>,
59 pub function_relocs: Vec<(CodeOffset, ir::FuncRef)>,
61 pub data_relocs: Vec<(CodeOffset, ir::GlobalValue, Addend)>,
63 pub custom_segment_section: Option<(String, String)>,
65 pub align: Option<u64>,
68}
69
70impl DataDescription {
71 pub fn new() -> Self {
73 Self {
74 init: Init::Uninitialized,
75 function_decls: PrimaryMap::new(),
76 data_decls: PrimaryMap::new(),
77 function_relocs: vec![],
78 data_relocs: vec![],
79 custom_segment_section: None,
80 align: None,
81 }
82 }
83
84 pub fn clear(&mut self) {
86 self.init = Init::Uninitialized;
87 self.function_decls.clear();
88 self.data_decls.clear();
89 self.function_relocs.clear();
90 self.data_relocs.clear();
91 self.custom_segment_section = None;
92 self.align = None;
93 }
94
95 pub fn define_zeroinit(&mut self, size: usize) {
97 debug_assert_eq!(self.init, Init::Uninitialized);
98 self.init = Init::Zeros { size };
99 }
100
101 pub fn define(&mut self, contents: Box<[u8]>) {
105 debug_assert_eq!(self.init, Init::Uninitialized);
106 self.init = Init::Bytes { contents };
107 }
108
109 pub fn set_segment_section(&mut self, seg: &str, sec: &str) {
111 self.custom_segment_section = Some((seg.to_owned(), sec.to_owned()))
112 }
113
114 pub fn set_align(&mut self, align: u64) {
116 assert!(align.is_power_of_two());
117 self.align = Some(align);
118 }
119
120 pub fn import_function(&mut self, name: ModuleRelocTarget) -> ir::FuncRef {
126 self.function_decls.push(name)
127 }
128
129 pub fn import_global_value(&mut self, name: ModuleRelocTarget) -> ir::GlobalValue {
137 self.data_decls.push(name)
138 }
139
140 pub fn write_function_addr(&mut self, offset: CodeOffset, func: ir::FuncRef) {
142 self.function_relocs.push((offset, func))
143 }
144
145 pub fn write_data_addr(&mut self, offset: CodeOffset, data: ir::GlobalValue, addend: Addend) {
147 self.data_relocs.push((offset, data, addend))
148 }
149
150 pub fn all_relocs<'a>(
152 &'a self,
153 pointer_reloc: Reloc,
154 ) -> impl Iterator<Item = ModuleReloc> + 'a {
155 let func_relocs = self
156 .function_relocs
157 .iter()
158 .map(move |&(offset, id)| ModuleReloc {
159 kind: pointer_reloc,
160 offset,
161 name: self.function_decls[id].clone(),
162 addend: 0,
163 });
164 let data_relocs = self
165 .data_relocs
166 .iter()
167 .map(move |&(offset, id, addend)| ModuleReloc {
168 kind: pointer_reloc,
169 offset,
170 name: self.data_decls[id].clone(),
171 addend,
172 });
173 func_relocs.chain(data_relocs)
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 use crate::ModuleRelocTarget;
180
181 use super::{DataDescription, Init};
182
183 #[test]
184 fn basic_data_context() {
185 let mut data = DataDescription::new();
186 assert_eq!(data.init, Init::Uninitialized);
187 assert!(data.function_decls.is_empty());
188 assert!(data.data_decls.is_empty());
189 assert!(data.function_relocs.is_empty());
190 assert!(data.data_relocs.is_empty());
191
192 data.define_zeroinit(256);
193
194 let _func_a = data.import_function(ModuleRelocTarget::user(0, 0));
195 let func_b = data.import_function(ModuleRelocTarget::user(0, 1));
196 let func_c = data.import_function(ModuleRelocTarget::user(0, 2));
197 let _data_a = data.import_global_value(ModuleRelocTarget::user(0, 3));
198 let data_b = data.import_global_value(ModuleRelocTarget::user(0, 4));
199
200 data.write_function_addr(8, func_b);
201 data.write_function_addr(16, func_c);
202 data.write_data_addr(32, data_b, 27);
203
204 assert_eq!(data.init, Init::Zeros { size: 256 });
205 assert_eq!(data.function_decls.len(), 3);
206 assert_eq!(data.data_decls.len(), 2);
207 assert_eq!(data.function_relocs.len(), 2);
208 assert_eq!(data.data_relocs.len(), 1);
209
210 data.clear();
211
212 assert_eq!(data.init, Init::Uninitialized);
213 assert!(data.function_decls.is_empty());
214 assert!(data.data_decls.is_empty());
215 assert!(data.function_relocs.is_empty());
216 assert!(data.data_relocs.is_empty());
217
218 let contents = vec![33, 34, 35, 36];
219 let contents_clone = contents.clone();
220 data.define(contents.into_boxed_slice());
221
222 assert_eq!(
223 data.init,
224 Init::Bytes {
225 contents: contents_clone.into_boxed_slice()
226 }
227 );
228 assert_eq!(data.function_decls.len(), 0);
229 assert_eq!(data.data_decls.len(), 0);
230 assert_eq!(data.function_relocs.len(), 0);
231 assert_eq!(data.data_relocs.len(), 0);
232 }
233}