详细的实验代码可参看:
https://github.com/elvinsys/arm_tq2440/blob/master/1_uboot/1-10.c_start/start.S
https://github.com/elvinsys/arm_tq2440/blob/master/1_uboot/1-10.c_start/main.c
一、 堆栈初始化
1. 栈,是一种具有“后进先出”性质的数据组织方式
栈底,第一个进栈的数据所处的位置
栈顶,最后一个进栈的数据所处的位置
SP,堆栈指针
2. 满栈,SP总是指向压入堆栈的数据
空栈,SP总是指向下一个将要放入数据的空位置
(而ARM采用的是满栈的形式)
3. 随着数据的入栈,SP的移动方向分为:
升栈,SP从低地址->高地址移动
降栈,SP从高地址->低地址移动
(而ARM采用的是降栈的形式)
4. 栈帧,函数所使用的那部分栈,所有函数的栈帧串起来组成一个完整的栈,栈帧的两个边界分别是有fp(r11),sp(r13)组成的
5. 栈的作用
我们进行反汇编,分析汇编代码后,可总结为以下三点:保存局部变量,传递参数,保存寄存器的值
6. 栈的初始化的具体实验代码为:
init_stack:
ldr sp, =0x34000000
mov pc, lr
二、 BSS段初始化
1. BSS段的作用:是保存未初始化的全局变量
2. 为了防止未定义变量取任意值,需要把bss段清零
3. 具体实验代码为:
clean_bss:
ldr r0, =bss_start
ldr r1, =bss_end
cmp r0, r1
moveq pc, lr
clean_loop:
mov r2, #0
str r2, [r0], #4
cmp r0, r1
bne clean_loop
mov pc, lr
三、 从汇编到C语言
1. 经过上面对堆栈和bss段初始化后,C语言的基本环境已准备好,用于相对跳转的指令有B、BL,绝对跳转的指令有LDR
2. 实现的方法是在start.S的末尾,加入跳转指令,然后在文件夹中另外创建一个main.c文件已实现汇编到C的转换
3. 实验代码:
3.1 在start.S中的reset的末尾加入
ldr pc, =gboot_main
3.2 另外touch一个main.c,main.c中插入如下代码:
#define pGPBCON (volatile unsigned long *)0x56000010
#define pGPBDAT (volatile unsigned long *)0x56000014
int gboot_main()
{
*pGPBCON = 0x1540;
*pGPBDAT = 0x75f;
return 0;
}
四、 关于C语言与汇编语言混合编程
1. 汇编语言相比起C语言来说,执行效率高,但编写方法繁琐,而C语言可读性强,移植性较汇编要好。而混合编程后,有执行效率高,以及可直接控制处理器等特点。
2. 混合编程的类型包括三种
2.1 汇编语言调用C语言函数:可直接 ldr pc, =函数名
2.2 C语言调用汇编函数
2.3 C语言内嵌汇编代码
3. 实现的方式
3.1 第一种实现形式,可现在汇编文件中,把 light_led声明为全局变量,在全局变量下填入汇编代码,然后再C语言中直接调用该全局变量,就能执行汇编代码了
.global light_led
light_led:
ldr r0, =pGPBCON
ldr r1, =0x15400
str r1, [r0]
................................
3.2 在C语言中嵌入汇编代码,代码范例如下:
#define pGPBCON 0x56000010
#define pGPBDAT 0x56000014
int gboot_main()
{
__asm__(
"ldr r1, =0x15400\n"
"str r1, [%0]\n"
"ldr r1, =0x75f\n"
"str r1, [%1]\n"
:
:"r"(pGPBCON), "r"(pGPBDAT)
:"r1"
);
return 0;
}