C语言运行环境构建
创建start.s
① 设置6ULL处于SVC模式下。
图 1 9种运行模式
所有的处理器模式都共用一个CPSR物理寄存器,因此CPSR可以在任何模式下被访问。设置CPSR寄存器的bit4-0位10011=0X13。
读写状态寄存器需要用到MRS和MSR指令。MRS将CPSR寄存器数据读出到通用寄存器,MSR将通用寄存器的值写入到CPSR寄存器。
图 2 处理器模式位
② 设置SP指针
我们将SP指针指向DDR。512MB的DDR范围是0x80000000 - 0x9FFFFFFF。栈大小可以设置为0x200000 = 2MB,由于SP指针是向下增长的,所以我们将SP指向0x80200000。
③ 跳转到C语言
使用b指令,跳转到C语言函数,比如main函数。
汇编代码实现如下。
1 2 3 4 5 6 7 8 9
| .GLOBAL _start _start: MRS R0, CPSR BIC R0, #0x1F ORR R0, #0x13 MSR CPSR,R0
LDR SP,=0x80200000 b main
|
简单C语言实现
main.h
1 2 3 4 5 6 7 8 9 10 11 12
| #ifndef _main_h_ #define _main_h_
#define CCM_CCGR1 *((volatile unsigned int*)0x020C406C)
#define SW_MUX_GPIO1_IO03 *((volatile unsigned int *)0X020E0068) #define SW_PAD_GPIO1_IO03 *((volatile unsigned int *)0X020E02F4)
#define GPIO1_DR *((volatile unsigned int *)0X0209C000) #define GPIO1_GDIR *((volatile unsigned int *)0X0209C004)
#endif
|
main.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| #include "main.h" void Clk_En() { CCM_CCGR1 = 0xffffffff; }
void LED_Init() { SW_MUX_GPIO1_IO03 = 0x5; SW_PAD_GPIO1_IO03 = 0x10B0; GPIO1_GDIR = 0x8; }
void delay_short(volatile unsigned int n) { while(n--); }
void delay(volatile unsigned int ms) { while(ms--) { delay_short(0x7ff); } }
void Led_Set_Pin(int a) { if(a == 0) { GPIO1_DR &= ~(1 << 3); } else if(a == 1) { GPIO1_DR |= (1 << 3); } else return; }
int main() { Clk_En(); LED_Init(); while(1) { delay(500); Led_Set_Pin(1); delay(500); Led_Set_Pin(0); } return 0; }
|
编写MakeFile
思路:首先将objs定义为最终目标ledc.bin的依赖目标集合,第3行定义了ledc.bin的生成必须要objs中的文件,当你有了objs中的文件后把代码段(.text)放到地址0x87800000后生成ledc.elf,再将ledc.elf转换为bin文件。第9-15行规定了对应每一种文件编译到.o文件的规则。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| objs := start.o main.o
ledc.bin : $(objs) arm-linux-gnueabihf-ld -Ttext 0x87800000 -o ledc.elf $^ arm-linux-gnueabihf-objcopy -O binary -S ledc.elf $@
%.o :%.s arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<
%.o: %.S arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<
%.o: %.c arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $< clean: rm -rf *.o ledc.bin ledc.elf ledc.dis
|
链接脚本的编写
下面这段代码规定了可执行代码段从0X87800000开始。.rodata表示只读数据段,跟在.text段的后面,ALIGN(4)表示保证4字节对齐,.data表示已初始化的全局变量,.bss表示未初始化的全局变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| SECTIONS{ . = 0X87800000; .text: { start.o main.o *(.text) } .rodata ALIGN(4) :{*(.rodata*)} .data ALIGN(4):{*(.data)} __bss_start = .; .bss ALIGN(4) : { *(.bss) *(COMMON) } __bss_end = .; }
|
编译完链接脚本后,将MakeFile的第四行改为
arm-linux-gnueabihf-ld -Timx6ul.lds -o ledc.elf $^
运行结果
图 3 运行结果