【ARM裸板】启动文件与栈的简略分析

2020-03-08来源: eefocus关键字:ARM裸板  启动文件  

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

;跳转到[0x0c]main函数,并保存返回地址(下一条指令的地址,即0x08)到LR中


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 ;r3 = [0x18+8+52] = [0x54] 

  1c: e50b3008 str r3, [fp, #-8] ;把r3(0x56000050)存放在[4084] ==> 保存局部变量

  20: e59f3030 ldr r3, [pc, #48] ; 58 ;r3 = [0x20+8+48] = [0x58]

  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 ; instruction: 0x56000050

  58: 56000054 ; instruction: 0x56000054


上面的汇编代码可以看到,并没有想上面图中所画的,将fp, sp, lr, pc全部都入栈,而是只入栈这四个寄存器中有改动的。fp是肯定要保存的,它指向的是每个函数栈帧的栈基址,而sp一般不用入栈,因为它的值一般保存在fp中,因为刚进入一个函数的时候,将上个函数的fp入栈保存以后,当前函数的栈空间应该是空的,fp应该指向与sp相同的位置,然后才会对sp做减法来分配栈空间保存临时变量。而如果当前函数中没有对其它函数的调用的时候,是不会对lr寄存器做修改的,所以也就不用保存了。

关键字:ARM裸板  启动文件   编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic490814.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:【ARM裸板】S3C2440 时钟设置与分析
下一篇:ARM处理器的未定义指令异常处理过程分析

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

ARM裸板实现LCD显示
的项目,如下:all: start.o sdram_init.o interrupt.o nand_flash.o main.o  led.o uart.o   execption.o  timer.o lib1funcs.o my_printf.o  string_utils.o lcd.o  arm-linux-ld -T lcd.lds  $^ libgcc.a -o lcd.elf arm-linux-objcopy -O binary -S lcd.elf lcd.bin arm-linux-objdump -D lcd.elf >
发表于 2020-05-04
ARM裸板实现LCD显示
ARM裸板程序的开发和编译(以点亮LED灯为例)
从这两个地方启动。具体就是把代码烧写到Nor flash或者Nand flash处,如果在Nand flash,启动时硬件会自动拷贝代码到4KB的内部RAM。GT2440开发板nGCS0接的是Norflash。无论哪种模式启动,上电后CPU跳转到0地址处开始执行。如果在片内内存中,我们必须用4KB的代码完成Nand flash,内存控制器的初始化,并且把代码搬运到片外内存中。如果在Nor flash中,我们同样需要初始化内存控制器。由于裸板程序较小,不会超过4KB,因此我们暂时不需要做这些操作(如果在Norflash中我们可直接运行的代码量更大)。此外,ARM处理器还有多种异常。系统上电和看门狗超时都会产生复位异常,跳转到0地址处执行
发表于 2020-04-11
ARM裸板程序的开发和编译(以点亮LED灯为例)
linux系统学习1-8:第1个ARM裸板程序及引申
为1),GPF4配置为输出设置GPFDAT[4]=1:输出高电平,led熄灭设置GPFDAT[4]=0:输出低电平,led点亮S3C2440框架与启动过程:S3C2440框架图: 启动过程:大多数ARM芯片从0地址启动Nor启动时候,Nor Flash基地址为0;片内RAM地址为0x4000,0000 cpu读出Nor上第一个指令(前4字节),执行,cpu继续读出其他指令执行。Nand启动,片内4kRAM基地址为0; Nor Flash不可以访问 2440硬件把Nand前4k内容复制到片内RAM,然后cpu从0地址取出第一条指令执行。第003节:编写第一个程序点亮LED怎么让GPF4输出1/0的方法:先
发表于 2020-03-28
linux系统学习1-8:第1个ARM裸板程序及引申
第008课 第1个ARM裸板程序及引申(点亮LED灯)
led_on.S    arm-linux-ld -Ttext 0 led_on.o -o led_on.elf    arm-linux-objcopy -O binary -S led_on.elf led_on.binclean:    rm *.bin *.o *.elf  以后只需要 使用 make 命令进行编译, make clean 命令进行清理。最后烧写到开发板上,即可看到只有一个LED亮,符合我们预期。第004节_汇编与机器码前面介绍过伪指令,伪指令是实际不存在的ARM命令,编译器在编译时转换成存在的ARM指令。我们代码中的ldr r1
发表于 2020-03-20
第008课 第1个ARM裸板程序及引申(点亮LED灯)
ARM裸板程序及引申_点亮LED
*.elf以后只需要 使用 make 命令进行编译, make clean 命令进行清理。最后烧写到开发板上,即可看到只有一个LED亮,符合我们预期。第004节_汇编与机器码:前面介绍过伪指令,伪指令是实际不存在的ARM命令,编译器在编译时转换成存在的ARM指令。我们代码中的ldr r1, =0x56000050这条伪指令的真实指令时什么呢?我们可以通过反汇编来查看。生成的led_on.dis就是反汇编文件。led_on.dis如下:led_on.elf:     file format elf32-littlearmDisassembly of section .text:00000000 <
发表于 2020-03-16
ARM裸板程序及引申_点亮LED
ARM裸板调用流程
一、汇编mdk软件会选择用户添加到工程文件里面的汇编文件执行(例startup_stm32f10x_md.s),对基本内容进行初始化比如栈空间,这个文件通常由芯片厂家提供,用户使用选择调用即可。二、跳转main函数在汇编执行初始化之后,最终在下面圈红的地方跳转到main函数。__main可以修改成其他名字比如smain,对应main函数名改成smain,也可以完成跳转
发表于 2020-03-11
ARM裸板调用流程
小广播
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2020 EEWORLD.com.cn, Inc. All rights reserved