1*9c3d1028Sbjorn3 //! Defines `DataDescription`.
2747ad3c4Slazypassion 
31dc27c93Sbjorn3 use cranelift_codegen::binemit::{Addend, CodeOffset, Reloc};
4747ad3c4Slazypassion use cranelift_codegen::entity::PrimaryMap;
56e828df6SBenjamin Bouvier use cranelift_codegen::ir;
60b613caaSCarlo Kok use std::borrow::ToOwned;
7747ad3c4Slazypassion use std::boxed::Box;
80b613caaSCarlo Kok use std::string::String;
9747ad3c4Slazypassion use std::vec::Vec;
10747ad3c4Slazypassion 
11b23f534cSAfonso Bordado use crate::ModuleRelocTarget;
1290ac295eSAlex Crichton use crate::module::ModuleReloc;
138a9b1a90SBenjamin Bouvier 
14747ad3c4Slazypassion /// This specifies how data is to be initialized.
15141af752Sbjorn3 #[derive(Clone, PartialEq, Eq, Debug)]
169ec02f9dSChristopher Serr #[cfg_attr(
179ec02f9dSChristopher Serr     feature = "enable-serde",
189ec02f9dSChristopher Serr     derive(serde_derive::Serialize, serde_derive::Deserialize)
199ec02f9dSChristopher Serr )]
20747ad3c4Slazypassion pub enum Init {
21747ad3c4Slazypassion     /// This indicates that no initialization has been specified yet.
22747ad3c4Slazypassion     Uninitialized,
23747ad3c4Slazypassion     /// Initialize the data with all zeros.
24747ad3c4Slazypassion     Zeros {
25747ad3c4Slazypassion         /// The size of the data.
26747ad3c4Slazypassion         size: usize,
27747ad3c4Slazypassion     },
28747ad3c4Slazypassion     /// Initialize the data with the specified contents.
29747ad3c4Slazypassion     Bytes {
30747ad3c4Slazypassion         /// The contents, which also implies the size of the data.
31747ad3c4Slazypassion         contents: Box<[u8]>,
32747ad3c4Slazypassion     },
33747ad3c4Slazypassion }
34747ad3c4Slazypassion 
35747ad3c4Slazypassion impl Init {
36747ad3c4Slazypassion     /// Return the size of the data to be initialized.
size(&self) -> usize37747ad3c4Slazypassion     pub fn size(&self) -> usize {
38747ad3c4Slazypassion         match *self {
399f506692SPeter Huene             Self::Uninitialized => panic!("data size not initialized yet"),
409f506692SPeter Huene             Self::Zeros { size } => size,
419f506692SPeter Huene             Self::Bytes { ref contents } => contents.len(),
42747ad3c4Slazypassion         }
43747ad3c4Slazypassion     }
44747ad3c4Slazypassion }
45747ad3c4Slazypassion 
46747ad3c4Slazypassion /// A description of a data object.
4767c85b88Sbjorn3 #[derive(Clone, Debug)]
489ec02f9dSChristopher Serr #[cfg_attr(
499ec02f9dSChristopher Serr     feature = "enable-serde",
509ec02f9dSChristopher Serr     derive(serde_derive::Serialize, serde_derive::Deserialize)
519ec02f9dSChristopher Serr )]
52747ad3c4Slazypassion pub struct DataDescription {
53747ad3c4Slazypassion     /// How the data should be initialized.
54747ad3c4Slazypassion     pub init: Init,
55747ad3c4Slazypassion     /// External function declarations.
56b23f534cSAfonso Bordado     pub function_decls: PrimaryMap<ir::FuncRef, ModuleRelocTarget>,
57747ad3c4Slazypassion     /// External data object declarations.
58b23f534cSAfonso Bordado     pub data_decls: PrimaryMap<ir::GlobalValue, ModuleRelocTarget>,
59747ad3c4Slazypassion     /// Function addresses to write at specified offsets.
60747ad3c4Slazypassion     pub function_relocs: Vec<(CodeOffset, ir::FuncRef)>,
61747ad3c4Slazypassion     /// Data addresses to write at specified offsets.
62747ad3c4Slazypassion     pub data_relocs: Vec<(CodeOffset, ir::GlobalValue, Addend)>,
636b470798SCarlo Kok     /// Object file section
640b613caaSCarlo Kok     pub custom_segment_section: Option<(String, String)>,
65*9c3d1028Sbjorn3     /// Alignment in bytes. `None` means that the default alignment of the
66*9c3d1028Sbjorn3     /// respective module should be used.
6784c6ec32Sbjorn3     pub align: Option<u64>,
68*9c3d1028Sbjorn3     /// Whether or not to request the linker to preserve this data object even
69*9c3d1028Sbjorn3     /// if not referenced.
70*9c3d1028Sbjorn3     pub used: bool,
71747ad3c4Slazypassion }
72747ad3c4Slazypassion 
731dc27c93Sbjorn3 impl DataDescription {
7467c85b88Sbjorn3     /// Allocate a new `DataDescription`.
new() -> Self7567c85b88Sbjorn3     pub fn new() -> Self {
7667c85b88Sbjorn3         Self {
7767c85b88Sbjorn3             init: Init::Uninitialized,
7867c85b88Sbjorn3             function_decls: PrimaryMap::new(),
7967c85b88Sbjorn3             data_decls: PrimaryMap::new(),
8067c85b88Sbjorn3             function_relocs: vec![],
8167c85b88Sbjorn3             data_relocs: vec![],
8267c85b88Sbjorn3             custom_segment_section: None,
8367c85b88Sbjorn3             align: None,
84*9c3d1028Sbjorn3             used: false,
8567c85b88Sbjorn3         }
8667c85b88Sbjorn3     }
8767c85b88Sbjorn3 
8867c85b88Sbjorn3     /// Clear all data structures in this `DataDescription`.
clear(&mut self)8967c85b88Sbjorn3     pub fn clear(&mut self) {
9067c85b88Sbjorn3         self.init = Init::Uninitialized;
9167c85b88Sbjorn3         self.function_decls.clear();
9267c85b88Sbjorn3         self.data_decls.clear();
9367c85b88Sbjorn3         self.function_relocs.clear();
9467c85b88Sbjorn3         self.data_relocs.clear();
9567c85b88Sbjorn3         self.custom_segment_section = None;
9667c85b88Sbjorn3         self.align = None;
97*9c3d1028Sbjorn3         self.used = false;
9867c85b88Sbjorn3     }
9967c85b88Sbjorn3 
10067c85b88Sbjorn3     /// Define a zero-initialized object with the given size.
define_zeroinit(&mut self, size: usize)10167c85b88Sbjorn3     pub fn define_zeroinit(&mut self, size: usize) {
10267c85b88Sbjorn3         debug_assert_eq!(self.init, Init::Uninitialized);
10367c85b88Sbjorn3         self.init = Init::Zeros { size };
10467c85b88Sbjorn3     }
10567c85b88Sbjorn3 
10667c85b88Sbjorn3     /// Define an object initialized with the given contents.
10767c85b88Sbjorn3     ///
10867c85b88Sbjorn3     /// TODO: Can we avoid a Box here?
define(&mut self, contents: Box<[u8]>)10967c85b88Sbjorn3     pub fn define(&mut self, contents: Box<[u8]>) {
11067c85b88Sbjorn3         debug_assert_eq!(self.init, Init::Uninitialized);
11167c85b88Sbjorn3         self.init = Init::Bytes { contents };
11267c85b88Sbjorn3     }
11367c85b88Sbjorn3 
11467c85b88Sbjorn3     /// Override the segment/section for data, only supported on Object backend
set_segment_section(&mut self, seg: &str, sec: &str)11567c85b88Sbjorn3     pub fn set_segment_section(&mut self, seg: &str, sec: &str) {
11667c85b88Sbjorn3         self.custom_segment_section = Some((seg.to_owned(), sec.to_owned()))
11767c85b88Sbjorn3     }
11867c85b88Sbjorn3 
11967c85b88Sbjorn3     /// Set the alignment for data. The alignment must be a power of two.
set_align(&mut self, align: u64)12067c85b88Sbjorn3     pub fn set_align(&mut self, align: u64) {
12167c85b88Sbjorn3         assert!(align.is_power_of_two());
12267c85b88Sbjorn3         self.align = Some(align);
12367c85b88Sbjorn3     }
12467c85b88Sbjorn3 
125*9c3d1028Sbjorn3     /// Set whether or not the linker should preserve this data object even if
126*9c3d1028Sbjorn3     /// not referenced.
set_used(&mut self, used: bool)127*9c3d1028Sbjorn3     pub fn set_used(&mut self, used: bool) {
128*9c3d1028Sbjorn3         self.used = used;
129*9c3d1028Sbjorn3     }
130*9c3d1028Sbjorn3 
13167c85b88Sbjorn3     /// Declare an external function import.
13267c85b88Sbjorn3     ///
13367c85b88Sbjorn3     /// Users of the `Module` API generally should call
13467c85b88Sbjorn3     /// `Module::declare_func_in_data` instead, as it takes care of generating
13567c85b88Sbjorn3     /// the appropriate `ExternalName`.
import_function(&mut self, name: ModuleRelocTarget) -> ir::FuncRef136b23f534cSAfonso Bordado     pub fn import_function(&mut self, name: ModuleRelocTarget) -> ir::FuncRef {
13767c85b88Sbjorn3         self.function_decls.push(name)
13867c85b88Sbjorn3     }
13967c85b88Sbjorn3 
14067c85b88Sbjorn3     /// Declares a global value import.
14167c85b88Sbjorn3     ///
14267c85b88Sbjorn3     /// TODO: Rename to import_data?
14367c85b88Sbjorn3     ///
14467c85b88Sbjorn3     /// Users of the `Module` API generally should call
14567c85b88Sbjorn3     /// `Module::declare_data_in_data` instead, as it takes care of generating
14667c85b88Sbjorn3     /// the appropriate `ExternalName`.
import_global_value(&mut self, name: ModuleRelocTarget) -> ir::GlobalValue147b23f534cSAfonso Bordado     pub fn import_global_value(&mut self, name: ModuleRelocTarget) -> ir::GlobalValue {
14867c85b88Sbjorn3         self.data_decls.push(name)
14967c85b88Sbjorn3     }
15067c85b88Sbjorn3 
15167c85b88Sbjorn3     /// Write the address of `func` into the data at offset `offset`.
write_function_addr(&mut self, offset: CodeOffset, func: ir::FuncRef)15267c85b88Sbjorn3     pub fn write_function_addr(&mut self, offset: CodeOffset, func: ir::FuncRef) {
15367c85b88Sbjorn3         self.function_relocs.push((offset, func))
15467c85b88Sbjorn3     }
15567c85b88Sbjorn3 
15667c85b88Sbjorn3     /// Write the address of `data` into the data at offset `offset`.
write_data_addr(&mut self, offset: CodeOffset, data: ir::GlobalValue, addend: Addend)15767c85b88Sbjorn3     pub fn write_data_addr(&mut self, offset: CodeOffset, data: ir::GlobalValue, addend: Addend) {
15867c85b88Sbjorn3         self.data_relocs.push((offset, data, addend))
15967c85b88Sbjorn3     }
16067c85b88Sbjorn3 
1611dc27c93Sbjorn3     /// An iterator over all relocations of the data object.
all_relocs<'a>( &'a self, pointer_reloc: Reloc, ) -> impl Iterator<Item = ModuleReloc> + 'a1628a9b1a90SBenjamin Bouvier     pub fn all_relocs<'a>(
1638a9b1a90SBenjamin Bouvier         &'a self,
1648a9b1a90SBenjamin Bouvier         pointer_reloc: Reloc,
1658a9b1a90SBenjamin Bouvier     ) -> impl Iterator<Item = ModuleReloc> + 'a {
1661dc27c93Sbjorn3         let func_relocs = self
1671dc27c93Sbjorn3             .function_relocs
1681dc27c93Sbjorn3             .iter()
1698a9b1a90SBenjamin Bouvier             .map(move |&(offset, id)| ModuleReloc {
170f0e821b9Sbjorn3                 kind: pointer_reloc,
1711dc27c93Sbjorn3                 offset,
1721dc27c93Sbjorn3                 name: self.function_decls[id].clone(),
1731dc27c93Sbjorn3                 addend: 0,
1741dc27c93Sbjorn3             });
1751dc27c93Sbjorn3         let data_relocs = self
1761dc27c93Sbjorn3             .data_relocs
1771dc27c93Sbjorn3             .iter()
1788a9b1a90SBenjamin Bouvier             .map(move |&(offset, id, addend)| ModuleReloc {
179f0e821b9Sbjorn3                 kind: pointer_reloc,
1801dc27c93Sbjorn3                 offset,
1811dc27c93Sbjorn3                 name: self.data_decls[id].clone(),
1821dc27c93Sbjorn3                 addend,
1831dc27c93Sbjorn3             });
1841dc27c93Sbjorn3         func_relocs.chain(data_relocs)
1851dc27c93Sbjorn3     }
1861dc27c93Sbjorn3 }
1871dc27c93Sbjorn3 
188747ad3c4Slazypassion #[cfg(test)]
189747ad3c4Slazypassion mod tests {
190b23f534cSAfonso Bordado     use crate::ModuleRelocTarget;
1918a9b1a90SBenjamin Bouvier 
19267c85b88Sbjorn3     use super::{DataDescription, Init};
193747ad3c4Slazypassion 
194747ad3c4Slazypassion     #[test]
basic_data_context()195747ad3c4Slazypassion     fn basic_data_context() {
19667c85b88Sbjorn3         let mut data = DataDescription::new();
19767c85b88Sbjorn3         assert_eq!(data.init, Init::Uninitialized);
19867c85b88Sbjorn3         assert!(data.function_decls.is_empty());
19967c85b88Sbjorn3         assert!(data.data_decls.is_empty());
20067c85b88Sbjorn3         assert!(data.function_relocs.is_empty());
20167c85b88Sbjorn3         assert!(data.data_relocs.is_empty());
202747ad3c4Slazypassion 
20367c85b88Sbjorn3         data.define_zeroinit(256);
204747ad3c4Slazypassion 
205b23f534cSAfonso Bordado         let _func_a = data.import_function(ModuleRelocTarget::user(0, 0));
206b23f534cSAfonso Bordado         let func_b = data.import_function(ModuleRelocTarget::user(0, 1));
207b23f534cSAfonso Bordado         let func_c = data.import_function(ModuleRelocTarget::user(0, 2));
208b23f534cSAfonso Bordado         let _data_a = data.import_global_value(ModuleRelocTarget::user(0, 3));
209b23f534cSAfonso Bordado         let data_b = data.import_global_value(ModuleRelocTarget::user(0, 4));
210747ad3c4Slazypassion 
21167c85b88Sbjorn3         data.write_function_addr(8, func_b);
21267c85b88Sbjorn3         data.write_function_addr(16, func_c);
21367c85b88Sbjorn3         data.write_data_addr(32, data_b, 27);
214747ad3c4Slazypassion 
21567c85b88Sbjorn3         assert_eq!(data.init, Init::Zeros { size: 256 });
21667c85b88Sbjorn3         assert_eq!(data.function_decls.len(), 3);
21767c85b88Sbjorn3         assert_eq!(data.data_decls.len(), 2);
21867c85b88Sbjorn3         assert_eq!(data.function_relocs.len(), 2);
21967c85b88Sbjorn3         assert_eq!(data.data_relocs.len(), 1);
220747ad3c4Slazypassion 
22167c85b88Sbjorn3         data.clear();
22267c85b88Sbjorn3 
22367c85b88Sbjorn3         assert_eq!(data.init, Init::Uninitialized);
22467c85b88Sbjorn3         assert!(data.function_decls.is_empty());
22567c85b88Sbjorn3         assert!(data.data_decls.is_empty());
22667c85b88Sbjorn3         assert!(data.function_relocs.is_empty());
22767c85b88Sbjorn3         assert!(data.data_relocs.is_empty());
228747ad3c4Slazypassion 
229747ad3c4Slazypassion         let contents = vec![33, 34, 35, 36];
230747ad3c4Slazypassion         let contents_clone = contents.clone();
23167c85b88Sbjorn3         data.define(contents.into_boxed_slice());
23267c85b88Sbjorn3 
233747ad3c4Slazypassion         assert_eq!(
23467c85b88Sbjorn3             data.init,
235747ad3c4Slazypassion             Init::Bytes {
236747ad3c4Slazypassion                 contents: contents_clone.into_boxed_slice()
237747ad3c4Slazypassion             }
238747ad3c4Slazypassion         );
23967c85b88Sbjorn3         assert_eq!(data.function_decls.len(), 0);
24067c85b88Sbjorn3         assert_eq!(data.data_decls.len(), 0);
24167c85b88Sbjorn3         assert_eq!(data.function_relocs.len(), 0);
24267c85b88Sbjorn3         assert_eq!(data.data_relocs.len(), 0);
243747ad3c4Slazypassion     }
244747ad3c4Slazypassion }
245