1 //! Defines `DataDescription`.
2 
3 use cranelift_codegen::binemit::{Addend, CodeOffset, Reloc};
4 use cranelift_codegen::entity::PrimaryMap;
5 use cranelift_codegen::ir;
6 use std::borrow::ToOwned;
7 use std::boxed::Box;
8 use std::string::String;
9 use std::vec::Vec;
10 
11 use crate::ModuleRelocTarget;
12 use crate::module::ModuleReloc;
13 
14 /// This specifies how data is to be initialized.
15 #[derive(Clone, PartialEq, Eq, Debug)]
16 #[cfg_attr(
17     feature = "enable-serde",
18     derive(serde_derive::Serialize, serde_derive::Deserialize)
19 )]
20 pub enum Init {
21     /// This indicates that no initialization has been specified yet.
22     Uninitialized,
23     /// Initialize the data with all zeros.
24     Zeros {
25         /// The size of the data.
26         size: usize,
27     },
28     /// Initialize the data with the specified contents.
29     Bytes {
30         /// The contents, which also implies the size of the data.
31         contents: Box<[u8]>,
32     },
33 }
34 
35 impl Init {
36     /// Return the size of the data to be initialized.
size(&self) -> usize37     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 /// A description of a data object.
47 #[derive(Clone, Debug)]
48 #[cfg_attr(
49     feature = "enable-serde",
50     derive(serde_derive::Serialize, serde_derive::Deserialize)
51 )]
52 pub struct DataDescription {
53     /// How the data should be initialized.
54     pub init: Init,
55     /// External function declarations.
56     pub function_decls: PrimaryMap<ir::FuncRef, ModuleRelocTarget>,
57     /// External data object declarations.
58     pub data_decls: PrimaryMap<ir::GlobalValue, ModuleRelocTarget>,
59     /// Function addresses to write at specified offsets.
60     pub function_relocs: Vec<(CodeOffset, ir::FuncRef)>,
61     /// Data addresses to write at specified offsets.
62     pub data_relocs: Vec<(CodeOffset, ir::GlobalValue, Addend)>,
63     /// Object file section
64     pub custom_segment_section: Option<(String, String)>,
65     /// Alignment in bytes. `None` means that the default alignment of the
66     /// respective module should be used.
67     pub align: Option<u64>,
68     /// Whether or not to request the linker to preserve this data object even
69     /// if not referenced.
70     pub used: bool,
71 }
72 
73 impl DataDescription {
74     /// Allocate a new `DataDescription`.
new() -> Self75     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     /// Clear all data structures in this `DataDescription`.
clear(&mut self)89     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     /// Define a zero-initialized object with the given size.
define_zeroinit(&mut self, size: usize)101     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     /// Define an object initialized with the given contents.
107     ///
108     /// TODO: Can we avoid a Box here?
define(&mut self, contents: Box<[u8]>)109     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     /// Override the segment/section for data, only supported on Object backend
set_segment_section(&mut self, seg: &str, sec: &str)115     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     /// Set the alignment for data. The alignment must be a power of two.
set_align(&mut self, align: u64)120     pub fn set_align(&mut self, align: u64) {
121         assert!(align.is_power_of_two());
122         self.align = Some(align);
123     }
124 
125     /// Set whether or not the linker should preserve this data object even if
126     /// not referenced.
set_used(&mut self, used: bool)127     pub fn set_used(&mut self, used: bool) {
128         self.used = used;
129     }
130 
131     /// Declare an external function import.
132     ///
133     /// Users of the `Module` API generally should call
134     /// `Module::declare_func_in_data` instead, as it takes care of generating
135     /// the appropriate `ExternalName`.
import_function(&mut self, name: ModuleRelocTarget) -> ir::FuncRef136     pub fn import_function(&mut self, name: ModuleRelocTarget) -> ir::FuncRef {
137         self.function_decls.push(name)
138     }
139 
140     /// Declares a global value import.
141     ///
142     /// TODO: Rename to import_data?
143     ///
144     /// Users of the `Module` API generally should call
145     /// `Module::declare_data_in_data` instead, as it takes care of generating
146     /// the appropriate `ExternalName`.
import_global_value(&mut self, name: ModuleRelocTarget) -> ir::GlobalValue147     pub fn import_global_value(&mut self, name: ModuleRelocTarget) -> ir::GlobalValue {
148         self.data_decls.push(name)
149     }
150 
151     /// Write the address of `func` into the data at offset `offset`.
write_function_addr(&mut self, offset: CodeOffset, func: ir::FuncRef)152     pub fn write_function_addr(&mut self, offset: CodeOffset, func: ir::FuncRef) {
153         self.function_relocs.push((offset, func))
154     }
155 
156     /// Write the address of `data` into the data at offset `offset`.
write_data_addr(&mut self, offset: CodeOffset, data: ir::GlobalValue, addend: Addend)157     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     /// An iterator over all relocations of the data object.
all_relocs<'a>( &'a self, pointer_reloc: Reloc, ) -> impl Iterator<Item = ModuleReloc> + 'a162     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)]
189 mod tests {
190     use crate::ModuleRelocTarget;
191 
192     use super::{DataDescription, Init};
193 
194     #[test]
basic_data_context()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 }
245