Fix WasmTy/WasmRet on big-endian hosts (#2384)

When invoking a WebAssembly routine from Rust code, arguments
are stored into an array of u128, and read from a piece of
generated trampoline code before calling the compiled target
function using the platform ABI calling convention.

The WasmTy/WasmRet routines handle the conversion between Rust
data types and those u128 buffers.  This currently works by
in effect converting the Rust object to a u128 and then storing
this u128 into the buffer.  The generated trampoline code will
then read an object of appropriate type from the beginning of
that buffer.

This does not work on big-endian platforms, since the above
approach causes the value to be stored into the rightmost
bytes of the u128 buffer, while the trampoline code reads
the leftmost bytes.

This patch fixes the problem by changing WasmTy/WasmRet to
use the leftmost bytes as well, by casting the u128 pointer
to a pointer of the correct type before storing to it (or
reading from it).

(Note that it is not necessary to actually byte-swap the
values since the trampoline code will not treat them like
WebAssembly little-endian memory, but simply access them
in native byte order.)
This commit is contained in:
Ulrich Weigand
2020-11-09 18:14:52 +01:00
committed by GitHub
parent a9d8abbf53
commit b326f29885

View File

@@ -1001,14 +1001,14 @@ unsafe impl WasmTy for i32 {
#[inline] #[inline]
unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi { unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi {
let ret = **ptr as Self; let ret = *(*ptr).cast::<Self>();
*ptr = (*ptr).add(1); *ptr = (*ptr).add(1);
return ret; return ret;
} }
#[inline] #[inline]
unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) { unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) {
*ptr = abi as u128; *ptr.cast::<Self>() = abi;
} }
} }
@@ -1083,14 +1083,14 @@ unsafe impl WasmTy for i64 {
#[inline] #[inline]
unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi { unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi {
let ret = **ptr as Self; let ret = *(*ptr).cast::<Self>();
*ptr = (*ptr).add(1); *ptr = (*ptr).add(1);
return ret; return ret;
} }
#[inline] #[inline]
unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) { unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) {
*ptr = abi as u128; *ptr.cast::<Self>() = abi;
} }
} }
@@ -1165,14 +1165,14 @@ unsafe impl WasmTy for f32 {
#[inline] #[inline]
unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi { unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi {
let ret = f32::from_bits(**ptr as u32); let ret = f32::from_bits(*(*ptr).cast::<u32>());
*ptr = (*ptr).add(1); *ptr = (*ptr).add(1);
return ret; return ret;
} }
#[inline] #[inline]
unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) { unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) {
*ptr = abi.to_bits() as u128; *ptr.cast::<u32>() = abi.to_bits();
} }
} }
@@ -1210,14 +1210,14 @@ unsafe impl WasmTy for f64 {
#[inline] #[inline]
unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi { unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi {
let ret = f64::from_bits(**ptr as u64); let ret = f64::from_bits(*(*ptr).cast::<u64>());
*ptr = (*ptr).add(1); *ptr = (*ptr).add(1);
return ret; return ret;
} }
#[inline] #[inline]
unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) { unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) {
*ptr = abi.to_bits() as u128; *ptr.cast::<u64>() = abi.to_bits();
} }
} }
@@ -1271,13 +1271,13 @@ unsafe impl WasmTy for Option<ExternRef> {
} }
unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi { unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi {
let ret = **ptr as usize as *mut u8; let ret = *(*ptr).cast::<usize>() as *mut u8;
*ptr = (*ptr).add(1); *ptr = (*ptr).add(1);
ret ret
} }
unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) { unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) {
ptr::write(ptr, abi as usize as u128); ptr::write(ptr.cast::<usize>(), abi as usize);
} }
} }
@@ -1324,13 +1324,13 @@ unsafe impl WasmTy for Option<Func> {
} }
unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi { unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi {
let ret = **ptr as usize as *mut wasmtime_runtime::VMCallerCheckedAnyfunc; let ret = *(*ptr).cast::<usize>() as *mut wasmtime_runtime::VMCallerCheckedAnyfunc;
*ptr = (*ptr).add(1); *ptr = (*ptr).add(1);
ret ret
} }
unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) { unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) {
ptr::write(ptr, abi as usize as u128); ptr::write(ptr.cast::<usize>(), abi as usize);
} }
} }