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