使用LLVM在window交叉编译Linux内核模块

简单一些的普通hello程序交叉编译点击这里。

环境搭建

我目前做的不好,甚至是愚蠢,但是没人教。
目前的技巧就是在linux中正常地编译一个内核模块和Makefile,正常使用之后,寻找一下具体执行的命令进行分解:
(步骤大概是通用的,也许路径不一样)
1.进入了/usr/src/linux-headers-3.4.9-rtai-686-pae/Makefile
2.进入了/usr/src/linux-headers-3.4.9-common-rtai/Makefile
3.进入了/usr/src/linux-headers-3.4.9-common-rtai/scripts/Makefile.build(其中有一些函数在Kbuild.include有定义):

# Built-in and composite module parts
$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
	$(call cmd,force_checksrc)
	$(call if_changed_rule,cc_o_c)

关键在最后一行,实际调用的是rule_cc_o_c函数(Makefile定义的),在下面打印一下:

        @echo "cmd is :",$(cmd_cc_o_c)

保存返回使用make:

gcc -nostdinc -isystem /usr/lib/gcc/i586-linux-gnu/4.9/include 
-I/usr/src/linux-headers-3.4-9-common-rtai/arch/x86/include 
-Iarch/x86/include/generated -Iinclude -I/usr/src/linux-headers-3.4-9-common-rtai/include ...

会有类似的打印,这样就大概将linux的文件夹拷贝到window中即可。

编译步骤

1.生成源文件的目标文件(.o):(注意这里没有使用-fPIC)

clang  --target=i586-linux-guneabi -std=gnu89 -fno-builtin -nostdinc -isystem 
D:\BUILDPATH\linux_X86/usr/lib/gcc/i586-linux-gnu/4.9/include -
ID:\BUILDPATH\linux_X86/usr/src/linux-headers-3.4-9-common-rtai/arch/x86/include -
ID:\BUILDPATH\linux_X86\usr\src\linux-headers-3.4-9-rtai-686-pae\arch/x86/include/generated 
-ID:\BUILDPATH\linux_X86\usr\src\linux-headers-3.4-9-rtai-686-pae\include -
ID:\BUILDPATH\linux_X86/usr/src/linux-headers-3.4-9-common-rtai/include -include 
D:\BUILDPATH\linux_X86/usr/src/linux-headers-3.4-9-common-rtai/include/linux/kconfig.h -
D__KERNEL__ -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-
common -Werror-implicit-function-declaration -Wno-format-security -fno-delete-null-pointer-
checks -O3 -m32 -msoft-float -mregparm=3 -freg-struct-return  -march=i686 -mtune=generic  -
ffreestanding -fstack-protector -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -
DCONFIG_AS_CFI_SECTIONS=1 -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables -mno-sse 
-mstack-alignment=2 -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -Wframe-larger-than=1024 -Wno-
unused-but-set-variable -fomit-frame-pointer -g -Wdeclaration-after-statement -Wno-pointer-
sign -fno-strict-overflow -DCC_HAVE_ASM_GOTO -w -g -ID:\BUILDPATH\linux_X86/usr/src/linux-
headers-3.4-9-common-rtai/. -I. -ID:\BUILDPATH\linux_X86/usr/realtime-3.4-9-rtai-686-
pae/include -ID:\BUILDPATH\linux_X86/usr/src/linux-headers-3.4-9-common-rtai/. -I. -
ID:\BUILDPATH\linux_X86/usr/realtime-3.4-9-rtai-686-pae/include -
ID:\BUILDPATH\linux_X86/usr/include/i386-linux-gnu -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -
fno-math-errno -funsafe-math-optimizations -fno-rounding-math -fno-signaling-nans -mhard-
float -DRTAI=3 -fno-fast-math -mieee-fp -fno-unsafe-math-optimizations -DRTAPI -
D_GNU_SOURCE -Drealtime -D__MODULE__ -
ID:\BUILDPATH\linux_X86/opt/linuxahead/include/linuxcnc -Wframe-larger-than=2560 = -DMODULE 
-DKBUILD_STR\(s\)=#s -DKBUILD_BASENAME=KBUILD_STR\(test_0\) -DKBUILD_MODNAME=KBUILD_STR\
(mod_test_0\) -c -o D:\BUILDPATH\linux_X86/test_0.o D:\BUILDPATH\linux_X86/test_0.c

