-
-
Save skoe/dbd3add2fc3baa600e9ebc995ddf0302 to your computer and use it in GitHub Desktop.
Pure Rust Start-Up Code - Attempt 2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this to the linker script: | |
.text : | |
{ | |
. = ALIGN(4); | |
/* Let the linker do the pointer arithmetic. The following values must | |
* have the same layout as struct MemInfo in the Rust init | |
* implementation. It must only contain FFI-safe types. For `LONG` refer | |
* to the GNU ld manual which is referenced by the LLVM lld manual: | |
* https://sourceware.org/binutils/docs/ld/Output-Section-Data.html | |
* | |
* struct MemInfo { | |
*/ | |
_mem_info = .; | |
LONG(_sbss); | |
LONG((_ebss - _sbss) / 4); | |
LONG(_sdata); | |
LONG((_edata - _sdata) / 4); | |
LONG(_sidata); | |
/* } */ | |
*(.text .text.*); | |
. = ALIGN(4); | |
} > FLASH |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[no_mangle] | |
pub unsafe extern "C" fn ResetHandler() -> ! { | |
run(); | |
} | |
/// Contains information about the DATA and BSS output sections. | |
/// | |
/// This struct is used to transfer information about these sections from the | |
/// linker script to the init code. This is done in an FFI-safe manner by | |
/// providing a raw pointer to machine sized words and a length per memory area. | |
/// Note that directly importing a slice is not considered FFI-safe at the time | |
/// of writing. | |
/// | |
/// Importing pointers like `_sdata` and `_edata` and performing pointer | |
/// arithmetic on them directly may lead to Undefined Behavior, because the | |
/// compiler may assume they come from different allocations and thus performing | |
/// undesirable optimizations on them. => I wonder why it should assume that. | |
/// | |
/// TODO: Check whether something like `MaybeUninit` is needed here. | |
/// => I think not, because the compiler cannot assume any state of the target | |
/// memory and therefore has to write to it. | |
/// TODO: Make it generic regarding word size. | |
#[repr(C)] | |
struct MemInfo { | |
/// BSS segment, must be machine word aligned. | |
sbss: *mut u32, | |
/// Number of words in the BSS segment. | |
lbss: usize, | |
/// DATA segment in RAM, must be machine word aligned. | |
sdata: *mut u32, | |
/// Number of words in the DATA segment. | |
ldata: usize, | |
/// LMA address of DATA segment, must be machine word aligned. | |
sidata: *const u32, | |
} | |
pub unsafe fn run() -> ! { | |
extern "C" { static _mem_info: MemInfo; } | |
let bss = slice::from_raw_parts_mut(_mem_info.sbss, _mem_info.lbss); | |
for i in bss { | |
*i = 0; | |
} | |
let data = slice::from_raw_parts_mut(_mem_info.sdata, _mem_info.ldata); | |
let idata = slice::from_raw_parts(_mem_info.sidata, _mem_info.ldata); | |
data.copy_from_slice(idata); | |
// Don't cross this line with loads and stores. The initializations | |
// done above could be "invisible" to the compiler, because we write to the | |
// same memory location that is used by statics after this point. | |
// Additionally, we assume that no statics are accessed before this point. | |
atomic::compiler_fence(Ordering::AcqRel); | |
main(); | |
} | |
pub fn main() -> ! { | |
loop { | |
// to work around https://github.com/rust-lang/rust/issues/28728 | |
atomic::spin_loop_hint(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is converted to a call to
memset
intrinsic.