stm32f305裸机程序的隐式类型转换错误

文章讲述了在程序中遇到的崩溃问题,涉及到内存溢出、类型转换和栈堆操作。作者分析了函数参数传递导致的u64值异常,以及内存碎片和栈溢出对程序的影响,并给出了相应的处理方法和预防措施。
摘要由CSDN通过智能技术生成

1.源代码

......
void  (*fun)(u64 time);
  fun=sleep;
......
void sleep(u64 time_ms)
{
  u64 start_time=gettime();
  do{
     start_time=gettime();
   }while(start_time<time_ms);

}
.....
//然后我有一个程序调用了它,程序崩掉了
fun(10);

2.debug结果:

    程序卡在do...while循环,一看time_ms变成了0x78 0000 000a。我明明给的是10,为什么是这么大的一个数呢?

3.分析原因;

    低32位依旧是10,高32位却产生了0x78这个数,为什么会有这个数呢?单片机是32位的,所以立即传递的实参是32位有符号的,但是有符号的转成u64应该是0x0000 0000 0000 000a。

函数的形参地址分配在栈上,所以函数名,形参表连续的,

函数名 u32 0X0800   offset 4

函数返回地址:u32 0x0804  offset 4

参数一:u64  0x0808     offset 8

局部变量:u8 0x0810    offset 1

.......

可见0x080f=0x78,说明新分配的这个内存是有别的数值的,造成这种现象有2个原因,一是内存碎片导致的,二是栈溢出覆盖堆导致的。

4.如何处理:

     如果是内存碎片,那么使用这一块区域需要再次初始化一下,不然传递的参数值不对。当然可以直接传输一个u64数据,不要传递u32,先强制转换一下。

     如果是栈溢出覆盖堆,那么堆一般是malloc人为主动分配的内存,存储一些数据,可能会导致其中的数据更改,如果是函数返回地址,那么程序就会跑飞甚至出问题,导致硬件故障。

5.后续预防

     明确的了解堆栈大小,内存分配不得超过堆区大小,函数嵌套尽可能的少,防止栈溢出。栈比较小时,少嵌套函数,少用局部变量,多用全局变量。

6.补充一些查看堆栈的方法

     裸机,所以堆栈在启动文件中,全程使用MSP,所以debug的R13(sp)寄存器存储当前栈顶。

     使用栈=初始化栈顶 - 当前栈顶  向下生长,就是0x20010100   0x20010ff........地址变小

     使用堆=当前堆顶指针 - 堆基础地址  向上生长  0x2000b100   0x2000b101.....地址变大

     栈向下,堆向上,最后会撞在一起,所以叫堆栈覆盖。

   栈存储局部变量,程序返回地址,函数参数,堆存储malloc函数分配的变量,裸机一般用不到。动态分配内存会用到堆,大部分裸机程序都不用。堆栈占据RAM内存。code占据flash内存。全局变量也占据RAM内存。栈满了覆盖堆,继续溢出会占据别的RAM内存,比如全局变量的内存。

char * p=malloc(size_t);  //c标准库函数
printf("当前分配的堆地址为:%d",p);
//根据输出的地址查看是否在分配好的堆地址中,在,没有溢出覆盖,不在,那么堆溢出,扩大容量
u32 * addr=_get_MSP();//core_m3.h中定义的
printf("当前的栈顶地址为:%d",addr);
//同理,判断栈地址是不是在分配好的区间

7.volatile

      告诉编译器不需要优化此变量,有些变量程序会优化它,导致程序运行时不更新而是直接调用缓存也就是寄存器中的值。你在中断中改了值但是主循环依旧判断未更改,这是编译器优化了导致的,加此变量每次执行都会从地址上读取此值。

标注:

      这个隐式类型转换没有问题,我一读地址,bug就再也发生不了了,很困惑。这个局部变量突变了,所以我待查它的地址,所以加了句获取局部变量栈地址,bug就不出现了,很神奇。

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值