Resolve libcall relocations for older CPUs (#5567)

* Resolve libcall relocations for older CPUs

Long ago Wasmtime used to have logic for resolving relocations
post-compilation for libcalls which I ended up removing during
refactorings last year. As #5563 points out, however, it's possible to
get Wasmtime to panic by disabling SSE features which forces Cranelift
to use libcalls for some floating-point operations instead. Note that
this also requires disabling SIMD because SIMD support has a baseline of
SSE 4.2.

This commit pulls back the old implementations of various libcalls and
reimplements logic necessary to have them work on CPUs without SSE 4.2

Closes #5563

* Fix log message in `wast` support

* Fix offset listed in relocations

Be sure to factor in the offset of the function itself

* Review comments
This commit is contained in:
Alex Crichton
2023-01-18 09:04:10 -06:00
committed by GitHub
parent 94b51cdb17
commit 9b896d2a70
7 changed files with 298 additions and 14 deletions

View File

@@ -1,6 +1,8 @@
//! Generate Cranelift compiler settings.
use crate::generators::ModuleConfig;
use arbitrary::{Arbitrary, Unstructured};
use std::collections::HashMap;
/// Choose between matching the host architecture or a cross-compilation target.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
@@ -32,6 +34,42 @@ impl CodegenSettings {
}
}
}
/// Features such as sse4.2 are unconditionally enabled on the x86_64 target
/// because they are hard required for SIMD, but when SIMD is disabled, for
/// example, we support disabling these features.
///
/// This method will take the wasm feature selection chosen, through
/// `module_config`, and possibly try to disable some more features by
/// reading more of the input.
pub fn maybe_disable_more_features(
&mut self,
module_config: &ModuleConfig,
u: &mut Unstructured<'_>,
) -> arbitrary::Result<()> {
let flags = match self {
CodegenSettings::Target { flags, .. } => flags,
_ => return Ok(()),
};
if !module_config.config.simd_enabled {
// Note that regardless of architecture these booleans are generated
// to have test case failures unrelated to codegen setting input
// that fail on one architecture to fail on other architectures as
// well.
let new_flags = ["has_sse3", "has_ssse3", "has_sse41", "has_sse42"]
.into_iter()
.map(|name| Ok((name, u.arbitrary()?)))
.collect::<arbitrary::Result<HashMap<_, bool>>>()?;
for (name, val) in flags {
if let Some(new_value) = new_flags.get(name.as_str()) {
*val = new_value.to_string();
}
}
}
Ok(())
}
}
impl<'a> Arbitrary<'a> for CodegenSettings {
@@ -103,6 +141,9 @@ impl<'a> Arbitrary<'a> for CodegenSettings {
// fail if these features are disabled, so unconditionally
// enable them as we're not interested in fuzzing without
// them.
//
// Note that these may still be disabled above in
// `maybe_disable_more_features`.
std:"sse3" => clif:"has_sse3" ratio: 1 in 1,
std:"ssse3" => clif:"has_ssse3" ratio: 1 in 1,
std:"sse4.1" => clif:"has_sse41" ratio: 1 in 1,

View File

@@ -294,6 +294,11 @@ impl<'a> Arbitrary<'a> for Config {
module_config: u.arbitrary()?,
};
config
.wasmtime
.codegen
.maybe_disable_more_features(&config.module_config, u)?;
// If using the pooling allocator, constrain the memory and module configurations
// to the module limits.
if let InstanceAllocationStrategy::Pooling(pooling) = &mut config.wasmtime.strategy {