c语言环境初始化&c语言和汇编混合编程
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语言和汇编混合编程的更多相关文章
- 【转】VxWorks中高精度实时时钟的实现及C语言汇编混合编程
最近一个项目中需要在VxWorks下使用一个高精度实时时钟,要求精度为1ms,溢 出时间大于5小时.VxWorks提供系统时钟,该时钟在操作系统启动后开始计数,精度为1个tick,可以通过tickGe ...
- ARM中C和汇编混合编程及示例(转)
在嵌入式系统开发中,目前使用的主要编程语言是C和汇编,C++已经有相应的编译器,但是现在使用还是比较少的.在稍大规模的嵌入式软件中,例如含有OS,大部分的代码都是用C编写的,主要是因为C语言的结构比较 ...
- C51与汇编混合编程详解
C51和汇编混合编程(1)-C语言中嵌入汇编 1.在 C文件中要嵌入汇编代码片以如下方式加入汇编代码: #pragma ASM ;Assembler Code Here #pragma ENDASM ...
- Part10-C语言环境初始化-C与汇编混合编程lesson4
1.为什么要混合编程 汇编语言:执行效率高:编写繁琐: 执行效率高:能够更直接地控制处理器. c语言:可读性强,移植性好,调试方便. 1.汇编调用c函数 2.c调用汇编函数 汇编语言定义的函数(标号) ...
- [Swift通天遁地]五、高级扩展-(13)图片资源本地化设置:根据不同的语言环境显示不同语言版本图片
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...
- Part10-C语言环境初始化-一跃进入C大门lesson3
1.跳转到c代码 因为内存中的代码来自于垫脚石SRAM,他们是相同的. 采用绝对跳转方式来完成. 因为我们是从汇编代码跳转到c语言的程序,所以我们要提前准备一个main.c文件. 修改makefile ...
- Part10-C语言环境初始化-栈初始化lesson1
1.概念解析 ARM系统使用的是满栈! ARM采用降栈!!! 栈帧 每一个进程会有一个栈,该进程中的每一个函数会分割栈的一部分,那么每一个函数使用的那部分栈就叫做栈帧.那么所有栈帧组成了整个栈. 子函 ...
- Part10-C语言环境初始化-Bss段初始化lesson2
1.BSS段的作用 初始化的全局变量存放在数据段: 局部变量存放在栈中: malloc的存放在堆: 未初始化的全局变量存放在BSS段: 找到bss段的起始与结束地址,往里面添加0,便初始化好了. 打开 ...
- arm:c语言和汇编混合编程
仅作演示. 1.C和汇编可相互调用,汇编子函数格式参考 汇编:普通的函数调用的汇编代码解析 http://www.cnblogs.com/mylinux/p/4139972.html 本文演示了 : ...
随机推荐
- Spark学习笔记3(IDEA编写scala代码并打包上传集群运行)
Spark学习笔记3 IDEA编写scala代码并打包上传集群运行 我们在IDEA上的maven项目已经搭建完成了,现在可以写一个简单的spark代码并且打成jar包 上传至集群,来检验一下我们的sp ...
- phpmailer的SMTP ERROR: Failed to connect to server: 10
请问,我在win7上学习使用phpmailer时,出现这种错误怎么处理啊? SMTP ERROR: Failed to connect to server: (0) SMTP connect() fa ...
- destoon 开启邮箱
- asp.net -mvc框架复习(1)-ASP.NET网站开发概述
1.网站开发的基本步骤: 2.网站开发的需要的知识结构 (1)网站开发前台页面技术 页面设计:HTML .CSS+DIV 页面特效:JavaScript.jQery (2)OOP编程核心公共技能 C ...
- mysql插入数据后返回自增ID的方法,last_insert_id(),selectkey
mysql插入数据后返回自增ID的方法 mysql和oracle插入的时候有一个很大的区别是,oracle支持序列做id,mysql本身有一个列可以做自增长字段,mysql在插入一条数据后,如何能获得 ...
- IntelliJ IDEA 2016.2.x 激活
注册码获取:http://idea.lanyus.com/
- linux libpcap的性能问题,请大家注意绕行。
内核代码中,ip_rcv是ip层收包的主入口函数,该函数由软中断调用.存放数据包的sk_buff结构包含有目的地ip和端口信息,此时ip层进行检查,如果目的地ip不是本机,且没有开启转发的话,则将包丢 ...
- 解决svn--Unable to connect to a repository at URL ‘https://xxxxxx’ 问题
在checkout项目时,出现如下错误: Error Unable to connect to a repository at URL 'https://XXXX' Error Access to ...
- awk解决实际问题例子
awk很有用,就不说了,下面记录几个我遇到的例子,汇总 1 获得linux环境变量(ENVIRON) awk 'BEGIN{print ENVIRON["PATH"];}' /et ...
- MongoDB投影有$slice如何只显示该字段
简单的投影 稍微用过MongoDB的都知道,投影很简单,就直接 db.student.find({_id:ObjectId('5a5085aed8f10c1a6cc0395b')},{comments ...