Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2243925
  • 博文数量: 668
  • 博客积分: 10016
  • 博客等级: 上将
  • 技术积分: 8588
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-29 19:22
文章分类

全部博文(668)

文章存档

2011年(1)

2010年(2)

2009年(273)

2008年(392)

分类:

2009-09-07 10:25:08

     对于这一问题的答案是:不能。C程序中所有的代码都是以函数的形式出现的。可能有人要说在C中也可以嵌入汇编代码,能不能用这种方式来实现整个boot loader呢?再看看题目,这里只考虑所有的代码只能是以函数的形式出现。那C程序中函数调用要一个什么样的环境呢?堆栈!我们写C程序时在函数名的后面,就是用花括号将代码括起来的,开始的花括号其实可以理解为有一段汇编代码(具体细节以后会有文章进行解释)对堆栈进行操作。那堆栈从哪来呢?显然,堆栈是一块内存区,也就是说我们用C程序写代码之前,必须保证内存已经初始化好了、可以用了。回忆一下,我们在《什么是boot loader》一文中提到,SDRAM内存芯片的初始化是boot loader中很重要的一步。也就是说,我们必须保证初始化好了SDRAM内存芯片后,才能进行C函数调用。因此,完全用C语言来实现boot loader是不可行的。

像Bootloader 这样底层的程序一般认为是要用纯汇编来写的。但是用汇编写的程序 
可读性肯定没有用C写的程序好。汇编程序不宜维护,没办法向其它类型的CPU 
去移植。这些方面C的程序是没有问题的!_ 

那么Bootloader能否用纯C语言去写呢?不可能。因为有些操作特殊寄存器的指 

令也是特殊指令,用C是实现不了的。有些功能用C也是不能实现的。用C不能 
作的有: 
1. 操作CP15寄存器的指令 
2. 中断使能 
3. 堆栈地址的设定 

所以,只要知道这几条汇编指令可以了,不必学习所有的汇编指令。是不是上手很 
快呀。下面来看看我们在Bootloader中所用到的汇编部分:
 
asm ("_my_start:
mov r14, #0x70
mcr p15, 0, r14, c1, c0, 0 /* MMU dISAbled, 32 Bit mode, Little endian */
mrs r14, cpsr
bic r14, r14, #0x1f /* Mask */
orr r14, r14, #0xc0 + 0x13 /* Diasble IRQ and FIQ, SVC32 Mode */
msr cpsr, r14
ldr r13, =0xc0020000 /* Setup Stack */
");

简单吧,比看几十K的汇编程序感觉好得多吧。 
也许你会问:硬件的初始化怎么办?那是要操作寄存器的。 
我说:看看这段C的代码: 

*((DWORD*)(dwHardwareBase + HW1_SYSCON1)) = SYSCON1_VALUE; 

明白了吧,ARM中把寄存器映射在内存中了,就跟读写内存没有区别。 
现在编写程序的问题已经全部解决了,但是否就没有问题了呢?不是。你的程序应 
该写成什么样呢?怎么编译生成二进制文件呢? 
让我们先写一个程序试一下吧: 

#define DWORD unsigned int
int main(void)
{
register DWORD dwHardwareBase;
asm ("_my_start:
mov r14, #0x70
mcr p15, 0, r14, c1, c0, 0 /* MMU dISAbled, 32 Bit mode, Little endian */
mrs r14, cpsr
bic r14, r14, #0x1f /* Mask */
orr r14, r14, #0xc0 + 0x13 /* Diasble IRQ and FIQ, SVC32 Mode */
msr cpsr, r14
ldr r13, =0xc0020000 /* Setup Stack */
");
dwHardwareBase = (DWORD)0x80000000;
return 0;
}

编译一下: 
C:>ccarm -c -O2 -mcpu=arm710 -mlittle-endian -nostdlib -fvolatile -nostdinc –static 
sam1.c 
C:>ldarm -o sam1.out -Ttext 10000000 sam1.o 
ldarm: warning: cannot find entry symbol _start; defaulting to 10000000 
sam1.o(.text+0xc):fake: undefined reference to `__gccmain' 
sam1.o(.text+0xc):fake: relocation truncated to fit: ARM_26 __gccmain 

我们发现应该把main定义成_start 

#define DWORD unsigned int
void start(void) //gcc需要把它定义成_start,的egcs要把它定义成start。
{
register DWORD dwHardwareBase;
asm ("_my_start:
mov r14, #0x70
mcr p15, 0, r14, c1, c0, 0 /* MMU dISAbled, 32 Bit mode, Little endian */
mrs r14, cpsr
bic r14, r14, #0x1f /* Mask */
orr r14, r14, #0xc0 + 0x13 /* Diasble IRQ and FIQ, SVC32 Mode */
msr cpsr, r14
ldr r13, =0xc0020000 /* Setup Stack */
");
dwHardwareBase = (DWORD)0x80000000;
}

编译一下: 

C:>ccarm -c -O2 -mcpu=arm710 -mlittle-endian -nostdlib -fvolatile -nostdinc –static 
sam1.c 
C:>ldarm -o sam1.out -Ttext 10000000 sam1.o 
C:>objdumparm -d sam1.out > sam1.asm 
现在来看看汇编的源代码: 

sam1.out: file format coff-arm-little 
DISAssembly of section .text: 
10000000 <_start>: 
10000000: e1a0c00d mov ip, sp 
10000004: e92dd800 stmdb sp!, {fp, ip, lr, pc} 
10000008: e24cb004 sub fp, ip, #4 
1000000c <_my_start>: 
1000000c: e3a0e070 mov lr, #70 
10000010: ee01ef10 mcr 15, 0, lr, cr1, cr0, {0} 
10000014: e10fe000 mrs lr, cpsr 
10000018: e3cee01f bic lr, lr, #1f 
1000001c: e38ee0d3 orr lr, lr, #d3 

10000020: e129f00e msr cpsr, lr 
10000024: e59fd000 ldr sp, 1000002c <$$lit__1> 
10000028: e91ba800 ldmdb fp, {fp, sp, pc} 
1000002c <$$lit__1>: 
1000002c: c0020000 andgt r0, r2, r0 
10000030 <__CTOR_LIST__>: 
10000030: ffffffff swinv 0x00ffffff 
10000034: 00000000 andeq r0, r0, r0 
10000038 <__DTOR_LIST__>: 
10000038: ffffffff swinv 0x00ffffff 
1000003c: 00000000 andeq r0, r0, r0 
哈哈!在<_start>和<_my_start>之间的代码在干什么?是在保存现场吧,还用到了 
堆栈。而这时堆栈还没初始化,向堆栈里写东西那不乱套了!应该屏蔽这段代码。 
那就在<_start>之前放一个跳转指令跳到<_my_start>吧。 

#define DWORD unsigned int
asm ("
.text
.global _start
_start:
bl _my_start /* Omit the entry code for function c_start() */
");

void c_start(void)
{
register DWORD dwHardwareBase;
asm ("_my_start:
mov r14, #0x70
mcr p15, 0, r14, c1, c0, 0 /* MMU dISAbled, 32 Bit mode, Little endian */
mrs r14, cpsr
bic r14, r14, #0x1f /* Mask */
orr r14, r14, #0xc0 + 0x13 /* Diasble IRQ and FIQ, SVC32 Mode */
msr cpsr, r14
ldr r13, =0xc0020000 /* Setup Stack */
");
dwHardwareBase = (DWORD)0x80000000;
}
阅读(1200) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~