STM32大小端序与堆栈及其增长方向分析

STM32大小端序与堆栈及其增长方向分析,第1张

  在开源电子中看到一篇文章讲的是栈增长和大端/小端问题。学C语言的时候,我们知道堆栈的区别:

  (1)栈区(stack):由编译器自动分配和释放,存放函数的参数值、局部变量的值等,其 *** 作方式类似于数据结构中的栈。

   (2)堆区(heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由 *** 作系统回收。分配方式类似于数据结构中的链表。

   (3)全局区(静态区)(staTIc):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统自动释放。

   (4)文字常量区:常量字符串就是存放在这里的。

   (5)程序代码区:存放函数体的二进制代码。

  下面的帖子:主要意思是要证明stm32是小端模式,堆从RAM的起始地址处(0x2000 0000)分配内存给全局变量和静态变量,并且堆是向上增长,栈是向下增长。

  1,首先来看:栈(STACK)的问题。

  函数的局部变量,都是存放在“栈”里面,栈的英文是:STACK.STACK的大小,我们可以在stm32的启动文件里面设置,以战舰stm32开发板为例,在startup_stm32f10x_hd.s里面,开头就有:

  Stack_Size EQU 0x00000800

  表示栈大小是0X800,也就是2048字节。这样,CPU处理任务的时候,函数局部变量做多可占用的大小就是:2048字节,注意:是所有在处理的函数,包括函数嵌套,递归,等等,都是从这个“栈”里面,来分配的。

  所以,如果一个函数的局部变量过多,比如在函数里面定义一个u8 buf[512],这一下就占了1/4的栈大小了,再在其他函数里面来搞两下,程序崩溃是很容易的事情,这时候,一般你会进入到hardfault.。。。

  这是初学者非常容易犯的一个错误。切记不要在函数里面放N多局部变量,尤其有大数组的时候!

  对于栈区,一般栈顶,也就是MSP,在程序刚运行的时候,指向程序所占用内存的最高地址。比如附件里面的这个程序序,内存占用如下图:

  STM32大小端序与堆栈及其增长方向分析,STM32大小端序与堆栈及其增长方向分析,第2张

  图中,我们可以看到,程序总共占用内存:20+2348字节=2368=0X940那么程序刚开始运行的时候:MSP=0X2000 0000+0X940=0X2000 0940.事实上,也是如此,如图:

  STM32大小端序与堆栈及其增长方向分析,STM32大小端序与堆栈及其增长方向分析,第3张

  图中,MSP就是:0X2000 0940.程序运行后,MSP就是从这个地址开始,往下给函数的局部变量分配地址。

  再说说栈的增长方向,我们可以用如下代码测试

  [objc] view plain copy//保存栈增长方向

  //0,向下增长;1,向上增长。

  staTIc u8 stack_dir;

  //查找栈增长方向,结果保存在stack_dir里面。

  void find_stack_direcTIon(void)

  {

  staTIc u8 *addr=NULL; //用于存放第一个dummy的地址。

  u8 dummy; //用于获取栈地址

  if(addr==NULL) //第一次进入

  {

  addr=&dummy; //保存dummy的地址

  find_stack_direction (); //递归

  }else //第二次进入

  {

  if(&dummy》addr)stack_dir=1; //第二次dummy的地址大于第一次dummy,那么说明栈增长方向是向上的。

  else stack_dir=0; //第二次dummy的地址小于第一次dummy,那么说明栈增长方向是向下的。

  }

  }

  这个代码不是我写的,网上抄来的,思路很巧妙,利用递归,判断两次分配给dummy的地址,来比较栈是向下生长,还是向上生长。

  如果你在STM32测试这个函数,你会发现,STM32的栈,是向下生长的。事实上,一般CPU的栈增长方向,都是向下的。

  2,再来说说,堆(HEAP)的问题。

  全局变量,静态变量,以及内存管理所用的内存,都是属于“堆”区,英文名:“HEAP”与栈区不同,堆区,则从内存区域的起始地址,开始分配给各个全局变量和静态变量。

  堆的生长方向,都是向上的。在程序里面,所有的内存分为:堆+栈。 只是他们各自的起始地址和增长方向不同,他们没有一个固定的界限,所以一旦堆栈冲突,系统就到了崩溃的时候了。

  同样,我们用附件里面的例程测试:

  STM32大小端序与堆栈及其增长方向分析,STM32大小端序与堆栈及其增长方向分析,第4张

  stack_dir的地址是0X20000004,也就是STM32的内存起始端的地址。

  这里本来应该是从0X2000 0000开始分配的,但是,我仿真发现0X2000 0000总是存放:0X2000 0398,这个值,貌似是MSP,但是又不变化,还请高手帮忙解释下。

  其他的,全局变量,则依次递增,地址肯定大于0X20000004,比如cpu_endian的地址就是0X20000005.

  这就是STM32内部堆的分配规则。

  3,再说说,大小端的问题。

  大端模式:低位字节存在高地址上,高位字节存在低地址上

  小端模式:高位字节存在高地址上,低位字节存在低地址上

  STM32属于小端模式,简单的说,比如u32 temp=0X12345678;

  假设temp地址在0X2000 0010.

  那么在内存里面,存放就变成了:

  地址 | HEX |

  0X2000 0010 | 78 56 43 12 |

  CPU到底是大端还是小端,可以通过如下代码测试:

  //CPU大小端

  //0,小端模式;1,大端模式。

  static u8 cpu_endian;

  //获取CPU大小端模式,结果保存在cpu_endian里面

  void find_cpu_endian(void)

  {

  int x=1;

  if(*(char*)&x==1)cpu_endian=0; //小端模式

  else cpu_endian=1; //大端模式

  }

  以上测试,在STM32上,你会得到cpu_endian=0,也就是小端模式。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/dianzi/2717509.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-08-17
下一篇 2022-08-17

发表评论

登录后才能评论

评论列表(0条)

保存