内存与cpu运行

之前一直很好奇就cpu执行一段程序的运行方式。今天就查阅了一些资料和大牛神迹,对这个问题有了稍许的理解,记录下来。其中也包括部分startup.s的内容。

 

首先,一段程序本质上是有不同的段组成的。

这些段分为: bss段、data段、text段等

这些段在嵌入式系统的设计中非常重要,当嵌入式系统运行时其影响到内存分配,存储单元空间等问题。

 

startup_.s文件是系统的启动文件,其包括堆和栈的初始化配置、中断向量表的配置以及将程序引导到main()函数等功能。

 

在一般的段式内存管理架构中,这些段的意义如下:

1, .BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。【包括未初始化的全局变量和局部静态变量,我们知道未初始化的全局变量和局部静态变量默认值都为0, 本来它们也可以被放在.data 段的, 但是因为它们都是 0, 所以为它们在.data 段分配空间并且存放数据 0 是没有必要的。 程序运行的时候它们的确是要占内存空间的, 并且可执行文件必须记录所冇未初始化的全局变量和局部静态变量的大小总和, 记为.Bss段。 所以.bss 段只是为未初始化的全局变量和局部静态变量预留位置而已, 它并没有内容, 所以它在文件中也不占据空间。】 

  

2, .data段:数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。 【全局变量和局部变量数据经常放在数据段】

  

3, .text段:代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。【程序源代码编译后的机器指令经常放在代码段】

 

总体来说, 程序源代码被编译以后主要分成两种段: 程序指令和程序数据。 代码段厲于

程序指令, 而数据段和.bss 段属于程序数据

 

而在.bin文件中,包括Vectors段,ramcode段,SysApp段以及相对独立的功能段FeatureX

 

Vectors段即对应启动文件Cstartup.S,必须放置在bin文件0地址处。

ramcode段紧接着vectors段,对应程序中被标记为ramcode的函数。

SysApp段在Vectors段之后,其对应main.c以及一些程序逻辑代码等,包含对应的code,rodata,data(含retention和非retention)段。【retention内容为:在RAM中具有一段被保护的内存空间,此空间具有掉电保护机制,不会因为MCU掉电而擦除。】

FeatureX段为一个独立的功能段,包含对应的code,rodata,data等。

 

总体来说, 程序源代码被编译以后主要分成两种段: 程序指令和程序数据。 代码段厲于程序指令, 而数据段和.bss 段属于程序数据 。

 

顺便回忆一下堆栈的意义:

堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减) 

  

栈(stack):栈又称堆栈,是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。 

 

.section  

.section 表示要进行段操作,即对接下来段进行填充等。

举个栗子: .section    .vectors,”ax”   //将后面的代码放到.vectors段中

.section .data //.data段保存程序的数据,是可读可写的,相当于C程序的全局变量。(data segment)

.section .text //.text段保存代码,是只读和可执行的,后面那些指令都属于.text段。(code segment/text segment)

.section .bss //.bss段用来存放程序中未初始化的全局变量的一块内存区域,BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。

.section .vectors //中断向量段。

 

 

.globl/global

.globl/global表示接下来定义的内容是全局的。

举个栗子:.global   __reset         //告诉编译器__reset是全局的,会被连接器用到。

 

.globl _start是一个符号(Symbol),符号在汇编程序中代表一个地址,可以用在指令中,汇编程序经过汇编器的处理之后,所有的符号都被替换成它所代表的地址值。在C语言中我们通过变量名访问一个变量,其实就是读写某个地址的内存单元,我们通过函数名调用一个函数,其实就是跳转到该函数第一条指令所在的地址,所以变量名和函数名都是符号,本质上是代表内存地址的。

 

.globl指示告诉汇编器,后面定义的符号要被链接器用到,所以要在目标文件的符号表中标记它是一个全局符号。而_start就像C程序的main函数一样特殊,是整个程序的入口,链接器在链接时会查找目标文件中的_start符号代表的地址,把它设置为整个程序的入口地址,所以每个汇编程序都要提供一个_start符号并且用.globl声明。如果一个符号没有用.globl声明,就表示这个符号不会被链接器用到。

 

_start:

这里定义了_start符号,汇编器在翻译汇编程序时会计算每个数据对象和每条指令的地址,当看到这样一个符号定义时,就把它后面一条指令的地址作为这个符号所代表的地址。而_start这个符号又比较特殊,它所代表的地址是整个程序的入口地址,所以下一条指令就成了程序中第一条被执行的指令。

 

【以上部分内容源自:https://www.cnblogs.com/snail-micheal/p/4189632.html

 

 

.align 对齐段落

.align 后面接立即数,缺省是4字节对齐。属于编译器的指令(不属于ARM指令)。

 

.section .vectors

.align 10

 

 

.import 导入外部标号

.import 声明标号来自外部文件,跟C语言中的EXTERN关键字类似

 

.import irq_dispatch

.import g_int_cnt

 

.space 分配内存空间

.space 0x200

 

.word或.long 数据定义

为特定的数据分配存储单元,也可以完成已分配储存单元的初始化

 

.long Reset_Handler

.long vec_handler

 

ADS和GNU两种环境下的对比

.byte == DCB(分配字节存储单元)-128~255之间的数字或字符串

.hword或.short == DCW(分配半字存储单元)-32768~65535间的数字表达式

.word或.long == DCD(分配字存储单元)是表达式

.quad == 8字节

.float ==定义浮点数

.string/.asciz/.ascii ==定义多个字符串

*/

 

举个栗子:

.word  (AAA) //开辟AAA类型bytes空间,存放版本号

.word 0x12 //表示在此前定义的地址内写入0x12

 

类似的可以如此定义:

_reset:

loader r0, FAA

loader r1, FAA+1(0x12 为1byte长度)

loader r2, FAA + 5(此处假设_start_data_为四个字节长度)

 

FAA:

.word 0x12

.word (_start_data_)

.word (_max_ram_data)

由FAA可知,此段内容意义为将FAA的数据填入r0, r1 ,r2

因此可以用.word 初始化堆栈指针等。

 

操作指令还有很多不再一一赘述,主要一些汇编指令我不是很清楚,这里就等遇到再请教大牛们了。

 

下面为从CPU执行程序的过程。

首先,Flash以及SRAM分为如下几部分:

 

                                             内存与cpu运行

芯片上电后首先做的是将.vectors段和.ram_code从flash中读取其code到RAM地址中,然后CPU通过cache读取RAM和flash中的信息。【注意:实际上CPU永远只跟cache交互.如果cache没有命中,那么就会停止,并让MMU来把内存换入到cache中.只要操作系统保证了页表的相关机制,那么CPU能识别的都是逻辑地址.】

 

一般而言Bootloader的分为两种模式,即启动加载模式和下载模式。

 

关于存储:其实存储系统往简单了说,内存就是磁盘的一个缓存而已,cache又是内存的缓存.注意这里一直是操作虚拟地址的。

 

RAM芯片的存储速度比ROM芯片的速度快,但比Cache 【高速缓冲存储器】 的速度慢。

 

原文链接:https://blog.csdn.net/Kshine2017/article/details/84308045

单片机运行及原理:原文链接:https://blog.csdn.net/qinze5857/article/details/99654855