免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: snow888
打印 上一主题 下一主题

从 0 开始,打造自己的 Linux 。 [复制链接]

论坛徽章:
381
CU十二周年纪念徽章
日期:2014-01-04 22:46:58CU大牛徽章
日期:2013-03-13 15:32:35CU大牛徽章
日期:2013-03-13 15:38:15CU大牛徽章
日期:2013-03-13 15:38:52CU大牛徽章
日期:2013-03-14 14:08:55CU大牛徽章
日期:2013-04-17 11:17:19CU大牛徽章
日期:2013-04-17 11:17:32CU大牛徽章
日期:2013-04-17 11:17:37CU大牛徽章
日期:2013-04-17 11:17:42CU大牛徽章
日期:2013-04-17 11:17:47CU大牛徽章
日期:2013-04-17 11:17:52CU大牛徽章
日期:2013-04-17 11:17:56
21 [报告]
发表于 2012-04-11 15:52 |只看该作者
嗯,期待你的大作.
建议你尽量少用过程的解释,重点集中在总结性的方面.

不过,俺真的觉得这咚咚发在这里不是太合适,毕竟对于新手来说,是深了一些(虽然,俺也是新手 ^_^.)

你娃算新手?太谦虚了.

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
22 [报告]
发表于 2012-04-11 16:02 |只看该作者
回复 21# chenyx


    过程中需要详细理解的地方,俺会有解释,能掠过的尽量略过。

总结性的东西,其实不多,是实现的思想,或者说是提纲携领的东西。

希望通过总结,让新手知道这操作系统是咋回事,如何实现。

通过中间的细节部分的注意事项,让新手在这个过程中对于如何构建一个完整的系统,能有一个全面的了解。

当然,最后的总结部分,俺也会说说我们目前使用的操作系统是如何来的,如何演化到今天这个样子的。不是说操作系统的历史,而是从操作系统实现的技术层面来说,我们今天的操作系统是如何来的。

PS:俺不只一次被人说成是新手了。确实,估计没人敢说自己是老手。 ^_^.

论坛徽章:
0
23 [报告]
发表于 2012-04-11 16:03 |只看该作者
我什么都不懂,纯粹打酱油的。www.sjzfk1.com

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
24 [报告]
发表于 2012-04-11 16:35 |只看该作者
本帖最后由 snow888 于 2012-04-11 16:51 编辑

好,需要的工具和系统软件,咱基本都有了,下面开始咱得第一个工作,展开我们下载的软件包。

为了稳妥起见,我们建立一个 work 用户,以后我们的工作将在这个 work 用户下面进行。

# useradd -d /home/work -s /bin/bash -C "Build My Operations Users" -m work
# cd /My_Operation
# chown -R work:work *

我们这样做得目的是以后我们所有的工作都将在 work 用户下完成,这样避免在编译过程中如果带的编译参数错误,而对母体的操作系统产生影响,切记!切记!

如果是 bz2 的压缩包,我们用如下命令 bzip2 -d filename ,如果是 gz 的压缩包,我们使用 gzip -d filename 解开压缩。

解开压缩以后,我们使用 tar 命令来展开打包文件。

$ tar xvf filename                                       ;; 没有人工作是在 root 用户下面干的吧?我们使用 work 用户来干这个事情。

下面,我们开始实现我们自己的系统了。


前面说到操作系统的基础知识,不知道大家是否还记得,其中的操作系统和语言的关系?我们再重复一下:我们所有的系统软件,包括操作系统软件,很大部分是用 C 语言来写成的,除 bootloader 部分与具体的硬件架构有关以外,需要用汇编完成,其它的部分几乎都是用 C 写成的,在整个 Linux 内核程序代码中,仅有不到 0.04 % 的代码是由汇编语言完成的。当然,C 语言的源代码和 binutils 的源代码中也有很小的部分与机器有直接的关联,是用汇编写成的。

那么,通过上面的知识,我们可以确定,要打造一个操作系统,你首先得有一个基本的开发环境,这是前提(至于最早的第一个操作系统是如何做出来的,我们在最后的总结部分做简单的说明与回顾)。

那么,很显然,我们需要一个开发环境,这个环境是独立的,是我们以后需要用到的。那么来吧,让我们来编译 gcc 等开发工具。

要编译一个开发语言环境,我们首先得有一个汇编环境,而汇编环境又来源于链接器(^_^. 是不是有点接近最底层的感觉了?),很显然,我们得先有链接器,然后有汇编器,最后才是 gcc 。从零开始打造链接器(Gnu ld)?大可不必,幸运的是,有人已经给我们做了最前面的部分,我们不必从 0、1 开始编码,这得感谢我们的前辈。

展开 binutils (见前面的准备编译环境的说明部分) 。 进入其中,我们开始编译(这是一个临时的编译环境,以后我们还会二次编译这个咚咚,为什么需要二次编译,我们到具体的编译时再讲)。

