1 //! Defines `DataContext`. 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::module::ModuleReloc; 12 use crate::ModuleExtName; 13 14 /// This specifies how data is to be initialized. 15 #[derive(Clone, PartialEq, Eq, Debug)] 16 pub enum Init { 17 /// This indicates that no initialization has been specified yet. 18 Uninitialized, 19 /// Initialize the data with all zeros. 20 Zeros { 21 /// The size of the data. 22 size: usize, 23 }, 24 /// Initialize the data with the specified contents. 25 Bytes { 26 /// The contents, which also implies the size of the data. 27 contents: Box<[u8]>, 28 }, 29 } 30 31 impl Init { 32 /// Return the size of the data to be initialized. 33 pub fn size(&self) -> usize { 34 match *self { 35 Self::Uninitialized => panic!("data size not initialized yet"), 36 Self::Zeros { size } => size, 37 Self::Bytes { ref contents } => contents.len(), 38 } 39 } 40 } 41 42 /// A description of a data object. 43 #[derive(Clone)] 44 pub struct DataDescription { 45 /// How the data should be initialized. 46 pub init: Init, 47 /// External function declarations. 48 pub function_decls: PrimaryMap<ir::FuncRef, ModuleExtName>, 49 /// External data object declarations. 50 pub data_decls: PrimaryMap<ir::GlobalValue, ModuleExtName>, 51 /// Function addresses to write at specified offsets. 52 pub function_relocs: Vec<(CodeOffset, ir::FuncRef)>, 53 /// Data addresses to write at specified offsets. 54 pub data_relocs: Vec<(CodeOffset, ir::GlobalValue, Addend)>, 55 /// Object file section 56 pub custom_segment_section: Option<(String, String)>, 57 /// Alignment in bytes. `None` means that the default alignment of the respective module should 58 /// be used. 59 pub align: Option<u64>, 60 } 61 62 impl DataDescription { 63 /// An iterator over all relocations of the data object. 64 pub fn all_relocs<'a>( 65 &'a self, 66 pointer_reloc: Reloc, 67 ) -> impl Iterator<Item = ModuleReloc> + 'a { 68 let func_relocs = self 69 .function_relocs 70 .iter() 71 .map(move |&(offset, id)| ModuleReloc { 72 kind: pointer_reloc, 73 offset, 74 name: self.function_decls[id].clone(), 75 addend: 0, 76 }); 77 let data_relocs = self 78 .data_relocs 79 .iter() 80 .map(move |&(offset, id, addend)| ModuleReloc { 81 kind: pointer_reloc, 82 offset, 83 name: self.data_decls[id].clone(), 84 addend, 85 }); 86 func_relocs.chain(data_relocs) 87 } 88 } 89 90 /// This is to data objects what cranelift_codegen::Context is to functions. 91 pub struct DataContext { 92 description: DataDescription, 93 } 94 95 impl DataContext { 96 /// Allocate a new context. 97 pub fn new() -> Self { 98 Self { 99 description: DataDescription { 100 init: Init::Uninitialized, 101 function_decls: PrimaryMap::new(), 102 data_decls: PrimaryMap::new(), 103 function_relocs: vec![], 104 data_relocs: vec![], 105 custom_segment_section: None, 106 align: None, 107 }, 108 } 109 } 110 111 /// Clear all data structures in this context. 112 pub fn clear(&mut self) { 113 self.description.init = Init::Uninitialized; 114 self.description.function_decls.clear(); 115 self.description.data_decls.clear(); 116 self.description.function_relocs.clear(); 117 self.description.data_relocs.clear(); 118 self.description.custom_segment_section = None; 119 self.description.align = None; 120 } 121 122 /// Define a zero-initialized object with the given size. 123 pub fn define_zeroinit(&mut self, size: usize) { 124 debug_assert_eq!(self.description.init, Init::Uninitialized); 125 self.description.init = Init::Zeros { size }; 126 } 127 128 /// Define an object initialized with the given contents. 129 /// 130 /// TODO: Can we avoid a Box here? 131 pub fn define(&mut self, contents: Box<[u8]>) { 132 debug_assert_eq!(self.description.init, Init::Uninitialized); 133 self.description.init = Init::Bytes { contents }; 134 } 135 136 /// Override the segment/section for data, only supported on Object backend 137 pub fn set_segment_section(&mut self, seg: &str, sec: &str) { 138 self.description.custom_segment_section = Some((seg.to_owned(), sec.to_owned())) 139 } 140 141 /// Set the alignment for data. The alignment must be a power of two. 142 pub fn set_align(&mut self, align: u64) { 143 assert!(align.is_power_of_two()); 144 self.description.align = Some(align); 145 } 146 147 /// Declare an external function import. 148 /// 149 /// Users of the `Module` API generally should call 150 /// `Module::declare_func_in_data` instead, as it takes care of generating 151 /// the appropriate `ExternalName`. 152 pub fn import_function(&mut self, name: ModuleExtName) -> ir::FuncRef { 153 self.description.function_decls.push(name) 154 } 155 156 /// Declares a global value import. 157 /// 158 /// TODO: Rename to import_data? 159 /// 160 /// Users of the `Module` API generally should call 161 /// `Module::declare_data_in_data` instead, as it takes care of generating 162 /// the appropriate `ExternalName`. 163 pub fn import_global_value(&mut self, name: ModuleExtName) -> ir::GlobalValue { 164 self.description.data_decls.push(name) 165 } 166 167 /// Write the address of `func` into the data at offset `offset`. 168 pub fn write_function_addr(&mut self, offset: CodeOffset, func: ir::FuncRef) { 169 self.description.function_relocs.push((offset, func)) 170 } 171 172 /// Write the address of `data` into the data at offset `offset`. 173 pub fn write_data_addr(&mut self, offset: CodeOffset, data: ir::GlobalValue, addend: Addend) { 174 self.description.data_relocs.push((offset, data, addend)) 175 } 176 177 /// Reference the initializer data. 178 pub fn description(&self) -> &DataDescription { 179 debug_assert!( 180 self.description.init != Init::Uninitialized, 181 "data must be initialized first" 182 ); 183 &self.description 184 } 185 } 186 187 #[cfg(test)] 188 mod tests { 189 use crate::ModuleExtName; 190 191 use super::{DataContext, Init}; 192 193 #[test] 194 fn basic_data_context() { 195 let mut data_ctx = DataContext::new(); 196 { 197 let description = &data_ctx.description; 198 assert_eq!(description.init, Init::Uninitialized); 199 assert!(description.function_decls.is_empty()); 200 assert!(description.data_decls.is_empty()); 201 assert!(description.function_relocs.is_empty()); 202 assert!(description.data_relocs.is_empty()); 203 } 204 205 data_ctx.define_zeroinit(256); 206 207 let _func_a = data_ctx.import_function(ModuleExtName::user(0, 0)); 208 let func_b = data_ctx.import_function(ModuleExtName::user(0, 1)); 209 let func_c = data_ctx.import_function(ModuleExtName::user(0, 2)); 210 let _data_a = data_ctx.import_global_value(ModuleExtName::user(0, 3)); 211 let data_b = data_ctx.import_global_value(ModuleExtName::user(0, 4)); 212 213 data_ctx.write_function_addr(8, func_b); 214 data_ctx.write_function_addr(16, func_c); 215 data_ctx.write_data_addr(32, data_b, 27); 216 217 { 218 let description = data_ctx.description(); 219 assert_eq!(description.init, Init::Zeros { size: 256 }); 220 assert_eq!(description.function_decls.len(), 3); 221 assert_eq!(description.data_decls.len(), 2); 222 assert_eq!(description.function_relocs.len(), 2); 223 assert_eq!(description.data_relocs.len(), 1); 224 } 225 226 data_ctx.clear(); 227 { 228 let description = &data_ctx.description; 229 assert_eq!(description.init, Init::Uninitialized); 230 assert!(description.function_decls.is_empty()); 231 assert!(description.data_decls.is_empty()); 232 assert!(description.function_relocs.is_empty()); 233 assert!(description.data_relocs.is_empty()); 234 } 235 236 let contents = vec![33, 34, 35, 36]; 237 let contents_clone = contents.clone(); 238 data_ctx.define(contents.into_boxed_slice()); 239 { 240 let description = data_ctx.description(); 241 assert_eq!( 242 description.init, 243 Init::Bytes { 244 contents: contents_clone.into_boxed_slice() 245 } 246 ); 247 assert_eq!(description.function_decls.len(), 0); 248 assert_eq!(description.data_decls.len(), 0); 249 assert_eq!(description.function_relocs.len(), 0); 250 assert_eq!(description.data_relocs.len(), 0); 251 } 252 } 253 } 254