[从 0 开始写一个操作系统] 六、编译过程分析

六、编译过程分析

作者:解琛
时间:2020 年 12 月 18 日

清华操作系统实验课程实验一:系统软件启动过程

基于一个基本的 helloWorld 工程来分析其编译过程。

6.1 终端输出分析

使用 make 进行编译,终端输出如下。

moocos-> make
+ cc kern/init/init.c
+ ld bin/kernel
+ cc boot/bootasm.S
+ cc boot/bootmain.c
+ cc tools/sign.c
+ ld bin/bootblock
'obj/bootblock.out' size: 484 bytes
build 512 bytes boot sector: 'bin/bootblock' success!
10000+0 records in
10000+0 records out
5120000 bytes (5.1 MB) copied, 0.0393024 s, 130 MB/s
1+0 records in
1+0 records out
512 bytes (512 B) copied, 0.000188811 s, 2.7 MB/s
11+1 records in
11+1 records out
6138 bytes (6.1 kB) copied, 0.000236221 s, 26.0 MB/s

对终端的输出结果进行分析。

+ cc kern/init/init.c

+cc 表示编译了 kern/init 文件中的 init.c 文件。

+ ld bin/kernel
'obj/bootblock.out' size: 484 bytes
build 512 bytes boot sector: 'bin/bootblock' success!

+ ld 表示将文件转化成可执行程序 kernel,并放到 bin 目录下。这里转化成 bootblock.out,可以理解成一个 Bootloader 的执行程序,大小为 484 字节。

再将 bootblock.out 转化为 512 字节对齐的、符合规范的主引导扇区文件 bootblock,放到 bin 目录中。

10000+0 records in
10000+0 records out
5120000 bytes (5.1 MB) copied, 0.0393024 s, 130 MB/s

这里表示创建并生成了一个 5.1 MB 的虚拟硬盘,这个虚拟硬盘就会基于里面的数据来执行相应的代码,写入的速度为 130 MB/s。

1+0 records in
1+0 records out
512 bytes (512 B) copied, 0.000188811 s, 2.7 MB/s
11+1 records in
11+1 records out
6138 bytes (6.1 kB) copied, 0.000236221 s, 26.0 MB/s

这里表示前面生成的 bootblock 引导程序和 kernel 内核程序被成功写入到了硬盘中。

6.2 编译详细过程分析

gcc -I -L -l区别

Gcc编译选项-fno-builtin -fno-builtin-function

gcc中的-w -W和-Wall选项

GCC -c选项:生成目标文件

gcc编译为什么要加-g选项

make V= 命令查看 make 命令的详细执行过程。

moocos-> make V=
+ cc kern/init/init.c
gcc -Ikern/init/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/init/init.c -o obj/kern/init/init.o
+ ld bin/kernel
ld -m    elf_i386 -nostdlib -T tools/kernel.ld -o bin/kernel  obj/kern/init/init.o  
+ cc boot/bootasm.S
gcc -Iboot/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Os -nostdinc -c boot/bootasm.S -o obj/boot/bootasm.o
+ cc boot/bootmain.c
gcc -Iboot/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Os -nostdinc -c boot/bootmain.c -o obj/boot/bootmain.o
+ cc tools/sign.c
gcc -Itools/ -g -Wall -O2 -c tools/sign.c -o obj/sign/tools/sign.o
gcc -g -Wall -O2 obj/sign/tools/sign.o -o bin/sign
+ ld bin/bootblock
ld -m    elf_i386 -nostdlib -N -e start -Ttext 0x7C00 obj/boot/bootasm.o obj/boot/bootmain.o -o obj/bootblock.o
'obj/bootblock.out' size: 484 bytes
build 512 bytes boot sector: 'bin/bootblock' success!
dd if=/dev/zero of=bin/ucore.img count=10000
10000+0 records in
10000+0 records out
5120000 bytes (5.1 MB) copied, 0.0369833 s, 138 MB/s
dd if=bin/bootblock of=bin/ucore.img conv=notrunc
1+0 records in
1+0 records out
512 bytes (512 B) copied, 0.000196741 s, 2.6 MB/s
dd if=bin/kernel of=bin/ucore.img seek=1 conv=notrunc
11+1 records in
11+1 records out
6138 bytes (6.1 kB) copied, 0.000172118 s, 35.7 MB/s