当然你可以有多个这个的.o,都是一样的。中间遇到了一些问题,还有一些困惑我还没有理解,可见注意事项一。

2.合并为一个.o

该步骤比较简单,一个命令:

ld.lld  -m elf_i386 -r -o mod_test_0.o test_0.o test_1.o ..

3.该步骤以下是在linux进行的,并没有完全在window编译

(1)生成mod.c

该mod.c比较让人困惑,目前的理解是该文件其中包含我们上一步的mod_test_0.o中所有使用到的外部符号和其CRC值。主要是用来匹配内核模块再进行加载时是否和内核版本匹配?(通过CRC可以查看其引用的符号是否和内核符号位置对应来判断)。这里我不过多误导了。

为啥不在window进行编译了,就是因为这个我window不知道怎么编。

linux生成.mod.c:

 cd /usr/src/linux-headers-3.4-9-rtai-686-pae/
scripts/mod/modpost -m -i /usr/src/linux-headers-3.4-9-rtai-686-pae/Module.symvers 
-I /home/aheadtechs/XCompilation/PLC/Module.symvers -e /usr/realtime-3.4-9-rtai-686-pae/modules/linuxcnc/Module.symvers 
-e /usr/realtime-3.4-9-rtai-686-pae/modules/ethercat/Module.symvers 
-o /home/aheadtechs/XCompilation/PLC/Module.symvers -S -w -c -s 
/home/USER/mod_test_0.o

可以看出modpost根据我们生成的.o来生成了.mod.c文件!

(2)生成.mod.o

该步骤和上一步的命令类似。

(3)生成.ko

ld -r -m elf_i386 -T /usr/src/linux-headers-3.4-9-common-rtai/scripts/module-common.lds 
--build-id -o /home/USE/mod_test_0.ko /home/USE/mod_test_0.o /home/USE/mod_test_0.mod.o

可以看出ko就是使用了最后的一个.o和我们的mod.o.

(4)拷贝到响应的目录

cp mod_test_0.ko /XXX/

注意事项

一:

1. window编译最开始的.o的报错:

expanded from macro 'BUILD_BUG_ON'
((void)sizeof(char[1 - 2*!!(condition)]));

这里使用linux -O0优化也会有报错,但是我们默认了-O2的优化,但是在clang就不行了,我怎么做的呢,我去源码文件将这个注释掉了!

就在这:

static __always_inline
void __kfree_rcu(struct rcu_head *head, unsigned long offset)
{
	typedef void (*rcu_callback)(struct rcu_head *);

	//BUILD_BUG_ON(!__builtin_constant_p(offset));就是这个

	/* See the kfree_rcu() header comment. */
	BUILD_BUG_ON(!__is_kfree_rcu_offset(offset));

	kfree_call_rcu(head, (rcu_callback)offset);
}

操作太无脑了,有没有问题我也不知道啊!

2.fmax符号表冲突

我生成的每一个小的.o都有fmax的符号,而linux编译就没有,这里我添加了-std=gnu89解决了,怀疑是内置函数,fmax在gnu89标准是属于内置函数?后续再说。

3.clang缺少gcc有的参数:

下面这个字节对齐设置,名字改为:

-mpreferred-stack-boundary=2       ==> clang:-mstack-alignment =2
?:  -fconserve-stack 
?:  -fcx-limited-range
?:  -Wa,-mtune=generic32

这三个参数都没有找到,具体功能再研究,先从clang命令中除去了。

结论

.mod.c以及以下的部分并不是在window上进行编译的,很不满。而且我还不能确认我上面的.o是不是可以正常使用,简单的测试是可以的,但是心虚,有问题再更新。

你可能感兴趣的:(LLVM)