国嵌上学期笔记-自己实现bootloader-第四节

摘要:本节把代码复制到内存。初始化C语言的环境,并调到main函数开始执行。

1、从NAND启动,则NAND前4KB的代码会被复制到SRAM,从SRAM开始执行,这4KB的代码把NAND剩下的代码复制到内存中,调到内存相应位置执行。

本节首先将SRAM的代码复制到内存运行。因为NAND还没有初始化。

2、链接地址:

当main函数执行时,调用了一个函数,PC指针就会被赋值为这个函数的链接地址。

ldr伪指令直接修改PC指针为链接地址,跳转到相应地址执行。

上电之后,还不在内存,PC为0,b指令和bl指令是相对跳转(bl会把返回地址放到 lr 寄存器),相对跳转不是把链接地址直接给PC,而是计算一下跳转位置和当前位置的差,给PC指针加上一个差值。

所以要把代码拷贝到链接起始地址处。

3、反汇编:arm-linux-objdump -D -S gboot.elf > dump

             -D反汇编所有段,-S尽可能反汇编出源代码,尤其当编译的时候指定了-g这种调试参数时。

4、栈初始化:

(1)满栈:SP指针总是指向最后压入栈的数据。

        空栈:SP指针总是指向下一个将要放入数据的空位置。

        ARM采用满栈。

        升栈:SP指针从低地址到高地址。

        降栈:SP指针从高地址到低地址。

        ARM采用降栈。

        栈帧:每个函数使用的一部分栈成为栈帧。栈帧的上边界FP(R11),下边界SP(R13)。main函数调用fun,则fun栈帧里面保存着main函数的FP和SP。

国嵌上学期笔记-自己实现bootloader-第四节

(2)栈的作用:

保存局部变量:汇编第一句,保存FP,!表示SP-4之后再赋值给SP。

传递参数:参数个数大于4的时候,用栈传递,参数小于4用寄存传递。(不一定是4,x86_64是6个参数)

保存寄存器的值:改变寄存器之前,将寄存器的值保存到栈里面。

国嵌上学期笔记-自己实现bootloader-第四节

(3)SP指针:0x3400 0000    内存地址

5、BSS段的初始化:将BSS段清0。

(1)BSS段的作用:初始化的全局变量存放在数据段。

        局部变量在栈中。

        malloc来自于堆。

        未初始化全局变量和静态变量存放在BSS段。

(2)初始化原因:如果不初始化,写程序的时候又忘记初始化全局变量,直接用,会是不确定的值,为了避免错误,将BSS段             的内存全部初始化为0。

6、跳转到main函数,进入C语言:

相对跳转B和BL只能在一个代码段里面跳转,main函数在sram和内存中都有,必须用绝对跳转。

7、C与汇编混合编程。

(1)汇编:效率高,直接控制处理器。

C语言:可读性强,移植性好。

(2)种类:

C调用汇编:例如,汇编中的标号是led,直接在C语言中 led() 就可以(led必须声名为全局的.global  led)。

汇编调用C:把函数名赋值给PC指针。

C内嵌汇编:_asm_或者asm都可以。有4个部分:第一部分必须有,其余三部分可以省略,但是冒号都不能省略。

        _asm_(

          汇编语句

        :输出部分-------------->在汇编中可能修改C语言的变量,这些变量在输出部分

        :输入部分-------------->汇编需要拿到C语言的一些值作为参数

        :破坏描述部分--------->如果修改某些寄存器的值,这些寄存器放在这里

        );