知识点补充:

Linux进程中的五个段

BSS段(Block Started bySymbol,意为“以符号开始的块”):

  BSS,是Unix链接器产生的未初始化数据段。通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS段属于静态内存分配。

代码段(code segment/text segment):

  代码段通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

堆(heap):

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

栈(stack):

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


PS:

  全局的未初始化变量存在于.bss段中,具体体现为一个占位符;全局的已初始化变量存于.data段中;而函数内的自动变量都在栈上分配空间。.bss是不占用.exe文件空间的,其内容由操作系统初始化(清零);而.data却需要占用,其内容由程序初始化,因此造成了上述情况。

  bss段(未手动初始化的数据)并不给该段的数据分配空间,只是记录数据所需空间的大小。

data(已手动初始化的数据)段则为数据分配空间,数据保存在目标文件中。 数据段包含经过初始化的全局变量以及它们的值。BSS段的大小从可执行文件中得到 ,然后链接器得到这个大小的内存块,紧跟在数据段后面。当这个内存区进入程序的地址空间后全部清零。包含数据段和BSS段的整个区段此时通常称为数据区。

BSS段为什么要初始化/清除?

  BSS段是不会出现在程序下载文件(*.bin *.hex)中的,因为全都是0。如果把它们出现在程序下载文件中,会增加程序下载文件的大小。实际应用中,通常只需要把bss段的起始地址和结束地址保存起来,而不需要将程序下载文件中出现bss段(一堆0)将来真正运行程序的时候,再根据这两个数据进行bss段的初始化就行了。

可执行映像文件

  ELF:Linux操作系统下可执行映像文件格式,在Linux环境下用GCC编译器生成的可执行映像文件格式即为ELF格式,在Linux操作系统下可直接运行。

  可执行映像文件主要分为3个段,即RO段、RW段和ZI段,如下图所示:

  • RO段:只读代码段;
  • RW段:RW区域放的是已赋值(赋0除外)的全局变量;
  • ZI段:ZI区域放的是未赋值的全局变量或初始化为0的全局变量。

ARM裸板开发流程:

  ARM系统上电后,首先就运行系统初始化程序,系统初始化程序主要完成系统最基本的硬件初始化,为后面的C语言应用程序提供运行环境。ARM系统初始化启动代码完成的主要功能如下:

  1. 初始化ARM CPU异常处理向量表;
  2. 禁止看门狗;
  3. 禁止中断;
  4. 初始化系统时钟,包括CPU主频FCLK、系统总线时钟频率HCLK、外设总线时钟频率PCLK;
  5. 初始化SDRAM控制器;
  6. 设置ARM CPU在各种模式下的栈指针(栈顶);
  7. 设置ARM中断向量表,安装中断处理程序;
  8. 搬运可执行映像文件的RW段到RAM中,并初始化ZI段为0;
  9. 跳转到C语言应用程序的Main函数,开始执行C语言应用程序。

  到此,系统的初始化启动程序就完成了ARM系统的启动过程。

  ARM系统的初始化启动代码一般用汇编语言编写,根据以上的分析,我们知道ARM系统初始化启动程序的流程如下图所示:

MOV PC,LR 指令解析

  • SP(R13寄存器)
  • LR(R14寄存器)
  • pc(R15寄存器)

MOV PC,LR

LR寄存器保存了子程序的返回地址

而PC保存的是当前的地址,将LR的值给PC,即从子程序返回

LR寄存器在使用完跳转指令BL后会保存LR子程序的地址

如下例程:


.text
.global _start
_start: //设置栈
ldr sp,=0x80200000 bl clean_bss //清除bss段 bl main halt:
b halt //清除BSS段
clean_bss: ldr r1, =__bss_start
ldr r2, =__bss_end
mov r3, #0
clean:
str r3, [r1] //r1寄存器中的值所指向的地址处清零
add r1, r1, #4 //r1寄存器加4
cmp r1, r2 //r1的值减去r2的值,并改变相应的标志寄存器的值
bne clean //零标志位不等于零时跳转到标号clean处执行 mov pc, lr //子程序返回

mov pc, lr 起到的作用是在清除完bss段后回到bl clean处继续往下执行下一个指令(bl main)

LR寄存器一般来说有两个作用:

