Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/module/src/data_context.rs
1692 views
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.
37
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`.
75
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`.
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.
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?
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
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.
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.
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`.
136
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`.
147
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`.
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`.
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.
162
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]
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
246