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