inkwell
inkwell copied to clipboard
Segmentation Fault While Running Kaleidoscope
Describe the Bug
Running examples/kaleidoscope/main.rs
on my environment causes a segmentation fault when given the following inputs:
?> extern printd(double)
?> printd(10)
To Reproduce
(1) run cargo init
, (2) put examples/kaleidoscope/main.rs
in src/
, (3) add inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm12-0"] }
to Cargo.toml
, (4) run cargo run
or cargo run --release
, and (5) type extern printd(double)
and printd(10)
.
Expected Behavior
printd
function defined in main.rs
(lines 1202 - 1207) should be called.
LLVM Version (please complete the following information):
- LLVM Version: 12.0
- Inkwell Branch Used: master
$ yay -Q llvm
llvm 12.0.1-2
$ tail -n1 Cargo.toml
inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm12-0"] }
Desktop (please complete the following information):
- OS: Arch Linux
Additional Context
$ rustc --version
rustc 1.54.0 (a178d0322 2021-07-26)
I think I'm seeing this behavior as well in a small test program I'm running.
Somewhat relatedly is there a canonical (and small) example of writing function in rust that the JIT linker can find and call appropriately? I assume that's what the #[used] EXTERNAL_FNS provides here. Is there any way to tell the JIT about symbols more explicitly?
We probably want https://thedan64.github.io/inkwell/llvm_sys/support/fn.LLVMAddSymbol.html but it doesn't look like we currently wrap it? Probably due to wild unsafety. I wouldn't be opposed to someone adding an unsafe
wrapper to it
For anyone wanting to remedy this with LLVMAddSymbol
, it's not super involved.
I created a file to put all the 'library' functions in and defined a static cstr name for each.
macro_rules! cstr {
($str:expr) => {
unsafe { CStr::from_bytes_with_nul_unchecked(concat!($str, "\0").as_bytes()) }
};
}
static PUTCHARD_NAME: &'static CStr = cstr!("putchard");
#[no_mangle]
pub extern "C" fn putchard(x: f64) -> f64 {
then I created a struct to track the type and name of these print functions, and made a static array of all of them, e.g.
pub static PRINT_FNS: [PrintFunc; 2] = [ ... ];
Then I defined a shim function like this
fn shim_lib_functions() {
for func in &crate::library::PRINT_FNS {
let fn_name = func.name.as_ptr();
let fn_ptr = func.func_pointer as *mut c_void;
unsafe { LLVMAddSymbol(fn_name, fn_ptr) };
}
}
and called it before the repl's main loop:
fn run(&mut self) -> Result<(), std::io::Error> {
Self::shim_lib_functions();
loop {
...
Should there be an issue open to get the kaleidoscope example running with the current state of the library? Perhaps providing a wrapper over LLVMAddSymbol and using it when compiling external function prototypes?
I was able to get the example running using the above suggestion but its not as clean or safe as I would want.