我试图在一个用Rust编写的解释器项目中,在运行时组装和调用代码.我用assembler
crate来做这个.我想对JIT代码可以直接调用的重要运行时功能有extern "C" fn
个包装.为了最小化生成的代码段中的复杂性,我希望将解释器状态保持为全局变量.
然而,每当我试图访问和/或修改任何全局状态时,程序都会不断崩溃.一个简单的println!("hello world")
与一般保护故障一起崩溃,似乎是在stdio::_print()
访问stdout
时.还有一个简单的示例,其中包含static mut
个变量转储核心.有趣的是,虽然前者在Valgrind下崩溃,堆栈跟踪整洁,但后一个示例运行正常,实际上传递了提示程序按预期工作的断言.请注意,静态变量不需要是可变的,读取它就足以导致崩溃.
我对assembler
crate 下面使用的mmap
个细节一无所知,但我无法找到我的方法崩溃的任何线索.任何指导都将不胜感激.
我创造了一个Repl.it repl with an MRE.
use anyhow::Result;
use assembler::*;
use assembler::mnemonic_parameter_types::{registers::*, immediates::*};
const CHUNK_LENGTH: usize = 4096;
const LABEL_COUNT: usize = 64;
static mut X: u32 = 0;
#[no_mangle]
unsafe extern "C" fn foo() {
// printing here will lead to a coredump,
// Valgrind will provide more insight (general protection fault)
// println!("hello world");
// modifying a global variable instead will also dump
// core but will run without fail in Valgrind
X += 1
}
fn main() -> Result<()> {
let mut memory_map = ExecutableAnonymousMemoryMap::new(CHUNK_LENGTH, true, true)?;
let mut instr_stream = memory_map.instruction_stream(&InstructionStreamHints {
number_of_labels: LABEL_COUNT,
..Default::default()
});
let f = instr_stream.nullary_function_pointer::<i64>();
instr_stream.call_function(foo as unsafe extern "C" fn());
instr_stream.mov_Register64Bit_Immediate64Bit(Register64Bit::RAX, Immediate64Bit(0x123456789abcdef0));
instr_stream.ret();
instr_stream.finish();
assert_eq!(unsafe { f() }, 0x123456789abcdef0);
assert_eq!(unsafe { X }, 1);
Ok(())
}
以下是两种情况下的Valgrind输出.
全局变量:
==4186== Memcheck, a memory error detector
==4186== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==4186== Using Valgrind-3.16.1 and LibVEX; rerun with -h for copyright info
==4186== Command: target/debug/jit-ffi-fault-mre
==4186==
==4186==
==4186== HEAP SUMMARY:
==4186== in use at exit: 0 bytes in 0 blocks
==4186== total heap usage: 14 allocs, 14 frees, 199,277 bytes allocated
==4186==
==4186== All heap blocks were freed -- no leaks are possible
==4186==
==4186== For lists of detected and suppressed errors, rerun with: -s
==4186== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
println!
:
==4341== Memcheck, a memory error detector
==4341== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==4341== Using Valgrind-3.16.1 and LibVEX; rerun with -h for copyright info
==4341== Command: target/debug/jit-ffi-fault-mre
==4341==
==4341==
==4341== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==4341== General Protection Fault
==4341== at 0x13FB7A: std::io::stdio::_print (stdio.rs:1028)
==4341== by 0x1174B0: foo (main.rs:15)
==4341== by 0x4E58004: ???
==4341== by 0x11A1BC: jit_ffi_fault_mre::main (main.rs:35)
==4341== by 0x113FEA: core::ops::function::FnOnce::call_once (function.rs:248)
==4341== by 0x11497D: std::sys_common::backtrace::__rust_begin_short_backtrace (backtrace.rs:122)
==4341== by 0x114E70: std::rt::lang_start::{{closure}} (rt.rs:145)
==4341== by 0x13CA95: call_once<(), (dyn core::ops::function::Fn<(), Output=i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe)> (function.rs:280)
==4341== by 0x13CA95: do_call<&(dyn core::ops::function::Fn<(), Output=i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe), i32> (panicking.rs:492)
==4341== by 0x13CA95: try<i32, &(dyn core::ops::function::Fn<(), Output=i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe)> (panicking.rs:456)
==4341== by 0x13CA95: catch_unwind<&(dyn core::ops::function::Fn<(), Output=i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe), i32> (panic.rs:137)
==4341== by 0x13CA95: {closure#2} (rt.rs:128)
==4341== by 0x13CA95: do_call<std::rt::lang_start_internal::{closure_env#2}, isize> (panicking.rs:492)
==4341== by 0x13CA95: try<isize, std::rt::lang_start_internal::{closure_env#2}> (panicking.rs:456)
==4341== by 0x13CA95: catch_unwind<std::rt::lang_start_internal::{closure_env#2}, isize> (panic.rs:137)
==4341== by 0x13CA95: std::rt::lang_start_internal (rt.rs:128)
==4341== by 0x114E3F: std::rt::lang_start (rt.rs:144)
==4341== by 0x11A37B: main (in /home/runner/UnsightlyAwfulPhases/jit-ffi-fault-mre/target/debug/jit-ffi-fault-mre)
==4341==
==4341== HEAP SUMMARY:
==4341== in use at exit: 85 bytes in 3 blocks
==4341== total heap usage: 14 allocs, 11 frees, 199,277 bytes allocated
==4341==
==4341== LEAK SUMMARY:
==4341== definitely lost: 0 bytes in 0 blocks
==4341== indirectly lost: 0 bytes in 0 blocks
==4341== possibly lost: 0 bytes in 0 blocks
==4341== still reachable: 85 bytes in 3 blocks
==4341== suppressed: 0 bytes in 0 blocks
==4341== Rerun with --leak-check=full to see details of leaked memory
==4341==
==4341== For lists of detected and suppressed errors, rerun with: -s
==4341== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
/tmp/nix-shell-4318-0/rc: line 1: 4341 Segmentation fault (core dumped) valgrind target/debug/jit-ffi-fault-mre