diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs
index a8ebb4b3219f7..eb2277d8baacd 100644
--- a/library/panic_abort/src/lib.rs
+++ b/library/panic_abort/src/lib.rs
@@ -14,11 +14,13 @@
 #![feature(core_intrinsics)]
 #![feature(nll)]
 #![feature(panic_runtime)]
+#![feature(std_internals)]
 #![feature(staged_api)]
 #![feature(rustc_attrs)]
 #![feature(asm)]
 
 use core::any::Any;
+use core::panic::BoxMeUp;
 
 #[rustc_std_internal_symbol]
 #[allow(improper_ctypes_definitions)]
@@ -28,7 +30,7 @@ pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Sen
 
 // "Leak" the payload and shim to the relevant abort on the platform in question.
 #[rustc_std_internal_symbol]
-pub unsafe extern "C" fn __rust_start_panic(_payload: usize) -> u32 {
+pub unsafe extern "C" fn __rust_start_panic(_payload: *mut &mut dyn BoxMeUp) -> u32 {
     abort();
 
     cfg_if::cfg_if! {
diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs
index 0b74a844fec6e..9ce9c477ec0f0 100644
--- a/library/panic_unwind/src/lib.rs
+++ b/library/panic_unwind/src/lib.rs
@@ -104,9 +104,8 @@ pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any
 // implementation.
 #[rustc_std_internal_symbol]
 #[unwind(allowed)]
-pub unsafe extern "C" fn __rust_start_panic(payload: usize) -> u32 {
-    let payload = payload as *mut &mut dyn BoxMeUp;
-    let payload = (*payload).take_box();
+pub unsafe extern "C" fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32 {
+    let payload = Box::from_raw((*payload).take_box());
 
-    imp::panic(Box::from_raw(payload))
+    imp::panic(payload)
 }
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 8ba3feccb6bcc..6cd572cbe87c1 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -44,11 +44,11 @@ use realstd::io::set_output_capture;
 extern "C" {
     fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static);
 
-    /// `payload` is actually a `*mut &mut dyn BoxMeUp` but that would cause FFI warnings.
-    /// It cannot be `Box<dyn BoxMeUp>` because the other end of this call does not depend
-    /// on liballoc, and thus cannot use `Box`.
+    /// `payload` is passed through another layer of raw pointers as `&mut dyn Trait` is not
+    /// FFI-safe. `BoxMeUp` lazily performs allocation only when needed (this avoids allocations
+    /// when using the "abort" panic runtime).
     #[unwind(allowed)]
-    fn __rust_start_panic(payload: usize) -> u32;
+    fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32;
 }
 
 /// This function is called by the panic runtime if FFI code catches a Rust
@@ -637,7 +637,7 @@ pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! {
 fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! {
     let code = unsafe {
         let obj = &mut msg as *mut &mut dyn BoxMeUp;
-        __rust_start_panic(obj as usize)
+        __rust_start_panic(obj)
     };
     rtabort!("failed to initiate panic, error {}", code)
 }