Fix libcall relocations for precompiled modules (#5608)

* Fix libcall relocations for precompiled modules

This commit fixes some asserts and support for relocation libcalls in
precompiled modules loaded from disk. In doing so this reworks how mmaps
are managed for files from disk. All non-file-backed `Mmap` entries are
read/write but file-backed versions were readonly. This commit changes
this such that all `Mmap` objects, even if they're file-backed, start as
read/write. The file-based versions all use copy-on-write to preserve
the private-ness of the mapping.

This is not functionally intended to change anything. Instead this
should have some more memory writable after a module is loaded but the
text section, for example, is still left as read/execute when loading is
finished. Additionally this makes modules compiled in memory more
consistent with modules loaded from disk.

* Update a comment

* Force images to become readonly during publish

This marks compiled images as entirely readonly during the
`CodeMemory::publish` step which happens just before the text section
becomes executable. This ensures that all images, no matter where they
come from, are guaranteed frozen before they start executing.
This commit is contained in:
Alex Crichton
2023-01-25 12:09:15 -06:00
committed by GitHub
parent 38bf38c514
commit 4ad86752de
4 changed files with 124 additions and 79 deletions

View File

@@ -168,3 +168,49 @@ fn serialize_not_overly_massive() -> Result<()> {
Ok(())
}
// This test specifically disables SSE4.1 in Cranelift which force wasm
// instructions like `f32.ceil` to go through libcalls instead of using native
// instructions. Note that SIMD is also disabled here because SIMD otherwise
// requires SSE4.1 to be enabled.
//
// This test then also tests that loading modules through various means, e.g.
// through precompiled artifacts, all works.
#[test]
#[cfg_attr(not(target_arch = "x86_64"), ignore)]
fn missing_sse_and_floats_still_works() -> Result<()> {
let mut config = Config::new();
config.wasm_simd(false);
unsafe {
config.cranelift_flag_set("has_sse41", "false");
}
let engine = Engine::new(&config)?;
let module = Module::new(
&engine,
r#"
(module
(func (export "f32.ceil") (param f32) (result f32)
local.get 0
f32.ceil)
)
"#,
)?;
let bytes = module.serialize()?;
let module2 = unsafe { Module::deserialize(&engine, &bytes)? };
let tmpdir = tempfile::TempDir::new()?;
let path = tmpdir.path().join("module.cwasm");
std::fs::write(&path, &bytes)?;
let module3 = unsafe { Module::deserialize_file(&engine, &path)? };
for module in [module, module2, module3] {
let mut store = Store::new(&engine, ());
let instance = Instance::new(&mut store, &module, &[])?;
let ceil = instance.get_typed_func::<f32, f32>(&mut store, "f32.ceil")?;
for f in [1.0, 2.3, -1.3] {
assert_eq!(ceil.call(&mut store, f)?, f.ceil());
}
}
Ok(())
}