lab_0 清华大学ucore实验环境配置详细步骤!(小白入)

lab_1 清华大学ucore bootload启动ucore os(预备知识)

Lab_1:练习1——理解通过make生成执行文件的过程

练习一:理解通过make生成执行文件的过程。

列出本实验各练习中对应的OS原理的知识点,并说明本实验中的实现部分如何对应和体现了原理中的基本概念和关键知识点。

在此练习中,大家需要通过静态分析代码来了解:

  1. 操作系统镜像文件ucore.img是如何一步一步生成的?(需要比较详细地解释Makefile中每一条相关命令和命令参数的含义,以及说明命令导致的结果)
  2. 一个被系统认为是符合规范的硬盘主引导扇区的特征是什么?

补充材料:

如何调试Makefile

当执行make时,一般只会显示输出,不会显示make到底执行了哪些命令。

如想了解make执行了哪些命令,可以执行:

$ make "V="

要获取更多有关make的信息,可上网查询,并请执行

$ man make

一、操作步骤

1、输入make clean,删掉上次的make命令所产生的object文件(后缀为“.o”的文件)及可执行文件

myliuxb@myliuxb-virtual-machine:~/ucore/labcodes_answer/lab1_result$ make clean rm -f -r obj bin

2、输入make V=这实际就是设置一个标记,使得make它的执行过程能够展现出来。能够知道Bootloader和ucore是如何一步步生成的。

myliuxb@myliuxb-virtual-machine:~/ucore/labcodes_answer/lab1_result$ make V= + cc kern/init/init.c i386-elf-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 + cc kern/libs/stdio.c i386-elf-gcc -Ikern/libs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/libs/stdio.c -o obj/kern/libs/stdio.o + cc kern/libs/readline.c i386-elf-gcc -Ikern/libs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/libs/readline.c -o obj/kern/libs/readline.o + cc kern/debug/panic.c i386-elf-gcc -Ikern/debug/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/debug/panic.c -o obj/kern/debug/panic.o + cc kern/debug/kdebug.c i386-elf-gcc -Ikern/debug/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/debug/kdebug.c -o obj/kern/debug/kdebug.o + cc kern/debug/kmonitor.c i386-elf-gcc -Ikern/debug/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/debug/kmonitor.c -o obj/kern/debug/kmonitor.o + cc kern/driver/clock.c i386-elf-gcc -Ikern/driver/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/clock.c -o obj/kern/driver/clock.o + cc kern/driver/console.c i386-elf-gcc -Ikern/driver/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/console.c -o obj/kern/driver/console.o + cc kern/driver/picirq.c i386-elf-gcc -Ikern/driver/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/picirq.c -o obj/kern/driver/picirq.o + cc kern/driver/intr.c i386-elf-gcc -Ikern/driver/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/intr.c -o obj/kern/driver/intr.o + cc kern/trap/trap.c i386-elf-gcc -Ikern/trap/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/trap/trap.c -o obj/kern/trap/trap.o + cc kern/trap/vectors.S i386-elf-gcc -Ikern/trap/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/trap/vectors.S -o obj/kern/trap/vectors.o + cc kern/trap/trapentry.S i386-elf-gcc -Ikern/trap/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/trap/trapentry.S -o obj/kern/trap/trapentry.o + cc kern/mm/pmm.c i386-elf-gcc -Ikern/mm/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/mm/pmm.c -o obj/kern/mm/pmm.o + cc libs/string.c i386-elf-gcc -Ilibs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/  -c libs/string.c -o obj/libs/string.o + cc libs/printfmt.c i386-elf-gcc -Ilibs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/  -c libs/printfmt.c -o obj/libs/printfmt.o + ld bin/kernel i386-elf-ld -m    elf_i386 -nostdlib -T tools/kernel.ld -o bin/kernel  obj/kern/init/init.o obj/kern/libs/stdio.o obj/kern/libs/readline.o obj/kern/debug/panic.o obj/kern/debug/kdebug.o obj/kern/debug/kmonitor.o obj/kern/driver/clock.o obj/kern/driver/console.o obj/kern/driver/picirq.o obj/kern/driver/intr.o obj/kern/trap/trap.o obj/kern/trap/vectors.o obj/kern/trap/trapentry.o obj/kern/mm/pmm.o  obj/libs/string.o obj/libs/printfmt.o + cc boot/bootasm.S i386-elf-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 i386-elf-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 i386-elf-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: 500 bytes build 512 bytes boot sector: 'bin/bootblock' success! dd if=/dev/zero of=bin/ucore.img count=10000 记录了10000+0 的读入 记录了10000+0 的写出 5120000 bytes (5.1 MB, 4.9 MiB) copied, 0.0416907 s, 123 MB/s dd if=bin/bootblock of=bin/ucore.img conv=notrunc 记录了1+0 的读入 记录了1+0 的写出 512 bytes copied, 0.000462614 s, 1.1 MB/s dd if=bin/kernel of=bin/ucore.img seek=1 conv=notrunc 记录了146+1 的读入 记录了146+1 的写出 74844 bytes (75 kB, 73 KiB) copied, 0.000676749 s, 111 MB/s

