From 66520102e8cbff1596a5b4465ad374e3b1fdfb62 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Wed, 21 Feb 2024 18:37:04 +0100 Subject: [PATCH 1/3] avoid 32-bit relocation to __BOOTLOADER_CONFIG As explained in my comment in #427, the compiler seems to have trouble emitting relocations for references to global variables in custom sections. For custom sections, it always emits 32-bit relocations even when a 64-bit relocation would be required. This patch works around that by never referencing the global in the custom section directly from code, but only through a pointer from another global variable in the non-custom .data section. The relocation used for the pointer in the global variable will always use a 64-bit relocation. --- api/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/src/lib.rs b/api/src/lib.rs index 4ada525f..047e3cec 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -120,13 +120,17 @@ macro_rules! entry_point { config.serialize() }; + // Workaround for https://github.com/rust-osdev/bootloader/issues/427 + static __BOOTLOADER_CONFIG_REF: &[u8; $crate::BootloaderConfig::SERIALIZED_LEN] = + &__BOOTLOADER_CONFIG; + #[export_name = "_start"] pub extern "C" fn __impl_start(boot_info: &'static mut $crate::BootInfo) -> ! { // validate the signature of the program entry point let f: fn(&'static mut $crate::BootInfo) -> ! = $path; // ensure that the config is used so that the linker keeps it - $crate::__force_use(&__BOOTLOADER_CONFIG); + $crate::__force_use(__BOOTLOADER_CONFIG_REF); f(boot_info) } From b785b6d4f059c5b08a7a1a9cfa95a5ffaa35af9d Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Fri, 23 Feb 2024 20:17:38 +0100 Subject: [PATCH 2/3] add another level of indirection This prevents the compiler from optimzing out __BOOTLOADER_CONFIG_REF in favor of accessing __BOOTLOADER_CONFIG directly. --- api/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/src/lib.rs b/api/src/lib.rs index 047e3cec..2075256a 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -130,7 +130,7 @@ macro_rules! entry_point { let f: fn(&'static mut $crate::BootInfo) -> ! = $path; // ensure that the config is used so that the linker keeps it - $crate::__force_use(__BOOTLOADER_CONFIG_REF); + $crate::__force_use(&__BOOTLOADER_CONFIG_REF); f(boot_info) } @@ -139,7 +139,7 @@ macro_rules! entry_point { } #[doc(hidden)] -pub fn __force_use(slice: &[u8]) { +pub fn __force_use(slice: &&[u8; BootloaderConfig::SERIALIZED_LEN]) { let force_use = slice.as_ptr() as usize; unsafe { core::arch::asm!("add {0}, 0", in(reg) force_use, options(nomem, nostack)) }; } From d0d10feec87e591ded71d66995e6a4752b62036b Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Thu, 7 Mar 2024 19:02:38 +0100 Subject: [PATCH 3/3] don't call slice::as_ptr We want to avoid directly accessing the data in the .bootloader-config section and slice::as_ptr gets a pointer to that data. Instead we cast a reference to a reference to the data in .bootloader-config to an address and pass that to the asm! block. The problem with as_ptr was that it's a method on the slice and not the reference and so by calling slice::as_ptr, we once again directly accessed the slice when we only meant to access the reference to the reference to the data. --- api/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/lib.rs b/api/src/lib.rs index 2075256a..e1fb0fb3 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -140,6 +140,6 @@ macro_rules! entry_point { #[doc(hidden)] pub fn __force_use(slice: &&[u8; BootloaderConfig::SERIALIZED_LEN]) { - let force_use = slice.as_ptr() as usize; + let force_use = slice as *const _ as usize; unsafe { core::arch::asm!("add {0}, 0", in(reg) force_use, options(nomem, nostack)) }; }