Stuck trying to use LLVM 'setjmp/longjmp' on 'stm32f407' board

Hello :crab:,

I'm trying to include calls to LLVM intrinsics setjmp/longjmp in my code to be run on my stm32f407g-disc1 board.

I used setjmp and longjmp in the same way used in the program from chapter 12 of book 'Rust in Action' in my program. The program from the book builds and runs successfully in Ubuntu.

cargo build fails with an error as below:

note: rust-lld: error: undefined symbol: setjmp
  
... (info on regions in code that refer to the undefined symbol)

note: rust-lld: error: undefined symbol: longjmp

... (info on regions in code that refer to the undefined symbol)

After this, I tried changing the linker I'm using (from rust-lld to the GNU linker (arm-none-eabi-ld)).
Now the program compiles without errors, but it doesn't load to my board..

Reading symbols from target/thumbv7em-none-eabihf/debug/stm32f407g_paranoia...done.
0x00000000 in ?? ()
Function "DefaultHandler" not defined.
Make breakpoint pending on future shared library load? (y or [n]) [answered N; input not from terminal]
Function "HardFault" not defined.
Make breakpoint pending on future shared library load? (y or [n]) [answered N; input not from terminal]
Function "rust_begin_unwind" not defined.
Make breakpoint pending on future shared library load? (y or [n]) [answered N; input not from terminal]
Function "main" not defined.
Make breakpoint pending on future shared library load? (y or [n]) [answered N; input not from terminal]
semihosting is enabled
Start address 0x8000, load size 0
Transfer rate: 0 bits in <1 sec.
openocd.gdb:35: Error in sourced command file:
Warning:
Cannot insert breakpoint 0.
Cannot access memory at address 0x8004

Has anyone successfully used LLVM intrinsics setjmp/longjmp on an embedded board before?

Thank you for reading :smiley_cat:

Out of curiosity, where do the setjmp and longjmp symbols come from? Could it be that they're available in your Ubuntu machine's copy of glibc, but because the stm32f407g-disc doesn't link to a libc, the symbols just don't exist?

I also wasn't able to see setjmp and longjmp on the docs for core::intrinsics. Are you adding your own declarations in an extern block and relying on the linker to find the symbols, or are these functions coming from a 3rd party dependency?

EDIT: it looks like you are using the undocumented llvm.setjmp intrinsic. Have you tried linking to the official llvm.eh.sjlj.setjmp instead?

1 Like

So the program from the book does build successfully when the build target is x86_ubuntu.

Thank you for pointing this out..
I'm not sure whether the llvm-intrinsics setjmp/longjmp link to setjmp/longjmp defined in libc, or the intrinsics provide a separate implementation of setjmp/longjmp..

extern {
    #[link_name = "llvm.setjmp"]
    pub fn setjmp(a: *mut i8) -> i32;

    #[link_name = "llvm.longjmp"]
    pub fn longjmp(a: *mut i8, b: i32) -> ();
}

Oops! I wasn't aware of the official llvm.eh.sjlj.setjmp!

I'll try using that right away :crab:

Switching to the official llvm.eh.sjlj.setjmp worked!
I've just successfully built and flashed the program to my board.
It runs successfully as expected!
Thank you so much for your help :man_superhero:
You saved my day :sun_with_face:

1 Like

That's the gist I was getting from this mailing list anyway.

LLVM supports two flavors of setjmp/longjmp intrinsics: llvm.{set|long}jmp
and llvm.eh.sjlj.{set|long}jmp
The latter is documented in Exception Handling in LLVM — LLVM 18.0.0git documentation and
has some tests for it. The former is not documented anywhere and has no
tests. The former is handled by lowering the intrinsic call to calling the
actual library function in SelectionDAGBuilder.cpp

It's from 2013 though...

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.