历史上的今天
返回首页

历史上的今天

今天是:2025年04月06日(星期日)

2020年04月06日 | C语言及ARM中堆栈指针SP设置的理解与总结

2020-04-06 来源:eefocus

什么是栈:


百度这么说:栈是一种特殊的线性表,是一种只允许在表的一端进行插入或删除操作的线性表。表中允许进行插入、删除操作的一端称为栈顶。表的另一端称为栈底。栈顶的当前位置是动态的,对栈顶当前位置的标记称为栈顶指针。当栈中没有数据元素时,称之为空栈。栈的插入操作通常称为进栈或入栈,栈的删除操作通常称为退栈或出栈。


简易理解:


客栈,即临时寄存的地方,计算机中的堆栈主要用来保存临时数据,局部变量和中断/调用子程序程序的返回地址。程序中栈主要是用来存储函数中的局部变量以及保存寄存器参数的,如果你用了操作系统,栈中还可能存储当前进线程的上下文。设置栈大小的一个原则是,保证栈不会下溢出到数据空间或程序空间。CPU在运行程序时,会自动的使用堆栈,所以堆栈指针SP就必须要在调用C程序前设定。


CPU的内存RAM空间存放规律一般是分段的,从低地址向高地址,依次为:程序段(.text)、BSS段,上面还可能会有堆空间,然后最上面才是栈段。这样安排堆栈,是因为堆栈的特点决定的,堆栈的指针SP初始化一般在堆栈段的高地址,也就是内存的高地址,然后让堆栈指针向下增长(其实就是递减)。


这样做的好处就是堆栈空间远离了其他段,不会跟其他段重叠,造成修改其他段数据,而引起不可预料的后果,还有设置堆栈大小的原则,要保证栈不会下溢出到数据空间或者程序空间。所谓堆栈溢出,是指堆栈指针SP向下增长到其他段空间,如果栈指针向下增长到其他段空间,称为堆栈溢出。堆栈溢出会修改其他空间的值,严重情况下可造成死机。


堆栈指针的设置


开始将堆栈指针设置在内部RAM,是因为不是每个板上都有外部RAM,而且外部RAM的大小也不相同,而且如果是SDRAM,还需要初始化,在内部RAM开始运行的一般是一个小的引导程序,基本上不怎么使用堆栈,因此将堆栈设置在内部RAM。但这也就要去改引导程序不能随意使用大量局部变量。


片内4K的SRAM,SDRAM大小64M,从0x30000000到0x33FFFFFF,当程序在片内SRAM运行的时候,sp的值设置为4096,当程序在SDRAM内运行的时候sp设置为0x34000000,当程序在内部SRAM运行,若已经初始化SDRAM,此时也可以将堆栈指针设置为0x34000000,更加防止了堆栈溢出。


栈的整体作用


a.保存现场;

b.传递参数:汇编代码调用C函数时,需传递参数;


c.保存临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量;


1)保存现场:


现场,意思就相当于案发现场,总有一些现场的情况,要记录下来的,否则被别人破坏掉之后,你就无法恢复现场了。而此处说的现场,就是指CPU运行的时候,用到了一些寄存器,比如r0,r1等等,对于这些寄存器的值,如果你不保存而直接跳转到子函数中去执行,那么很可能就被其破坏了,因为其函数执行也要用到这些寄存器。因此,在函数调用之前,应该将这些寄存器等现场,暂时保持起来(入栈 push),等调用函数执行完毕返回后(出栈 pop),再恢复现场。这样CPU就可以正确的继续执行了。


保存寄存器的值,一般用的是push指令,将对应的某些寄存器的值,一个个放到栈中,把对应的值压入到栈里面,即所谓的压栈。然后待被调用的子函数执行完毕的时候,再调用pop,把栈中的一个个的值,赋值给对应的那些你刚开始压栈时用到的寄存器,把对应的值从栈中弹出去,即所谓的出栈。其中保存的寄存器中,也包括lr的值(因为用bl指令进行跳转的话,那么之前的PC 的值是存在lr中的),然后在子程序执行完毕的时候,再把栈中的lr的值pop出来,赋值给PC,这样就实现了子函数的正确的返回。


2)  传递参数


C 语言进行函数调用的时候,常常会传递给被调用的函数一些参数,对于这些C语言级别的参数,被编译器翻译成汇编语言的时候,就要找个地方存放一下,并且让被调用的函数能够访问,否则就没发实现传递参数了。对于找个地方放一下,分两种情况。一种情况是,本身传递的参数不多于4个,就可以通过寄存器r0~r3传送参数。因为在前面的保存现场的动作中,已经保存好了对应的寄存器的值,那么此时,这些寄存器就是空闲的,可以供我们使用的了,那就可以放参数。另一种情况是,参数多于4个时,寄存器不够用,就得用栈了。


3)临时变量保存在栈中


包括函数的非静态局部变量以及编译器自动生成的其他临时变量。