现在对这段编译过程进行详细的分析。

gcc -Ikern/init/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/init/init.c -o obj/kern/init/init.o

使用 gcc 对 .c 文件进行预处理、编译和汇编,具体参数的含义如下。

参数解释
-Ikern/init/从 kern/init/ 目录中寻找头文件;
-fno-builtin不使用 C 语言的内建函数;
-Wall编译后显示所有警告;
-ggdb生成可供 gdb 使用的调试信息;
-m32生成适用于 32 位环境的代码;
-gstabs生成 stabs 格式的调试信息;
-nostdinc不在标准系统文件夹寻找头文件,只在 -I 等参数指定的文件夹中搜索头文件;
-fno-stack-protector不生成用于检测缓冲区溢出的代码;
-Ilibs/从 libs/ 目录中寻找头文件;
-Ikern/debug/从 kern/debug/ 目录中寻找头文件;
-Ikern/driver/从 kern/driver/ 目录中寻找头文件;
-Ikern/trap/从 kern/trap/ 目录中寻找头文件;
-Ikern/mm/从 kern/mm/ 目录中寻找头文件;
-c kern/init/init.c将 kern/init/ 目录中的 init.c 的 c 文件进行预处理、编译和汇编;
-o obj/kern/init/init.o指定输出的文件到 obj/kern/init/ 目录中,并命名为 init.o。
ld -m elf_i386 -nostdlib -T tools/kernel.ld -o bin/kernel  obj/kern/init/init.o  

使用 ld 命令将指定文件链接为可执行程序,具体参数的含义如下。

参数解释
-m elf_i386指定模拟仿真链接器为 elf_i386;
-nostdlib只搜索命令行上显式指定的库目录,在链接器脚本中指定的库目录(包括在命令行中指定的链接器脚本)将被忽略;
-T tools/kernel.ld指定链接器的脚本为 tools 目录下的 kernel.ld 文件;
-o bin/kernel obj/kern/init/init.o将转化好的可执行文件放到 bin/ 目录下,并命名为 kernel,链接的文件为 obj/kern/init/ 目录中的 init.o。
gcc -Iboot/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Os -nostdinc -c boot/bootasm.S -o obj/boot/bootasm.o
参数解释
-Os为减小代码大小而进行优化;
gcc -Itools/ -g -Wall -O2 -c tools/sign.c -o obj/sign/tools/sign.o
参数解释
-g编译时保留代码的文字信息,便于 gbk 调试;
ld -m    elf_i386 -nostdlib -N -e start -Ttext 0x7C00 obj/boot/bootasm.o obj/boot/bootmain.o -o obj/bootblock.o
参数解释
-N将文本和数据部分设置为可读和可写,不对数据段进行页对齐,禁用对共享库的链接;
-e start使用 start 作为程序开始执行的显式符号,而不是默认的入口点;如果没有名为 start 的符号,链接器将尝试将条目解析为一个数字,并使用该数字作为入口地址(该数字将以 10 进制进行解析;可以使用前缀 0x 表示 16 为基数,或使用前缀 0 表示 8 进制);
-Ttext 0x7C00-Ttext 等同于 --section-start,即将 0x7C00 作为段的起始地址, -e start -Ttext 0x7C00,即使用 start 作为程序开始的显式符号,若不存在,则使用 0x7C00 作为段的起始地址;
dd if=/dev/zero of=bin/ucore.img count=10000

使用以上 dd 命令,通过将 /dev/zero 文件拷贝的方式来创建一个 5.1 MB 的虚拟硬盘 ucore.img。

参数解释
if=/dev/zero从 /dev/zero 文件中读取内容来替代标准输入 stdin;
of=bin/ucore.img将输出的内容写入到 bin 目录下的 ucore.img,替代标准的输出 stdout;
count = 10000复制 10000 个输入块;
dd if=bin/bootblock of=bin/ucore.img conv=notrunc
参数解释
conv=notrunc根据逗号分隔的符号列表转换文件,不截断输出文件;
dd if=bin/kernel of=bin/ucore.img seek=1 conv=notrunc
参数解释
seek=1在输出开始时跳过 1 个单位大小的块;
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

解琛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值