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

热门文章

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

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

比熊犬专用狗粮推荐(比熊犬专用狗粮推荐一下)

摘要: 今天给各位分享比熊犬专用狗粮推荐的知识,其中也会对比熊犬专用狗粮推荐一下进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!本文目录一览:1、比熊吃什么狗粮比较.

动物医院办理条件是什么(动物医院手续)

摘要: 本篇文章给大家谈谈动物医院办理条件是什么,以及动物医院手续对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。本文目录一览:1、如何开一家宠物医院?2、... 本篇

如何从AngularJS模板的HTML中调用encodeURIComponent?

要创建一个调用encodeURIComponent的过滤器,以下是HTML- <div ng-app = "app">    &

兽药百强企业(兽药百强企业有哪些)

摘要: 今天给各位分享兽药百强企业的知识,其中也会对兽药百强企业有哪些进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!本文目录一览:1、迪沙药业集团的集团简介...

兽用活疫苗和死疫苗的保存方法(兽用活疫苗和死疫苗的保存方法区别)

摘要: 本篇文章给大家谈谈兽用活疫苗和死疫苗的保存方法,以及兽用活疫苗和死疫苗的保存方法区别对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。本文目录一览:1、兽药疫苗能放冰箱吗...

vue实现拖拽排序、移除

vue实现拖拽排序、可用于图片、模块交换位置 效果 以“首页模块”为例 录屏软件很卡,实际效果是非常流畅的 本质都一样,只不过一个是单行、一个是双列,使用的是vuedraggle组件vued

12月6日更新19.7M/S,2024年最新高速V2ray/Shadowrocket/SSR/Clash订阅链接免费节点订阅

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

北京农业大学动物医院挂号(北京农大动物医院怎么挂号)

摘要: 今天给各位分享北京农业大学动物医院挂号的知识,其中也会对北京农大动物医院怎么挂号进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!本文目录一览:1、如何预约挂.

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

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

归纳