$ cd binutils-2.16.1
$
我们直接在这个目录下进行编译,我在测试的时候,发现如果是在别的环境下面进行编译,则会造成我们在编译 ld 的时候失败,切记,切记

$ ./configure --prefix=/My_Operation/myuser/tmptools --host=TARGETS_LISTS --targets=TARGETS_LISTS --build=TARGETS_LISTS --enable-targets=all --enable-install-libbfd --disable-rpath
$ make LDFLAGS="-static"

$ cd ld
$ ./configure --prefix=/My_Operation/myuser/tmptools --host=TARGETS_TRIPLET --targets=TARGETS_TRIPLET --build=TARGETS_TRIPLET --enable-targets=all --enable-install-libbfd --disable-rpath
$ make LDFLAGS="-static"

$ cd ..
$ make install
$ cd ld
$ make install


解释一下,这里的安装,新的汇编器和链接器还是会使用系统默认的 glibc 和 linux-heards-libc 的库文件(因为这个时候,还没有我们自己的内核,glibc 和 内核库文件)。
这个 TARGETS_TRIPLET 的具体内容,可以通过运行 ./config.guess 来得到,这个东西很重要,我们的汇编器和链接器其实就是安装在 $PREFIX/bin 和 $PREFIX/$TARGETS_TRIPLET/bin 目录下的。以后,我们安装的 gcc 在调用汇编器和链接器的时候,也会自动到这个目录下去查找汇编器和链接器,如果这个信息错误,你将无法使用自己的汇编器和链接器。

论坛徽章:
4
CU大牛徽章
日期:2013-03-13 15:29:07CU大牛徽章
日期:2013-03-13 15:29:49CU大牛徽章
日期:2013-03-13 15:30:192015年迎新春徽章
日期:2015-03-04 09:57:09
25 [报告]
发表于 2012-04-11 16:35 |只看该作者
LFS啊,写出来不容易

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
26 [报告]
发表于 2012-04-11 16:40 |只看该作者
回复 25# dooros


    不能完全说是 lfs ,因为这咚咚把操作系统的实现涵盖了,所有的操作系统实现都是这样的,你没办法逃出这个内容。

所以可以说,其实就是 lfs ,不同的是加点自己的理解和说明。不是纯过程的罗列而已。

论坛徽章:
11
CU十二周年纪念徽章
日期:2013-10-24 15:41:342015年辞旧岁徽章
日期:2015-03-03 16:54:15丑牛
日期:2015-01-14 10:36:40技术图书徽章
日期:2015-01-12 15:46:11白羊座
日期:2014-11-14 09:35:36狮子座
日期:2014-10-30 13:18:49巳蛇
日期:2014-10-11 12:52:08子鼠
日期:2014-09-28 14:11:06双鱼座
日期:2014-04-22 13:05:48午马
日期:2014-02-11 17:58:002015年迎新春徽章
日期:2015-03-04 09:55:28
27 [报告]
发表于 2012-04-11 17:15 |只看该作者
楼主继续,我是新手菜鸟,学习中!

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
28 [报告]
发表于 2012-04-11 23:47 |只看该作者
请注意,我在编译 binutils 的时候,带了一个很特殊的参数 --enable-targets=all

这个参数的含义是编译出所有的机器码,这个参数的用处在于,如果你需要做一个跨平台的编译器,那么你需要指明这个 --enable-targets=<language> , 如果没有这个参数,默认是编译的和你的母机一样的开发环境。


那么好,现在我们已经有了一个基本的汇编器和链接器了。

下面我们需要开始编译 GCC 了。

我们创建一个编译目录(这里脱离源码目录的好处是一旦编译失败,或者我们设定的编译参数有问题,我们可以直接删除这个编译目录下的内容而不会影响到我们的源码环境)。

$ cd /My_Operation/myuser/tools_src
$ mkdir gccbuild
$ cd gccbuild
$ ../gcc-4.0.3/configure  --prefix=/My_Operation/myuser/tmptools  --disable-nls --enable-shared --with-gnu-as --with-gnu-ld
$ make BOOT_LDFLAGS="-all-static" bootstrap

这里需要说明的第一个参数是 --enable-shared , 我试过,如果没有这个参数,将无法正确编译出 libgcc_s.so.1 和 libgcc_eh.a ,这个很奇怪,不能正确编译出 libgcc_s.so.1 很好理解,因为这个是共享库,不能正确编译出 libgcc_eh.a 就无法理解了,因为这个是一个静态库,本质上来说不需要带 --enable-shared 参数就可以编译出来,然而事实就是如此。

第二个需要解释的地方是 BOOT_LDFLAGS="-all-static" , 这个是告诉编译器,生成的可执行文件全部采用静态方式链接,这样做得目的是使得我们下面的工具能脱离母体,因为如果是没有这个参数,你的 gcc 将需要母体系统的 libgcc_s.so.1 的支持,那我们打造一个完全脱离母体的系统的目标就失败了。

