读书频道 > 系统 > linux > 深度探索Linux操作系统系统构建和原理解析
3.2.7 内核映像构建过程总结
2013-09-28 16:17:50     我来说两句 
收藏    我要投稿   
全书一共8章:第1章介绍了如何准备工作环境。在第2章中构建了编译工具链,这是后面构建操作系统各个组件的基础。在这一章中,不仅详细讲解了工具链的构建过程,而且还通过对编译链接过程的探讨,深入讨论了工具链  立即去当当网订购

前面我们简要讨论了内核映像的构建,内核映像的构建过程大体上可以概括为“三次编译链接,一次组合”,如图3-2所示。

 

(1)第一次编译链接

kbuild分别编译各个子目录下的目标文件,如built-in.o、lib.a(如果有)等,然后将他们链接为ELF格式的vmlinux,并存放在顶层目录中。这一步相当于构建有效载荷。

(2)第二次编译链接

kbuild使用工具objcopy,将顶层目录的vmlinux复制到arch/x86/boot/compressed目录下,去掉其中的符号信息、重定位信息,删除段“.comment”,并命名为vmlinux.bin。然后,kbuild将其压缩为vmlinux.bin.gz(假设内核采用核默认的gzip压缩方式),封装到piggy.S中,并调用汇编器将其编译为piggy.o,这一步是对有效载荷进行了压缩。

同时,kbuild也调用编译器编译arch/x86/boot/compressed目录下的head_32.c、misc.c等作为内核的非压缩部分,这一步相当于构建二级推进系统

然后,kbuild调用链接器将压缩的有效载荷和二级推进系统链接为vmlinux。注意这里文件名虽然也是vmlinux,但是不要与顶层目录下的vmlinux混淆,arch/x86/boot/compressed目录下的vmlinux是二级推进系统和有效载荷的组合,与顶层目录下的vmlinux是包含的关系。

最后,kbuild调用objcopy将arch/x86/boot/compressed目录下的vmlinux复制到arch/x86/boot目录下,同时将其转换为裸二进制格式,并命名为vmlinux.bin,为在arch/x86/boot目录下进行的最后的组装做好准备。

(3)第三次编译链接

kbuild将arch/x86/boot下的a20.o、bioscall.o等目标文件链接为setup.elf,使用objcopy将其转换为裸二进制格式,并命名为setup.bin。这一步,相当于构建一级推进系统。
(4)一次组合

最后,kbuild调用内核自带的程序build,将vmlinux.bin和setup.bin合并为bzImage。至此,航天器的一级推进系统和包含有效载荷的二级推进系统装配完毕。

在3.1节,我们曾粗略讨论了内核映像的组成。在了解了内核的构建过程后,让我们近距离的再观察一下bzImage。以下是bzImage的链接脚本:
linux-3.7.4/arch/x86/boot/compressed/vmlinux.lds.S:
SECTIONS
{
    . = 0;
    .head.text : {
        _head = . ;
        HEAD_TEXT
        _ehead = . ;
    }
    .rodata..compressed : {
        *(.rodata..compressed)
    }
    .text : {
        ...
    }
    .rodata : {
        ...
    }
    .got : {
        ...
    }
    .data : {
        ...
    }
    . = ALIGN(L1_CACHE_BYTES);
    .bss : {
        _bss = . ;
        ...
        _ebss = .;
    }
#ifdef CONFIG_X86_64
    ...
#endif
    _end = .;
}

首先来看链接脚本中的段“.head.text”,其中宏HEAD_TEXT的定义为:
linux-3.7.4/include/asm-generic/vmlinux.lds.h:
#define HEAD_TEXT  *(.head.text)

而结合文件head_32.S:
linux-3.7.4/arch/x86/boot/compressed/head_32.S:
    .text

#include <linux/init.h>
...
    __HEAD
ENTRY(startup_32)
...
ENDPROC(startup_32)

        .text
relocated:

/*
 * Clear BSS (stack is currently empty)
 */
    xorl    %eax, %eax
    ...

以及宏__HEAD的定义:
linux-3.7.4/include/linux/init.h:
#define __HEAD      .section    ".head.text","ax"

可见,在head_32.S中,函数startup_32通过宏__HEAD明确要求链接器将函数startup_32链接到段“.head.text”。而根据bzImage的链接脚本,段“.head.text”被安排在了内核映像的起始位置,也就是说,函数startup_32被链接到了内核映像的开头。

接下来的段“.rodata..compressed”,想必读者一定猜出来了,这里就是放置内核的压缩映像部分。根据piggy.S的内容即可见这一点:
linux-3.7.4/arch/x86/boot/compressed/piggy.S:
.section ".rodata..compressed","a",@progbits
.globl z_input_len
z_input_len = 1721556
...
.incbin "arch/x86/boot/compressed/vmlinux.bin.gz"
input_data_end:

在piggy.S中,明确定义了内核压缩部分所在的段为“.rodata..compressed”。

接下来的“.text”、“.data”等段就是保存内核非压缩部分的代码和数据了,包括misc.o、string.o、cmdline.o、early_serial_console.o以及head_32.o中的不属于段“.head.text”的部分。因为内核非压缩部分被编译为位置无关(PIC)代码,所以我们看到其包含got表。

综上所述,bzImage的布局如图3-3所示。

 

点击复制链接 与好友分享!回本站首页
分享到: 更多
您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力  
上一篇:3.2.6 bzImage的组合过程
下一篇:3.3 配置内核
相关文章
图文推荐
3.3.6 GNOME的软件管
3.3.5 GNOME的文件管
3.3.4 GNOME的窗口管
3.3.3 收藏夹和快捷
排行
热门
文章
下载
读书

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训
版权所有: 红黑联盟--致力于做最好的IT技术学习网站