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