wasmer_wasix/state/linker/
wasm_utils.rs1use tracing::trace;
2use wasmer::{
3 AsStoreMut, ExportError, ExternType, Global, GlobalType, ImportType, Instance, MemoryType,
4 Module, Table, TableType, Type, Value, WasmTypeList,
5};
6
7use super::LinkError;
8
9pub(super) fn get_integer_global_type_from_import(
10 import: &ImportType,
11) -> Result<GlobalType, LinkError> {
12 let import_type = import.ty();
13 let ExternType::Global(ty) = import_type else {
14 return Err(LinkError::BadImport(
15 import.module().to_owned(),
16 import.name().to_owned(),
17 import_type.clone(),
18 ));
19 };
20
21 if !matches!(ty.ty, Type::I32 | Type::I64) {
22 return Err(LinkError::NonIntegerGlobal(
23 import.module().to_owned(),
24 import.name().to_owned(),
25 ));
26 }
27
28 Ok(*ty)
29}
30
31pub(super) fn define_integer_global_import(
32 store: &mut impl AsStoreMut,
33 import: &ImportType,
34 value: u64,
35) -> Result<Global, LinkError> {
36 let ExternType::Global(GlobalType { ty, mutability }) = import.ty() else {
37 return Err(LinkError::BadImport(
38 import.module().to_string(),
39 import.name().to_string(),
40 import.ty().clone(),
41 ));
42 };
43
44 let new_global = if mutability.is_mutable() {
45 Global::new_mut
46 } else {
47 Global::new
48 };
49
50 let global = match ty {
51 Type::I32 => new_global(store, wasmer::Value::I32(value as i32)),
52 Type::I64 => new_global(store, wasmer::Value::I64(value as i64)),
53 _ => {
54 return Err(LinkError::BadImport(
55 import.module().to_string(),
56 import.name().to_string(),
57 import.ty().clone(),
58 ));
59 }
60 };
61
62 Ok(global)
63}
64
65pub(super) fn main_module_function_table_type(
66 main_module: &Module,
67) -> Result<TableType, LinkError> {
68 main_module
69 .imports()
70 .tables()
71 .filter_map(|t| {
72 if t.ty().ty == Type::FuncRef
73 && t.name() == "__indirect_function_table"
74 && t.module() == "env"
75 {
76 Some(*t.ty())
77 } else {
78 None
79 }
80 })
81 .next()
82 .ok_or(LinkError::MissingMainModuleImport(
83 "env.__indirect_function_table".to_string(),
84 ))
85}
86
87pub(super) fn main_module_memory_type(main_module: &Module) -> Result<MemoryType, LinkError> {
88 main_module
89 .imports()
90 .memories()
91 .filter_map(|t| {
92 if t.name() == "memory" && t.module() == "env" {
93 Some(*t.ty())
94 } else {
95 None
96 }
97 })
98 .next()
99 .ok_or(LinkError::MissingMainModuleImport("env.memory".to_string()))
100}
101
102pub(super) fn create_indirect_function_table(
103 store: &mut impl AsStoreMut,
104 table_type: TableType,
105 expected_len: u32,
106) -> Result<Table, LinkError> {
107 trace!(
108 minimum_size = ?table_type.minimum,
109 "Creating indirect function table"
110 );
111 let table = Table::new(store, table_type, Value::FuncRef(None))
112 .map_err(LinkError::TableAllocationError)?;
113
114 if table.size(store) < expected_len {
115 let current_size = table.size(store);
116 let delta = expected_len - current_size;
117 trace!(?current_size, ?delta, "Growing indirect function table");
118 table
119 .grow(store, delta, Value::FuncRef(None))
120 .map_err(LinkError::TableAllocationError)?;
121 }
122
123 trace!(
124 size = table.size(store),
125 "Indirect function table initial size"
126 );
127
128 Ok(table)
129}
130
131pub(super) fn create_main_stack_pointer_global(
132 store: &mut impl AsStoreMut,
133 main_module: &Module,
134 initial_value: u64,
135) -> Result<Global, LinkError> {
136 let import = main_module
137 .imports()
138 .find(|i| i.module() == "env" && i.name() == "__stack_pointer")
139 .ok_or(LinkError::MissingMainModuleImport(
140 "__stack_pointer".to_string(),
141 ))?;
142
143 define_integer_global_import(store, &import, initial_value)
144}
145
146pub(super) fn set_integer_global(
147 store: &mut impl AsStoreMut,
148 name: &str,
149 global: &Global,
150 value: u64,
151) -> Result<(), LinkError> {
152 match global.ty(store).ty {
153 Type::I32 => global
154 .set(store, Value::I32(value as i32))
155 .map_err(|e| LinkError::GlobalUpdateFailed(name.to_owned(), e))?,
156 Type::I64 => global
157 .set(store, Value::I64(value as i64))
158 .map_err(|e| LinkError::GlobalUpdateFailed(name.to_owned(), e))?,
159 _ => {
160 unreachable!("Internal error: expected global of type I32 or I64");
162 }
163 }
164
165 Ok(())
166}
167
168pub(super) fn call_initialization_function<Ret: WasmTypeList>(
169 instance: &Instance,
170 store: &mut impl AsStoreMut,
171 name: &str,
172) -> Result<Option<Ret>, LinkError> {
173 match instance.exports.get_typed_function::<(), Ret>(store, name) {
174 Ok(f) => {
175 let ret = f
176 .call(store)
177 .map_err(|e| LinkError::InitFunctionFailed(name.to_string(), e))?;
178 Ok(Some(ret))
179 }
180 Err(ExportError::Missing(_)) => Ok(None),
181 Err(ExportError::IncompatibleType) => {
182 Err(LinkError::InitFuncWithInvalidSignature(name.to_string()))
183 }
184 }
185}
186
187pub(super) fn get_tls_base_export(
188 instance: &Instance,
189 store: &mut impl AsStoreMut,
190) -> Result<Option<u64>, LinkError> {
191 match instance.exports.get_global("__tls_base") {
192 Ok(global) => match global.get(store) {
193 Value::I32(x) => Ok(Some(x as u64)),
194 Value::I64(x) => Ok(Some(x as u64)),
195 _ => Err(LinkError::BadTlsBaseExport),
196 },
197 Err(ExportError::Missing(_)) => Ok(None),
198 Err(ExportError::IncompatibleType) => Err(LinkError::BadTlsBaseExport),
199 }
200}