第三个需要解释的地方是 bootstrap , 这个参数是告诉编译器,首先用母体的编译器编译一个 gcc 出来 (事实上形成的是 xgcc ),然后用这个 xgcc 再次编译自己,形成第二个 xgcc ,然后用第二次编译出来的 xgcc 与第一次的 xgcc 比较,没有问题的话,再用第二次的 xgcc 编译出第三个 xgcc ,并将第三次编译出来的 gcc 与前两次的比较,如果没有问题,就用第三次的 xgcc 编译最终的目标 xgcc 并与前面的三次形成的 xgcc 进行比较,如果没有问题,此次编译才算正式通过。
为什么要这么复杂?原因很简单,这是我们做操作系统的基础中的基础,如果这个错了,我们开发的任何软件都无法保证其正确性,更遑论保证操作系统本身的正确性?


$ make install

这个编译会形成的几个很特殊的文件,这里说明一下:

libgcc_s.so.1                                                ;; 这个是我们所有 ELF 文件格式的内链动态链接库,我们所有的可执行文件,只要是采用动态链接方式生成的,都与这个动态库有关,如果这个库文件被删除,我们的系统也就基本完蛋了。
libgcc_eh.a                                                   ;; 这个是我们所有静态链接生成的可执行文件的内链的静态链接库,如果我们编译程序是带有 -Bstatic 这个参数,那么系统将从这个静态链接库连接我们可执行文件的最基本的信息。

crtbegin.o                                                     ;; 所有我们的可执行文件被载入内存的基地址。
crtend.o                                                        ;; 所有我们的可执行文件最后退出的结束地址信息。

这两个文件如果没有,我们无法形成可执行文件。

crtn.o                                                            ;; 这个是一个中间程序代码和数据的分离器(我这样描述也许不确切,但我实在找不到改如何表达这些内容)。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
29 [报告]
发表于 2012-04-11 23:49 |只看该作者
写得好累啊。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
30 [报告]
发表于 2012-04-12 16:10 |只看该作者
本帖最后由 snow888 于 2012-04-12 16:11 编辑

好了,通过上面的努力,我们已经有了一个基本的工具链,从 gcc 到汇编器 as , 再到链接器 ld , 是不是很有趣?

刚刚测试了一下,binutils 在编译的时候,如果带有 --enablllle-targets=all 则编译在 objdump 的时候会失败,不知道是因为我在虚拟机上操作的原因,还是母体的编译器的原因


我们来找找那几个特殊的文件吧。

进入 /My_Operation/myuser/tmptools/lib/gcc/i686-pc-linux-gnu/4.0.3 下面,

ls -al 看看,你能看到什么?   ^_^.

这几个所有程序的总纲文件,是不是都已经存在了?

还记得我们在编译 binutils 的时候说过什么?

如果用我们编译生成的 ld 来开发程序,目前链接的依然是母体的 libgcc_s.so.1 或者是 libgcc_eh.a ,郁闷吗?不要紧,我们来调整一下。

再次进入 /My_Operation/myuser/tools_src/binutils-2.16.1/ld

$ gmake -k clean                           ;; 我们将 ld 目录下所编译生成的所有文件删除
$ gmake LDFLAGS="-static" LIB_PATH=/My_Operation/myuser/tmptools/lib                   ;; 让我们的链接器在链接二进制文件的时候找 /My_Operation/myuser/tmptools/lib 目录下的那些个特殊文件。
$ gmake install

为什么在这个时候调整?因为我们已经有了基础了

特别要注意的是,我们在编译 gcc 的时候, host 、target、build 这三个参数与编译 binutils 的时候要完全一致,否则你的 gcc 将找不到汇编器和链接器,切记!切记!
如无特殊说明,在我们下面的编译过程中,这三个参数都采用前面的值,不再重复提醒。

另一个需要注意的地方是,在安装完 binutils 之后,我们需要进入 /My_Operation/myuser/tmptools/bin 目录,将 ld 改名为 ld-new ,进入 /My_Operation/myuser/tmptools/i686-pc-linux-gnu/bin 目录,将 ld 改名为 ld-new 。

这样做的原因是我们的 glibc 还没有安装,有大量的软件包在链接的时候会使用 -l 参数来指定我们编译的程序需要链接哪些库包,遗憾的是,目前我们还没有,因此使用这个新的调整后的 ld 链接器会出现大量的错误。


下面我们该开始安装 linux-libc-headers 了,这个需要讲的地方不多,其实就是 linux 内核的头文件。

展开,拷贝到 /My_Operation/myuser/tmptools/include 目录下即可。

$ cd linux-libc-header-2.6.12.0/include
$ cp -Rv asm-i386 /My_Operation/myuser/tmptools/include/asm
$ cp -Rv linux /My_Operation/myuser/tmptools/include



您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP