bootloader通常会分为两个阶段:第一阶段采用汇编语言来编写,主要是一些核心的初始化工作(内存,时钟的初始化),第二阶段使用C语言来编写,主要是它会完成一些板载硬件的初始化(串口,网口)然后其启动我们的操作系统。所以我们需要先搭建好C语言环境。
-----------------------------------------------------
栈的初始化(只有一行,但信息量巨大,而且非常重要,对以后嵌入式的学习起了至关重要的作用):
栈:一种后进先出性质的数据组织方式。
满栈:当堆栈指针sp总是指向最后压入堆栈的数据
空栈:当堆栈指针sp总是指向下一个将要放入数据的空位置。
ARM采用满栈。
--------------------------------------------------
升栈和降栈:
升栈:sp指针从地地址到高地址
降栈:sp指针从高地址到地地址
ARM采用降栈。
-------------------------------------------
栈帧:就是一个函数所使用的那部分栈,所以函数的栈帧串起来就组成了一个完整的栈,栈帧的两个边界分别由fp(r11)和sp(r13)来限定。main与main函数中所有调用的函数,共同形成一个栈,main也是一个栈帧。
栈帧与栈帧之间的界定:上边界为fp指针,下边界为sp指针。
而main函数的边界保存在所调用的函数中,通过指针映射,将整个main函数包含进来。
---------------------------------------------------------
三个实例阐述栈的作用:
1.保存局部变量(局部变量保存在栈中):
#include<stdio.h>
int main()
{
int a;
a++;
return a;
}
arm-linux-gcc -g -o stack1 stack1.c
arm-linux-objdump -D -S stack1 >dump
vim dump
:/main
(str fp,[sp,#-4]!),将fp放到sp减去4个字节的位置,"!"表示sp减去4个字节后的值还要赋值给sp.
2.传递参数(当参数个数大于4是,使用栈来传递参数):
#include<stdio.h>
void func1(int a,int b,int c,int d,int e,int f)
{
int k;
k=e+f;
}
int main()
{
func1(1,2,3,4,5,6);
return 0;
}
arm-linux-gcc -g -o stack1 stack2.c
arm-linux-objdump -D -S stack2 >dump2
vim dump2
:/main
push {1,2}先压入的是2。
3.保存寄存器的值:
#include<stdio.h>
void func2(int a,int b)
{
int k;
k=a+b;
}
void func1(int a,int b){
int c;
func2(3,4);
c=a+b;
}
int main()
{
func1(1,2);
return 0;
}
arm-linux-gcc -g -o stack1 stack2.c
arm-linux-objdump -D -S stack2 >dump3
vim dump3
:/main
-------------------------------------------------------
栈初始化编程:
bl init_stack
bl light_led
init_stack:
ldr sp,=0x54000000 //210:0x24000000 //2440:0x34000000
mov cp,lr
-------------------------------------------------------
初始化bss段(就是对bss段进行整体性清零,防止为初始化的全局变量产生错误):
bss段的作用:
初始化的全局变量存放在数据段,局部变量存放在栈段,未初始化的全局变量存放在bss段,malloc内存分配在堆中。面试易考。
如:#include<stdio.h>
int year;
int main()
{
year=2014;
return year;
}
arm-linux-gcc bss.c -o bss
arm-linux-readelf -a bss >dump
vim dump
查看year是否存放在bss段的起止位置之间。
-------------------------------------------------
首先我们要找到bss段的起始位置,然后在bss段中全部填0.
起始位置可以在链接器脚本中找到。
bl clean_bss
clean_bss:
ldr r0,=bss_start
ldr r1,=bss_end
cmp r0,r1 //比较bss段的起始位置是否相等
moveq pc,lr //相等则返回pc
clean_loop:
mov r2,#0 //每次清零4个字节
str r2,[r0],#4 //将r2的值放到r0中
cmp r0,r1
bne clean_loop
mov pc,lr
--------------------------------------------------
一跃进入c大门:采用什么方式跃,检验是否跃成功。
相对跳转:b,bl:跳转到内存当中的main
绝对跳转:pc=....:跳转到SRAM中的main
vi main.c
int gboot_main()
{
return 0;
}
reset:
ldr pc,=gboot_main
vim makefile
加上++main.o
-------------------------------------------
接下来是验证C程序已经被执行到了。这次我们使用c语言来点亮led.打开之前编写的start.S文件,然后将里面用汇编语言写的bl light_led的代码都注释掉,将它的实现部分放到main.c中。
实际代码:
#define GPKCON (volatile unsigned long*) 0x7f008800
#define GPKDAT (volatile unsigned long*) 0x7f008800

int gboot_main()
{
*(GPKCON) = 0x11110000
*(GPKDAT) = 0xa0
return 0;
}
210的开发板需要起点处向后移16字节的头。
-----------------------------------------------
c与汇编混合编程:
C语言:可读性强,移植性好,调试方便
汇编语言:执行效率高,编写繁琐,能直接控制处理器(关键)。
1.汇编调用c函数:
ldr pc,gboot_main:调用C函数。
2.C语言中调用汇编函数:
直接将汇编函数名放到c语言的main中:light_led;还有一点,就是要将其申明为全局:
.global light_led
light_led:
3.c内嵌汇编:
格式:
__asm__(
汇编语句部分
:输出部分
:输入部分
:破坏描述部分
);
void write_p15_c1(unsigned long value){
__asm__(
"mcr p15,0,,%0,c1,c0,0\n"//从%0中读取参数放到c1中
:
:"r"(value)将value赋值给r,然后将r中的值放到c1中。
);
}
-----------------------------------------------------
实例2:
unsigned long read_p15_c1(void){
unsigned long value;
__asm__(
"mrc p15,0,%0,c1,c0,0\n" //从c1中读出值写到%0中。
:"=r"(value)@"="表示只写操作数,用于输出部分
:
:"memory");//表示内存的值被修改了,value存在于内存。
return value;
}
------------------------------------------------
优化:
unsigned long old;
unsigned long temp;
__asm__volatile(
"mrs %0,cpsr \n"
"orr %1,%0,#128 \n"
"msr cpsr_c,%1\n"
:"=r"(0ld),"=r"(temp)
:
:"memory");
使用volatile来告诉编译器,不要对接下来的这部分代码进行优化。
-----------------------------------------------------
使用内嵌汇编点亮led:
start.S
main.c
#define GPKCON 0x7f008800
#define GPKDAT 0x7f008808
int gboot_main(){
__asm__(
"ldr r1,=0x11110000\n"
"str r1,[%0]\n"
"ldr r1,=0xa0\n"
"str r1,[%1]\n"
:
:"r"(GPKCON),"r"(GPKDAT)
:"r1"

);
return 0;
}

c语言环境初始化&c语言和汇编混合编程的更多相关文章

  1. 【转】VxWorks中高精度实时时钟的实现及C语言汇编混合编程

    最近一个项目中需要在VxWorks下使用一个高精度实时时钟,要求精度为1ms,溢 出时间大于5小时.VxWorks提供系统时钟,该时钟在操作系统启动后开始计数,精度为1个tick,可以通过tickGe ...

  2. ARM中C和汇编混合编程及示例(转)

    在嵌入式系统开发中,目前使用的主要编程语言是C和汇编,C++已经有相应的编译器,但是现在使用还是比较少的.在稍大规模的嵌入式软件中,例如含有OS,大部分的代码都是用C编写的,主要是因为C语言的结构比较 ...

  3. C51与汇编混合编程详解

    C51和汇编混合编程(1)-C语言中嵌入汇编 1.在 C文件中要嵌入汇编代码片以如下方式加入汇编代码: #pragma ASM ;Assembler Code Here #pragma ENDASM ...

  4. Part10-C语言环境初始化-C与汇编混合编程lesson4

    1.为什么要混合编程 汇编语言:执行效率高:编写繁琐: 执行效率高:能够更直接地控制处理器. c语言:可读性强,移植性好,调试方便. 1.汇编调用c函数 2.c调用汇编函数 汇编语言定义的函数(标号) ...

  5. [Swift通天遁地]五、高级扩展-(13)图片资源本地化设置:根据不同的语言环境显示不同语言版本图片

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  6. Part10-C语言环境初始化-一跃进入C大门lesson3

    1.跳转到c代码 因为内存中的代码来自于垫脚石SRAM,他们是相同的. 采用绝对跳转方式来完成. 因为我们是从汇编代码跳转到c语言的程序,所以我们要提前准备一个main.c文件. 修改makefile ...

  7. Part10-C语言环境初始化-栈初始化lesson1

    1.概念解析 ARM系统使用的是满栈! ARM采用降栈!!! 栈帧 每一个进程会有一个栈,该进程中的每一个函数会分割栈的一部分,那么每一个函数使用的那部分栈就叫做栈帧.那么所有栈帧组成了整个栈. 子函 ...

  8. Part10-C语言环境初始化-Bss段初始化lesson2

    1.BSS段的作用 初始化的全局变量存放在数据段: 局部变量存放在栈中: malloc的存放在堆: 未初始化的全局变量存放在BSS段: 找到bss段的起始与结束地址,往里面添加0,便初始化好了. 打开 ...

  9. arm:c语言和汇编混合编程

    仅作演示. 1.C和汇编可相互调用,汇编子函数格式参考 汇编:普通的函数调用的汇编代码解析 http://www.cnblogs.com/mylinux/p/4139972.html 本文演示了 : ...

随机推荐

  1. 二维数组模拟实现酒店管理系统-java

    业务分析 1.需要一个房间类,包含房间的属性,比如房间编号.房间类型.是否占用. 2.需要一个旅馆类,旅馆有房间,提供的方法需要有 预订房间.打印房间信息.初始化房间.退房. 3.测试类,测试预订房间 ...

  2. Version 1.7.0_80 of the JVM is not suitable for this product.Version: 1.8 or greater is required.

    Eclipse启动失败,设置eclipse启动jdk有2种方法 第一种: 直接安装eclipse对应的jdk版本,并设置环境变量 第二种: 修改eclipse配置文件eclipse.ini 在plug ...

  3. JS和H5做一个音乐播放器,附带源码

    http://mp.weixin.qq.com/s/KpXT9X46AMlUVXQvpHuXGQ 效果图: 实现的功能 1.首页 2.底部播放控件 3.播放页面 4.播放列表 5.排行榜 6.音乐搜索 ...

  4. channelartlist|频道文档:

    http://help.dedecms.com/v53/archives/tag/global/channelartlist/ {/dede:channelartlist} 参数说明: typeid ...

  5. dedecms首页调用软件下载地址

    这段时间利用dedecms开发一个软件下载的网站,应客户需求,需要在网站首页调用软件下载地址.在网上查找了一些资料,都没有很好的解决这个问题,后来自己研究了一下,就将自己的方法跟大家共享一下.有不好的 ...

  6. iOS关闭键盘的两种简单方法

    方法一: //1     [[[UIApplication sharedApplication] keyWindow] endEditing:YES]; ,为了关闭弹出的软键盘要遍历然后调用resig ...

  7. RMQ算法 (ST算法)

     概述: RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中 ...

  8. mysql alter总结

    mysql alter总结(转载) 1:删除列 ALTER TABLE [表名字] DROP [列名称] 2:增加列 ALTER TABLE [表名字] ADD [列名称] INT NOT NULL  ...

  9. cocos2dx 从2.2.6 到3.16 升级流水记录

    一个cocos2dx项目从2.2.6 升级至3.16 的过程,由于没有直升工具,类库升级也变动很大,有一部分需要手工完工升级.此记录供参考 1. 没有采用项目直升方式,先新建一个3.16的项目,然后把 ...

  10. 1.JavaScript 教程:基础语法

    简介: JavaScript web 开发人员必须学习的 3 门语言中的一门: HTML 定义了网页的内容 CSS 描述了网页的布局 JavaScript 网页的行为 用法: (1)HTML 中的脚本 ...