编译uclinux下的应用程序和内核模块

时间:2022-09-28 22:30:27

编译uclinux下的应用程序和内核模块

早年写的笔记,压箱底了,翻出来晒晒

 

        录

编译uclinux下的应用程序和内核模块...1

      ... 1

实验环境...1

编译应用程序的正确方法...2

编译运行Helloworld程序...2

编译运行多文件Helloworld程序...3

编译应用程序的方法摸索...4

其他错误...5

编译内核模块...6

编译运行uClinux2.4的helloworld模块...6

编译运行uClinux2.6的helloworld模块...7

编译运行uClinux2.4的多文件helloworld模块...8

编译运行uClinux2.6的多文件helloworld模块...10

编译运行内核模块的摸索...11

invalid module format错误...11

多文件helloworld模块错误...11

快速找到内核编译的语句...12

 

 

实验环境

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-floatuclinux 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.hMakefile

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

/***************************************************/