三分钟了解ARM运行C程序的内部机制_第1页
三分钟了解ARM运行C程序的内部机制_第2页
三分钟了解ARM运行C程序的内部机制_第3页
三分钟了解ARM运行C程序的内部机制_第4页
三分钟了解ARM运行C程序的内部机制_第5页
已阅读5页,还剩5页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第第页三分钟了解ARM运行C程序的内部机制一.代码之前学习了ARM裸机的LED点亮C语言实现,了解了ARM程序中,main函数需要有一段汇编指令来自引导,汇编指令的作用是:设置栈地址,也就是指明程序的存储地址;引导main函数。

这里借这个程序分析一下ARM中,C程序执行的内部机制以及程序在栈中的存储位置。

下面是C程序的源代码、引导的汇编指令,以及交叉编译生产的反汇编文件:

C:

intmain(){unsignedint*pGPFCON=(unsignedint*)0x56000050;unsignedint*pGPFDAT=(unsignedint*)0x56000054;

/*配置GPF4为输出引脚*/*pGPFCON=0x100;/*设置GPF4输出0*/*pGPFDAT=0;

return0;}

汇编指令:

.text.global_start

_start:

/*设置内存:sp栈*/ldrsp,=4096/*nand启动*///ldrsp,=0x40000000+4096/*nor启动*/

/*调用main*/blmain

halt:bhalt

反汇编文件(Disassembler):

Disassemblyofsection.text:

/*地址*//*机器码*//*汇编指令*/00000000:0:e3a0da01movsp,#4096;0x10004:eb000000blc

00000008:8:eafffffeb8

0000000c:c:e1a0c00dmovip,sp10:e92dd800stmdbsp!,{fp,ip,lr,pc}14:e24cb004subfp,ip,#4;0x418:e24dd008subsp,sp,#8;0x81c:e3a03456movr3,#1442840576;0x5600000020:e2833050addr3,r3,#80;0x5024:e50b3010strr3,[fp,#-16]28:e3a03456movr3,#1442840576;0x560000002c:e2833054addr3,r3,#84;0x5430:e50b3014strr3,[fp,#-20]34:e51b2023ldrr2,[fp,#-16]38:e3a03c01movr3,#256;0x1003c:e5823000strr3,[r2]40:e51b2023ldrr2,[fp,#-20]44:e3a03000movr3,#0;0x048:e5823000strr3,[r2]4c:e3a03000movr3,#0;0x050:e1a00003movr0,r354:e24bd00csubsp,fp,#12;0xc58:e89da800ldmiasp,{fp,sp,pc}Dment:

/*解释*/00000000:0:43434700cmpmir3,#0;0x04:4728203aundefined8:2029554eeorcsr5,r9,lr,asr#10c:2e342e33mrccs14,1,r2,cr4,cr3,{1}10:Address0x10isoutofbounds.

二.知识储备1.ARM汇编指令对ARM汇编的指令详细介绍见另一篇博客:

链接

先对汇编指令做一个简单的介绍:

这要从CPU说起,计算机的可识别语言是机器码,也就是二进制数,CPU可以识别执行人们用机器码编写的程序。这种开发方式太过于复杂而且不易掌握,所以就有了汇编指令,汇编指令实际上是对机器码的一个封装,汇编指令可以经过编译转换为机器码,只不过相比于机器码,汇编指令可以直接供人们进行阅读理解。ARM中的一条汇编指令可以转换为32位的机器码,ARM的CPU一次执行的机器码就是32位,就是ARM可以一次处理一条汇编指令。

CPU在控制器的控制下,可以对内存中的数据进行读写到CPU内部的寄存器中(就是r0、r1、sp、pc、lr…这些寄存器),然后由运算器对寄存器中的值进行运算,包括加减乘除和逻辑运算,得到的结果可以再写入指定的寄存器中。CPU还可以根据指令进行跳转执行,就是跳转到某一指定的内存地址来取指令执行。计算机的运行就是靠着CPU这样高速重复的简单操作来支撑的。

所以汇编指令的作用流程大体如下:程序员编写汇编指令,经过编译生成机器码,机器码存放在内存中,CPU读写内存,CPU执行机器码(汇编指令)。

如图示CPU的寄存器:2.寄存器知识子程序之间通过r0~r3寄存器来传递参数lr原来保存子程序的返回地址,当lr的值存储在数据栈中时,lr可以有其他用途sp作为数据栈指针,在进入、退出子程序是要相同,sp总是指向栈顶pc作为程序计数器,不能用于其他用途ip是子程序内部调用的scratch寄存器

三.代码解析引导代码的汇编指令,有俩个作用:设置栈、引导函数

