[讨论] [分享][转帖]用GNU工具编译二进制文件

duandi   2006-12-28 09:16 楼主
不久前尝试用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的理解,也省了不少事。
:^)

回复评论

暂无评论,赶紧抢沙发吧
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复