环境:ubuntu+(arm-linux-gcc)+minicom+dnw+mini2440
每换一个架构的处理器,总是会先对LED做些实验.对于启动代码(虽说2440有现成的启动代码,但是是基于ADS下的,在GNU下面用必须得修改伪指 令,而且对于裸奔爱好者来说,只要一小段代码不是自己写的,用起来就浑身不自在),虽然书里有讲它的作用,但是对此我一直存在着几点疑问,,,,
疑惑1)启动代码可有可无?
对于使用ADS来写的朋友,启动代码可有可无这点你们可以无需知道,因为编译器已经帮你做好了,而对于linux下的朋友,启动代码这块必须得了解,理由如其名字,,,,对于这个问题,我做了以下实验:
先写一个简单的led.c的文件,内容如下:
- #define GPBCON (*(volatile unsigned *)0x56000010)
- #define GPBDAT (*(volatile unsigned *)0x56000014)
- void main()
- {
- GPBCON = 0x55<<10; //01010101<<10
- GPBDAT = 0x0;
- }
start.s启动脚本:
- .text
- .global start
- start:
- ldr sp,=1024*4
- bl main
- loop:
- b loop
然后用我之前写的一篇叫ARM9裸奔篇之Makefile 里 的makefile编译链接一下,烧到NANDflash里,灯都亮了,然后把start.s改名为start(这样makefile就不会编译它了)然 后在make一下,烧进板子,灯也是全亮了,对于书中写到裸机程序必须要有启动代码这一说我表示十分疑惑,,,,,为什么可有可无?下面会说到,,,
疑惑2)当我似乎弄懂了上面的疑惑后,我开始led的第二步实验,流水灯,,,(不用启动代码)
led.c的代码:
- #define GPBCON (*(volatile unsigned *)0x56000010)
- #define GPBDAT (*(volatile unsigned *)0x56000014)
- void delay()
- {
- unsigned int i = 50000;
while(1);
- }
- void main()
- {
- unsigned char i;
- GPBCON = 0x55<<10; //01010101<<10
- // GPBDAT = 0x0;
- while(1)
- {
- for(i=0;i<4;i++)
- {
- GPBDAT = ~(1<<(5+i));
- delay();
- }
- }
- }
make一下后烧录进板子,发现居然不亮了,然后检查了半天代码,没发现有问题,此刻,我就想起了不久前被我抛弃了的启动代码,加进去后,仍然不亮,,,WHY?然后我又想起了看反汇编的程序(make后生成的.dis文件)内容如下:
- example.bin_elf: file format elf32-littlearm
- Disassembly of section .text:
- 00000000 <delay>:
- 0: e52db004 push {fp} ; (str fp, [sp, #-4]!)
- 4: e28db000 add fp, sp, #0
- 8: e24dd00c sub sp, sp, #12
- c: e59f3034 ldr r3, [pc, #52] ; 48 <delay+0x48>
- 10: e50b3008 str r3, [fp, #-8]
- 14: e51b3008 ldr r3, [fp, #-8]
- 18: e3530000 cmp r3, #0
- 1c: 03a03000 moveq r3, #0
- 20: 13a03001 movne r3, #1
- 24: e20330ff and r3, r3, #255 ; 0xff
- 28: e51b2008 ldr r2, [fp, #-8]
- 2c: e2422001 sub r2, r2, #1
- 30: e50b2008 str r2, [fp, #-8]
- 34: e3530000 cmp r3, #0
- 38: 1afffff5 bne 14 <delay+0x14>
- 3c: e28bd000 add sp, fp, #0
- 40: e8bd0800 pop {fp}
- 44: e12fff1e bx lr
- 48: 0000c350 andeq ip, r0, r0, asr r3
- 0000004c <main>:
- 4c: e92d4800 push {fp, lr}
- 50: e28db004 add fp, sp, #4
- 54: e24dd008 sub sp, sp, #8
- 58: e59f304c ldr r3, [pc, #76] ; ac <main+0x60>
- 5c: e3a02b55 mov r2, #87040 ; 0x15400
- 60: e5832000 str r2, [r3]
- 64: e3a03000 mov r3, #0
- 68: e54b3005 strb r3, [fp, #-5]
- 6c: ea00000a b 9c <main+0x50>
- 70: e59f3038 ldr r3, [pc, #56] ; b0 <main+0x64>
- 74: e55b2005 ldrb r2, [fp, #-5]
- 78: e2822005 add r2, r2, #5
- 7c: e3a01001 mov r1, #1
- 80: e1a02211 lsl r2, r1, r2
- 84: e1e02002 mvn r2, r2
- 88: e5832000 str r2, [r3]
- 8c: ebffffdb bl 0 <delay>
- 90: e55b3005 ldrb r3, [fp, #-5]
- 94: e2833001 add r3, r3, #1
- 98: e54b3005 strb r3, [fp, #-5]
- 9c: e55b3005 ldrb r3, [fp, #-5]
- a0: e3530003 cmp r3, #3
- a4: 9afffff1 bls 70 <main+0x24>
- a8: eaffffed b 64 <main+0x18>
- ac: 56000010 undefined instruction 0x56000010
- b0: 56000014 undefined instruction 0x56000014
- 000000b4 <start>:
- b4: e3a0da01 mov sp, #4096 ; 0x1000
- b8: ebffffe3 bl 4c <main>
- 000000bc <loop>:
- bc: eafffffe b bc <loop>
- Disassembly of section .ARM.attributes:
- 00000000 <.ARM.attributes>:
- 0: 00002741 andeq r2, r0, r1, asr #14
- 4: 61656100 cmnvs r5, r0, lsl #2
- 8: 01006962 tsteq r0, r2, ror #18
- c: 0000001d andeq r0, r0, sp, lsl r0
- 10: 00543405 subseq r3, r4, r5, lsl #8
- 14: 01080206 tsteq r8, r6, lsl #4
- 18: 04120109 ldreq r0, [r2], #-265 ; 0x109
- 1c: 01150114 tsteq r5, r4, lsl r1
- 20: 01180317 tsteq r8, r7, lsl r3
- 24: 061e021a undefined instruction 0x061e021a
- Disassembly of section .comment:
- 00000000 <.comment>:
- 0: 3a434347 bcc 10d0d24 <__bss_end__+0x10c8c64>
- 4: 74632820 strbtvc r2, [r3], #-2080 ; 0x820
- 8: 312d676e teqcc sp, lr, ror #14
- c: 312e362e teqcc lr, lr, lsr #12
- 10: 2e342029 cdpcs 0, 3, cr2, cr4, cr9, {1}
- 14: 00332e34 eorseq r2, r3, r4, lsr lr
看完后恍然一悟!!!!第一个执行的居然是delay()函数,而启动代码居然是在000000b4位置!!!就等于执行完delay()函数后跳到lr所指向的位置了,,,知道了这事情后,让我明白了,为什么裸机程序需要启动代码(用汇编写快些,当然也能用C写,反正也会编译成汇编,就是产生的汇编代码多了),然后我修改了makefile里的编译顺序后,,,led华丽地动起来啦~~~~~~~~~~