00:00
很多人调试STM32时都说过一句话,程序跑飞了,但程序又没有翅膀,它到底飞到哪里去了?所谓程序跑飞,本质上就是CPU接下来要执行的地址不对了。我也给大家准备了嵌入式自学路线、硬核实战项目、大场面试真题、简历模板等技术干货,有需要的同学66、领取CPU执行程序时,有一个非常关键的寄存器叫PC,也就是程序计数器,它保存着下一条指令的地址。正常情况下,PC会按照程序流程不断变化,遇到函数调用,它就跳到函数入口,函数执行结束,再根据返回地址跳回来。所谓跑飞,就是PC被抓进了一个错误地址,可能跳进一片无效内存,也可能跳进某段数据区域,甚至可能跳到了一个看起来合法,实际上完全不该执行的位置。那PC为什么会出错?最常见的原因是占一出函数调用时,返回地址和部分寄存器会被保存起来,如果局部数组太大,函数嵌套太深,或者发生的递归。
01:00
不用占空间,可能被用完继续往下写,就会破坏其他数据,甚至覆盖函数返回地址。函数执行完以后,CPU从站里取出一个已经被破坏的返回地址,于是直接跳走。第2种原因是数组越界或者也指针,比如一个错误的指针刚好写到了站函数指针或者对象回调地址所在的位置,程序当时可能没反应,等到后面函数返回或者调用回调时才突然跑飞。第三种原因是调用了错误的函数指针,函数指针没有初始化或者被错误赋值,CPU就可能跳到一个根本不是函数入口的地址。第4种原因是中断向量或者启动配置有问题,比如更换了程序地址,却没有正确重定位向量表,或者进入了一个没有正确实现的异常处理函数,表面看起来也像程序突然失控。在Cortexm内核上,如果CPU访问了非法地址,执行了非法指令,或者发生某些总线和内存错误,通常不会凭空消失,而是会进入hardfort等异常处理函数。
02:00
所以很多时候,程序所谓的飞走了,其实是飞进了hard for handler, 然后在里面无限循环。怎么查?发现程序不动以后,先暂停CPU,看PC停在哪里。如果停在hard fort handler, 不要只会按复位键继续查看LR。进入异常时,LR里通常会保存一个特殊的exc re t值,它能帮助判断异常发生前使用的是哪个站,然后从对应的MSSP或中找到异常现场自动压站的寄存器,其中保存的PC才更接近真正出错的那条指令地址。拿到这个地址以后,可以结合返回编map文件或者调试器定位它对应的函数和代码位置。同时还要查看c fsrh fsr b farr mmarr这些故障状态寄存器,他们可以帮助判断是非法指令总线访问错误,未对其访问,还是访问了不允许的内存区域。如果程序偶尔才跑飞,还要重点检查战胜于空间宿主边界指针生命。
03:00
7中断共享数据和DMA缓冲区。因为真正写坏内存的位置往往比程序崩溃的位置更早。面试时不要只回答跑飞就是进入死循环,更完整的说法是程序跑飞通常是PC或返回地址被破坏,CPU跳到了错误位置,非法执行可能进一步触发hard for应该通过异常现场故障、寄存器、map文件和反汇编定位原因。好了,今天的分享就到这里,如果觉得有用,记得点赞关注,咱们下期见。
我来说两句