From 4ecbed698241e637a13048a199d29c142445c360 Mon Sep 17 00:00:00 2001 From: Ian McIntyre Date: Wed, 12 Mar 2025 21:50:39 -0400 Subject: Place .xip sections into flash We added the `.xip` section to ensure that the reset handler and pre-init functions would be placed in flash. This commit lets users place other content into that section. `.xip` is intended for instructions. The runtime builder will place these instructions into the same load region as `.text`. However, there's no pre-`main` relocation. Aligning the `.xip` and the `.text` section produces more predictable behavior between GNU's ld and LLVM's lld. --- CHANGELOG.md | 6 ++++++ examples/blink-rtic.rs | 9 ++++++++- src/host/imxrt-link.x | 5 +++-- tests/inspect_elf.rs | 37 +++++++++++++++++++++++++++++-------- 4 files changed, 46 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd6fb98..2920663 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## [Unreleased] +Place sections starting with `.xip` into the same load region of `.text`. +Unlike `.text`, the contents in `.xip` will not be relocated. + +Four byte align both the `.xip` and `.text` sections for more predictable +behaviors across linkers. + ## [0.1.6] 2025-03-01 Add new MCU targets: diff --git a/examples/blink-rtic.rs b/examples/blink-rtic.rs index 04446e3..e463f33 100644 --- a/examples/blink-rtic.rs +++ b/examples/blink-rtic.rs @@ -12,6 +12,13 @@ use imxrt_rt as _; /// This is checked in an automated test. static mut DATA: u32 = 5; +#[unsafe(link_section = ".xip")] +#[unsafe(no_mangle)] +#[inline(never)] +fn increment_data() { + unsafe { crate::DATA = crate::DATA.wrapping_add(1) }; +} + #[rtic::app(device = board::rtic_support, peripherals = false)] mod app { const PIT_PERIOD_US: u32 = 1_000_000; @@ -35,7 +42,7 @@ mod app { #[task(binds = PIT, local = [led, pit])] fn pit(cx: pit::Context) { - unsafe { crate::DATA += 1 }; + crate::increment_data(); cx.local.led.toggle(); cx.local.pit.clear_interrupts(); } diff --git a/src/host/imxrt-link.x b/src/host/imxrt-link.x index a389325..dfe7355 100644 --- a/src/host/imxrt-link.x +++ b/src/host/imxrt-link.x @@ -70,14 +70,15 @@ SECTIONS __sivector_table = LOADADDR(.vector_table); /* This section guarantees VMA = LMA to allow the execute-in-place entry point to be inside the image. */ - .xip : + .xip : ALIGN(4) { /* Included here if not otherwise included in the boot header. */ *(.Reset); *(.__pre_init); + *(.xip .xip.*); } > REGION_LOAD_TEXT - .text : + .text : ALIGN(4) { FILL(0xff); __stext = .; diff --git a/tests/inspect_elf.rs b/tests/inspect_elf.rs index cdb3245..e9211eb 100644 --- a/tests/inspect_elf.rs +++ b/tests/inspect_elf.rs @@ -239,18 +239,19 @@ fn imxrt1010evk() { ); assert_eq!(binary.section_lma(".vector_table"), 0x6000_2000); + let xip = binary.section(".xip").unwrap(); let text = binary.section(".text").unwrap(); assert_eq!(text.address, ITCM, "text"); assert_eq!( binary.section_lma(".text"), - 0x6000_2000 + vector_table.size, + aligned(0x6000_2000 + vector_table.size + xip.size, 4), "text VMA expected behind vector table" ); let rodata = binary.section(".rodata").unwrap(); assert_eq!( rodata.address, - 0x6000_2000 + vector_table.size + aligned(text.size, 4), + aligned(0x6000_2000 + vector_table.size + text.size + xip.size, 4), "rodata LMA & VMA expected behind text" ); assert_eq!(rodata.address, binary.section_lma(".rodata")); @@ -298,6 +299,12 @@ fn imxrt1010evk() { ); assert_eq!(heap.size, 1024); assert_eq!(binary.section_lma(".heap"), heap.address, "Heap is NOLOAD"); + + let increment_data_xip = binary.symbol_value("increment_data").unwrap(); + assert!( + 0x6000_0000 < increment_data_xip && increment_data_xip < 0x7000_0000, + "increment_data is not XiP" + ); } fn baseline_teensy4(binary: &ImxrtBinary, dcd_at_runtime: u32, stack_size: u64, heap_size: u64) { @@ -334,6 +341,7 @@ fn baseline_teensy4(binary: &ImxrtBinary, dcd_at_runtime: u32, stack_size: u64, assert_eq!(binary.section_lma(".stack"), stack.address); let vector_table = binary.section(".vector_table").unwrap(); + let xip = binary.section(".xip").unwrap(); assert_eq!( Section { address: stack.address + stack.size, @@ -349,14 +357,14 @@ fn baseline_teensy4(binary: &ImxrtBinary, dcd_at_runtime: u32, stack_size: u64, assert_eq!(binary.section_lma(".vector_table"), 0x6000_2000); let text = binary.section(".text").unwrap(); - assert_eq!( - text.address, - binary.section_lma(".vector_table") + vector_table.size, - "text" + let expected_text_address = aligned( + binary.section_lma(".vector_table") + vector_table.size + xip.size, + 4, ); + assert_eq!(text.address, expected_text_address, "text"); assert_eq!( binary.section_lma(".text"), - 0x6000_2000 + vector_table.size, + aligned(0x6000_2000 + vector_table.size + xip.size, 4), "text VMA expected behind vector table" ); @@ -414,6 +422,12 @@ fn baseline_teensy4(binary: &ImxrtBinary, dcd_at_runtime: u32, stack_size: u64, "{heap_size} byte heap in DTCM behind uninit" ); assert_eq!(binary.section_lma(".heap"), heap.address, "Heap is NOLOAD"); + + let increment_data_xip = binary.symbol_value("increment_data").unwrap(); + assert!( + 0x6000_0000 < increment_data_xip && increment_data_xip < 0x7000_0000, + "increment_data is not XiP" + ); } #[test] @@ -562,11 +576,12 @@ fn imxrt1170evk_cm7() { ); assert_eq!(binary.section_lma(".vector_table"), 0x3000_2000); + let xip = binary.section(".xip").unwrap(); let text = binary.section(".text").unwrap(); assert_eq!(text.address, ITCM, "text"); assert_eq!( binary.section_lma(".text"), - 0x3000_2000 + vector_table.size, + aligned(0x3000_2000 + vector_table.size + xip.size, 4), "text VMA expected behind vector table" ); @@ -622,4 +637,10 @@ fn imxrt1170evk_cm7() { "0 byte heap in DTCM behind rodata table" ); assert_eq!(binary.section_lma(".heap"), heap.address, "Heap is NOLOAD"); + + let increment_data_xip = binary.symbol_value("increment_data").unwrap(); + assert!( + 0x3000_0000 < increment_data_xip && increment_data_xip < 0x4000_0000, + "increment_data is not XiP" + ); } -- cgit v1.2.3