编译uclinux下的应用程序和内核模块
早年写的笔记,压箱底了,翻出来晒晒
目 录
编译运行uClinux2.4的helloworld模块...6
编译运行uClinux2.6的helloworld模块...7
编译运行uClinux2.4的多文件helloworld模块...8
编译运行uClinux2.6的多文件helloworld模块...10
实验环境
IXP425DP(P720板) 266Mhz 64M ram16M flash
u Vmware6.5, 2CPU.
u FC4: kernel 2.6.11-1.1369_FC4smp(FC6也行),安装在虚拟机上
u arm-linux-tools-20051123.tar.gz:gcc 3.4.4编译器
u snapgear-3.5.0.tar.gz: snapgear发布的uClinux包
u snapgear-modules-20071004.sh: snapgear发布的uClinux包
u BSD_ixp400AccessLibrary-2_4.zip: IXP网卡驱动
u IPL_ixp400NpeLibrary-2_4.zip: IXP网卡驱动补丁
u files in /home/linuxuser/snapgear
编译应用程序的正确方法
编译uClinux的过程中,make menuconfig关于c库有三种:uClibc,uc-libc和glibc。在本系列实验过程中均使用了uClibc。因为采用了uClibc,编译的方法就有所不同。
编译运行Hello world程序
hello.c程序的源码如下,非常简单。
/***************************************************/
#include<stdio.h>
int main(void)
{
int i =0;
i += 9; //i only for extra information forlater debug
printf("hello world, i = %d\n",i);
return 0;
}
/***************************************************/
Makefile中arm-linux-gcc前面需要添加/home/linuxuser/snapgear/tools/ucfront-gcc
Makefile全文如下
/***************************************************/
KERNEL_UC_VERSION= linux-2.4.x
C_FLAGS =-mbig-endian -I/home/linuxuser/snapgear/$(KERNEL_UC_VERSION)/include -Wall -Wstrict-prototypes -O-fno-strict-aliasing -fno-common -Uarm -fno-common -pipe -mapcs-32-D__LINUX_ARM_ARCH__=5 -mcpu=xscale -mtune=xscale -malignment-traps
CC=/home/linuxuser/snapgear/tools/ucfront-gccarm-linux-gcc
arm:
$(CC) $(C_FLAGS) -o hello hello.c
pc:
gcc -o hello hello.c
clean:
rm -f *.o
rm hello
/***************************************************/
在helloworld程序所在目录执行
#exportPATH=$PATH:/home/linuxuser/usr/local/bin
#make arm
就会得到hello,下载到IX425DP的板子上运行hello,情形如下
# ./hello
hello world, i =9
当然也可以用make pc来先生成PC上可以运行的程序debug。
如果是编译uClinux2.6下的程序,把Makefile中的KERNEL_UC_VERSION= linux-2.4.x
改成KERNEL_UC_VERSION = linux-2.6.x就可以了
编译运行多文件Hello world程序
一共三个文件hello_lib.c,hello_lib.h, hello_main.c。CC的定义是关键。
Hello_lib.c如下
/***************************************************/
#include<stdio.h>
voidhelloworld(void)
{
int i =0;
i += 9;
printf("hello world, i = %d\n",i);
}
/***************************************************/
Hello_lib.h如下
/***************************************************/
voidhelloworld(void);
/***************************************************/
hello_main.c
/***************************************************/
#include<stdio.h>
#include"hello_lib.h"
int main(void)
{
helloworld();
return 0;
}
/***************************************************/
Makefile文件如下:
/***************************************************/
KERNEL_UC_VERSION= linux-2.4.x
C_FLAGS =-mbig-endian -I/home/linuxuser/snapgear/$( KERNEL_UC_VERSION)/include -Wall -Wstrict-prototypes -O-fno-strict-aliasing -fno-common -Uarm -fno-common -pipe -mapcs-32-D__LINUX_ARM_ARCH__=5 -mcpu=xscale -mtune=xscale -malignment-traps
CC=/home/linuxuser/snapgear/tools/ucfront-gccarm-linux-gcc
CC+=$(C_FLAGS)
OBJ=hello_main.ohello1.o
hello:$(OBJ)
$(CC) $(C_FLAGS) -o $@ $?
$(OBJ):hello1.h
clean:
rm -f *.o
rm hello
/***************************************************/
编译完成之后得到hello文件,运行效果和单文件的完全一样。
其中makefile中hello:$(OBJ)一句,hello定义最终的可执行文件的名字,可以修改为任意的名字。
如果是编译uClinux2.6下的程序,把Makefile中的KERNEL_UC_VERSION= linux-2.4.x
改成KERNEL_UC_VERSION = linux-2.6.x就可以了
编译应用程序的方法摸索
在此仅仅需要讨论单文件hello.c的编译执行情况。
很明确的一点是,必须使用arm-linux-gcc作为编译器,执行如下命令:
# arm-linux-gcc-o hello hello.c
得到hello文件下载到板子上执行,得到如下信息;
sh: ./hello: cannot execute binary file
Google“uclinux cannot execute binary file”,得知可以用file命令查看文件的属性
# file hello
hello: ELF 32-bit LSB executable, ARM,version 1 (ARM), for GNU/Linux 2.0.0,dynamically linked (uses shared libs), not stripped
查看一个能够在板子上正确执行的文件的属性
# file busybox
busybox: ELF 32-bit MSB executable, ARM,version 1 (ARM), for GNU/Linux 2.0.0,dynamically linked (uses shared libs), not stripped
很明显就是MSB和LSB的问题,猜想应该是编译选项的问题。参考查看make编译内核时的打印信息:
arm-linux-gcc -mbig-endian xxxxx之类的信息,应该就是这个选项了。
于是修改编译命令如下:
arm-linux-gcc -mbig-endian -o hello hello.c
在板子上执行得到如下结果
# ./hello
libc.so.6: aborted attempt to load ./hello!
Google libc.so.6,发现是编译库的问题。三个编译库uClibc,uc-libc和glibc有不同的库文件,libc.so.6应该是glibc的库文件。想到在编译内核的时候设置menuconfig,选择的是uClibc,那么应该include该库。但是不知道怎么才可以使用uClibc。于是故意menuconfig的busybox的一个选项,使make uClinux内核的时候多编译一个bunzip2程序,希望能够看到编译的信息。Make内核的时候,编译程序输出如下信息:
ucfront-gccarm-linux-gcc -mbig-endian -O1 -pipe -fno-common -fno-builtin -Wall -Dlinux -D__linux__ -Dunix -DEMBED-I/home/linuxuser/snapgear/user/busybox/include-I/home/linuxuser/snapgear/user/busybox/include -I -D_BSD_SOURCE -D__USE_BSD-Wall -Wstrict-prototypes -Wshadow -Os -fstrict-aliasing -fomit-frame-pointer-D_GNU_SOURCE -DNDEBUG -mbig-endian -c-o /home/linuxuser/snapgear/user/busybox/archival/bunzip2.o/home/linuxuser/snapgear/user/busybox/archival/bunzip2.c
很明显,除了多了很多编译选项意外,在arm-linux-gcc的前面多出了ucfront-gcc, google ucfront-gcc查到一篇文章。修改编译命令如下:
#/home/linuxuser/snapgear/tools/ucfront-gccarm-linux-gcc -mbig-endian -o hello hello.c
下载到板子上运行,正确打印出helloworld.
其他错误
在中间有一步,因为看到kernel编译的时候加上了不少选项,就基本上全部照抄,但是出现如下错误:
/home/linuxuser/usr/local/bin/../lib/gcc/arm-linux/3.4.4/../../../../arm-linux/bin/ld:ERROR: /home/linuxuser/snapgear/uClibc/lib/libc.so uses hardware FP, whereashello.o uses software FP
/home/linuxuser/usr/local/bin/../lib/gcc/arm-linux/3.4.4/../../../../arm-linux/bin/ld:failed to merge target specific data of file/home/linuxuser/snapgear/uClibc/lib/libc.so
/home/linuxuser/usr/local/bin/../lib/gcc/arm-linux/3.4.4/../../../../arm-linux/bin/ld:ERROR: /home/linuxuser/snapgear/uClibc/lib/crtn.o uses hardware FP, whereashello.o uses software FP
/home/linuxuser/usr/local/bin/../lib/gcc/arm-linux/3.4.4/../../../../arm-linux/bin/ld:failed to merge target specific data of file/home/linuxuser/snapgear/uClibc/lib/crtn.o
collect2: ld returned 1 exit status
make: *** [arm] Error 1
看样子应该是float运算的选项的错误,经过检查发现编译选项里面有-msoft-float,去掉以后错误就消失了。
编译内核模块
编译运行uClinux2.4的helloworld模块
Hello.c的内容如下
/***************************************************/
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/init.h>
static int __inithello_init(void)
{
int i = 9;
printk(KERN_ALERT "hellow world: i =%d\n", i);
return 0;
}
static void__exit hello_exit(void)
{
int i = 5;
printk(KERN_ALERT "bye, world: i =%d\n", i);
return;
}
module_init(hello_init);
module_exit(hello_exit);
/***************************************************/
Makefile 全文如下:
/***************************************************/
KERNELDIR=/home/linuxuser/snapgear/linux-2.4.x
CFLAGS =-D__KERNEL__ -I$(KERNELDIR)/include -Wall -Wstrict-prototypes -O -pipe-mapcs-32 -D__LINUX_ARM_ARCH__=5 -msoft-float -DMODULE -O2 -mbig-endian
CC =arm-linux-gcc
all: hello.o
clean:
rm -f hello.o
/***************************************************/
需要注意的一点是,编译module的时候不需要ucfront-gcc,并且可以使用-msoft-float,uclinux kernel编译的时候也是这样使用选项
下载到板子上运行,结果如下:
# insmod hello.o
Using hello.o
hellow world: i= 9
# lsmod
Module Size Used by
hello 208 0 (unused)
# rmmod hello
bye, world: i =5
编译运行uClinux2.6的helloworld模块
程序不用改,只要makefile改用如下内容
/***************************************************/
KERNELDIR=/home/linuxuser/snapgear/linux-2.6.x
CFLAGS =-D__KERNEL__ -I$(KERNELDIR)/include -Wall -Wstrict-prototypes -O -pipe-mapcs-32 -D__LINUX_ARM_ARCH__=5 -msoft-float -DMODULE -O2 -mbig-endian
CROSS_COMPILE=arm-linux-
CC=$(CROSS_COMPILE)gcc
PWD:=$(shellpwd)
#all: hello.o
obj-m=hello.o
default:
$(MAKE) -C $(KERNELDIR) ARCH=armCROSS_COMPILE=arm-linux- M=$(PWD)
clean:
rm -f *.o
rm -f *.ko
/***************************************************/
编译之后效果和kernel2.4的一样,唯一的不同是2.6的模块是ko文件而2.4的是o文件。
编译运行uClinux2.4的多文件helloworld模块
一共有5个文件:hello_main.c, hello_lib.c, hello_lib.h,Makefile
hello_lib.c源码如下
/***************************************************/
intincrease_int(int ori)
{
return (ori+1);
}
/***************************************************/
hello_main.c源码如下
/***************************************************/
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/init.h>
#include"hello_lib.h"
int test_int =5;
static int__init hello_init(void)
{
int i = 9;
printk(KERN_ALERT "hellow world: i =%d\n", i);
test_int = increase_int(test_int);
return 0;
}
static void__exit hello_exit(void)
{
int i = 5;
printk(KERN_ALERT "bye, world: i = %d, test_int= %d\n", i, test_int);
return;
}
module_init(hello_init);
module_exit(hello_exit);
/***************************************************/
hello_lib.h源码如下
/***************************************************/
intincrease_int(int ori);
/***************************************************/
Makefile文件如下:
/***************************************************/
#2.4arm-linux-gcc cross compile
ROOTDIR=.
include$(ROOTDIR)/make_config
INCLUDES =$(I_CINCLUDES)
COMMON_CFLAGS =$(INCLUDES)
CFLAGS +=$(I_CFLAGS)
CFLAGS +=$(COMMON_CFLAGS)
MODULE = hello.o
OBJS =hello_main.o hello_lib.o
all: $(OBJS)
$(LD) -EB -r -o $(ROOTDIR)/$(MODULE) $(OBJS)
$(OBJ_DIR)/%.o: %.c
@echo "Compiling $<"
$(CC) -c -o $@ $(CFLAGS) $<
clean:
rm -f $(OBJS)
rm -f *~
rm -f $(MODULE)
/***************************************************/
make_config文件如下:
/***************************************************/
OBJ_PATH=$(ROOTDIR)/obj
MAKE=/usr/bin/gmake
# If you arerunning a cross compiler, you may want to set this
# to somethingmore interesting, like "powerpc-linux-".
UCGCC =/home/linuxuser/snapgear/tools/ucfront-gcc
CROSS=arm-linux-
CC=/home/linuxuser/snapgear/tools/ucfront-gcc$(CROSS)gcc
AR=$(CROSS)ar
LD=$(CROSS)ld
STRIP=$(CROSS)strip
I_CFLAGS = -D__KERNEL__ -DMODULE \
-mcpu=xscale -mtune=xscale -mbig-endian\
-Wall -O2 # -DPREFERENCE_B_WIRE
CFLAGS = -mbig-endian-D__KERNEL__ -I/home/linuxuser/snapgear/linux-2.4.x/include -Wall -Wstrict-prototypes -Wno-trigraphs -O-fno-strict-aliasing -fno-common -Uarm -fno-common -pipe -mapcs-32-D__LINUX_ARM_ARCH__=5 -mcpu=xscale -mtune=xscale -malignment-traps -msoft-float-Uarm -DMODULE -DCPU=XSCALE -DXSCALE=33-DSIMSPARCSOLARIS=34 -DSIMLINUX=35 -D__linux-DIX_NPEDL_READ_MICROCODE_FROM_FILE -DIX_UTOPIAMODE=0 -DIX_MPHYSINGLEPORT=0-DIX_ACC_DRAM_PHYS_OFFSET=0 -D__ixp42X
I_CINCLUDES=-I/home/linuxuser/snapgear/linux-2.4.x/include
/***************************************************/
编译完成之后下载到板子上运行,结果如下
# insmod hello.o
Using hello.o
hellow world: i= 9
# lsmod
Module Size Used by
hello 320 0 (unused)
# rmmod hello
bye, world: i =5, test_int = 6
编译运行uClinux2.6的多文件helloworld模块
源码文件不需要改变,make_config文件也不需要。Makefile文件改成下面的内容
/***************************************************/
KERNELDIR=/home/linuxuser/snapgear/linux-2.6.x
CFLAGS =-D__KERNEL__ -I$(KERNELDIR)/include -Wall -Wstrict-prototypes -O -pipe-mapcs-32 -D__LINUX_ARM_ARCH__=5 -msoft-float -DMODULE -O2 -mbig-endian
CROSS_COMPILE=arm-linux-
CC=$(CROSS_COMPILE)gcc
PWD:=$(shellpwd)
#all: hello.o
obj-m:=hello.o
hello-objs:=hello_main.ohello_lib.o
default:
$(MAKE) -C $(KERNELDIR) ARCH=armCROSS_COMPILE=arm-linux- M=$(PWD)
clean:
rm -f *.o
rm -f *.ko
rm -f *.mod.c
/***************************************************/