xref: /wasmtime-44.0.1/tests/all/relocs.rs (revision 48f4621f)
1 //! These tests are intended to exercise various relocation-based logic of
2 //! Wasmtime, especially the "jump veneer" insertion in the object-file-assembly
3 //! for when platform-specific relative call instructors can't always reach
4 //! their destination within the platform-specific limits.
5 //!
6 //! Note that the limits of AArch64 are primarily what's being stressed here
7 //! where the jump target for a call is 26-bits. On x86_64 the jump target is
8 //! 32-bits, and right now object files aren't supported larger than 4gb anyway
9 //! so we would need a lot of other support necessary to exercise that.
10 
11 #![cfg(not(miri))]
12 
13 use wasmtime::*;
14 
15 const MB: usize = 1 << 20;
16 const PADDING: usize = if cfg!(target_pointer_width = "32") {
17     1 * MB
18 } else {
19     128 * MB
20 };
21 
store_with_padding(padding: usize) -> Result<Store<()>>22 fn store_with_padding(padding: usize) -> Result<Store<()>> {
23     let mut config = Config::new();
24     // This is an internal debug-only setting specifically recognized for
25     // basically just this set of tests.
26     unsafe {
27         config.cranelift_flag_set(
28             "wasmtime_linkopt_padding_between_functions",
29             &padding.to_string(),
30         );
31     }
32     let engine = Engine::new(&config)?;
33     Ok(Store::new(&engine, ()))
34 }
35 
36 #[test]
forward_call_works() -> Result<()>37 fn forward_call_works() -> Result<()> {
38     let mut store = store_with_padding(PADDING)?;
39     let module = Module::new(
40         store.engine(),
41         r#"
42             (module
43                 (func (export "foo") (result i32)
44                     call 1)
45                 (func (result i32)
46                     i32.const 4)
47             )
48         "#,
49     )?;
50 
51     let i = Instance::new(&mut store, &module, &[])?;
52     let foo = i.get_typed_func::<(), i32>(&mut store, "foo")?;
53     assert_eq!(foo.call(&mut store, ())?, 4);
54     Ok(())
55 }
56 
57 #[test]
backwards_call_works() -> Result<()>58 fn backwards_call_works() -> Result<()> {
59     let mut store = store_with_padding(PADDING)?;
60     let module = Module::new(
61         store.engine(),
62         r#"
63             (module
64                 (func (result i32)
65                     i32.const 4)
66                 (func (export "foo") (result i32)
67                     call 0)
68             )
69         "#,
70     )?;
71 
72     let i = Instance::new(&mut store, &module, &[])?;
73     let foo = i.get_typed_func::<(), i32>(&mut store, "foo")?;
74     assert_eq!(foo.call(&mut store, ())?, 4);
75     Ok(())
76 }
77 
78 #[test]
mixed() -> Result<()>79 fn mixed() -> Result<()> {
80     test_many_call_module(store_with_padding(MB)?)
81 }
82 
83 #[test]
mixed_forced() -> Result<()>84 fn mixed_forced() -> Result<()> {
85     let mut config = Config::new();
86     unsafe {
87         config.cranelift_flag_set("wasmtime_linkopt_force_jump_veneer", "true");
88     }
89     let engine = Engine::new(&config)?;
90     test_many_call_module(Store::new(&engine, ()))
91 }
92 
test_many_call_module(mut store: Store<()>) -> Result<()>93 fn test_many_call_module(mut store: Store<()>) -> Result<()> {
94     const N: i32 = 200;
95 
96     let mut wat = String::new();
97     wat.push_str("(module\n");
98     wat.push_str("(func $first (result i32) (i32.const 1))\n");
99     for i in 0..N {
100         wat.push_str(&format!("(func (export \"{i}\") (result i32 i32)\n"));
101         wat.push_str("call $first\n");
102         wat.push_str(&format!("i32.const {i}\n"));
103         wat.push_str("i32.add\n");
104         wat.push_str("call $last\n");
105         wat.push_str(&format!("i32.const {i}\n"));
106         wat.push_str("i32.add)\n");
107     }
108     wat.push_str("(func $last (result i32) (i32.const 2))\n");
109     wat.push_str(")\n");
110 
111     let module = Module::new(store.engine(), &wat)?;
112 
113     let instance = Instance::new(&mut store, &module, &[])?;
114 
115     for i in 0..N {
116         let name = i.to_string();
117         let func = instance.get_typed_func::<(), (i32, i32)>(&mut store, &name)?;
118         let (a, b) = func.call(&mut store, ())?;
119         assert_eq!(a, i + 1);
120         assert_eq!(b, i + 2);
121     }
122     Ok(())
123 }
124