momo zone

调核人的blog

Monthly Archives: 七月 2010

上海浦东高级苹果摊

周末我有幸去了一下浦东苹果旗舰店。 本来打算开业那天就去,但看到全国各地的粉丝涌向那里 ,我作为一个伪果粉自然不敢围观,生怕自己的脑残形象上了各IT版面的头条。

这周末去了,感觉没什么太新奇,除了那价值连城的玻璃和光亮如新的毛玻璃下沉式旋转阶梯,其他没有什么特别的印象。没有ipad,没有iphone (不用怀疑,联通的行货iphone也没有,难道说apple根本就不承认阉割版?)。 看到整齐的imac和itouch,mac book 我感到深深的审美疲劳。 不过令人惊奇的是这里有众多萝丽和正太的身影,围在imac前玩弄着jobs 精心设计的小游戏(说实话我没看清楚那具体是什么)。我不免为身边家长的钱包担心 。
店里的“精英销售团体”正在和有意购买的用户充分讲解mac的好处,这些销售不知道薪资比太平洋里的装机商高多少,据说还有海归。我也看到一个女生现场买了一台macbook pro 高配版,我心里暗想,钱多人傻阿,买港水可以便宜3000多RMB。 来这里可以看到唯一不同的是,很多正版软件摆在那里,以及很多正品配件。我上去看了一下,一个键盘保护膜相当不错,看了一下价格 230RMB 晕了,我的工包G6也没有超过130RMB 。再看一下15米超6类屏蔽双绞线,280RMB ,再次晕倒。膜拜一下吧,不过这网线确实不错,15米掂量了一下快有1斤重了。
出去的时候我看到一个手拿iphone 3GS,背着mac book电脑包 带着印有黑苹果太阳帽的年轻人急匆匆走进店里。在我看来果粉其实已经和nike ,阿迪的超级粉丝没有什么区别了,都是这个时代的嘲人,领先了中国目前至少10年消费水准的一群年轻人。
写到这里正好受到apple的邮件了,新品5连发:
全新MAC PRO , 最高I7 X2 共16核心
全新i3,i5,i7 IMAC
全新MAC cinema display
新品多点触摸板
新品AA电池充电套装(这个令人比较意外)

Advertisements

gcc 常用参数

突然想回顾一下gcc 的编译参数了,于是就翻翻了gnu的站点,看看手册, Oh my God ,几年没看,又多了一堆参数, 好吧我承认我不是编译方面的专家,也不是吃嵌入式这碗饭的,随便看看而已。

 
自己常用的参数还是如下几个(陆续补充中):


-c : 编译,汇编,但不做最终连结(输出.o文件)
-S : 只进行编译(输出汇编码.s文件)

-E : 将预处理结果写入档名
-o filename : 指定输出档名 
-ansi : 程式要求依据ansi c标准 
-Dmacro : 使定义宏(marco)为有效 
-Dmarco=defn : 使定义宏(marco)为defn
 

-Wa,option : 将选项(option)传给编译器 
-Wl,option : 将选项(option)传给连结器 
-I : 追加include档案的搜寻路径 
-L : 追加library档案的搜寻路径 
-l : 指定连结的函式库(比如libusb 就是-lusb , 会自动根据ld 的设置来找到库文件) 
-Wall : 显示所有的警告讯息 
-g : 编入除错资讯(要使用GDB除错一定要加) 
-O2 : 做最佳化 
※ 使用范例 

Example: 

gcc -o file a.c b.c c.c 
gcc -Wall -g -o test test.c 
gcc -Iinclude -Llibrary -lmy_lib -o test1 test1.c 
gcc -DDEBUG_ON -o test2 test2.c 
gcc -c -o test3 test.c 

编译内核模块问题总结

这里遇到的问题绝大多数都是内核配置不满足造成的:

这里假设执行了make mrproper,模块源码在外部代码树。

question 1:
make: Entering directory `/usr/src/linux-2.6.34-12′

ERROR: Kernel configuration is invalid.
include/generated/autoconf.h or include/config/auto.conf are missing.
Run ‘make oldconfig && make prepare’ on kernel src to fix it.


WARNING: Symbol version dump /usr/src/linux-2.6.34-12/Module.symvers
is missing; modules will have no dependencies and modversions.

CC [M]  /root/mymod.o
/root/mymod.c:1:0: error: code model ‘kernel’ not supported in the 32 bit mode
/root/mymod.c:1:0: sorry, unimplemented: 64-bit mode not compiled in
make[1]: *** [/root/mymod.o] Error 1
make: *** [_module_/root] Error 2
make: Leaving directory `/usr/src/linux-2.6.34-12′

很明显kernel 编译配置没有指定。
copy boot 下的当前内核配置档然后执行下列:
make oldconfig

HOSTCC  scripts/basic/fixdep
HOSTCC  scripts/basic/docproc
HOSTCC  scripts/basic/hash
HOSTCC  scripts/kconfig/conf.o
HOSTCC  scripts/kconfig/kxgettext.o
SHIPPED scripts/kconfig/zconf.tab.c
SHIPPED scripts/kconfig/lex.zconf.c
SHIPPED scripts/kconfig/zconf.hash.c
HOSTCC  scripts/kconfig/zconf.tab.o
HOSTLD  scripts/kconfig/conf
scripts/kconfig/conf -o arch/x86/Kconfig
#
# configuration written to .config
#
这样就配置好了kconfig
make prepare

scripts/kconfig/conf -s arch/x86/Kconfig
CHK     include/linux/version.h
UPD     include/linux/version.h
CHK     include/generated/utsrelease.h
UPD     include/generated/utsrelease.h
CC      kernel/bounds.s
GEN     include/generated/bounds.h
CC      arch/x86/kernel/asm-offsets.s
GEN     include/generated/asm-offsets.h
CALL    scripts/checksyscalls.sh

question 2:

再次执行编译提示:
make: Entering directory `/usr/src/linux-2.6.34-12′

WARNING: Symbol version dump /usr/src/linux-2.6.34-12/Module.symvers
is missing; modules will have no dependencies and modversions.

CC [M]  /root/mymod.o
/root/mymod.c: In function ‘__inittest’:
/root/mymod.c:13:1: warning: return from incompatible pointer type
Building modules, stage 2.
MODPOST 1 modules
/bin/sh: scripts/mod/modpost: No such file or directory
make[1]: *** [__modpost] Error 127
make: *** [modules] Error 2
make: Leaving directory `/usr/src/linux-2.6.34-12′

看样子是modpost 不存在的原因,google了一下 发现应该 再执行一下
make scripts:

HOSTCC  scripts/genksyms/genksyms.o
SHIPPED scripts/genksyms/lex.c
SHIPPED scripts/genksyms/parse.h
SHIPPED scripts/genksyms/keywords.c
HOSTCC  scripts/genksyms/lex.o
SHIPPED scripts/genksyms/parse.c
HOSTCC  scripts/genksyms/parse.o
HOSTLD  scripts/genksyms/genksyms
CC      scripts/mod/empty.o
HOSTCC  scripts/mod/mk_elfconfig
MKELF   scripts/mod/elfconfig.h
HOSTCC  scripts/mod/file2alias.o
HOSTCC  scripts/mod/modpost.o
HOSTCC  scripts/mod/sumversion.o
HOSTLD  scripts/mod/modpost
HOSTCC  scripts/selinux/genheaders/genheaders
HOSTCC  scripts/selinux/mdp/mdp
HOSTCC  scripts/kallsyms
HOSTCC  scripts/conmakehash
HOSTCC  scripts/bin2c
还有一个make modules_prepare 其实就是make prepare + make scripts


