用来生成二进制内核的Makefile样例

来源:互联网 发布:ant 指定java版本 编辑:程序博客网 时间:2024/05/16 12:08

弄出了下面这个Makefile,在偶的Linux试了一切正常:

Makefile
AS = nasm                                    # 使用nasm作为汇编器. -s 打印错误信息到标准输出.
LD 
= ld                                      # GNU的gld作为连接器.
CC 
= gcc                                     # 使用GNU Compiler作为C编译器.
OBJCOPY 
= objcopy -O binary -R .note -R .comment -S
                                             # 
-O binary 输出为二进制格式.
                                             # 
-R .note -R .comment 删除目标文件中的.note和.comment段.
                                             # 
-S 删除所有符号信息.

ASFLAGS 
= -Iinclude                          # -Iinclude 仅在include目录中寻找包含文件.
LDFLAGS 
= ---M                           # -s 省略符号信息. -x 删除局部符号. -M 导出连接映像(Link map)到标准输出.
CFLAGS 
= -Wall -O2 -fomit-frame-pointer      # -Wall 显示所有警告. -O2 二级优化.
                                             # 
-fomit-frame-pointer 优化函数的框架指针(Frame pointer).
CFLAGS_KERNEL 
= --nostdinc -Iinclude       # -c 仅编译生成目标文件而不连接.
                                             # 
-nostdinc -Iinclude 仅在include目录中寻找包含文件.

.PHONY: all clean dep

all : Image

Image : boot
/bootsect boot/setup vmlinux tools/build
 $(OBJCOPY) vmlinux vmlinux.
out              # 使用objcopy将ELF内核vmlinux解包成为二进制机器码vmlinux.out.
 tools
/build boot/bootsect boot/setup vmlinux.out > $@ # 使用build工具合成最终内核镜像Image.
 rm 
-f vmlinux.out                           # 删除临时文件vmlinux.out

kernel
/head.o : kernel/head.asm
 $(AS) $(ASFLAGS) 
-felf -o $@ $<             # 汇编boot/head.asm生成boot/head.o目标文件.
                                             # 
-felf 汇编boot/head.asm生成boot/head的ELF目标文件.

init
/main.o : init/main.c
 $(CC) $(CFLAGS) $(CFLAGS_KERNEL) 
-o $@ $<   # 编译init/main.c生成init/main.o目标文件.

tools
/build : tools/build.c
 $(CC) $(CFLAGS) 
-o $@ $<                    # 编译tools/build.c生成内核合成工具build.

boot
/setup : boot/setup.asm
 $(AS) $(ASFLAGS) 
-fbin -o $@ $<             # 汇编boot/setup.asm生成boot/setup二进制机器码.
                                             # 
-fbin 对于nasm来说是指定输出二进制机器码而不是目标文件.
boot
/bootsect : boot/bootsect.asm
 $(AS) $(ASFLAGS) 
-fbin -o $@ $<             # 汇编boot/bootsect.asm生成boot/bootsect二进制机器码.

vmlinux : kernel
/head.o init/main.o            # 连接所有内核模块到一个单一的ELF文件vmlinux中.
 $(LD) $(LDFLAGS) kernel
/head.o init/main.o -o $@ > System.map
                                             # 重定向连接映像到System.map文件.

CLEAN_FILES 
= Image System.map boot/bootsect boot/setup tools/build 
 boot
/*.o init/*.o kernel/*.o vmlinux                   # 这里是所有要清除的文件列表.

clean :
 rm -f $(CLEAN_FILES)                        # clean命令清除所有编译生成的文件.

dep :
                                             # 目前还没有.

在blog上排版有点乱,各位看客(真的存在么?~~;-)不要介意。

需要说明的是上面这个东西不能直接用,因为Makefile是不允许把注释和指令写到同一行的,所以要让上面的Makefile能用,最简单的方法就是删除所有注释。

目前这个系统还没什么内容,主要就下面几个文件:

boot/bootsect.asm          磁盘引导扇区
boot/setup.asm             内核加载模块(就是Loader)
kernel/head.asm            内核头部
init/main.c                内核主体
tools/build.c              合成工具

了解Linux内核结构的人一看就知道,该代码结构和Linux一模一样,甚至文件名都几乎一致。没关系,这样看起来确实更清晰,对了解linux内核结构也很有帮助。

Makefile的格式什么的我就不说了,偶也很少用- -。这个Makefile也是属于赶鸭子上架,硬凑凑出来的。

另外要说这个Makefile是参照0.11和2.4.33.4的Makefile写的,里面的符号名,文件名等等都来自Linux内核,在研究2.4.33.4的Makefile的过程中也学到不少,同时也发现一些有趣的东西。

vmlinux这个文件名你一定很眼熟,没错!编Linux的内核的时候它也出现过,它就是内核的ELF形式,用objcopy脱掉它的MJ就是二进制内核。

我这里并没有像Linux一样先把bootsect和setup模块编成ELF再全部连接后脱成bin,而是直接把它们做成bin,通过build这个工具把内核模块“连接”(叫粘接可能更形象些= =)起来。至于为什么,可能只是因为好玩吧,可能以后会改掉。

正如我以前所说,可以用nasm的incbin来替代build,我这里没有这么做,因为一自己写比较有趣,二incbin不能判断文件的大小,如果模块大小超过上限也不会报错,调试的时候反而可能会遇到麻烦。

下面我想重点说说编译和连接的全过程。

首先分别用nasm汇编boot/bootsect.asm和boot/setup.asm,生成二进制代码文件boot/bootsect和boot/setup,然后编译boot/head.asm和init/main.c,分别生成两个ELF文件boot/head.o和init/main.o。随后CALL来ld(GNU的连接器,原名gld),把所有内核的.o连接在一起(一定要注意连接文件的顺序!),连接生成了我们前面说过的那个叫做vmlinux的ELF文件。(注意,与linux的不同,这vmlinux并没有包含bootsect和setup模块,它其实就是0.11中的system模块)

关键就是objcopy这个东东,它的作用就是能把目标文件中的代码提出来,变成纯二进制的机器码文件。我们依照Makefile把vmlinux脱成vmlinux.out,再用我自己的build工具把boot/bootsect、boot/setup和vmlinux.out粘合在一起,生成最终的Image!这个Image就是内核文件了,把它当作磁盘镜像放到VM上面可以直接跑!!当然你要用VPC或者boch就自己把它的大小补到1.44M吧,这个问题前面也说过了就不罗嗦了。

P.S.一下,诸位大概都知道linux的内核文件叫zImage或者bzImage,z似乎指的是压缩?具体我还没研究过,所以就沿用0.11的镜像名字——Image

这样看来,混合编程写内核其实也是一件很容易的事情了,二进制内核文件也根本没有想象中得那么复杂。如果你愿意,你可以用c++来写,反正生成的都是ELF,不过效率嘛。。。

这个Makefile还远未完成(主要是内核还远未完成- -),以后有机会我就会扩充它的!

 

 

原创粉丝点击