长时间写java程序,但从来没去研究main函数是如何执行的,今天学习嵌入式终于知道了原理。
之前看过一本30天做一个操作系统这本书,可以通过写个2进制文件来启动系统。然后进化到汇编语言,通过工具把汇编转为二进制一样可以启动系统(虚拟机)。这个系统的执行过程与我们的main函数有什么联系么。做java的同学知道,只要执行java命令自然会执行main函数。做c语言的同学,知道在编译后执行可执行文件(sha.out)自然也会执行main函数。但为什么呢?看下面这段汇编代码:
.text.global_start_start:ldrr0,=0x
WATCHDOG寄存器地址movr1,#0x0strr1,[r0]写入0,禁止WATCHDOG,否则CPU会不断重启ldrsp,=*4设置堆栈,注意:不能大于4k,因为现在可用的内存只有4Knandflash中的代码在复位后会移到内部ram中,此ram只有4Kblmain调用C程序中的main函数halt_loop:bhalt_loopstart段开始后的前3行是关门看门狗程序,防止重启。ldr是设置一个4k的内存,也就是程序的存放地址。bl就是调用main函数了,后面是死循环不用管。
下面我们再写段C语言:#defineGPFCON(*(volatileunsignedlong*)0x)#defineGPFDAT(*(volatileunsignedlong*)0x)intmain(){GPFCON=0x;//设置GPF4为输出口,位[8:7]=0b01GPFDAT=0x;//GPF4输出0,LED1点亮return0;}
上面两个宏是定义控制寄存器的地址,为什么是0x,这是从板子的数据手册中找到的。如下图:
最后这个c语言程序与汇编程序如何连起来呢?看makefile文件:arm-linux-gcc-g-c-ocrt0.ocrt0.Sarm-linux-gcc-g-c-oled_on_c.oled_on_c.carm-linux-ld-Ttext0x-gcrt0.oled_on_c.o-oled_on_c_elfarm-linux-objcopy-Obinary-Sled_on_c_elfled_on_c.binarm-linux-objdump-D-marmled_on_c_elfled_on_c.dis
先编译汇编程序(crto.S),再编译c语言(led_on_c.c),再把这两生成的目标文件链接为led_on_c_elf文件,再把这个转为二进制文件。这个就可以烧进板子执行了。其实30天制作操作系统也可以通过这个方法也制作,不过工具不是arm-linux_gcc,我们这也相当于在开始制作一个系统了。