japaric / cargo-call-stack

Whole program static stack analysis
Apache License 2.0
560 stars 50 forks source link

intrinsic to direct call assumption could be less pessimistic #67

Open japaric opened 2 years ago

japaric commented 2 years ago

for this code:

#![no_main]
#![no_std]

use core::{cmp::Ordering, panic::PanicInfo};

#[no_mangle]
fn _start() -> (usize, usize) {
    (yes as usize, no as usize)
}

fn no(a: &str, b: &str) -> bool {
    if a.len() == 4 && b.len() == 4 {
        a.cmp(b) == Ordering::Equal
    } else {
        false
    }
}

fn yes(a: &str, b: &str) -> bool {
    a.cmp(b) == Ordering::Equal
}

#[panic_handler]
fn panic(_: &PanicInfo) -> ! {
    loop {}
}

call-stack v0.1.11 produces the following call graph

cg

if you look at the machine code, the function no does not call the memcmp function

000200f6 <app::no>:
   200f6:       4684            mov     ip, r0
   200f8:       2000            movs    r0, #0
   200fa:       2904            cmp     r1, #4
   200fc:       bf01            itttt   eq
   200fe:       2b04            cmpeq   r3, #4
   20100:       6810            ldreq   r0, [r2, #0]
   20102:       f8dc 1000       ldreq.w r1, [ip]
   20106:       1a08            subeq   r0, r1, r0
   20108:       bf04            itt     eq
   2010a:       fab0 f080       clzeq   r0, r0
   2010e:       0940            lsreq   r0, r0, #5
   20110:       4770            bx      lr

the LLVM IR does contain a call @memcmp and that's why call-stack adds that edge

; app::no
define internal noundef zeroext i1 @_ZN3app2no17hfff1cfbfed4433e3E ; etc.
  ; ..
  %_19.i.i.i = tail call i32 @memcmp ; etc.
  ; ..

in the particular case of Cortex-M where call-stack analyzes the machine code and sees no 'branch' instruction, call-stack should not add the edge

cc #63