二、问题一:操作系统镜像文件ucore.img是如何一步一步生成的?

问题:操作系统镜像文件ucore.img是如何一步一步生成的?(需要比较详细地解释Makefile中每一条相关命令和命令参数的含义,以及说明命令导致的结果)

1.大概流程

1.在下图代码中可以看到它调用了gcc,把C的源代码编译成了所谓的.o文件,是目标文件。通过查看make的执行过程,可以发现将项目中的kern和libs boot中的C文件都编译成.o文件

通过make生成执行文件的过程详解_在线工具

通过make生成执行文件的过程详解_在线工具

最后生成的.o文件全部存在obj文件夹中

2.然后通过ld会把这些目标文件转换成 像下面bootblock.out这样的可执行文件,可以理解为是bootloader一个执行程序(后文bootblock和bootloader其实是一个意思)

通过make生成执行文件的过程详解_在线工具

3.dd命令可以把bootloader放到一个虚拟的硬盘里面去,在这里生成一个虚拟硬盘叫ucore.img 然后我们的硬件模拟器就会基于这个虚拟硬盘中的数据来执行相应的代码。把bootloader放到ucore.img的虚拟硬盘中

通过make生成执行文件的过程详解_在线工具

4.我们可以看到最后生成两个软件,第一个是kernel,第二个叫Bootloader,kernel实际上是ucore的组成部分。

通过make生成执行文件的过程详解_在线工具

通过make生成执行文件的过程详解_在线工具

其实如何生成这两个文件是取决于Makefile文件,但是这个文件比较复杂,其实只要关注到底用了哪些.C程序来最后生成Bootloader和ucore就够了。

