历史上的今天
今天是:2025年03月08日(星期六)
2020年03月08日 | 【ARM裸板】启动文件与栈的简略分析
2020-03-08 来源:eefocus
1.start.S过程
设置栈
调用main函数,并把返回地址保存在LR(R14)中
.text
.global _start
_start:
/* 设置内存: sp栈 */
ldr sp, = 4096 /* nand 启动 */
/* 调用main函数 */
bl main
halt:
b halt
2.led.c过程
定义两个局部变量
设置变量
return 0
int main(void)
{
volatile unsigned int *pGPFCON = (volatile unsigned int *)0x56000050;
volatile unsigned int *pGPFDAT = (volatile unsigned int *)0x56000054;
*pGPFCON = 0x100;
*pGPFDAT = 0;
return 0;
}
3.问题
函数的调用规则ATPCS:ARM-THUMB procedure call standard(ARM-Thumb过程调用标准)
参考文章 Arm汇编学习笔记(六)——函数调用栈空间以及fp寄存器
3.1 为什么要设置栈?
因为C函数所需
保存局部变量
保存LR等寄存器(返回地址)

调用者如何传递参数给被调用者
被调用者如何传返回这给调用者
怎么从栈中恢复那些寄存器
调用者和被调用者通过r0-r3寄存器传递参数和返回值
在函数中,r4-r11可能被使用,所以:在入口保存他们,在出口恢复他们
高标号寄存器存放在高地址
3.2 反汇编程序分析
00000000 <_start>:
0: e3a0da01 mov sp, #4096 ; 0x1000 ;设置栈指针大小为4096
4: eb000000 bl c 00000008 8: eafffffe b 8 0000000c c: e52db004 push {fp} ; (str fp, [sp, #-4]!) ;fp的值存入[4096-4](4092)中,sp = sp-4 ==> 将【栈帧底部】指针fp压入栈中;创建属于main函数的栈帧。 10: e28db000 add fp, sp, #0 ;fp = sp+0 = 4092+0 = 4092 ==> fp指针为函数栈帧的底部 14: e24dd00c sub sp, sp, #12 ;sp = 4092-12 = 4080 ==> sp指针为【栈帧顶部】,同时为栈的栈顶 18: e59f3034 ldr r3, [pc, #52] ; 54 1c: e50b3008 str r3, [fp, #-8] ;把r3(0x56000050)存放在[4084] ==> 保存局部变量 20: e59f3030 ldr r3, [pc, #48] ; 58 24: e50b300c str r3, [fp, #-12] ;把r3(0x56000054)存放在[4080] ==> 保存局部变量 28: e51b3008 ldr r3, [fp, #-8] ;r3 = [0x4084] = 0x56000050 2c: e3a02c01 mov r2, #256 ; 0x100 ;r2 = 0x100 30: e5832000 str r2, [r3] ;[r3] = 0x100 ==> 写入0x100至GPFCON寄存器 34: e51b300c ldr r3, [fp, #-12] ;r3 = [0x4080] = 0x56000054 38: e3a02000 mov r2, #0 ;r2 = 0 3c: e5832000 str r2, [r3] ;[r3] = 0 ==> 写入0至GPFDAT寄存器 40: e3a03000 mov r3, #0 ;r3 = 0 ==> return 0的返回值存放先在r3 44: e1a00003 mov r0, r3 ;r0 = 0 ==> return 0的返回值存放在r0 48: e28bd000 add sp, fp, #0 ;sp = fp-0 = 4092 4c: e49db004 pop {fp} ; (ldr fp, [sp], #4) ;fp = [4092] ==> 恢复fp,sp = sp+4 = 4096 ==>恢复栈 50: e12fff1e bx lr ;跳转值lr寄存器所指向的地址并切换指令集 54: 56000050 ; 58: 56000054 ; 上面的汇编代码可以看到,并没有想上面图中所画的,将fp, sp, lr, pc全部都入栈,而是只入栈这四个寄存器中有改动的。fp是肯定要保存的,它指向的是每个函数栈帧的栈基址,而sp一般不用入栈,因为它的值一般保存在fp中,因为刚进入一个函数的时候,将上个函数的fp入栈保存以后,当前函数的栈空间应该是空的,fp应该指向与sp相同的位置,然后才会对sp做减法来分配栈空间保存临时变量。而如果当前函数中没有对其它函数的调用的时候,是不会对lr寄存器做修改的,所以也就不用保存了。
史海拾趣
|
中心议题: 电池管理的常见难题精确测量的重要性解决方案: 电流测量:电量计精度的基础电流测量的度偏移电流测量:电量计精度的基锂离子电池由于拥有能量密度高、电压高、自放电率低,以及无记忆效应等优势,因而逐渐成为使用充电电池的便携应用产 ...… 查看全部问答> |
|
platform builder5.0 导出SDK 遇到的问题 用pb5.0定制了wince的内核,选择的模板是mobile handheld,bsp用的是北京博创的270S_BSP_20080918.bsp,内核到是能正常生成,在导出SDK的时候,遇到了这样的错误: Committing database changes Creating \'required\' feature Adding required ...… 查看全部问答> |
|
camera VGA video format 能过LTK吗 LTK camera 模块测试,录象时包含有VGA分辨率,可以通过LTK测试吗?有哪位试过? 我测试时,Camera_and_DirectShow_Integration_Test中testcase 508,ASF writing tests, testing all supported video formats.跑到测试VGA时就失败了。 ???… 查看全部问答> |
|
1.中断问题 今天小弟我看到了中断这一章了, 但是到现在还搞不清楚SWI的一些地方, 特请教各位高手, 谢谢! 问题就是在加载中断这个地方 unsigned Install_Handler(unsigned routine, unsigned *vector) { vec = (rout ...… 查看全部问答> |
|
有这样两个工程—— 工程1:把输入的50MHz时钟通过dcm倍频,顶层模块除了把dcm的6个端口引出外不作任何处理。testbench里一直将dcm的对应复位脚赋0。仿真表明,倍频是成功的。 工程2:把输入的50MHz时钟通过dcm倍频。顶层模块用dcm输出的倍频信 ...… 查看全部问答> |
|
1、硬件环境搭建 (1)、将开发板上的G2231芯片换成附赠的G2211,因为G2231不带比较器,只有G2211才带,2231带SPI和串口等 (2)、将开发板上的R34和C24焊下,焊接时小心,我就是焊接时把PCB焊坏了,这两个贴片是焊补上去了,到时只有飞线了,郁 ...… 查看全部问答> |




