从汇编到C
一. 设置栈
1.1. C语言运行时需要和栈的意义
1.1.1. “C语言运行时(runtime)”需要一定的条件,这些条件由汇编来提供。C语言运行时主要是需要栈
1.1.2. C语言与栈的关系
a. C语言中的局部变量都是用栈来实现的。如果我们汇编部分没有给C部分预先设置合理合法的栈地址,那么C代码中定义的局部变量就会落空,整个程序就死掉了。
b. 我们平时在编写单片机程序(譬如51单片机)或者编写应用程序时并没有去设置栈,但是C程序还是可以运行的。原因是:在单片机中由硬件初始化时提供了一个默认可用的栈,在应用程序中我们编写的C程序其实并不是全部,编译器(gcc)在链接的时候会帮我们自动添加一个头,这个头就是一段引导我们的C程序能够执行的一段汇编实现的代码,这个代码中就帮我们的C程序设置了栈及其他的运行时需要。
1.1.3. CPU模式和各种模式下的栈
1.1.3. 在ARM中37个寄存器中,每种模式下都有自己的独立的SP寄存器(r13),为什么这么设计?
a. 如果各种模式都使用同一个SP,那么就意味着整个程序(操作系统内核程序、用户自己编写的应用程序)都是用一个栈的。你的应用程序如果一旦出错(譬如栈溢出),就会连累操作系统的栈也损坏,整个操作系统的程序就会崩溃。这样的操作系统设计是非常脆弱的,不合理的。
b. 解决方案就是各种模式下用不同的栈。我的操作系统内核使用自己的栈,每个应用程序也使用自己独立的栈,这样各是各的,一个损坏不会连累其他人。
PS: S5PV210系统在复位后默认是进入SVC模式的,裸机程序运行在此模式
1.2. 汇编程序设置栈
a. 栈必须是当前一段可用的内存(可用的意思是这个地方必须有被初始化过可以访问的内存,而且这个内存只会被我们用作栈,不会被其他程序征用)
b. 当前CPU刚复位(刚启动),外部的DRRAM尚未初始化,目前可用的内存只有内部的SRAM(因为它不需初始化即可使用)。因此我们只能在SRAM中找一段内存来作为SVC的栈。
c. 栈有四种:满减栈 满增栈 空减栈 空增栈,详情查看《ARM汇编3》
d. 查阅《iROM_application_note》中的memory map,可知SVC栈应该设置为0xd0037D80
#define SVC_STACK 0xd0037d80 ldr sp, = SVC_STACK @set stack
二. 使用c编程
2.1. 汇编启动代码
a. 设置栈地址
b. 调用C函数led_blink
/* * file name :set_stack.S * author: MUSK * description:set stack, */ #define WATCHCON 0xE2700000 #define SVC_STACK 0xd0037d80 .global _start _start: ldr r1, =WATCHCON @Watchdog Timer Control Register address ldr r0, [r1] @config corresponding register and r0, r0,#(~(0x01<<5)) @config corresponding register str r0, [r1] ldr sp, = SVC_STACK @set stack bl led_blink b . @while(1)
2.2. 编写C文件
a. 该文件主要实现LED的闪烁
#define GPJ0CON ((volatile unsigned int *)0xE0200240) #define GPJ0DAT ((volatile unsigned int *)0xE0200244) void delay(void); void led_blink(void) { //led初始化, *GPJ0CON &=0xff000fff; *GPJ0CON |=0x00111000; while(1) { *GPJ0DAT &=~((0x01<<3)|(0x01<<4)|(0x01<<5)); delay(); *GPJ0DAT |=((0x01<<3)|(0x01<<4)|(0x01<<5)); delay(); } } void delay(void) { volatile unsigned int times =900000; while(times--); }
三. 编译测试
3.1. 编译前Makefile文件
set_stack.bin: set_stack.o led.o arm-linux-ld -Ttext 0x0 -o set_stack.elf $^ arm-linux-objcopy -O binary set_stack.elf set_stack.bin arm-linux-objdump -D set_stack.elf > set_stack_elf.dis gcc mkv210_image.c -o mkx210 ./mkx210 set_stack.bin 210.bin %.o : %.S arm-linux-gcc -o $@ $< -c %.o : %.c arm-linux-gcc -o $@ $< -c clean: rm *.o *.elf *.bin *.dis mkx210 -f
3.2. 编译结果
a. 编译报错:led.o:(.ARM.exidx+0x0): undefined reference to `__aeabi_unwind_cpp_pr1'
b. google问题后解决方法是编译命令后加上-nostdlib
root@ubuntu:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2# ls led.c Makefile mkv210_image.c set_stack.S write2sd 说明.txt root@ubuntu:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2# root@ubuntu:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2# root@ubuntu:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2# make arm-linux-gcc -o set_stack.o set_stack.S -c #-nostdlib arm-linux-gcc -o led.o led.c -c #-nostdlib arm-linux-ld -Ttext 0x0 -o set_stack.elf set_stack.o led.o led.o:(.ARM.exidx+0x0): undefined reference to `__aeabi_unwind_cpp_pr1' led.o:(.ARM.exidx+0x8): undefined reference to `__aeabi_unwind_cpp_pr0' make: *** [set_stack.bin] Error 1 root@ubuntu:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2#
3.3. 修改后的Makefile文件
a. 增加-nostdlib
set_stack.bin: set_stack.o led.o arm-linux-ld -Ttext 0x0 -o set_stack.elf $^ arm-linux-objcopy -O binary set_stack.elf set_stack.bin arm-linux-objdump -D set_stack.elf > set_stack_elf.dis gcc mkv210_image.c -o mkx210 ./mkx210 set_stack.bin 210.bin %.o : %.S arm-linux-gcc -o $@ $< -c -nostdlib %.o : %.c arm-linux-gcc -o $@ $< -c -nostdlib clean: rm *.o *.elf *.bin *.dis mkx210 -f
b. 重新make
root@ubuntu:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2# make clean rm *.o *.elf *.bin *.dis mkx210 -f root@ubuntu:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2# make arm-linux-gcc -o set_stack.o set_stack.S -c -nostdlib arm-linux-gcc -o led.o led.c -c -nostdlib arm-linux-ld -Ttext 0x0 -o set_stack.elf set_stack.o led.o arm-linux-objcopy -O binary set_stack.elf set_stack.bin arm-linux-objdump -D set_stack.elf > set_stack_elf.dis gcc mkv210_image.c -o mkx210 ./mkx210 set_stack.bin 210.bin root@ubuntu:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2#
参考《朱老师.1.2ARM裸机课件》