My use case is a bit specific, my target platform is a cortex-m arm that runs Zephyr RTOS (no_std + alloc). I statically link to the rust static app to the Zepher C code.
The issue is because I am using the MPU to restrict access to certain partitions of memory. The rust app runs in a user thread. In order to access global variables I need to link them to tell the linker where to place them or I get an MPU fault, something like this:
This works well, the problem is I cannot add the link section decorator to the external global static. So my solution right now is to use rustc version 1.68.2 (1.70 should work too). Otherwise I would have to maintain a fork of rustc with the decorator applied which is not something I would like to do.
My question is: Is there a third option where I could make some change to the build.rs to tell the linker where to place the external static variable so that I can keep using the latest version of rust?
that symbol is not defined in liballoc (nor libstd for that matter), but actually required by liballoc to exist when linking (it's in an extern block) and typically generated by rustc. if you use rustc to drive the final linking stage, the symbol will be correctly linked. if you drive the linking stage using a C/C++ linker, you'll have to define the symbol yourself in a C or C++ object (together with the allocator functions like __rust_alloc, __rust_dealloc etc required by liballoc, if you are not linking an #[global_allocator] rust crate)
no_std + alloc is special for embedded platform. alloc crate doesn't actually contains allocator implementation, but defines the allocator api. when a no_std crate uses alloc, it assumes their will be an allocator implementation being linked to the final binary, this can either be an #[global_allocator] crate or libstd, or even an C library that implements the rust allocator api. the symbole __rust_no_alloc_shim_is_unstable is part of the api. as I said, if you drive your final linking step with C/C++ toolchain, you'll have to define it yourself, even if you use an #[global_allocator] crate for embedded, as #[global_allocator] only provides functions of the allocator api, but the placeholder symbol __rust_no_alloc_shim_is_unstable is generated by rustc for the final binary target that needs linking.
also see the comments for an detailed explanation here:
that being said, I don't think the __rust_no_alloc_shim_is_unstable is ever accessed at runtime, so it shouldn't trigger any protection error even if you put it in a "protected" section.
It is accessed using read_volatile because that is the only way I know of to reliably ensure any attempt to allocate will result in a linker error if that symbol is not defined. Anything else risks getting optimized out and thus no longer referencing it at link time.
Thank you so much for this explanation In the end the only thing that seems to work is to create a dedicated memory partition in Zephyr and mapping the address of __rust_no_alloc_shim_is_unstable to that at runtime before anything runs in userspace.
I tried to use the weak link to __rust_no_alloc_shim_is_unstable since that seems like the best way but the way the zephyr build scripts work this does not work.
thanks for the correction. I didn't read the code. sorry for the misleading information.
I don't know about the zephyr build system, but if you are linking the final executable using C/C++ toolchain, that symbol doesn't need to be weak.
I played with it a bit, and it seems direct linking a rlib with a C toolchain is still not supported. on Windows using nightly-msvc toolchain, I got an unresolved reference to alloc::alloc::handle_alloc_error using the following test code. but I assume this is not the case for embedded target such as cortex-m, since you need build liballoc anyway.
Must be the way I am compiling/linking because it seems the Rust definition always takes precedence. If I do not flag it as weak I get a compilation error due to multiple definitions. Probably something wrong with the linking order or something.... Got it in a workable state now and do not have time to investigate further. Think both the C and Rust are compiled independently and then linked afterwards, that must be the issue.