154_frame_return_address.toy (1040B)
1 // @frame_address / @return_address: walk the frame-pointer chain at levels 2 // 0/1/2. The functions are @[.noinline] so the call chain is real at every opt 3 // level: inside deepest(), level 0/1/2 name deepest/middle/outer respectively. 4 // The stack grows down, so each caller frame sits at a higher address than its 5 // callee; return addresses are never null. Exits 42 on success. 6 7 fn @[.noinline] deepest(): i64 { 8 let f0: usize = @frame_address(0) as usize; 9 let f1: usize = @frame_address(1) as usize; 10 let f2: usize = @frame_address(2) as usize; 11 let r0: usize = @return_address(0) as usize; 12 let r1: usize = @return_address(1) as usize; 13 if f0 == 0 { return 1; } 14 if r0 == 0 { return 2; } 15 if r1 == 0 { return 3; } 16 if f1 <= f0 { return 4; } // caller frame is higher (stack grows down) 17 if f2 <= f1 { return 5; } 18 return 42; 19 } 20 21 fn @[.noinline] middle(): i64 { return deepest(); } 22 fn @[.noinline] outer(): i64 { return middle(); } 23 24 fn __user_main(): i64 { return outer(); } 25 26 fn main(): i32 { return __user_main() as i32; }