question 3:


再次执行编译,终于ok了,不过还有一个warning 现不管他了

make: Entering directory `/usr/src/linux-2.6.34-12′

WARNING: Symbol version dump /usr/src/linux-2.6.34-12/Module.symvers
is missing; modules will have no dependencies and modversions.

Building modules, stage 2.
MODPOST 1 modules
CC      /root/mymod.mod.o
LD [M]  /root/mymod.ko
make: Leaving directory `/usr/src/linux-2.6.34-12′

执行insmod ./mymod.ko 提示
insmod: error inserting ‘./mymod.ko’: -1 Invalid module format
无效格式? 看看日志
tail -f /var/log/message
Jul 26 20:47:39 linux kernel: [468192.584691] mymod: no symbol version for module_layout

起初以为内核源码中关于版本的几个宏没有定义呢, 结果忙活了半天还是不行,只能google 大法了,
原因是那个warning处提到的Module.symvers 没有找到,它应该在内核代码树的根目录下。
然后不用想了,应该是执行一次内核完整编译就应该有了,但这样的话还必须安装一次自己编译的内核。官方应该有某个包里有这个文件,去找这个文件属于哪个包吧。
这里让人疑惑的是suse 没有kernel-header 这个包 ,也没有其他包中含有这个文件。 最后突然想到去/boot 下去翻一下。 果然在这里:
symvers-*.gz (还有这里也有:/usr/src/linux-2.6.34-12-obj/i586/desktop/Module.symvers )
需要用gunzip 解压(注意这是单个gzip文件,不是tar包), 然后copy过去就ok了

make: Entering directory `/usr/src/linux-2.6.34-12′
Building modules, stage 2.
MODPOST 1 modules
CC      /root/mymod.mod.o
LD [M]  /root/mymod.ko
make: Leaving directory `/usr/src/linux-2.6.34-12
关于Module.symvers的本质 由下面的问题描述:
CONFIG_MODVERSIONS 用来决定是否开启版本控制,该选项防止将接口定义和当前内核版本不再匹配的废弃模块载入内核。

在编译 vmlinux 时,最后会利用 modpost 来解析 vmlinux.o 对象文件,并将基本内核导出的所有符号都记录到文件 Module.symvers 中去。如果没有打开 CONFIG_MODVERSIONS 选项,那么你看到的 Module.symvers 文件中第一列符号 CRC 校验值都是 0x00000000 。如果打开该选项,那么第一列就会显示出各个符号的 CRC 校验值,如:

0x2d6c0f40      put_mnt_ns      vmlinux EXPORT_SYMBOL
0x6c386a8c      clear_bdi_congested     vmlinux EXPORT_SYMBOL
… …

一旦设置过这个配置选项,就意味着打开了内核的 Module versioning功能。Module versioning 功能应用在我们使用模块的场合。如果 Module versioning 功能被打开的话,它会以每个导出符号的 C 原型声明作为输入,计算出对应的CRC校验值,保存在文件 Module.symvers 中。如此一来,内核在后面要加载使用模块的时候,会两相比较模块中的CRC值和保存下来的CRC值,如果发现不相等,内核就拒绝加载这个模块。

内核模块编译方法

以往的内核版本中, 编译内核模块比较麻烦, 需要我们对这些Makefile做出许多更改. 2.6的内核采用了"kbuild"编译系统, 简化了这些问题. 关于kbuild, 可参考内核源码树中的 /Documentation/kbuild/modules.txt.

编译之前, 肯定是需要源文件的. 这些源文件可以放在内核源码树中, 也可以放在内核源码树之外的任何地方. 根据源文件存在的目录, 存在两种编译方法: 在源码树之中和在源码树之外.

在源码树中编译模块

官方内核模块的源代码都是按模块(驱动)类型组织的, 我们到内核源码树的drivers目录可以看到char, usb, block之类的子目录. 那么我们在内核源码树中添加文件时, 最好也遵循这些分类. 分类的规则自己灵活把握.

下面以前面的"hello, world"这个简单的模块为例, 来看看如何在内核源码树中编译内核模块.

1, 不新建子目录

(1) 先在内核源码树中的drivers目录编辑一个c源程序, 名为hello.c.
(2) 修改drivers目录的Makefile文件, 添加: obj-m += hello.o
(3) 重新编译内核(回到源码树根目录, 运行 $ sudo make).

这样, 在drivers目录多出了这样几个文件: hello.mod.c, hello.mod.o, hello.o, hello.ko. hello.ko就是编译出来的模块了.

2, 新建子目录

如果源文件比较多, 可以在drivers目录中新建子目录. 还是以hello, world为例:

(1) 在内核源码树的drivers目录中新建一个hello子目录, 并将hello.c放在hello目录中.
(2) 修改drivers目录的Makefile文件, 添加: obj-m += hello/
(3) 在hello目录中新建一个Makefile文件, 内容为: obj-m += hello.o
(4) 重新编译内核(回到源码树根目录, 运行 $ sudo make).

这样, 新生成的模块文件就位于hello目录中.

若在内核源码树中编译内核模块, 如果不新建子目录, 那么只需修改当前目录的Makefile, 否则应该在当前新建的子目录中新建Makefile指定编译选项, 并修改上层目录的Makefile以让kbuild能够进入新建的子目录.

在源码树之外编译模块

还是以上面的hello, world为例. 在当前目录有个hello.c:

(1)首先在模块代码所在的目录新建一个Makefile, 内容为:

obj-m := hello.o

(2)这样调用make命令:

$ sudo make -C /usr/local/src/kernel/linux-2.6.16.20 SUBDIRS=$PWD modules

这里/usr/local/src/kernel/linux-2.6.16.20是内核源码树所在的目录.

-C表示要求make先切换到-C指定的目录. SUBDIRS(也可以用M代替SUBDIRS)使make在编译内核模块之前回到当前目录.

整个编译过程实际上是执行-C指定的内核源码树的Makefile, 并通过SUBDIR指定你要编译的内核源文件的目录.

简化命令行输入

每次调用make的时候输入这些参数比较比较麻烦, 可以这样来改写Makefile以简化:

obj-m += hello.oall: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modulesclean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
这样, 只需在当前目录调用 $ sudo make 就可以完成上面的工作. 调用 $ sudo make clean 将删除所有新生成的文件.

上面的Makefile是这样确定内核源码树所在的目录的: 我们先到/lib/modules目录, 会看到一些以内核版本为名的目录, 目录中有一个build文件, 它是一个符号连接, 指向内核源码树. 那么如何确定进入哪个内核版本的目录呢? 这就可以通过 $ uname -r 来确定, 它指出了当前运行内核的版本.

还可以进一步简化这个Makefile:

  1. obj-m :hello.o  
  2. KERNELDIR ?= /lib/modules/$(shell uname -r)/build  
  3. PWD := $(shell pwd)  
  4. default:   
  5. $(MAKE) -C $(KERNELDIR) M=$(PWD) modules  
  6. clean:   
  7. $(MAKE) -C $(KERNELDIR) M=$(PWD) clean 

这样不用在Makefile中一次又一次地指定内核代码树的目录.

上面的例子中只讨论了所有的代码在一个文件中的情况. 若代码分布在多个源文件中, 比如file1.c, file2.c, 生成hello.ko. 应该这样写Makefile:

  1. obj-m :hello.o  
  2. hello-objs :file1.o file2.o 

注意, 虽然我们的目的是生成.ko文件, 但在Makefile中写为.o!

将TXT档读入MYSQL数据库

