Stream: cranelift

Topic: ✔ SIGSEGV when calling an external symbol


view this post on Zulip Ivan Chinenov (Nov 12 2021 at 15:34):

With this https://github.com/JohnDowson/CraneLisp/blob/jit-primary/src/jit.rs
code generating following function,

function u0:0(f64) -> f64 system_v {
    sig0 = (f64) -> f64 system_v
    fn0 = u0:0 sig0

block0(v0: f64):
    v1 = f64const 0x1.0000000000000p0
    v2 = call fn0(v1)
    return v2
}

and external symbol being

#[no_mangle]
pub extern "C" fn cl_print(n: f64) -> f64 {
    println!("{}", n);
    0.0
}

defined in the same binary as JIT engine.
Stepping through with the debugger yields following picture one step before segfault

; No Symbol Info
; Source location: unknown
5555562E10E0: 55                         pushq  %rbp
5555562E10E1: 48 89 E5                   movq   %rsp, %rbp
5555562E10E4: 48 BE 00 00 00 00 00 00 >  movabsq $0x3ff0000000000000, %rsi  ; imm = 0x3FF0000000000000
5555562E10EE: 66 48 0F 6E C6             movq   %rsi, %xmm0
5555562E10F3: 48 8B 35 66 DF FF FF       movq   -0x209a(%rip), %rsi  <-- cursor here
5555562E10FA: FF D6                      callq  *%rsi
5555562E10FC: 48 89 EC                   movq   %rbp, %rsp
5555562E10FF: 5D                         popq   %rbp
5555562E1100: C3                         retq
5555562E1101: 00 00                      addb   %al, (%rax)
5555562E1103: 00 00                      addb   %al, (%rax)
Lisp in rust using cranelift as compiler backend. Contribute to JohnDowson/CraneLisp development by creating an account on GitHub.

view this post on Zulip Ivan Chinenov (Nov 12 2021 at 16:04):

And then we end up in std::sys::unix::stack_overflow::imp::signal_handler

view this post on Zulip Ivan Chinenov (Nov 12 2021 at 16:26):

Tagging @bjorn3 as that seems to be the only person known to google to run into segfaults with JIT

view this post on Zulip bjorn3 (Nov 12 2021 at 16:40):

@Ivan Chinenov What is the value of rsi? (You can use p $rsi in your debugger I think)

view this post on Zulip Ivan Chinenov (Nov 12 2021 at 16:49):

@bjorn3 0x0000000000000000.

view this post on Zulip bjorn3 (Nov 12 2021 at 16:50):

Where is cl_print defined? It seems like it failed to look it up using dlsym.

view this post on Zulip Ivan Chinenov (Nov 12 2021 at 16:51):

bjorn3 said:

Where is cl_print defined? It seems like it failed to look it up using dlsym.

In the same binary, https://github.com/JohnDowson/CraneLisp/blob/jit-primary/src/main.rs#L35-L39

Lisp in rust using cranelift as compiler backend. Contribute to JohnDowson/CraneLisp development by creating an account on GitHub.

view this post on Zulip Ivan Chinenov (Nov 12 2021 at 16:53):

There must be a way to define a symbol manually, at least it seems that there was a method for that in SimpleJIT which isn't a thing anymore.

view this post on Zulip bjorn3 (Nov 12 2021 at 16:53):

Does cranelift_jit::backend::lookup_with_dlsym get run if you place a breakpoint on it? And does it run with "cl_print" as argument at least once?

view this post on Zulip bjorn3 (Nov 12 2021 at 16:54):

Ivan Chinenov said:

There must be a way to define a symbol manually, at least it seems that there was a method for that in SimpleJIT which isn't a thing anymore.

The JITBuilder has a method called .symbol().

view this post on Zulip Ivan Chinenov (Nov 12 2021 at 17:00):

bjorn3 said:

Does cranelift_jit::backend::lookup_with_dlsym get run if you place a breakpoint on it? And does it run with "cl_print" as argument at least once?

It does in fact run with "cl_print", exactly once

view this post on Zulip bjorn3 (Nov 12 2021 at 17:01):

Are you on linux? If so does nm -D /path/to/executable | grep cl_print show cl_print for you?

view this post on Zulip bjorn3 (Nov 12 2021 at 17:03):

Using .symbol() may be the easiest way to fix the problem.

view this post on Zulip bjorn3 (Nov 12 2021 at 17:03):

https://github.com/bytecodealliance/wasmtime/blob/f2939111d9b892e5f92a1e8c52b4f4b1e0e1e6ec/cranelift/jit/src/backend.rs#L96

Standalone JIT-style runtime for WebAssembly, using Cranelift - wasmtime/backend.rs at f2939111d9b892e5f92a1e8c52b4f4b1e0e1e6ec · bytecodealliance/wasmtime

view this post on Zulip Ivan Chinenov (Nov 12 2021 at 17:05):

Yes, I am on linux. nm -Ddoes not output "cl_print". Could it be that it is removed by compiler even in debug mode despite being extern "C" and no_mangle?

view this post on Zulip bjorn3 (Nov 12 2021 at 17:07):

Right, executables don't generally export any symbols other than a specific whitelist inside the linker (or linker script).

view this post on Zulip Ivan Chinenov (Nov 12 2021 at 17:18):

Weird then that putting cl_print into a lib.rs doesn't do anything either. Using .symbol() does fix the issue though, although it is not very ergonomic at all

view this post on Zulip bjorn3 (Nov 12 2021 at 17:20):

Rust normally statically links libraries. The linker treats object files from statically linked libraries pretty much identical to those from the main executable. Only if you were to make a dynamic library would cl_print be exported.

view this post on Zulip Notification Bot (Nov 12 2021 at 17:26):

Ivan Chinenov has marked this topic as resolved.

view this post on Zulip Ivan Chinenov (Nov 12 2021 at 17:26):

I see. Thanks for helping out.

view this post on Zulip Chris Fallin (Nov 12 2021 at 20:35):

I remember hitting this problem before -- it's an oddity of the way that symbol lookup works at the system level, as @bjorn3 says, and not something that we can really do anything about at the library level (since if the symbol is already invisible from dlsym(), there's not any other way to look it up).

There is a hack used in Lucet to make all symbols visible to dlsym() -- in Lucet the symbol lookup is actually done by dlopen() when loading a precompiled .so, but I think that this might solve the issue here too: this .cargo/config file adds -C link-args=-rdynamic to the build when the runtime binary (which exports the symbols) is built.

Maybe the above would help?

Lucet, the Sandboxing WebAssembly Compiler. Contribute to bytecodealliance/lucet development by creating an account on GitHub.

view this post on Zulip bjorn3 (Nov 12 2021 at 20:56):

It would be nice to make finalize_definitions panic for unresolved symbols again like it used to before I implemented hot swap functionality.

view this post on Zulip Ivan Chinenov (Nov 13 2021 at 09:01):

bjorn3 said:

It would be nice to make finalize_definitions panic for unresolved symbols again like it used to before I implemented hot swap functionality.

Maybe if it were to be a fallible operation, it should return a result?
I'd rather avoid those sorts of hidden errors

view this post on Zulip Ivan Chinenov (Nov 13 2021 at 09:26):

With JITBuilder.symbol() method I can ever do a wildly unsound thing: define a lambda as a symbol by casting it first to fn pointer then to *const u8


Last updated: Dec 23 2024 at 13:07 UTC