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 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(Clone, 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 #[derive(Clone)] 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>(&'a self, pointer_reloc: Reloc) -> impl Iterator<Item = MachReloc> + 'a { 63 let func_relocs = self 64 .function_relocs 65 .iter() 66 .map(move |&(offset, id)| MachReloc { 67 kind: pointer_reloc, 68 offset, 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 name: self.data_decls[id].clone(), 79 addend, 80 }); 81 func_relocs.chain(data_relocs) 82 } 83 } 84 85 /// This is to data objects what cranelift_codegen::Context is to functions. 86 pub struct DataContext { 87 description: DataDescription, 88 } 89 90 impl DataContext { 91 /// Allocate a new context. 92 pub fn new() -> Self { 93 Self { 94 description: DataDescription { 95 init: Init::Uninitialized, 96 function_decls: PrimaryMap::new(), 97 data_decls: PrimaryMap::new(), 98 function_relocs: vec![], 99 data_relocs: vec![], 100 custom_segment_section: None, 101 align: None, 102 }, 103 } 104 } 105 106 /// Clear all data structures in this context. 107 pub fn clear(&mut self) { 108 self.description.init = Init::Uninitialized; 109 self.description.function_decls.clear(); 110 self.description.data_decls.clear(); 111 self.description.function_relocs.clear(); 112 self.description.data_relocs.clear(); 113 self.description.custom_segment_section = None; 114 self.description.align = None; 115 } 116 117 /// Define a zero-initialized object with the given size. 118 pub fn define_zeroinit(&mut self, size: usize) { 119 debug_assert_eq!(self.description.init, Init::Uninitialized); 120 self.description.init = Init::Zeros { size }; 121 } 122 123 /// Define an object initialized with the given contents. 124 /// 125 /// TODO: Can we avoid a Box here? 126 pub fn define(&mut self, contents: Box<[u8]>) { 127 debug_assert_eq!(self.description.init, Init::Uninitialized); 128 self.description.init = Init::Bytes { contents }; 129 } 130 131 /// Override the segment/section for data, only supported on Object backend 132 pub fn set_segment_section(&mut self, seg: &str, sec: &str) { 133 self.description.custom_segment_section = Some((seg.to_owned(), sec.to_owned())) 134 } 135 136 /// Set the alignment for data. The alignment must be a power of two. 137 pub fn set_align(&mut self, align: u64) { 138 assert!(align.is_power_of_two()); 139 self.description.align = Some(align); 140 } 141 142 /// Declare an external function import. 143 /// 144 /// Users of the `Module` API generally should call 145 /// `Module::declare_func_in_data` instead, as it takes care of generating 146 /// the appropriate `ExternalName`. 147 pub fn import_function(&mut self, name: ir::ExternalName) -> ir::FuncRef { 148 self.description.function_decls.push(name) 149 } 150 151 /// Declares a global value import. 152 /// 153 /// TODO: Rename to import_data? 154 /// 155 /// Users of the `Module` API generally should call 156 /// `Module::declare_data_in_data` instead, as it takes care of generating 157 /// the appropriate `ExternalName`. 158 pub fn import_global_value(&mut self, name: ir::ExternalName) -> ir::GlobalValue { 159 self.description.data_decls.push(name) 160 } 161 162 /// Write the address of `func` into the data at offset `offset`. 163 pub fn write_function_addr(&mut self, offset: CodeOffset, func: ir::FuncRef) { 164 self.description.function_relocs.push((offset, func)) 165 } 166 167 /// Write the address of `data` into the data at offset `offset`. 168 pub fn write_data_addr(&mut self, offset: CodeOffset, data: ir::GlobalValue, addend: Addend) { 169 self.description.data_relocs.push((offset, data, addend)) 170 } 171 172 /// Reference the initializer data. 173 pub fn description(&self) -> &DataDescription { 174 debug_assert!( 175 self.description.init != Init::Uninitialized, 176 "data must be initialized first" 177 ); 178 &self.description 179 } 180 } 181 182 #[cfg(test)] 183 mod tests { 184 use super::{DataContext, Init}; 185 use cranelift_codegen::ir; 186 187 #[test] 188 fn basic_data_context() { 189 let mut data_ctx = DataContext::new(); 190 { 191 let description = &data_ctx.description; 192 assert_eq!(description.init, Init::Uninitialized); 193 assert!(description.function_decls.is_empty()); 194 assert!(description.data_decls.is_empty()); 195 assert!(description.function_relocs.is_empty()); 196 assert!(description.data_relocs.is_empty()); 197 } 198 199 data_ctx.define_zeroinit(256); 200 201 let _func_a = data_ctx.import_function(ir::ExternalName::user(0, 0)); 202 let func_b = data_ctx.import_function(ir::ExternalName::user(0, 1)); 203 let func_c = data_ctx.import_function(ir::ExternalName::user(1, 0)); 204 let _data_a = data_ctx.import_global_value(ir::ExternalName::user(2, 2)); 205 let data_b = data_ctx.import_global_value(ir::ExternalName::user(2, 3)); 206 207 data_ctx.write_function_addr(8, func_b); 208 data_ctx.write_function_addr(16, func_c); 209 data_ctx.write_data_addr(32, data_b, 27); 210 211 { 212 let description = data_ctx.description(); 213 assert_eq!(description.init, Init::Zeros { size: 256 }); 214 assert_eq!(description.function_decls.len(), 3); 215 assert_eq!(description.data_decls.len(), 2); 216 assert_eq!(description.function_relocs.len(), 2); 217 assert_eq!(description.data_relocs.len(), 1); 218 } 219 220 data_ctx.clear(); 221 { 222 let description = &data_ctx.description; 223 assert_eq!(description.init, Init::Uninitialized); 224 assert!(description.function_decls.is_empty()); 225 assert!(description.data_decls.is_empty()); 226 assert!(description.function_relocs.is_empty()); 227 assert!(description.data_relocs.is_empty()); 228 } 229 230 let contents = vec![33, 34, 35, 36]; 231 let contents_clone = contents.clone(); 232 data_ctx.define(contents.into_boxed_slice()); 233 { 234 let description = data_ctx.description(); 235 assert_eq!( 236 description.init, 237 Init::Bytes { 238 contents: contents_clone.into_boxed_slice() 239 } 240 ); 241 assert_eq!(description.function_decls.len(), 0); 242 assert_eq!(description.data_decls.len(), 0); 243 assert_eq!(description.function_relocs.len(), 0); 244 assert_eq!(description.data_relocs.len(), 0); 245 } 246 } 247 } 248