不久前尝试用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的理解,也省了不少事。
:^)