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