推荐阅读

史海拾趣

Harvatek Corporation公司的发展小趣事

背景:随着电子技术的飞速发展,Hantronix始终站在技术创新的前沿。公司不断投入研发资源,致力于开发具有自主知识产权的新产品和技术。

发展:Hantronix成功推出了一系列创新产品,如液晶显示器、图形模块、触摸屏等,这些产品不仅性能卓越,而且设计独特,满足了市场多样化的需求。同时,公司还积极申请专利保护,确保其技术成果得到法律的有效保障。

Electro Technik Industries公司的发展小趣事

ETI公司成立于20世纪初,当时电子产业正处于起步阶段。创始人张三看准了电子技术的巨大潜力,决定投身其中。然而,初创时期资金短缺、技术落后、市场竞争激烈等问题让ETI步履维艰。张三凭借着对电子技术的热情和不懈的努力,带领团队不断研发新产品,拓展市场,最终使ETI在电子行业中崭露头角。

Holtek(合泰)公司的发展小趣事

作为一家具有社会责任感的企业,ETI始终关注环保问题。公司积极推广绿色生产理念,采用环保材料和工艺进行生产。同时,ETI还投入大量资金用于环保设施的建设和运营,减少了对环境的污染。此外,ETI还积极参与社会公益活动,为环保事业贡献自己的力量。这些举措使ETI在业界树立了良好的形象,赢得了社会各界的广泛赞誉。

BOPLA公司的发展小趣事

随着电子行业的快速发展,BOPLA意识到传统的电子元件已经无法满足市场的需求。于是,公司投入大量资源进行技术研发,成功推出了一系列具有创新性的电子元件产品。这些产品不仅性能优异,而且具有更高的可靠性和稳定性,赢得了市场的广泛好评。

Graseby Infrared公司的发展小趣事
首先确认三相电源是否正常,可以使用万用表测量电源电压和相序。
FINTEK公司的发展小趣事

在快速发展的同时,FINTEK公司始终不忘履行社会责任和推动可持续发展。公司积极参与环保公益事业,致力于减少生产过程中的能源消耗和废物排放。同时,FINTEK还加大了对清洁能源和可再生能源技术的研发投入,以推动电子行业的绿色转型。此外,FINTEK还积极履行纳税义务,为社会创造更多的就业机会和税收贡献。这些举措不仅彰显了FINTEK作为行业领导者的责任感,也为公司的长远发展奠定了良好的社会基础。

问答坊 | AI 解惑

为啥选stm32 和 allegro,而不是用51,protel

这是为参与者将来考虑。 51 找工作太不值钱,能找到1500的,都是烧搞香,而且,必须软件硬件全做。 stm32 是cortex-m3最新的arm结构,找arm的工作,低于3000,您别考虑。 另外,protel简直跟51是配对的,找工作,待遇也一样。 而用allegro是国 ...…

查看全部问答>

TCPMP LINK问题

用VS2005编译TCPMP,WINCE用的是6.00的 ,其中,在编译完ffmpeg,link的之后,log如下: Linking... ffmpeg.obj : warning LNK4078: multiple \'.text\' sections found with different attributes (60301020) Build log was saved at \"file://f ...…

查看全部问答>

1602显示复位后,光标后移

如题,代码如下求解决 #include #include sbit LcdRs                = P2^0; sbit LcdRw                = P2^1; sbit LcdEn      & ...…

查看全部问答>

在wince下如何使用OffsetWindowOrgEx函数

各位前辈,本人是个菜鸟,刚刚开始学习windows程序设计 想把windows中程序移植到WINCE上,可是在OffsetWindowOrgEx函数和SetWindowExtEx;SetViewportExtEx等函数上出现了问题 查询MSDN发现这些函数不支持wince 向问下有什么函数可以代替 ...…

查看全部问答>

EVC程序运行时出现Assertion Fild!

程序编译时没有提示错误. 下载到ARM板上刚开始运行时也没有问题,程序里面有部分程序是截取图片存储到SD卡上,当图片存了一部分后,就会出现 Assertion Fild! abc.htp:c:\\Document and Settings\\Administrator\\,line 2271 这个错误,把SD卡 ...…

查看全部问答>

passthru分网卡获取数据问题

各位大侠好,小弟有个问题请教! 我在一台机子上装了两个网卡,安装了自己改写的passthru程序。我知道passthru会自动绑定到两个网卡,问题是,当我收到包的时候,比如在ptreceive里面,怎么能判断这个包是哪个网卡收到的呢?…

查看全部问答>

请教关于中断的问题。

我使用msp430f1611中遇到如下问题。请高人指教。谢谢! 用p2.4做外部中断。下降沿出发 测试程序如下: #include <msp430x16x.h> void main( void ) { int i; WDTCTL = WDTPW + WDTHOLD; P1SEL=0; P1DIR = 0xFF; P2SEL |=BIT4; P2I ...…

查看全部问答>