wasmer_wasix/state/linker/
wasm_utils.rs

1use 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            // This should be caught by resolve_global_import, so just panic here
161            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}