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::ModuleRelocTarget;
12use crate::module::ModuleReloc;
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_section: Option<String>,
68 pub align: Option<u64>,
71 pub used: bool,
74}
75
76impl DataDescription {
77 pub fn new() -> Self {
79 Self {
80 init: Init::Uninitialized,
81 function_decls: PrimaryMap::new(),
82 data_decls: PrimaryMap::new(),
83 function_relocs: vec![],
84 data_relocs: vec![],
85 custom_section: None,
86 align: None,
87 used: false,
88 }
89 }
90
91 pub fn clear(&mut self) {
93 self.init = Init::Uninitialized;
94 self.function_decls.clear();
95 self.data_decls.clear();
96 self.function_relocs.clear();
97 self.data_relocs.clear();
98 self.custom_section = None;
99 self.align = None;
100 self.used = false;
101 }
102
103 pub fn define_zeroinit(&mut self, size: usize) {
105 debug_assert_eq!(self.init, Init::Uninitialized);
106 self.init = Init::Zeros { size };
107 }
108
109 pub fn define(&mut self, contents: Box<[u8]>) {
113 debug_assert_eq!(self.init, Init::Uninitialized);
114 self.init = Init::Bytes { contents };
115 }
116
117 pub fn set_custom_section(&mut self, section: &str) {
119 self.custom_section = Some(section.to_owned());
120 }
121
122 pub fn set_align(&mut self, align: u64) {
124 assert!(align.is_power_of_two());
125 self.align = Some(align);
126 }
127
128 pub fn set_used(&mut self, used: bool) {
131 self.used = used;
132 }
133
134 pub fn import_function(&mut self, name: ModuleRelocTarget) -> ir::FuncRef {
140 self.function_decls.push(name)
141 }
142
143 pub fn import_global_value(&mut self, name: ModuleRelocTarget) -> ir::GlobalValue {
151 self.data_decls.push(name)
152 }
153
154 pub fn write_function_addr(&mut self, offset: CodeOffset, func: ir::FuncRef) {
156 self.function_relocs.push((offset, func))
157 }
158
159 pub fn write_data_addr(&mut self, offset: CodeOffset, data: ir::GlobalValue, addend: Addend) {
161 self.data_relocs.push((offset, data, addend))
162 }
163
164 pub fn all_relocs<'a>(
166 &'a self,
167 pointer_reloc: Reloc,
168 ) -> impl Iterator<Item = ModuleReloc> + 'a {
169 let func_relocs = self
170 .function_relocs
171 .iter()
172 .map(move |&(offset, id)| ModuleReloc {
173 kind: pointer_reloc,
174 offset,
175 name: self.function_decls[id].clone(),
176 addend: 0,
177 });
178 let data_relocs = self
179 .data_relocs
180 .iter()
181 .map(move |&(offset, id, addend)| ModuleReloc {
182 kind: pointer_reloc,
183 offset,
184 name: self.data_decls[id].clone(),
185 addend,
186 });
187 func_relocs.chain(data_relocs)
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 use crate::ModuleRelocTarget;
194
195 use super::{DataDescription, Init};
196
197 #[test]
198 fn basic_data_context() {
199 let mut data = DataDescription::new();
200 assert_eq!(data.init, Init::Uninitialized);
201 assert!(data.function_decls.is_empty());
202 assert!(data.data_decls.is_empty());
203 assert!(data.function_relocs.is_empty());
204 assert!(data.data_relocs.is_empty());
205
206 data.define_zeroinit(256);
207
208 let _func_a = data.import_function(ModuleRelocTarget::user(0, 0));
209 let func_b = data.import_function(ModuleRelocTarget::user(0, 1));
210 let func_c = data.import_function(ModuleRelocTarget::user(0, 2));
211 let _data_a = data.import_global_value(ModuleRelocTarget::user(0, 3));
212 let data_b = data.import_global_value(ModuleRelocTarget::user(0, 4));
213
214 data.write_function_addr(8, func_b);
215 data.write_function_addr(16, func_c);
216 data.write_data_addr(32, data_b, 27);
217
218 assert_eq!(data.init, Init::Zeros { size: 256 });
219 assert_eq!(data.function_decls.len(), 3);
220 assert_eq!(data.data_decls.len(), 2);
221 assert_eq!(data.function_relocs.len(), 2);
222 assert_eq!(data.data_relocs.len(), 1);
223
224 data.clear();
225
226 assert_eq!(data.init, Init::Uninitialized);
227 assert!(data.function_decls.is_empty());
228 assert!(data.data_decls.is_empty());
229 assert!(data.function_relocs.is_empty());
230 assert!(data.data_relocs.is_empty());
231
232 let contents = vec![33, 34, 35, 36];
233 let contents_clone = contents.clone();
234 data.define(contents.into_boxed_slice());
235
236 assert_eq!(
237 data.init,
238 Init::Bytes {
239 contents: contents_clone.into_boxed_slice()
240 }
241 );
242 assert_eq!(data.function_decls.len(), 0);
243 assert_eq!(data.data_decls.len(), 0);
244 assert_eq!(data.function_relocs.len(), 0);
245 assert_eq!(data.data_relocs.len(), 0);
246 }
247}