|
不久前尝试用gnu的工具编译二进制文件,以便在arm开发板上直接运行编写的C或汇编“裸 ”代码, 而不跑操作系统。做了个实验,学到一点点东西,欢迎拍砖。 我是在sitsang板上做的实验,并且用了redboot作为bootloader,使用bootloader主要是 因为下载方便,不要老是擦写flash,而且也可以学习一些工具如ld等的用法 我采用的代码是linux内核里面的vsprintf.c文件的代码,在文件最后加了一点程序, 这个文件是printk内部实现的主函数,可以参看源代码 ////////////////
char buf[1024]; int printk(const char *fmt, ...) { va_list args; int i;
va_start(args, fmt); i=vsprintf(buf,fmt,args); va_end(args); xscale_puts(buf);
return i; }
int _main() { int f = 234; printk("hello %d, world %d ", f, f); for(;;) /* loop forever */ }
上面的xscale_puts是uncompress.h里面的函数 /* uncompress.h */ #define UART FFUART
static __inline__ void xscale_putc(char c) { while (!(UART[5] & 0x20)); UART[0] = c; }
static void xscale_puts(const char *s) { while (*s) { xscale_putc(*s); if (*s == ' ') xscale_putc('\r'); s++; } } 由于是bootloader启动的,所以这里不需要对UART做任何配置,因为这里沿用的是redboot 的 UART配置,xscale_puts函数其实是linux启动的时打出Uncompress kernel..........的函 数。
然后又写了一个head.S, .section ".start", #alloc, #execinstr
.align start: .type start,#function b _main
这段代码仅仅跳到vsprintf.c的_main入口
然后开始编译和复制二进制文件: arm-linux-gcc -D__KERNEL__ -I/home/sitsang/linux-2.4.19/include -Wall \ -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict-aliasing -fno-common -Uarm \ -fno-common -pipe -g -mapcs-32 -D__LINUX_ARM_ARCH__=5 -mcpu=xscale -mtune=xscale \ -mshort-load-bytes -msoft-float -nostdinc -I \ /usr/local/arm-linux//lib/gcc-lib/arm-linux/3.2.1/include -DKBUILD_BASENAME=vsprintf \ -c -o vsprintf.o vsprintf.c
arm-linux-gcc -D__ASSEMBLY__ -D__KERNEL__ -I/home/sitsang/linux-2.4.19/include \ -mapcs-32 -D__LINUX_ARM_ARCH__=5 -mcpu=xscale -mno-fpu -msoft-float \ -c -o lib1funcs.o lib1funcs.S
arm-linux-ar rcs lib.a lib1funcs.o
arm-linux-ld -p -X -T vmlinux.lds head.o vsprintf.o lib.a -o test arm-linux-objcopy -O binary -R .note -R .comment -S test test.bin
这里的lib1funcs.S是arm的一些复杂运算函数的汇编代码,因为vsprintf.c里面要用到除法 和模运算, gcc编译时没问题,但是连接是却需要这些代码。在arch目录下,找了好久才找到,我把它 考出来了。
连接时的vmlinux.lds是从内核代码里面的脚本修改而来的,我将起始地址改为0xa0200000 , 因为redboot启动时将test.bin装载到物理内存0xa0200000,再跳到那里去执行。如果改成 0x00000000,然后将最后的二进制文件烧到0x0开始的flash也可,只是那样要烧flash。
OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS {
. = 0xa0200000;
.text : { *(.start) *(.text) *(.fixup) *(.gnu.warning) *(.rodata) *(.rodata.*) *(.glue_7) *(.glue_7t) . = ALIGN(4); }
_etext = .;
_got_start = .; .got : { *(.got) } _got_end = .; .got.plt : { *(.got.plt) } .data : { *(.data) } _edata = .;
. = ALIGN(4); __bss_start = .; .bss : { *(.bss) } _end = .;
.stack (NOLOAD) : { *(.stack) }
.stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } }
在完成test.bin的二进制文件的拷贝以后,启动开发板,到redboot,将其下载到 地址0xa0200000,然后执行go 0xa0200000,然后终端打出 hello 234, world 234
程序成功运行。
后记:一直想在linux下编写不上操作系统的“裸”试验程序,原因是人懒,嫌学习ADS 太麻烦,使用gnu工具生成可运行的代码,加深了对binultils的理解,也省了不少事。 :^)
|
|