自己写个简单的ARM启动代码,了解C语言程序运行前的那点小动作
primula2012/10/24软件综合 IP:四川
通过这个例子应该可以明白两个问题
     1、 在做单片机和arm程序的时候,都会遇到启动代码。在单片机编程中,很多时候启动代码都是已经由集成开发环境准备好了,并不要我们自己去写。但是在arm中,因为ram啊,flash啊,还有各种设备是根据电路设计来的,所以启动代码不自己写都得自己修改。
      2、为什么不用C语言来写启动代码而必须是汇编?为什么不能在程序一开始就使用C语言的程序?C语言程序运行所需要的基本环境是什么?其实C语言程序并不一定要从main函数执行,也可以用自己定义的函数名,在例子后就会明白。

       其实上面的两个问题对于用汇编来写程序的人来说,都是理所当然的,但是更多的人是从C语言开始学习编程的,其约定俗成的都是从main函数开始执行的,很多地方也把这个main函数解释为程序的入口,听起来貌似这个入口就很特别。其实这个main函数和普通函数是差不多的,都是被调用了才会执行的,但是如果不统一的话,你的程序入口是main(),我的程序入口是start(),就很难统一,所以约定俗成的就是这个函数都叫main,当然也有不用main的,比如MFC。既然main函数和其它函数一样,那么他在被调用的时候就会有个动作,压栈,但是现在寄存器SP,也就是栈指针是指向哪里的?对了,这个指针还没有被初始化!也就是说,如果你想调用C语言的函数,就会用到堆栈,但是堆栈还没初始化,在一开始就不能调用C语言的程序,于是,这个时候就只能使用汇编语言的程序了。
以下是一个在算S3C2440上执行的最简单的启动代码:



这就是一个简单的启动代码了,在设置完栈后,跳到了一个名叫primula的函数,这个函数就相当于是我们的入口函数,就是一般用的那个main函数啦,再来看看C语言的程序:



#define rGPBCON (*(volatile unsigned long*)0x56000010)
#define rGPBDAT (*(volatile unsigned long*)0x56000014)

void primula()
{
    rGPBCON = 0x00015400;
    rGPBDAT = 0x00000140;  
}


这里面就只有两个关于寄存器的宏定义,和一个primula函数,将这两个文件编译连接后,就可以把生成的二进制文件下载到flash或者ram中运行试试了,在我的开发板上,led接在了GPIOB的5678端口上,这个primula函数中通过设置相关寄存器点亮了两个LED,但这个点led不是重点。重点是没有main函数但确实执行了primula这个函数并且把我的两个灯点亮了。没有main函数,没有include。

关于编译,可以写个makefile脚本(linux下)
我的脚本是这样写的:


c_XXXXXXn : startup.s  led.c
    arm-linux-gcc -nostdlib -g -c -o startup.o startup.s
    arm-linux-gcc -nostdlib -g -c -o led.o led.c
    arm-linux-ld -Ttext 0x00000000 -g startup.o led.o -o led_elf
    arm-linux-objcopy -O binary -S led_elf c_XXXXXXn
clean:
    rm -f c_led.dis c_XXXXXXn led_elf *.o


其中-nostdlib 这个选项是告诉编译器不连接系统标准启动文件和标准库文件,在有的gcc版本下貌似不用加上都不会出问题,但是我的编译器爆出了“undefined reference to `__aeabi_unwind_cpp”这样的错误,主要原因就是因为一般的C语言编译器,都会为了能够顺利执行你所写的C语言函数,而在你的程序前面加上一段代码,使得你的main函数会在运行时被自动调用,但是在这里,我们有自己的启动代码,去调用自己的函数,程序里连个main都木有!
+50  科创币    乖乖乖    2012/10/25 高科技
+1  科创币    布布卡    2013/08/15 汇编我一点也不懂。。
来自:计算机科学 / 软件综合
7
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
小陶
11年7个月前 IP:未同步
533427
受教,谢了!
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
laji3865689
11年7个月前 IP:未同步
533640
这个就是所谓bootloader吗?
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
.........
11年7个月前 IP:未同步
533641
LZ来尝试下汇编吧,Cortex-M3的指令集很有意思的.我努力了很久还是没用汇编点亮LED.
还有LZ不用初始化时钟中断向量表之类的东西的?
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
金星凌日
11年7个月前 IP:未同步
536704
Makefile为什么要这样写?有特殊的要求吗?
通常不是这样写吗?

c_XXXXXXn : led_elf
    arm-linux-objcopy -O binary -S led_elf c_XXXXXXn

led_elf : startup.o led.o
    arm-linux-ld -Ttext 0x00000000 -g startup.o led.o -o led_elf

startup.o : startup.s
    arm-linux-gcc -nostdlib -g -c -o startup.o startup.s

led.o : led.c
    arm-linux-gcc -nostdlib -g -c -o led.o led.c

clean:
    -rm -f c_led.dis c_XXXXXXn led_elf *.o
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
wzy41718682
11年5个月前 IP:未同步
560477
跟卫东山ARM好像哦。。。。。。。。。。。。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
vcasm
11年5个月前 IP:未同步
560512
和函数名关联不大,函数名只是告诉编译器的link在连接的时候将obj的动态指针表定位,对于mcu来说更简单,首字节加一个跳转,跳到哪个函数就是哪个函数执行
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
上级专业
同级专业
primula
学者 机友 笔友
文章
20
回复
184
学术分
1
2012/03/10注册,5个月18天前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:手机号
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}