1、当使用bl或者blx跳转到子过程的时候,r14保存了返回地址,可以在调用过程结尾恢复。

2、异常中断发生时,这个异常模式特定的物理R14被设置成该异常模式将要返回的地址。

子程序返回的三种方法:

1.MOV PC,LR

2.BL LR

3.在子程序入口处使用以下指令将R14存入堆栈

  STMFD SP!, {<Regs>,LR}

对应的,使用以下指令可以完成子程序的返回

  LDMFD SP! , {<Regs>,LR}


GPIO普遍适用的操作方法

GPIO:general-purpose input/output,通用输入输出口

GPIO的一般结构:

有多组的GPIO,每组有多个GPIO口

  • 使能:电源/时钟
  • 模式(Mode):引脚可用于GPIO或其他功能
  • 方向:引脚Mode设置为GPIO时,可以继续设置它是输出引脚还是输入引脚
  • 数值:对于输出引脚,可以设置寄存器让它输出高、低电平

    对于输入引脚们可以读取寄存器得到引脚的当前电平

对GPIO寄存器的操作

在芯片手册中找到介绍power/clock的相关章节,根据所述内容设置对应寄存器某个GPIO模块(Module)有些芯片的GPIO没有使能开关,是默认使能的,有的话则需要设置

具体到一个引脚,可以用于GPIO、串口、USB或其他的功能,有对应的寄存器来选择到底使用哪一个功能(芯片手册)

对于已经设置为GPIO功能的引脚,有方向寄存器用来设置它的方向:输出、输入

对于已经设置为GPIO功能的引脚,有数据寄存器用来读、写引脚电平状态

GPIO寄存器的2种操作方法

在平时开发时原则上是不能影响到其他的位

直接读写:读出、修改对应位、写入

模板:

  设置bit n:

val = data_reg;
val = val | (1<<n);
data_reg = val;

  要清除bit n:

val = data_reg;
val = val & ~(1<<n);
data_reg = val;

set-and-clear protocol:

set_reg , clr_reg , data_reg 三个寄存器对应的是同一个物理寄存器

要设置bit n:set_reg = (1<<n);

要清除bit n:clr_reg = (1<<n);

GPIO的其他功能:防抖动、中断、唤醒(后续补充)

对于IMX6ULL芯片的GPIO口

1、设置引脚功能(Mode、功能)

  见IMX6ULL芯片手册——Chapter 32:IOMUX Controller (IOMUX)

最新文章

  1. sql server2008给数据表,字段,添加修改注释
  2. Can&#39;t bind to local 8700 for debugger报错和解决
  3. NotePad ++的妙用:添加代码行数和格式不变复制代码
  4. ASP.NET WebApi Document Helper
  5. Vue自带的过滤器
  6. linux更改启动级别后,无法启动的问题解决
  7. C#中反射的使用(How to use reflect in CSharp)(3)Emit的使用
  8. passwordauthentication yes
  9. hdu1151 Air Raid 二分匹配
  10. Java公开课-01.类和对象
  11. ARC071D Infinite Sequence
  12. 后台跑包方法 断开ssh程序也能继续执行的方法screen命令
  13. CNN tricks
  14. CentOS6.x下yum安装MySQL5.5/5.6
  15. Kafka三款监控工具比较
  16. 自然语言处理领域重要论文&amp;资源全索引
  17. Nginx变量.md
  18. LeetCode:删除排序数组中的重复项 (Remove Duplicates from Sorted Array)
  19. solr&amp;lucene3.6.0源码解析(二)
  20. Java基础16:Java多线程基础最全总结

热门文章

  1. 12月21日内容总结——forms组件渲染标签、展示信息、校验数据的一些补充,forms组件参数和源码剖析,modelform组件,Django中间件
  2. 9月21日内容总结——计算机基础知识、typora软件的安装与软件内的部分markdown语法
  3. Swagger2多包扫描
  4. WAF Bypass 介绍与实战
  5. ubuntu20.04安装systemback
  6. UBUNTU切换内核
  7. 为Jekyll静态网站添加PlantUML插件
  8. python requests 最牛攻略
  9. 物语(monogatari)
  10. Vmware15 + Ubuntu18.0.4 安装教程(史上最详细记录)【多图预警】