Hi,
when building a bare-metal binary, in certain use-cases, it can happen that the compiler pulls in code and data that bloats the binary but is in the end unwanted and ineffective. I provided an example here: https://github.com/andre-richter/panic-test
This is a bare-metal binary with panic = "abort"
strategy.
#![no_main]
#![no_std]
#![feature(core_intrinsics)]
use core::intrinsics;
use core::panic::PanicInfo;
#[panic_handler]
#[inline(never)]
fn panic(_info: &PanicInfo) -> ! {
unsafe { intrinsics::abort() }
}
#[no_mangle]
pub unsafe extern "C" fn _start() -> ! {
const ARBITRARY_ADDR: *mut u64 = 0x1337 as *mut u64;
let mut x = core::ptr::read_volatile(ARBITRARY_ADDR);
x = 0x100 / x; // The division here pulls in core::panic* functions that
// have unneeded overhead given the panic handler above.
//
// Also adds debug strings to .rodata that can/will not be
// used (struct PanicInfo).
// get rid of compiler warnings
core::ptr::write_volatile(ARBITRARY_ADDR, x);
loop {}
}
Looking at the generated assembly, it seems the compiler is inserting a software-test to catch a division by zero, and if detecting one, pulls in our custom panic handler (which is inlined after making some preparatory calls, I guess). Here is a snippet, in the repository linked above you'll find the whole objdump containing more core::panic*
code.
201010: 48 8b 0c 25 37 13 00 00 movq 0x1337, %rcx
201018: 48 85 c9 testq %rcx, %rcx
20101b: 74 15 je 0x15 <_start+0x22>
20101d: b8 00 01 00 00 movl $0x100, %eax
201022: 31 d2 xorl %edx, %edx
201024: 48 f7 f1 divq %rcx
201027: 48 89 04 25 37 13 00 00 movq %rax, 0x1337
20102f: 90 nop
201030: eb fe jmp -0x2 <_start+0x20>
201032: 50 pushq %rax
201033: 48 8d 3d c6 0f 00 00 leaq 0xfc6(%rip), %rdi
20103a: e8 21 00 00 00 callq 0x21 <core::panicking::panic::h505722727939be58>
Also, the .rodata
section of the binary is filled with error handling strings (for struct PanicInfo
?) that won't be used at all:
Hex dump of section '.rodata':
0x00200190 7372632f 6d61696e 2e727300 00000000 src/main.rs.....
0x002001a0 61747465 6d707420 746f2064 69766964 attempt to divid
0x002001b0 65206279 207a6572 6f000000 00000000 e by zero.......
My point is that when writing a bare-metal binary, e.g. an OS Kernel, in that specific case, I don't want the software check for divison by zero, but rather let the CPU invoke it's hardware exception and handle it from there on.
Such a test might happen at an early time where I don't even have a vehicle for printing out information from PanicInfo
ready yet.
Is there a way to turn these kinds of software checks of?
BR,
Andre
CC @therealprof @japaric @phil-opp