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