需要把SAP 的数据放到Mysql 数据库中,由于没有搞定SAP的interface 也没有搞定MSSQL的DA 所以只能先把SAP的数据导成TXT,然后再导入Mysql 。以为导入mysql需要自己去写脚本,没想到mysql软件包中自带了一个mysqlimport ,这样省得自己动手了。
 
$mysqlimport -u root -padmin -d –local 218DB MSEG.txt
 
这里解释一下
-u 接db连接的用户名
-p 紧接用户名密码,注意中间没有空格
-d 表示在插入前先清空表
218DB 是数据库名,区分大小写
MSEG.txt  是要上传的数据,文件名即使对应的数据库表,区分大小写。
–local 直接从本地上传文档,而不是通过远程,管道文件或mysql的其他机制来获得文件。
 

深入介绍ucLinux

网上google到的一篇文章,写得比较全面

深入介绍ucLinux

一,嵌入式Linux的分类

n第一类是在利用Linux强大功能的前提下,使它尽可能的小,以满足许多嵌入式系统对体积的要求,如uClinux(http://www.uclinux.org); 
第二类是将Linux开发成实时系统尤其是硬/firm实时系统,应用于
一些关键的控制场合,如Fsmlabs公司(http://www.rtlinux.org)的RTLinux、MontaVista(http://www.mvista.com)的Hard Hat Linux等; 
第三类的产品就是将实时性和嵌入式方案结合起来的方案,很多公
司都这么做,并且提供集成化的开发方案,如Lineo、TimeSys、合肥华恒等。

为什么要使用uCLinux,什么是uCLinux?

全球每年生产的CPU的数量在二十亿颗左右,超过80%应用于专用性很强的各类嵌入式系统。其中又有相当一部分面向低端市场。为降低硬件成本及运行功耗,有一类CPU在设计中取消了内存管理单元(Memory Management Unit,简称MMU)功能模块。如Motorola公司的M68328、M68EN322 、MC68360、DragonBall系列如68EZ328、68VZ328,ColdFire系列的如5272、5307,ARM7TDMI and MC68EN302、ETRAX、Intel i960、PRISMA、Atari 68k等等。
标准Linux针对有MMU的处理器设计。在这种处理器上,虚拟地址被送
到MMU,把虚拟地址映射为物理地址。通过赋予每个任务不同的虚拟地址/物理地址转换映射,可支持不同任务之间的保护。
      最初,运行于这类没有MMU的CPU之上的都是一些很简单的单任务操作系统,或者更简单的控制程序,甚至根本就没有操作系统而直接运行应用程序。在这种情况下,系统无法运行复杂的应用程序,或者效率很低,而且,所有的应用程序需要重写,并要求程序员十分了解硬件特性。这些都阻碍了应用于这类CPU之上的嵌入式产品开发的速度。然而,随着uCLinux的诞生,这一切都改变了。

uCLinux是一个完全符合GNU/GPL公约的项目,完全开放代码,现由Lineo公司支持维护。英文单词中u表示Micro,小的意思,C表示Control,控制的意思,所以uCLinux就是Micro-Control-Linux,字面上的理解就是“微控制领域中的Linux系统”。它专门针对没有MMU的CPU,并专为嵌入式系统做了许多小型化的工作,已支持前面提到的多款CPU。官方主页在http://www.uclinux.org。国内从事uclinux开发有合肥华恒科技等几家公司 。


已成功使用uCLinux的案例(部分)

合肥华恒的基于coldfire 5272/5407的家庭网关Soho/Home/VPN Router、基于68EZ328的PDA开发套件
Maple 信号处理公司基于DragonBallVZ和TMS320C541xx DSP的DAQStick 系列嵌入式信号处理板卡
珠海万禾的基于VZ328的多串口设备Webport2000,基于68VZ328的PDA开发套件
Lineo 公司的uCsimm、uCdimm开发套件以及商业音乐媒体服务器BMMS-MP3.COM采用 
西南交通大学电气检测与故障诊断信息研究室的嵌入式电力设备运行状态监测系统
NetSilicon公司 NET+Works设备网络平台(基于ARM7TDMI)-为Wireless Networks 公司的BlueLAN 提供接入点
东软的智能家庭网关产品
爱立信的基于ARM7TDMI蓝芽BLIP无线通信设备
基于ARM7TDMI的Aplio公司的voice-over-IP电话
AXIS公司的AXIS2001网络数码相机
Adomo公司的家庭机顶盒
Snapsear的VPN安全设备
瑞士洛桑的Smartdata公司的微型计算机Chipslice

  

标准Linux使用的虚拟存储器技术


◇标准Linux是针对有内存管理单元的处理器设计的。虚拟地址被送到内存管理单元(MMU),把虚拟地址映射为物理地址。采用分页的方式来载入进程。实际存储器分割为相同大小的页面。
◇虚拟存储器由存储器管理机制及一个大容量的快速硬盘存储器支持。它的实现基于局部性原理,当一个程序在运行之前,没有必要全部装入内存,而是仅将那些当前要运行的那些部分页面装入内存运行(copy-on-write),其余暂时留在硬盘上程序运行时如果它所要访问的页已存在,则程序继续运行,如果发现不存在的页,操作系统将产生一个页失效异常,导致操作系统把需要运行的部分加载到内存中。必要时操作系统还可以把不需要的内存页交换到磁盘上。
◇通过赋予每个任务不同的虚拟–物理地址转换映射(页表),还可支持不同任务之间的保护、共享等。
◇对于多进程管理当处理器进行进程切换并执行一个新任务时,一个重要部分就是为新任务切换页表。
◇可以运行只加载了部分的程序,缩短了程序启动的时间
◇运行比内存还要大的程序。理想情况下应该可以运行任意大小的程序 ◇可以使多个程序同时驻留在内存中提高CPU的利用率 
◇可以运行重定位程序。即程序可以方于内存中的任何一处,而且可以在执行过程中移动 
◇写机器无关的代码。程序不必事先约定机器的配置情况 
◇减轻程序员分配和管理内存资源的负担
◇可以进行程序代码共享 
◇提供内存保护,进程不能以非授权方式访问或修改页面,内核保护单个进程的数据和代码以防止其它进程修改它们。否则,用户程序可能会偶然(或恶意)的破坏内核或其它用户程序 

代价:内存管理需要地址转换表和其他一些数据结构,留给程序的内存减少了。地址转换增加了每条指令的执行时间,而对于有额外内存操作的指令会更严重。当进程访问不在内存的页面时,系统处理失效的磁盘I/O操作极耗时间。

uClinux针对无MMU的特殊处理

uClinux针对没有MMU的处理器设计,不能使用处理器的虚拟内存管理技术,但出现简单和尽量靠拢标准Linux得需要,uClinux仍然沿用标准Linux的分页内存管理结构,系统在启动时把实际存储器进行分页,但实际上采用的是实存储器管理策略。
uClinux系统对于内存的访问是直接的,(它对地址的访问不需要经过MMU,而是直接送到地址线上输出),所有程序中访问的地址都是实际的物理地址。
操作系统对内存空间没有保护(这实际上是很多嵌入式系统的特点),各个进程实际上共享一个运行空间(没有独立的地址转换表)。
一个进程在执行前,系统必须为进程分配足够的连续地址空间,然后全部载入主存储器的连续空间中。由于程序加载地址与预期(ld文件中指出的)通常都不相同,这样relocation过程就是必须的。
磁盘交换空间无法使用的,系统执行时如果缺少内存将无法通过磁盘交换来得到改善。

从易用性来说,uClinux的内存管理实际上是一种倒退,退回了到了UNIX早期或是Dos系统时代。开发人员不得不参与系统的内存管理。从编译内核开始,开发人员必须告诉系统这块开发板到底拥有多少的内存。
由于应用程序加载时必须分配连续的地址空间,而针对可连续地址分配内存大小是受限的,开发人员在开发应用程序时必须考虑内存的分配情况并关注应用程序需要运行空间的大小。另外由于采用实存储器管理策略,
用户程序同内核以及其它用户程序在一个地址空间,程序开发时要保证不侵犯其它程序的地址空间,以使得程序不至于破坏系统的正常工作,或导致其它程序的运行异常。从内存的访问角度来看,开发人员的权利增大了(开发人员在编程时可以访问任意的地址空间),但与此同时系统的安全性也大为下降。
从嵌入式设备实现的功能来看,嵌入式设备通常在某一特定的环境下运行,只要实现特定的功能,其功能相对简单,内存管理的要求完全可以由开发人员考虑。

uCLinux内核加载方式介绍
uCLinux的内核有两种可选的运行方式:可以在flash上直接运行,也可以加载到内存中运行。后者可以减少内存需要。     Flash运行方式(XIP):把内核的可执行映像烧写到flash上,系统启动时从flash的某个地址开始逐句执行。这种方法实际上是很多嵌入式系统采用的方法。     内核加载方式:把内核的压缩文件存放在flash上,系统启动时读取压缩文件在内存里解压,然后开始执行,这种方式相对复杂一些,但是运行速度可能更快(RAM的存取速率要比Flash高)。

uCLinux的根文件系统
uCLinux系统采用romfs文件系统,这种文件系统相对于一般的ext2文件系统要求更少的空间。空间的节约来自于两个方面:首先内核支持romfs文件系统比支持ext2文件系统需要更少的代码;其次romfs文件系统相对简单,在建立文件系统超级块(superblock)需要更少的存储空间。Romfs文件系统不支持动态擦写保存,对于系统需要动态保存的数据采用虚拟ram盘/JFFS的方法进行处理(ram盘将采用ext2文件系统)。

uCLinux应用程序库
uCLinux小型化的另一个做法是重写了应用程序库,相对于越来越大且越来越全的glibc库,uClibc对libc做了精简。 http://uclibc.org/uClibc.html
uClibm数学库
uCLinux对用户程序采用静态链接的形式,这种做法会使应用程序变大,但是基于内存管理的问题,也就是基于没有MMU的特性,只能这样做,同时这种做法也更接近于通常嵌入式系统的做法。
标准Linux系统系统数据段,代码段,堆和栈在虚存层面是连续的。堆向上增长,栈向下增长,在堆底和栈顶之间有256MB的内存可供分配。uClinux采用了实内存模式,各个内存段在物理内存层面是连续的,栈段在同数据段在一起,堆有系统内存管理,所有进程共享,由于内存连续和保护的要求,栈段,数据段,代码段都是在程序加载是分配。 这种内存空间布局阻碍了动态连接库的运用。栈段的大小固定(在生成应用时可以指定栈段大小),开发人员在开发时不得不使用一些方法估计判断栈段的大小,使其即能满足程序的需要,又不浪费内存。

uCLinux的可执行文件格式
uCLinux系统使用flat可执行文件格式,目前也支持elf文件格式。
先解释几种可执行文件格式。
  coff(common object file format):一种通用的对象文件格式;
  elf(executive linked file):一种为Linux系统所采用的通用文件格式,支持动态连接和重定位;
  flat:elf格式有很大的文件头,flat文件对文件头和一些段信息做了简化,可执行程序小。
uCLinux的可执行文件的加载
当用户执行一个应用时,内核的执行文件加载器将对flat文件进行进一步处理,主要是对reloc段进行修正(详见fs/binfmt_flat.c)。
需要reloc段的根本原因是,程序在连接时连接器所假定的程序运行空间与实际程序加载到的内存空间不同。假如有这样一条指令:
jsr app_start;
这一条指令采用直接寻址,跳转到app_start地址处执行,连接程序将在编译完成是计算出app_start的实际地址(设若实际地址为0x10000),这个实际地址是根据ld文件计算出来。但实际上由于内存分配的关系,操作系统在加载时无法保证程序将按ld文件加载。这时如果程序仍然跳转到绝对地址0x10000处执行,通常情况这是不正确的。
一个解决办法是增加一个存储空间,用于存储app_start的实际地址,设若使用变量addr表示这个存储空间。则以上这句程序将改为:
movl addr, a0;    jsr (a0);
增加的变量addr将在数据段中占用一个4字节的空间,连接器将app_start的绝对地址存储到该变量。在可执行文件加载时,可执行文件加载器根据程序将要加载的内存空间计算出app_start在内存中的实际位置,写入addr变量。系统在实际处理是不需要知道这个变量的确切存储位置(也不可能知道),系统只要对整个reloc段进行处理就可以了(reloc段有标识,系统可以读出来)。处理很简单只需要对reloc段中存储的值统一加上一个偏置(如果加载的空间比预想的要靠前,实际上是减去一个偏移量)。偏置由实际的物理地址起始值同ld文件指定的地址起始值相减计算出。

uCLinux的多进程管理
MMU不是支持多进程的必要条件,只是更好的支持了多进程操作系统的实现。
   uClinux没有MMU管理存储器,不支持COW的机制,因此fork 的优化只有采用vfork这一途径,并且由于不支持虚拟地址空间,简单复制的fork实现也必须修正reloc段。 最终,uClinux的fork/vfork都用vfork实现。子进程要么代替父进程执行(此时父进程已经sleep)直到子进程调用exit退出,要么调用exec执行一个新的进程,这个时候将产生可执行文件的加载,即使这个进程只是父进程的拷贝,这个过程也不能避免。当子进程执行exit或exec后,子进程使用wakeup把父进程唤醒,父进程继续往下执行。
uCLinux的主要特征:
经过如上各方面的小型化改造,就形成了一个高度优化的、代码紧凑的嵌入式Linux,虽然它的体积很小,uCLinux仍然保留了Linux的大多数的优点:
稳定、良好的移植性、优秀的网络功能、完备的对各种文件系统的支持、以及标准丰富的API。它的主要特征如下:
  ●通用Linux API
  ●内核体积 < 512 KB
  ●内核 +文件系统<900 KB
  ●完整的TCP/IP 协议栈
  ●支持大量其它的网络协议
  ●支持各种文件系统,包括 NFS、ext2、ROMfs and JFFS、MS-DOS和FAT16/32

uCLinux开发环境
基于uCLinux的应用开发环境一般是由目标系统硬件开发板和宿主PC机所构成。硬件开发板用于操作系统和目标系统应用软件的运行,而操作系统内核的编译、应用软件的开发和调试则需要借助宿主PC机来完成。双方之间一般通过串口建立连接关系。

建立交叉开发环境
  在软件开发环境建立方面,由于uCLinux及相关工具集都是开放源码的项目,所以大多数软件都可以从网络上下载获得。首先要在宿主机上安装标准Linux发行版,比如Red-Hat Linux,接下来就可以建立交叉开发环境。
  1.安装交叉编译工具
  针对uCLinux目前有两套编译工具:m68k-coff和m68k-elf,它们都是GNU组织开发的优秀的编译器GCC的不同应用版本。它们的区别在于形成最终flat目标码之前的中间代码格式分别是coff和elf类型。elf格式的编译器比coff格式的编译器有许多优越性,建议使用m68k-elf交叉编译器。编译工具包中除了交叉编译器以外,还有链接器(ld)、汇编器(as)以及一些为了方便开发的二进制处理工具,包括生成静态库工具(ar、ranlib)、二进制码察看工具(nm、size)、二进制格式转换工具(objcopy)。这些都要安装在宿主机上。
    2.安装uCLinux内核
  利用已安装的交叉编译器编译生成运行与目标机上的uCLinux内核。与标准Linux相同的是,uCLinux内核可以以配置的方式选择需要安装的模块,而增加系统的灵活性。
  3.安装应用程序库
  用交叉编译器编译uC-libc和uC-libm源码,生成libc.a应用程序库和libm.a数学库。
  4.安装其他工具
  用GCC编译elf2flt源码,生成格式转换工具elf2flt。用GCC编译genromfs源码,得到生成romfs工具genromfs。
  经过以上的准备工作之后,下面要针对特定应用所需要的设备编写或改造设备驱动程序。有一些设备驱动,uCLinux本身就已经具有。即便没有,因为uCLinux开放源码的特性,用户也可以很方便地把自己的驱动程序加入内核。如果用户对系统实时性,特别是硬实时有特殊的要求,uCLinux可以加入RT-Linux的实时模块。完成这些工作,一个嵌入式应用开发平台就已经搭建好了,在此之上,根据不同需要可以开发不同的嵌入式应用。

参考文档和站点介绍

X window Server端程序相关

今天突然用到,这里记一下

打开第2个X:

$X :1   ,接下来启用一个xterm : xterm -display :1
嵌套启用第二个X:
$Xnest :1

打开一个有xterm的X :

$ xinit — :2


打开第2个KDE(对于SuSE而言):

$ startx — :1


打开另一个GDM:
$ gdm :1

除了标准的X ,还有如下X Server端程序:

Xdmx, Xephyr, Xnest, Xvfb

搞定arposion的移植

首先确定需要哪些工具包 , arposion 依赖libnet ,所以要这两个都要下载。libnet 在suse的源里面就有源码包,rpm -ivv libnet*.src.rpm 安装之后直接把libnet*.tar.gz 解压:

|– CVS
|   |– Entries
|   |– Repository
|   `– Root
|– Makefile
|– Makefile.am
|– Makefile.am.common
|– Makefile.in
|– README
|– VERSION
|– acconfig.h
|– acinclude.m4
|– aclocal.m4
|– autom4te.cache
|   |– CVS
|   |   |– Entries
|   |   |– Repository
|   |   `– Root
|   |– output.0
|   |– requests
|   `– traces.0
|– config.guess
|– config.log
|– config.status
|– config.sub
|– configure
|– configure.in
|– doc
|   |– BUGS
|   |– CHANGELOG
|   |– CONTRIB
|   |– COPYING
|   |– CVS
|   |   |– Entries
|   |   |– Repository
|   |   `– Root
|   |– DESIGN_NOTES
|   |– MIGRATION
|   |– PACKET_BUILDING
|   |– PORTED
|   |– RAWSOCKET_NON_SEQUITUR
|   |– TODO
|   |– html
|   |   |– acconfig_8h-source.html
|   |   |– annotated.html
|   |   |– bpf_8h-source.html
|   |   |– config_8h-source.html
|   |   |– doxygen.css
|   |   |– doxygen.png
|   |   |– files.html
|   |   |– functions.html
|   |   |– functions_vars.html
|   |   |– getopt_8h-source.html
|   |   |– globals.html
|   |   |– globals_defs.html
|   |   |– globals_func.html
|   |   |– gnuc_8h-source.html
|   |   |– graph_legend.dot
|   |   |– graph_legend.html
|   |   |– ifaddrlist_8h-source.html
|   |   |– in__systm_8h-source.html
|   |   |– index.html
|   |   |– libnet-asn1_8h-source.html
|   |   |– libnet-functions_8h-source.html
|   |   |– libnet-functions_8h.html
|   |   |– libnet-headers_8h-source.html
|   |   |– libnet-headers_8h.html
|   |   |– libnet-macros_8h-source.html
|   |   |– libnet-macros_8h.html
|   |   |– libnet-structures_8h-source.html
|   |   |– libnet-types_8h-source.html
|   |   |– libnet_8h-source.html
|   |   |– libnet_8h.html
|   |   |– structlibnet__802__1q__hdr.html
|   |   `– structlibnet__802__1x__hdr.html
|   |– libnet.doxygen.conf
|   `– man
|       |– CVS
|       |   |– Entries
|       |   |– Repository
|       |   `– Root
|       `– man3
|           |– libnet-functions.h.3
|           |– libnet-headers.h.3
|           |– libnet-macros.h.3
|           |– libnet.h.3
|           |– libnet_802_1q_hdr.3
|           `– libnet_802_1x_hdr.3
|– include
|   |– CVS
|   |   |– Entries
|   |   |– Repository
|   |   `– Root
|   |– Makefile
|   |– Makefile.am
|   |– Makefile.in
|   |– bpf.h
|   |– config.h
|   |– config.h.in
|   |– gnuc.h
|   |– ifaddrlist.h
|   |– libnet
|   |   |– CVS
|   |   |   |– Entries
|   |   |   |– Repository
|   |   |   `– Root
|   |   |– Makefile
|   |   |– Makefile.am
|   |   |– Makefile.in
|   |   |– libnet-asn1.h
|   |   |– libnet-functions.h
|   |   |– libnet-headers.h
|   |   |– libnet-macros.h
|   |   |– libnet-structures.h
|   |   `– libnet-types.h
|   |– libnet.h
|   |– libnet.h.in
|   |– libnet.h~
|   |– stamp-h.in
|   |– stamp-h1
|   `– win32
|       |– CVS
|       |   |– Entries
|       |   |– Repository
|       |   `– Root
|       |– config.h
|       |– getopt.h
|       |– in_systm.h
|       `– libnet.h
|– install-sh
|– libnet-config
|– libnet-config.in
|– libnet.doxygen.conf
|– man
|   `– CVS
|       |– Entries
|       |– Repository
|       `– Root
|– missing
|– mkinstalldirs
|– sample
|   |– CVS
|   |   |– Entries
|   |   |– Repository
|   |   `– Root
|   |– Makefile
|   |– Makefile.am
|   |– Makefile.in
|   |– arp
|   |– arp-new.c
|   |– arp.c
|   |– arp.o
|   |– bgp4_hdr
|   |– bgp4_hdr.c
|   |– bgp4_hdr.o
|   |– bgp4_notification
|   |– bgp4_notification.c
|   |– bgp4_notification.o
|   |– bgp4_open
|   |– bgp4_open.c
|   |– bgp4_open.o
|   |– bgp4_update
|   |– bgp4_update.c
|   |– bgp4_update.o
|   |– cdp
|   |– cdp.c
|   |– cdp.o
|   |– dhcp_discover
|   |– dhcp_discover.c
|   |– dhcp_discover.o
|   |– dns
|   |– dns.c
|   |– dns.o
|   |– dot1x
|   |– dot1x.c
|   |– dot1x.o
|   |– fddi_tcp1
|   |– fddi_tcp1.c
|   |– fddi_tcp1.o
|   |– fddi_tcp2
|   |– fddi_tcp2.c
|   |– fddi_tcp2.o
|   |– get_addr
|   |– get_addr.c
|   |– get_addr.o
|   |– gre
|   |– gre.c
|   |– gre.o
|   |– icmp6_echoreq
|   |– icmp6_echoreq.c
|   |– icmp6_echoreq.o
|   |– icmp_echo_cq
|   |– icmp_echo_cq.c
|   |– icmp_echo_cq.o
|   |– icmp_redirect
|   |– icmp_redirect.c
|   |– icmp_redirect.o
|   |– icmp_timeexceed
|   |– icmp_timeexceed.c
|   |– icmp_timeexceed.o
|   |– icmp_timestamp
|   |– icmp_timestamp.c
|   |– icmp_timestamp.o
|   |– icmp_unreach
|   |– icmp_unreach.c
|   |– icmp_unreach.o
|   |– ieee
|   |– ieee.c
|   |– ieee.o
|   |– ip_link
|   |– ip_link.c
|   |– ip_link.o
|   |– ip_raw
|   |– ip_raw.c
|   |– ip_raw.o
|   |– isl
|   |– isl.c
|   |– isl.o
|   |– libnet_test.h
|   |– mpls
|   |– mpls.c
|   |– mpls.o
|   |– ntp
|   |– ntp.c
|   |– ntp.o
|   |– ospf_hello
|   |– ospf_hello.c
|   |– ospf_hello.o
|   |– ospf_lsa
|   |– ospf_lsa.c
|   |– ospf_lsa.o
|   |– ping_of_death
|   |– ping_of_death.c
|   |– ping_of_death.o
|   |– rpc_tcp
|   |– rpc_tcp.c
|   |– rpc_tcp.o
|   |– rpc_udp
|   |– rpc_udp.c
|   |– rpc_udp.o
|   |– sebek
|   |– sebek.c
|   |– sebek.o
|   |– smurf
|   |– smurf.c
|   |– smurf.o
|   |– stp
|   |– stp.c
|   |– stp.o
|   |– synflood
|   |– synflood.c
|   |– synflood.o
|   |– synflood6
|   |– synflood6.c
|   |– synflood6.o
|   |– synflood6_frag
|   |– synflood6_frag.c
|   |– synflood6_frag.o
|   |– tcp1
|   |– tcp1.c
|   |– tcp1.o
|   |– tcp2
|   |– tcp2.c
|   |– tcp2.o
|   |– tftp
|   |– tftp.c
|   |– tftp.o
|   |– tring_tcp1
|   |– tring_tcp1.c
|   |– tring_tcp1.o
|   |– tring_tcp2
|   |– tring_tcp2.c
|   |– tring_tcp2.o
|   |– udp1
|   |– udp1.c
|   |– udp1.o
|   |– udp2
|   |– udp2.c
|   |– udp2.o
|   `– win32
|       |– CVS
|       |   |– Entries
|       |   |– Repository
|       |   `– Root
|       |– arp
|       |   |– CVS
|       |   |   |– Entries
|       |   |   |– Repository
|       |   |   `– Root
|       |   `– arp.vcproj
|       |– cdp
|       |   |– CVS
|       |   |   |– Entries
|       |   |   |– Repository
|       |   |   `– Root
|       |   `– cdp.vcproj
|       |– dhcp_discover
|       |   |– CVS
|       |   |   |– Entries
|       |   |   |– Repository
|       |   |   `– Root
|       |   `– dhcp_discover.vcproj
|       |– dns
|       |   |– CVS
|       |   |   |– Entries
|       |   |   |– Repository
|       |   |   `– Root
|       |   `– dns.vcproj
|       |– get_addr
|       |   |– CVS
|       |   |   |– Entries
|       |   |   |– Repository
|       |   |   `– Root
|       |   `– get_addr.vcproj
|       |– getopt.c
|       |– icmp_echo_cq
|       |   |– CVS
|       |   |   |– Entries
|       |   |   |– Repository
|       |   |   `– Root
|       |   `– icmp_echo_cq.vcproj
|       |– tcp1
|       |   |– CVS
|       |   |   |– Entries
|       |   |   |– Repository
|       |   |   `– Root
|       |   `– tcp1.vcproj
|       `– udp1
|           |– CVS
|           |   |– Entries
|           |   |– Repository
|           |   `– Root
|           |– dns.vcproj
|           `– udp1.vcproj
|– src
|   |– CVS
|   |   |– Entries
|   |   |– Repository
|   |   `– Root
|   |– Makefile
|   |– Makefile.am
|   |– Makefile.in
|   |– libnet.a
|   |– libnet_advanced.c
|   |– libnet_advanced.o
|   |– libnet_asn1.c
|   |– libnet_asn1.o
|   |– libnet_build_802.1q.c
|   |– libnet_build_802.1q.o
|   |– libnet_build_802.1x.c
|   |– libnet_build_802.1x.o
|   |– libnet_build_802.2.c
|   |– libnet_build_802.2.o
|   |– libnet_build_802.3.c
|   |– libnet_build_802.3.o
|   |– libnet_build_arp.c
|   |– libnet_build_arp.o
|   |– libnet_build_bgp.c
|   |– libnet_build_bgp.o
|   |– libnet_build_cdp.c
|   |– libnet_build_cdp.o
|   |– libnet_build_data.c
|   |– libnet_build_data.o
|   |– libnet_build_dhcp.c
|   |– libnet_build_dhcp.o
|   |– libnet_build_dns.c
|   |– libnet_build_dns.o
|   |– libnet_build_ethernet.c
|   |– libnet_build_ethernet.o
|   |– libnet_build_fddi.c
|   |– libnet_build_fddi.o
|   |– libnet_build_gre.c
|   |– libnet_build_gre.o
|   |– libnet_build_icmp.c
|   |– libnet_build_icmp.o
|   |– libnet_build_igmp.c
|   |– libnet_build_igmp.o
|   |– libnet_build_ip.c
|   |– libnet_build_ip.o
|   |– libnet_build_ipsec.c
|   |– libnet_build_ipsec.o
|   |– libnet_build_isl.c
|   |– libnet_build_isl.o
|   |– libnet_build_link.c
|   |– libnet_build_mpls.c
|   |– libnet_build_mpls.o
|   |– libnet_build_ntp.c
|   |– libnet_build_ntp.o
|   |– libnet_build_ospf.c
|   |– libnet_build_ospf.o
|   |– libnet_build_rip.c
|   |– libnet_build_rip.o
|   |– libnet_build_rpc.c
|   |– libnet_build_rpc.o
|   |– libnet_build_sebek.c
|   |– libnet_build_sebek.o
|   |– libnet_build_snmp.c
|   |– libnet_build_snmp.o
|   |– libnet_build_stp.c
|   |– libnet_build_stp.o
|   |– libnet_build_tcp.c
|   |– libnet_build_tcp.o
|   |– libnet_build_token_ring.c
|   |– libnet_build_token_ring.o
|   |– libnet_build_udp.c
|   |– libnet_build_udp.o
|   |– libnet_build_vrrp.c
|   |– libnet_build_vrrp.o
|   |– libnet_checksum.c
|   |– libnet_checksum.o
|   |– libnet_cq.c
|   |– libnet_cq.o
|   |– libnet_crc.c
|   |– libnet_crc.o
|   |– libnet_dll.c
|   |– libnet_error.c
|   |– libnet_error.o
|   |– libnet_if_addr.c
|   |– libnet_if_addr.o
|   |– libnet_init.c
|   |– libnet_init.o
|   |– libnet_internal.c
|   |– libnet_internal.o
|   |– libnet_link_bpf.c
|   |– libnet_link_dlpi.c
|   |– libnet_link_linux.c
|   |– libnet_link_linux.o
|   |– libnet_link_nit.c
|   |– libnet_link_none.c
|   |– libnet_link_pf.c
|   |– libnet_link_snit.c
|   |– libnet_link_snoop.c
|   |– libnet_link_win32.c
|   |– libnet_pblock.c
|   |– libnet_pblock.o
|   |– libnet_port_list.c
|   |– libnet_port_list.o
|   |– libnet_prand.c
|   |– libnet_prand.o
|   |– libnet_raw.c
|   |– libnet_raw.o
|   |– libnet_resolve.c
|   |– libnet_resolve.o
|   |– libnet_version.c
|   |– libnet_version.o
|   |– libnet_write.c
|   `– libnet_write.o
|– version.h
|– version.h.in
`– win32
    |– CVS
    |   |– Entries
    |   |– Repository
    |   `– Root
    |– Libnet-1.1.1-2002.sln
    |– Libnet-1.1.1-2003.ncb
    |– Libnet-1.1.1-2003.sln
    |– Libnet-1.1.1-2003.suo
    |– Libnet-1.1.1.vcproj
    |– Libnet-latest.ncb
    |– Libnet-latest.opt
    |– Libnet-latest.sln
    |– Libnet-latest.suo
    |– Libnet-latest.vcproj
    |– Libnet.dsp
    |– Libnet.dsw
    |– README.txt
    `– libnet_dll.def
该库的项目使用了automake。libnet库的核心就是那几个头文件和几个*.c文件(被编译成静态连接库*.o,最后还将被打包成ar包)
./configure CC=~/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/bin/mipsel-linux-uclibc-gcc –host=mipsel-linux
再看一下arposion
.
|– LICENSE
|– Makefile
|– README
|– TODO
|– arpoison
|– arpoison.8
|– arpoison.c
`– lookup.c
相对简单很多,只用到了make,核心就是arposion.c。 lookup.c 是根据hostname查ip,实际并没有被用到。

先编译libnet: 
设置configure,使用: 
./configure CC=~/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/bin/mipsel-linux-uclibc-gcc –host=mipsel-linux  
这里的–host=mipsel-linux是必须的,生成的config在文件config.status。
执行make:
Making all in include
make[1]: Entering directory `/root/libnet/include’
make  all-recursive
make[2]: Entering directory `/root/libnet/include’
Making all in libnet
make[3]: Entering directory `/root/libnet/include/libnet’
make[3]: Nothing to be done for `all’.
make[3]: Leaving directory `/root/libnet/include/libnet’
make[3]: Entering directory `/root/libnet/include’
make[3]: Leaving directory `/root/libnet/include’
make[2]: Leaving directory `/root/libnet/include’
make[1]: Leaving directory `/root/libnet/include’
Making all in src
make[1]: Entering directory `/root/libnet/src’
/root/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/mipsel-linux/bin/gcc -DHAVE_CONFIG_H -I. -I. -I../include     -g -O2 -Wall -c `test -f ‘libnet_asn1.c’ || echo ‘./’`libnet_asn1.c
In file included from libnet_asn1.c:60:
../include/libnet.h:117:10: macro names must be identifiers
make[1]: *** [libnet_asn1.o] Error 1
make[1]: Leaving directory `/root/libnet/src’
make: *** [all-recursive] Error 1
报错信息很明确../include/libnet.h第117行有问题,看了一下该行定义了一个空的宏
#include <errno.h>
#include <stdarg.h>

#define LIBNET_VERSION  "1.1.2.1"
#define  1

#include "./libnet/libnet-types.h"
#include "./libnet/libnet-macros.h"
#include "./libnet/libnet-headers.h"
#include "./libnet/libnet-structures.h"
#include "./libnet/libnet-asn1.h"
#include "./libnet/libnet-functions.h"
mark 掉就能通过了,然后继续杯具:
libnet_build_ip.c: In function `libnet_build_ipv4′:
libnet_build_ip.c:80: error: structure has no member named `ip_v’
libnet_build_ip.c:81: error: structure has no member named `ip_hl’
libnet_build_ip.c:96: error: structure has no member named `ip_hl’
libnet_build_ip.c: In function `libnet_autobuild_ipv4′:
libnet_build_ip.c:282: error: structure has no member named `ip_v’
libnet_build_ip.c:283: error: structure has no member named `ip_hl’
libnet_build_ip.c:298: error: structure has no member named `ip_hl’
libnet_build_ip.c: In function `libnet_build_ipv4_options’:
libnet_build_ip.c:435: error: structure has no member named `ip_hl’
make[1]: *** [libnet_build_ip.o] Error 1
make[1]: Leaving directory `/root/libnet/src’
make: *** [all-recursive] Error 1
找不到结构成员ip_v,ip_hl ,wiki 了一下发现应该是ip header 的结构,在头文件<netinet/ip.h>中。难道是没有包含该头文件?不假思索地在libnet_build_ip中include <netinet/ip.h> 然后尝试编译仍然报错。继续分析,发现这两个成员属于ip_hdr ,而不是glibc中的<netinet/ip.h>。ip_hdr的原型是libnet_ipv4,可以想象libnet的头文件重定义了标准头文件的一些结构。 那么这个libnet_ipv4在哪里呢 ? 翻了半天最终在include/libnet/libnet-headers.h中找到了:
struct libnet_ipv4_hdr
{
#if (LIBNET_LIL_ENDIAN)
    u_int8_t ip_hl:4,      /* header length */
           ip_v:4;         /* version */
#endif
#if (LIBNET_BIG_ENDIAN)
    u_int8_t ip_v:4,       /* version */
           ip_hl:4;        /* header length */
#endif
    u_int8_t ip_tos;       /* type of service */
#ifndef IPTOS_LOWDELAY
#define IPTOS_LOWDELAY      0x10
……..
}
应该是这个头文件没有被正确include进去吧
我把这一段结构直接贴到libnet_build_ip.c中然后编译,竟然还是不行。
这个真是杯具了,看来要卡死在这里了,找不到真正原因。
第二天继续看这个结构,我突然发现这里ip_v,ip_hl 都是条件编译! 
哦,明白了,应该是编译器既没有定义宏LIBNET_BIG_ENDIAN也没有定义LIBNET_LIL_ENDIAN ,所以这两个变量直接就pass了。
ok,直接在该文件头定义:
#include LIBNET_LIL_ENDIAN 1 //MIPSEL is LITTLE ENDIAN
这样编译就通过了,没有任何错误。生成了libnet.a ,庆祝一下~~
回过头来想这个头文件其实处理的很好,真正好的做法还是应该通过编译选项把这个宏定义出来,但我就不知道具体该怎么做了,还要继续深入研究一下了。

接下来就需要编译了arposion
首先把编译好的libnet.a 放到mipsel-linux-uclibc-gcc 可以搜索到的路径中, 先查看一下搜索顺序: 
#./mipsel-linux-uclibc-gcc -print-search-dirs
install: /home/nbd/wr/whiterussian-0.9/staging_dir_mipsel/lib/gcc/mipsel-linux-uclibc/3.4.4/

programs: =/root/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/bin/../libexec/gcc/mipsel-linux-uclibc/3.4.4/:
/root/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/bin/../libexec/gcc/:
/home/nbd/wr/whiterussian-0.9/staging_dir_mipsel/libexec/gcc/mipsel-linux-uclibc/3.4.4/:
/home/nbd/wr/whiterussian-0.9/staging_dir_mipsel/libexec/gcc/mipsel-linux-uclibc/3.4.4/:
/home/nbd/wr/whiterussian-0.9/staging_dir_mipsel/libexec/gcc/mipsel-linux-uclibc/:
/home/nbd/wr/whiterussian-0.9/staging_dir_mipsel/lib/gcc/mipsel-linux-uclibc/3.4.4/:
/home/nbd/wr/whiterussian-0.9/staging_dir_mipsel/lib/gcc/mipsel-linux-uclibc/:
/usr/libexec/gcc/mipsel-linux-uclibc/3.4.4/:
/usr/libexec/gcc/mipsel-linux-uclibc/:
/usr/lib/gcc/mipsel-linux-uclibc/3.4.4/:
/usr/lib/gcc/mipsel-linux-uclibc/:
/root/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/bin/../lib/gcc/mipsel-linux-uclibc/3.4.4/../../../../mipsel-linux-uclibc/bin/mipsel-linux-uclibc/3.4.4/:
/root/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/bin/../lib/gcc/mipsel-linux-uclibc/3.4.4/../../../../mipsel-linux-uclibc/bin/:
/home/nbd/wr/whiterussian-0.9/staging_dir_mipsel/mipsel-linux-uclibc/bin/mipsel-linux-uclibc/3.4.4/:/home/nbd/wr/whiterussian-0.9/staging_dir_mipsel/mipsel-linux-uclibc/bin/

libraries: =/root/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/bin/../lib/gcc/mipsel-linux-uclibc/3.4.4/:
/root/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/bin/../lib/gcc/:
/home/nbd/wr/whiterussian-0.9/staging_dir_mipsel/lib/gcc/mipsel-linux-uclibc/3.4.4/:
/usr/lib/gcc/mipsel-linux-uclibc/3.4.4/:
/root/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/bin/../lib/gcc/mipsel-linux-uclibc/3.4.4/../../../../mipsel-linux-uclibc/lib/mipsel-linux-uclibc/3.4.4/:
/root/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/bin/../lib/gcc/mipsel-linux-uclibc/3.4.4/../../../../mipsel-linux-uclibc/lib/:
/home/nbd/wr/whiterussian-0.9/staging_dir_mipsel/mipsel-linux-uclibc/lib/mipsel-linux-uclibc/3.4.4/:
/home/nbd/wr/whiterussian-0.9/staging_dir_mipsel/mipsel-linux-uclibc/lib/
一大堆看晕了,其实按照红色路径去放就对了
/root/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/bin/../lib/gcc/mipsel-linux-uclibc/3.4.4/

头文件就放在
/root/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/bin/../lib/gcc/mipsel-linux-uclibc/3.4.4/include 
包括libnet.h 和libnet 目录

然后编辑Makefile :
BINBASE=/root/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/mipsel-linux-uclibc/bin

CC=${BINBASE}/gcc

all:
        ${CC} -Wall `libnet-config –defines` arpoison.c -o arpoison `libnet-config –libs`
#       gcc –host=mipsel-linux -Wall `libnet-config –defines` arpoison.c -o arpoison `libnet-config –libs`
clean:

        rm arpoison

然后make 没有任何输出就证明编译成功~~ 
再次祝贺一下

OpenWrt 交叉编译工具链

该工具链其实就是mipsel的交叉编译工具链 ,大小175MB(已经不小了)

#du -h –max-depth=1
0       ./dl
4.0K    ./tmp
316K    ./docs
117K    ./scripts
175M    ./staging_dir_mipsel
0       ./build_mipsel
12K     ./package
80K     ./examples
80K     ./include
175M    .
工具链在staging_dir_mipsel
#du staging_dir_mipsel/ -h  –max-depth=1
42M     staging_dir_mipsel/bin
4.0K    staging_dir_mipsel/etc
17M     staging_dir_mipsel/lib
24M     staging_dir_mipsel/usr
22M     staging_dir_mipsel/libexec
1.0K    staging_dir_mipsel/stampfiles
24M     staging_dir_mipsel/mipsel-linux-uclibc
49M     staging_dir_mipsel/include
175M    staging_dir_mipsel/
其中bin,include,lib,libexec都是工具链不可缺少的东西。
bin目录都是uClinux的编译,连接和辅助程序
include目录放的是uClinux的头文件
lib目录里是uClinux的库文件
libexec是和库文件相关的连接程序,比如cc1
这里有个特殊的目录 staging_dir_mipsel,这个是工具链的工作目录,里面同样的bin,lib等目录就是映射的上一层对应的目录。这样做的目的估计是为了在部署工具链的时候能够更加灵活,不过我并没有进行部署。
 
#~/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/mipsel-linux # l
total 0
drwxr-xr-x  3  200    4 152 Jul 18 00:04 ./
drwxr-xr-x 10  200    4 360 Jan 31  2007 ../
drwxr-xr-x  2  200    4 288 Jan 31  2007 bin/
lrwxrwxrwx  1  200    4   6 Jul  7 23:31 lib -> ../lib/
lrwxrwxrwx  1 root root  57 Jul 18 00:04 libexec -> /root/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/libexec/
lrwxrwxrwx  1  200    4  10 Jul  7 23:31 sys-include -> ../include/
 
update:
host更新为64位系统需要下载更新的toolchain,从http://downloads.openwrt.org/attitude_adjustment/12.09/brcm47xx/generic/OpenWrt-Toolchain-brcm47xx-for-mipsel-gcc-4.6-linaro_uClibc-0.9.33.2.tar.bz2下载
用法:
  1. export STAGING_DIR=toolchain根目录,比如/root/OpenWrt-Toolchain-brcm47xx-for-mipsel-gcc-4.6-linaro_uClibc-0.9.33.2/toolchain-mipsel_gcc-4.6-linaro_uClibc-0.9.33.2
  2. 将toolchain下的bin目录加入PATH
  3. 对于有configure的项目执行CC=mipsel-openwrt-linux-gcc LD=mipsel-openwrt-linux-ld ./configure –prefix=/usr –host=mipsel-openwrt-linux,然后make

MIPS架构的交叉编译工具问题

某些MIPS的嵌入式提供了六种交叉编译工具GCC,如下:
· mipsel-linux-gcc
· mipsel-linux-uclibc-gcc
· mipsel-uclibc-gcc
· mips-linux-gcc
· mips-linux-uclibc-gcc
· mips-uclibc-gcc
先说一下uclibc(其实应该叫µClinux
uClinux 这个词的u和C 分别指的是mu(micro)和control。也就是"MicroController Linux" 。有意思的是,他的发音也同时可以叫做 you-see-Linux 。他是linux内核的一个“分支”,专门为了微控制器设计(不带有存储管理单元MMU)。而且他也是目前主流嵌入式系统ARM,MIPS的运行基础。
这六种有什么区别?分别用于什么情况呢?
1)首先,mips和mipsel的主要区别在于Big Endian(大端)和Little Endian(小端)结构。
mips对应的是Big Endian;
mipsel对应的是Little Endian。
2)其次,要明白uclibc库。
uclibc库其实有两个分别是uC-libc和uClibc。uC-libc是比较古老的一版,只实现了glibc的最小接口集。后来又有人写了uClibc,基本实现了glibc的接口和功能,这才使嵌入式平台的开发成熟起来。现在基本有时在用后者了。可以把uClibc当作glibc的lite版。
uClibc库是面向嵌入式Linux系统开发优化的C语言库。比GNU C Library更小,但接口兼容,且更易于配置。
uClibc可运行于标准的以及无MMU的Linux系统之上,支持i386、x86、x64、ARM、AVR32、Blackfin、H8300、M68K、MIPS、PowerPC、SuperH、SPARC和V850等处理器下列。
mips-uclibc-gcc表示采用uClibc库进行编译的GCC。
3)至于第三点“是否带linux的区别”则不清楚,以后再补充吧。