设置栈就是利用sp(StackPointer)栈指针,也就是栈顶指针,sp始终指向栈的顶部,程序运行的内存空间就在划分的栈空间内。

引导函数,就是引导ARM转到存储C语言编写的函数的内存空间去,去执行C语言编写的函数(内存中是机器码形式),引导采用跳转命令bl,可以使ARM跳转到指定的内存地址,并且将下一条指令的地址拷贝到lr寄存器,以便调用函数后,返回调用处可以接着执行下一条指令。可以使用:movpc,lr指令来回到调用之前的下一条指令,继续执行

1.指令分析下面具体分析每一条汇编指令:

第一条指令:movip,sp

是保存当前的栈顶指针sp到ip中。

第二条指令:stmdbsp!,{fp,ip,lr,pc}

首先,sp从4096的栈顶位置下移4Byte(db:先移位,后存储),然后将当前的pc寄存器的值存储在4092的内存地址,注意当前指令的地址为0X10,所以当前pc的值为:0X18(ARM流水线执行指令);

然后,sp从4092的内存地址再下移4Byte,将lr寄存器的值存储在4088的内存地址,lr寄存器中存放着汇编指令调用main函数时的现场,也就是内存地址8的指令。

然后,sp从4088的内存地址再下移4Byte,将ip寄存器的值存储在4084的内存地址,ip寄存器中存放着原始的栈顶指针地址,也就是4096.

然后,sp从4084的内存地址再下移4Byte,将fp寄存器的值存放在4080的内存地址

最后,sp指向的内存地址就是最后依次修改的地址,也就是4080。

此时的栈情况如图:第三条指令:subfp,ip,#4

将ip-4Byte的结果放入fp中,也就是4096-4=4092的内存地址(ip存放原始的栈顶指针指向4096),fp指向4092的内存地址。

第四条指令:subsp,sp,#8

这里将sp指向的内存地址下降8Byte,即在存储那四个寄存器信息的内存地址后面,腾出8Byte空间,恰好是俩条指令的空间,为后面存储俩个局部变量留空间。

第五、六条指令:movr3,#1442840576;0x56000000addr3,r3,#80;0x50strr3,[fp,#-16]

将0X56000050存入r3寄存器。

第七条指令:strr3,[fp,#-16]

将r3的内容,也就是局部变量0X56000050写入fp-16Byte的地址,fp-16Byte的内存地址正好是紧接着前四个寄存器的内存地址,可以看出调用函数的局部变量是存储在这四个基本信息寄存器后的。

第八、九、十条指令:movr3,#1442840576;0x56000000addr3,r3,#84;0x54strr3,[fp,#-20]

这三条指令与上面三条指令的意义一样,都是讲局部变量存储在内存中,将0X56000054紧挨着存储在0X56000050下面。注意,此时局部变量下紧接着就是sp栈顶指针。

此时栈情况如图:第十一条指令:ldrr2,[fp,#-16]

将0X56000050读取到r2寄存器中。

第十二条指令:movr3,#256;0X100

将0X100写入到r3寄存器中。

第十三条指令:strr3,[r2]

将0X100写到地址为0X56000050内存空间中,也就是写到GPFCON寄存器中,配置GPF4引脚的模式为输出。

第十四、十五、十六条指令:ldrr2,[fp,#-20]movr3,#0;0x0strr3,[r2]

与上面一样,就是将0写入GPFDAT寄存器中,点亮GPF4对应的LED,GPF4引脚输出低电平。

第十七、十八条指令:movr3,#0;0x0movr0,r3

将r0寄存器清零,相当于main函数中的return0,r0、r1、r2、r3寄存器就是在子程序之间传递参数的。

第十九条指令:subsp,fp,#12

将sp重新指向fp-12Byte的地址,也就是4080.

第二十条指令:ldmiasp,{fp,sp,pc}

从栈中恢复寄存器

首先,sp从当前地址4080,也就是刚开始保存fp的地址,读取4Byte,写入fp。

然后,sp从4080的内存地址上移4Byte,就是4084,读取4Byte,写入sp,就是将之前的ip值(4096)写入sp

然后,sp从4084的内存地址上移4Byte,就是4092,读取4Byte,写入pc,就是将之前的lr值(汇编引导main是的地址)写入pc,就是8,程序跳回0X8的地址,也就是main返回

2.总体分析可见,4K的空间包含了:寄存器初始值、局部变量、代码段,程序的运行在这4K内存中已经足够了。

做一下小总结:

栈后面会保存代码段

栈的开头保存原来寄存器:pc、lr、ip、fp,保证调用完函数可以返回到原来的位置

sp的值在进入、退出子程

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论