2.具体分析:(这里参考另一个博主

需要生成ucore.img首先需要生成bootblock,而生成bootblock需要先生成bootmain.o和bootasm.o还有sign.o

+ ld bin/kernel ld -m    elf_i386 -nostdlib -T tools/kernel.ld -o bin/kernel  obj/kern/init/init.o obj/kern/libs/readline.o obj/kern/libs/stdio.o obj/kern/debug/kdebug.o obj/kern/debug/kmonitor.o obj/kern/debug/panic.o obj/kern/driver/clock.o obj/kern/driver/console.o obj/kern/driver/intr.o obj/kern/driver/picirq.o obj/kern/trap/trap.o obj/kern/trap/trapentry.o obj/kern/trap/vectors.o obj/kern/mm/pmm.o  obj/libs/printfmt.o obj/libs/string.o

ld将.o文件整合成可执行文件kernel,而这些.o文件是Makefile文件通过命令使用gcc把有关kernel的.c文件编译生成

+ 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: 488 bytes build 512 bytes boot sector: 'bin/bootblock' success!

同理ld也将.o文件整合成可执行文件bootblock,大小为488字节,但还是放入512字节扇区中,但是,而这些.o文件也是Makefile文件通过命令使用gcc把有关bootloader的.c文件编译生成

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.0601803 s, 85.1 MB/s

创建10000块扇区,每个扇区512字节,制成ucore.img虚拟磁盘

dd if=bin/bootblock of=bin/ucore.img conv=notrunc 1+0 records in 1+0 records out 512 bytes (512 B) copied, 0.000141238 s, 3.6 MB/s

将bootblock存到ucore.img虚拟磁盘的第一块

dd if=bin/kernel of=bin/ucore.img seek=1 conv=notrunc 146+1 records in 146+1 records out 74923 bytes (75 kB) copied, 0.00356787 s, 21.0 MB/s

将kernel存到ucore.img虚拟磁盘的第二块及之后几块,注意seek1,最终ucore.img虚拟磁盘制作完成

3.分析Makefile文件

之前有总结过关于Makefile的规则,在第三节https://www.cnblogs.com/450go/p/16019887.html

Makefile文件中,可以看到对应的生成ucore.img的过程及相应语句如下:

# create ucore.img UCOREIMG	:= $(call totarget,ucore.img)  $(UCOREIMG): $(kernel) $(bootblock) 	$(V)dd if=/dev/zero of=$@ count=10000 	$(V)dd if=$(bootblock) of=$@ conv=notrunc 	$(V)dd if=$(kernel) of=$@ seek=1 conv=notrunc  $(call create_target,ucore.img)

逐条分析:

$(kernel):生成kernel。需要以下两步

1.编译kern/目录下的C程序,生成kernel需要的.o文件

$(call add_files_cc,$(call listf_cc,$(KSRCDIR)),kernel,$(KCFLAGS))

实际执行的命令为:

+ cc kern/init/init.c i386-elf-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 + cc kern/libs/stdio.c i386-elf-gcc -Ikern/libs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/libs/stdio.c -o obj/kern/libs/stdio.o + cc kern/libs/readline.c i386-elf-gcc -Ikern/libs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/libs/readline.c -o obj/kern/libs/readline.o + cc kern/debug/panic.c i386-elf-gcc -Ikern/debug/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/debug/panic.c -o obj/kern/debug/panic.o + cc kern/debug/kdebug.c i386-elf-gcc -Ikern/debug/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/debug/kdebug.c -o obj/kern/debug/kdebug.o + cc kern/debug/kmonitor.c i386-elf-gcc -Ikern/debug/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/debug/kmonitor.c -o obj/kern/debug/kmonitor.o + cc kern/driver/clock.c i386-elf-gcc -Ikern/driver/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/clock.c -o obj/kern/driver/clock.o + cc kern/driver/console.c i386-elf-gcc -Ikern/driver/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/console.c -o obj/kern/driver/console.o + cc kern/driver/picirq.c i386-elf-gcc -Ikern/driver/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/picirq.c -o obj/kern/driver/picirq.o + cc kern/driver/intr.c i386-elf-gcc -Ikern/driver/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/intr.c -o obj/kern/driver/intr.o + cc kern/trap/trap.c i386-elf-gcc -Ikern/trap/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/trap/trap.c -o obj/kern/trap/trap.o + cc kern/trap/vectors.S i386-elf-gcc -Ikern/trap/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/trap/vectors.S -o obj/kern/trap/vectors.o + cc kern/trap/trapentry.S i386-elf-gcc -Ikern/trap/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/trap/trapentry.S -o obj/kern/trap/trapentry.o + cc kern/mm/pmm.c i386-elf-gcc -Ikern/mm/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/mm/pmm.c -o obj/kern/mm/pmm.o

2.链接这些.o文件,生成kernel

# create kernel target kernel = $(call totarget,kernel)  $(kernel): tools/kernel.ld  $(kernel): $(KOBJS) 	@echo + ld $@ 	$(V)$(LD) $(LDFLAGS) -T tools/kernel.ld -o $@ $(KOBJS) 	@$(OBJDUMP) -S $@ > $(call asmfile,kernel) 	@$(OBJDUMP) -t $@ | $(SED) '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $(call symfile,kernel)

执行的实际命令为:

+ ld bin/kernel ld -m    elf_i386 -nostdlib -T tools/kernel.ld -o bin/kernel  obj/kern/init/init.o obj/kern/libs/readline.o obj/kern/libs/stdio.o obj/kern/debug/kdebug.o obj/kern/debug/kmonitor.o obj/kern/debug/panic.o obj/kern/driver/clock.o obj/kern/driver/console.o obj/kern/driver/intr.o obj/kern/driver/picirq.o obj/kern/trap/trap.o obj/kern/trap/trapentry.o obj/kern/trap/vectors.o obj/kern/mm/pmm.o  obj/libs/printfmt.o obj/libs/string.o

$(bootblock)****:生成bootblock。需要以下三步:

1.生成bootmain.o和bootasm.o

bootfiles = $(call listf_cc,boot) $(foreach f,$(bootfiles),$(call cc_compile,$(f),$(CC),$(CFLAGS) -Os -nostdinc))

执行的实际命令为

+ 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

2.编译tools/sign.c,生成sign.o

# create 'sign' tools $(call add_files_host,tools/sign.c,sign,sign) $(call create_target_host,sign,sign)

执行的实际命令为:

+ 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

3.链接以上的.o文件

bootblock = $(call totarget,bootblock)  $(bootblock): $(call toobj,$(bootfiles)) | $(call totarget,sign) 	@echo + ld $@ 	$(V)$(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 $^ -o $(call toobj,bootblock) 	@$(OBJDUMP) -S $(call objfile,bootblock) > $(call asmfile,bootblock) 	@$(OBJDUMP) -t $(call objfile,bootblock) | $(SED) '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $(call symfile,bootblock) 	@$(OBJCOPY) -S -O binary $(call objfile,bootblock) $(call outfile,bootblock) 	@$(call totarget,sign) $(call outfile,bootblock) $(bootblock)  $(call create_target,bootblock)

执行的实际命令为:

+ 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

$(V)dd if=/dev/zero of=$@ count=10000:生成一个有10000个块的文件,每个块默认512字节,用0填充。

执行的实际命令为:

dd ``if``=/dev/zero of=bin/ucore.img count=10000

$(V)dd if=$(bootblock) of=$@ conv=notrunc:把bootblock中的内容写到第一个块。

执行的实际命令为:

dd ``if``=bin/bootblock of=bin/ucore.img conv=notrunc

$(V)dd if=$(kernel) of=$@ seek=1 conv=notrunc:从第二个块开始写kernel中的内容。

执行的实际命令为:

dd ``if``=bin/kernel of=bin/ucore.img seek=1 conv=notrunc

三、问题二:一个被系统认为是符合规范的硬盘主引导扇区的特征是什么?

引导扇区的大小为512字节,最后两个字节为标志性结束字节0x55,0xAA,做完这样的检查才能认为是符合规范的磁盘主引导扇区。

在sign.c文件中,它完成了相应的特征的标记,查看sign.c文件

#include <stdio.h> #include <errno.h> #include <string.h> #include <sys/stat.h>  int main(int argc, char *argv[]) {     struct stat st;     if (argc != 3) {         fprintf(stderr, "Usage: <input filename> <output filename>\n");         return -1;     }     if (stat(argv[1], &st) != 0) {         fprintf(stderr, "Error opening file '%s': %s\n", argv[1], strerror(errno));         return -1;     }     printf("'%s' size: %lld bytes\n", argv[1], (long long)st.st_size);     if (st.st_size > 510) {         fprintf(stderr, "%lld >> 510!!\n", (long long)st.st_size);         return -1;     }     char buf[512];     memset(buf, 0, sizeof(buf));     FILE *ifp = fopen(argv[1], "rb");     int size = fread(buf, 1, st.st_size, ifp);     if (size != st.st_size) {         fprintf(stderr, "read '%s' error, size is %d.\n", argv[1], size);         return -1;     }     fclose(ifp);     buf[510] = 0x55;     buf[511] = 0xAA;     FILE *ofp = fopen(argv[2], "wb+");     size = fwrite(buf, 1, 512, ofp);     if (size != 512) {         fprintf(stderr, "write '%s' error, size is %d.\n", argv[2], size);         return -1;     }     fclose(ofp);     printf("build 512 bytes boot sector: '%s' success!\n", argv[2]);     return 0; }

通过make生成执行文件的过程详解_在线工具

引导扇区的大小为512字节,最后两个字节为标志性结束字节0x55,0xAA

热门文章

3月4日更新22.1M/S,2025年最新高速Clash/V2ray/SSR/Shadowrocket订阅链接免费节点地址分享

这一次的节点更新覆盖了日本、香港、欧洲、美国、加拿大、韩国、新加坡等地区,最高速度可达22.1 M/S。只需复制下方的Clash/v2ray订阅链接,在客户端添加后即可正常使用。

和田宠物医院污水处理方案(宠物医院污水处理方式)

摘要: 今天给各位分享和田宠物医院污水处理方案的知识,其中也会对宠物医院污水处理方式进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!本文目录一览:1、医院污水处理操.

宠物粮食排名前十名品牌有哪些(宠物粮品牌大全)

摘要: 本篇文章给大家谈谈宠物粮食排名前十名品牌有哪些,以及宠物粮品牌大全对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。本文目录一览:1、小型犬狗粮排名前十品牌...

并发编程基础底层原理学习_在线工具

进程 进程就是应用程序在内存中分配的空间,也就是正在运行的程序,各个进程之间互不干扰。同时进程保存着程序每一个时刻运行的状态。进程的两个基本元素是程序代码和与代码关联的数据集。进程执行的任意时刻包含了

2月24日更新23M/S,2025年最新高速V2ray/Shadowrocket/SSR/Clash订阅链接免费节点地址分享

这一次的节点更新覆盖了新加坡、欧洲、香港、美国、加拿大、日本、韩国等地区,最高速度可达23 M/S。只需复制下方的Clash/v2ray订阅链接,在客户端添加后即可正常使用。

2月26日更新20.9M/S,2025年最新高速SSR/Shadowrocket/V2ray/Clash订阅链接免费节点地址分享

这一次的节点更新覆盖了韩国、新加坡、加拿大、美国、欧洲、日本、香港等地区,最高速度可达20.9 M/S。只需复制下方的Clash/v2ray订阅链接,在客户端添加后即可正常使用。

动物疫苗作用是什么(动物疫苗的概念)

摘要: 今天给各位分享动物疫苗作用是什么的知识,其中也会对动物疫苗的概念进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!本文目录一览:1、宠物为什么要打疫苗?...

1月7日更新23M/S,2025年最新高速SSR/V2ray/Clash/Shadowrocket订阅链接免费节点地址分享

这一次的节点更新覆盖了日本、新加坡、加拿大、韩国、欧洲、香港、美国等地区,最高速度可达23 M/S。只需复制下方的Clash/v2ray订阅链接,在客户端添加后即可正常使用。

2月6日更新20.6M/S,2025年最新高速Shadowrocket/Clash/V2ray/SSR订阅链接免费节点地址分享

这一次的节点更新覆盖了加拿大、美国、日本、韩国、新加坡、香港、欧洲等地区,最高速度可达20.6 M/S。只需复制下方的Clash/v2ray订阅链接,在客户端添加后即可正常使用。

2月12日更新21.3M/S,2025年最新高速V2ray/SSR/Clash/Shadowrocket订阅链接免费节点地址分享

这一次的节点更新覆盖了美国、韩国、新加坡、加拿大、香港、欧洲、日本等地区,最高速度可达21.3 M/S。只需复制下方的Clash/v2ray订阅链接,在客户端添加后即可正常使用。

归纳