mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2026-01-12 20:36:42 +00:00
Merge 4fd87d8725 into d4034f1cfb
This commit is contained in:
commit
7d60d5ca71
10
.github/workflows/compilation_on_macos.yml
vendored
10
.github/workflows/compilation_on_macos.yml
vendored
|
|
@ -440,3 +440,13 @@ jobs:
|
|||
cmake ..
|
||||
cmake --build . --config Release --parallel 4
|
||||
./import-func-callback
|
||||
|
||||
- name: Test x18 register reservation (macOS ARM64 only)
|
||||
if: matrix.os == 'macos-15'
|
||||
run: |
|
||||
cd product-mini/platforms/darwin
|
||||
mkdir -p build && cd build
|
||||
cmake .. -DWAMR_BUILD_AOT=1
|
||||
cmake --build . --config Release --parallel 4
|
||||
cd ../../../../tests/standalone/test-aot-x18-reserve
|
||||
./run.sh --aot
|
||||
|
|
|
|||
|
|
@ -3005,6 +3005,10 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
|
|||
else
|
||||
vendor_sys = "-pc-windows-";
|
||||
}
|
||||
else if (!strcmp(abi, "darwin") || !strcmp(abi, "macho")) {
|
||||
/* macOS/Darwin: x18 is reserved by Apple */
|
||||
vendor_sys = "-apple-";
|
||||
}
|
||||
else {
|
||||
if (is_baremetal_target(arch, cpu, abi))
|
||||
vendor_sys = "-unknown-none-";
|
||||
|
|
@ -3050,6 +3054,14 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
|
|||
if (!abi)
|
||||
abi = "gnu";
|
||||
}
|
||||
else if (strstr(default_triple, "darwin")
|
||||
|| strstr(default_triple, "apple")) {
|
||||
/* macOS/Darwin: x18 is reserved by Apple, must use correct
|
||||
* triple to prevent LLVM from using it */
|
||||
vendor_sys = "-apple-darwin";
|
||||
if (!abi)
|
||||
abi = "";
|
||||
}
|
||||
else {
|
||||
vendor_sys = "-pc-linux-";
|
||||
if (!abi)
|
||||
|
|
@ -3139,6 +3151,30 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
|
|||
if (!features)
|
||||
features = "";
|
||||
|
||||
#if (defined(__APPLE__) || defined(__MACH__)) && defined(BUILD_TARGET_AARCH64)
|
||||
/* On macOS ARM64, x18 is reserved by Apple for TLS. Even though we're
|
||||
* generating ELF (Linux-style) AOT files, we must tell LLVM to not
|
||||
* use x18, otherwise the AOT code will crash when running on macOS. */
|
||||
{
|
||||
bool is_aarch64 = false;
|
||||
if (arch && !strncmp(arch, "aarch64", 7))
|
||||
is_aarch64 = true;
|
||||
else if (triple_norm && strstr(triple_norm, "aarch64"))
|
||||
is_aarch64 = true;
|
||||
|
||||
if (is_aarch64) {
|
||||
if (features[0] != '\0') {
|
||||
snprintf(features_buf, sizeof(features_buf),
|
||||
"%s,+reserve-x18", features);
|
||||
features = features_buf;
|
||||
}
|
||||
else {
|
||||
features = "+reserve-x18";
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get target with triple, note that LLVMGetTargetFromTriple()
|
||||
return 0 when success, but not true. */
|
||||
if (LLVMGetTargetFromTriple(triple_norm, &target, &err) != 0) {
|
||||
|
|
|
|||
120
tests/standalone/test-aot-x18-reserve/run.sh
Executable file
120
tests/standalone/test-aot-x18-reserve/run.sh
Executable file
|
|
@ -0,0 +1,120 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
# Test for x18 register reservation on macOS ARM64 (aarch64).
|
||||
#
|
||||
# On macOS ARM64, x18 is reserved by Apple for TLS (Thread Local Storage).
|
||||
# Without the +reserve-x18 LLVM flag, the AOT compiler may generate code
|
||||
# that uses x18, causing random SIGSEGV crashes when run on macOS.
|
||||
#
|
||||
# This test compiles a WASM module that stresses register allocation
|
||||
# (forcing x18 usage without the fix) and runs it 1000 times to verify
|
||||
# no crashes occur.
|
||||
#
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
|
||||
WAMR_DIR="${SCRIPT_DIR}/../../.."
|
||||
|
||||
# Detect platform
|
||||
UNAME_S=$(uname -s)
|
||||
UNAME_M=$(uname -m)
|
||||
|
||||
# Only run this test on macOS ARM64
|
||||
if [[ "${UNAME_S}" != "Darwin" ]] || [[ "${UNAME_M}" != "arm64" ]]; then
|
||||
echo "Skipping x18 reserve test: only applicable on macOS ARM64"
|
||||
echo "Current platform: ${UNAME_S} ${UNAME_M}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Determine iwasm path based on platform
|
||||
if [[ "${UNAME_S}" == "Darwin" ]]; then
|
||||
IWASM_CMD="${WAMR_DIR}/product-mini/platforms/darwin/build/iwasm"
|
||||
else
|
||||
IWASM_CMD="${WAMR_DIR}/product-mini/platforms/linux/build/iwasm"
|
||||
fi
|
||||
|
||||
WAMRC_CMD="${WAMR_DIR}/wamr-compiler/build/wamrc"
|
||||
|
||||
# Check if required binaries exist
|
||||
if [[ ! -x "${IWASM_CMD}" ]]; then
|
||||
echo "Error: iwasm not found at ${IWASM_CMD}"
|
||||
echo "Please build iwasm first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -x "${WAMRC_CMD}" ]]; then
|
||||
echo "Error: wamrc not found at ${WAMRC_CMD}"
|
||||
echo "Please build wamrc first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "${SCRIPT_DIR}"
|
||||
|
||||
# Find wat2wasm (check CI path first, then system PATH)
|
||||
if [[ -x "/opt/wabt/bin/wat2wasm" ]]; then
|
||||
WAT2WASM="/opt/wabt/bin/wat2wasm"
|
||||
elif command -v wat2wasm &> /dev/null; then
|
||||
WAT2WASM="wat2wasm"
|
||||
else
|
||||
echo "Error: wat2wasm not found"
|
||||
echo "Please install wabt tools"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Compile WAT to WASM if needed
|
||||
if [[ ! -f stress_registers.wasm ]] || [[ stress_registers.wat -nt stress_registers.wasm ]]; then
|
||||
echo "Compiling stress_registers.wat to WASM..."
|
||||
if ! ${WAT2WASM} stress_registers.wat -o stress_registers.wasm; then
|
||||
echo "Error: Failed to compile WAT to WASM"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $1 != "--aot" ]]; then
|
||||
echo "============> run stress_registers.wasm (interpreter mode)"
|
||||
echo "Running 1000 iterations in interpreter mode..."
|
||||
for i in $(seq 1 1000); do
|
||||
if ! ${IWASM_CMD} stress_registers.wasm 2>&1; then
|
||||
echo "FAILED: Crash at iteration $i"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
echo "PASSED: 1000 iterations completed without crash"
|
||||
else
|
||||
echo "============> compile stress_registers.wasm to AOT"
|
||||
|
||||
# Compile to AOT - the fix should add +reserve-x18 automatically on macOS ARM64
|
||||
if ! ${WAMRC_CMD} --opt-level=3 -o stress_registers.aot stress_registers.wasm; then
|
||||
echo "Error: Failed to compile WASM to AOT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "============> run stress_registers.aot"
|
||||
echo "Running 1000 iterations to verify x18 is properly reserved..."
|
||||
echo "(Without the fix, this would crash ~80% of the time)"
|
||||
|
||||
failed=0
|
||||
for i in $(seq 1 1000); do
|
||||
if ! ${IWASM_CMD} stress_registers.aot 2>&1 > /dev/null; then
|
||||
echo "FAILED: Crash at iteration $i"
|
||||
failed=1
|
||||
break
|
||||
fi
|
||||
# Progress indicator every 100 iterations
|
||||
if [[ $((i % 100)) -eq 0 ]]; then
|
||||
echo " Progress: $i/1000 iterations completed"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${failed} -eq 0 ]]; then
|
||||
echo "PASSED: 1000 iterations completed without crash"
|
||||
echo "The +reserve-x18 fix is working correctly"
|
||||
exit 0
|
||||
else
|
||||
echo "FAILED: x18 register corruption detected"
|
||||
echo "The +reserve-x18 fix may not be applied correctly"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
97
tests/standalone/test-aot-x18-reserve/stress_registers.wat
Normal file
97
tests/standalone/test-aot-x18-reserve/stress_registers.wat
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
;; Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
;; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
;; Test module that uses many local variables to stress register allocation.
|
||||
;; On ARM64, this will force LLVM to use x18 register if +reserve-x18 is not set.
|
||||
;; x18 is reserved by Apple on macOS for TLS, so using it causes crashes.
|
||||
|
||||
(module
|
||||
(memory (export "memory") 1)
|
||||
|
||||
(func $stress_registers (export "stress_registers") (param $input i64) (result i64)
|
||||
(local $a i64) (local $b i64) (local $c i64) (local $d i64)
|
||||
(local $e i64) (local $f i64) (local $g i64) (local $h i64)
|
||||
(local $i i64) (local $j i64) (local $k i64) (local $l i64)
|
||||
(local $m i64) (local $n i64) (local $o i64) (local $p i64)
|
||||
(local $q i64) (local $r i64) (local $s i64) (local $t i64)
|
||||
(local $u i64) (local $v i64) (local $w i64) (local $x i64)
|
||||
|
||||
;; Initialize all locals with different values based on input
|
||||
(local.set $a (i64.add (local.get $input) (i64.const 1)))
|
||||
(local.set $b (i64.mul (local.get $a) (i64.const 2)))
|
||||
(local.set $c (i64.add (local.get $b) (i64.const 3)))
|
||||
(local.set $d (i64.mul (local.get $c) (i64.const 4)))
|
||||
(local.set $e (i64.add (local.get $d) (i64.const 5)))
|
||||
(local.set $f (i64.mul (local.get $e) (i64.const 6)))
|
||||
(local.set $g (i64.add (local.get $f) (i64.const 7)))
|
||||
(local.set $h (i64.mul (local.get $g) (i64.const 8)))
|
||||
(local.set $i (i64.add (local.get $h) (i64.const 9)))
|
||||
(local.set $j (i64.mul (local.get $i) (i64.const 10)))
|
||||
(local.set $k (i64.add (local.get $j) (i64.const 11)))
|
||||
(local.set $l (i64.mul (local.get $k) (i64.const 12)))
|
||||
(local.set $m (i64.add (local.get $l) (i64.const 13)))
|
||||
(local.set $n (i64.mul (local.get $m) (i64.const 14)))
|
||||
(local.set $o (i64.add (local.get $n) (i64.const 15)))
|
||||
(local.set $p (i64.mul (local.get $o) (i64.const 16)))
|
||||
(local.set $q (i64.add (local.get $p) (i64.const 17)))
|
||||
(local.set $r (i64.mul (local.get $q) (i64.const 18)))
|
||||
(local.set $s (i64.add (local.get $r) (i64.const 19)))
|
||||
(local.set $t (i64.mul (local.get $s) (i64.const 20)))
|
||||
(local.set $u (i64.add (local.get $t) (i64.const 21)))
|
||||
(local.set $v (i64.mul (local.get $u) (i64.const 22)))
|
||||
(local.set $w (i64.add (local.get $v) (i64.const 23)))
|
||||
(local.set $x (i64.mul (local.get $w) (i64.const 24)))
|
||||
|
||||
;; Now use all of them together to prevent optimization
|
||||
(i64.add
|
||||
(i64.add
|
||||
(i64.add
|
||||
(i64.add
|
||||
(i64.add
|
||||
(i64.add
|
||||
(i64.add
|
||||
(i64.add
|
||||
(i64.add
|
||||
(i64.add
|
||||
(i64.add
|
||||
(i64.add
|
||||
(local.get $a)
|
||||
(local.get $b))
|
||||
(local.get $c))
|
||||
(local.get $d))
|
||||
(local.get $e))
|
||||
(local.get $f))
|
||||
(local.get $g))
|
||||
(local.get $h))
|
||||
(local.get $i))
|
||||
(local.get $j))
|
||||
(local.get $k))
|
||||
(local.get $l))
|
||||
(i64.add
|
||||
(i64.add
|
||||
(i64.add
|
||||
(i64.add
|
||||
(i64.add
|
||||
(i64.add
|
||||
(i64.add
|
||||
(i64.add
|
||||
(i64.add
|
||||
(i64.add
|
||||
(i64.add
|
||||
(local.get $m)
|
||||
(local.get $n))
|
||||
(local.get $o))
|
||||
(local.get $p))
|
||||
(local.get $q))
|
||||
(local.get $r))
|
||||
(local.get $s))
|
||||
(local.get $t))
|
||||
(local.get $u))
|
||||
(local.get $v))
|
||||
(local.get $w))
|
||||
(local.get $x))))
|
||||
|
||||
(func $_start (export "_start")
|
||||
(drop (call $stress_registers (i64.const 42)))
|
||||
)
|
||||
)
|
||||
Loading…
Reference in New Issue
Block a user