uCore2020 lab1练习一作业

news2024/11/12 14:39:44

在线环境(无需搭建环境即可复现)

在线实验指导书uCore2020,有些章节无法访问

文章目录

  • lab1
    • 练习一
      • 1、操作系统镜像文件ucore.img生成过程
        • `init.o等文件`的生成过程
        • `bin/kernal`的生成过程
        • `bin/sign`的生成过程
        • `bin/bootblock`的生成过程
        • `bin/ucore.img`的生成过程
      • 2、被系统认为是符合规范的的硬盘主引导扇区的特征
        • `<sys/stat.h>` 和 系统调用`stat()`
    • 拓展

lab1

练习一

练习一问题

1、操作系统镜像文件ucore.img生成过程

开始
编译 boot 目录下的文件生成.o 文件
编译多个 C 文件生成.o 文件
链接生成 bin/sign
链接生成obj/bootblock.o
objcopy 命令转换为obj/bootblock.out
调用sign生成 bin/bootblock
链接生成bin/kernal
使用 dd 命令创建 bin/ucore.img 并填充零
结束
# 详细展现make的编译执行过程
make V=  > make.txt
init.o等文件的生成过程
+ 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
  • -Ikern/init/:告诉GCC在编译过程中搜索头文件时,除了默认的目录外,还需要在kern/init/目录下查找。

  • -fno-builtin:这个参数告诉GCC不要使用内置函数。在某些情况下,这可以提高编译后的代码的可移植性,因为它避免了依赖特定编译器的内部实现。

  • -Wall:这个参数开启所有警告。在开发过程中,通过查看这些警告信息,可以帮助找到潜在的错误或不好的编程习惯。

  • -ggdb:这个参数告诉GCC生成调试信息,这对于调试程序时使用GDB调试器非常有用。

  • -m32:这个参数指定生成的是32位代码。这在构建针对32位系统的程序时非常有用。

  • -gstabs:这个参数告诉GCC使用STABS格式生成调试信息,这是GDB调试器支持的一种格式。

  • -nostdinc:这个参数告诉GCC不要使用标准的stdio.h等标准库头文件。这可能意味着你已经包含了特定的头文件,或者你不想使用标准库中的某些功能。

  • -fno-stack-protector:这个参数告诉GCC不要为代码段添加栈保护。这可能是在某些安全敏感的应用中,为了性能优化而做出的妥协。

  • -Ilibs/、-Ikern/debug/、-Ikern/driver/、-Ikern/trap/、-Ikern/mm/:这些参数分别指定了其他包含目录,用于包含特定目录下的头文件。

  • -c:这个参数告诉GCC只进行编译,不进行链接。这意味着只生成目标文件,而不会生成可执行文件。

  • kern/init/init.c:编译的源代码文件。

  • -o obj/kern/init/init.o:这是编译后的目标文件的输出路径。obj/目录通常用于存放编译后的目标文件。

bin/kernal的生成过程
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
  • -m elf_i386:指定了目标架构为Intel x86架构,使用ELF(Executable and Linkable Format)格式。

  • -nostdlib:表示不使用标准库,这意味着链接器不会自动包含任何标准库函数。

  • -T tools/kernel.ld:指定了一个链接脚本文件kernel.ld,其中包含了关于如何链接和布局各个目标文件的详细信息。

  • -o bin/kernel:指定了输出文件的名称为bin/kernel

目标文件(.o文件)的列表,它们包含了内核的各个部分:
obj/kern/init/init.o:初始化模块的代码
obj/kern/libs/readline.o:用于命令行输入处理的代码
obj/kern/libs/stdio.o:标准输入输出库的代码
obj/kern/debug/kdebug.oobj/kern/debug/kmonitor.oobj/kern/debug/panic.o:调试相关的代码
obj/kern/driver/clock.oobj/kern/driver/console.oobj/kern/driver/intr.oobj/kern/driver/picirq.o:驱动程序相关的代码
obj/kern/trap/trap.oobj/kern/trap/trapentry.oobj/kern/trap/vectors.o:中断处理相关的代码
obj/kern/mm/pmm.o:内存管理模块的代码
obj/libs/printfmt.oobj/libs/string.o:字符串处理和格式化函数的代码
ld工具会将上述*.o文件链接到一起,合并成一个完整的内核映像文件

bin/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

GCC首先会编译tools/sign.c文件生成目标文件obj/sign/tools/sign.o,然后会将这个目标文件链接成一个可执行文件bin/sign。这个可执行文件可以用来执行特定的签名操作,可能是用于对文件或数据进行数字签名的工具。

bin/bootblock的生成过程
+ 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
+ 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

Makefile中的命令对obj/bootblock进一步处理得到bin/bootblock
在这里插入图片描述

bin/ucore.img的生成过程
dd if=/dev/zero of=bin/ucore.img count=10000
dd if=bin/bootblock of=bin/ucore.img conv=notrunc
dd if=bin/kernel of=bin/ucore.img seek=1 conv=notrunc

Linux系统中使用dd命令来创建和操作磁盘镜像

dd if=/dev/zero of=bin/ucore.img count=10000
  • dd:这是用于复制文件的命令,它可以将数据从输入文件(if)复制到输出文件(of)。
  • if=/dev/zero:指定输入文件为/dev/zero。这是一个特殊的文件,读取它会得到无限的0。
  • of=bin/ucore.img:指定输出文件为当前目录下的bin/ucore.img。
  • count=10000:指定要复制的块的数量,这里是10000块。每块的大小默认为512字节,所以这将创建一个大约5MB的文件。
dd if=bin/bootblock of=bin/ucore.img conv=notrunc
  • if=bin/bootblock:指定输入文件为当前目录下的bin/bootblock,这通常是一个启动块或者引导扇区。
  • of=bin/ucore.img:指定输出文件为bin/ucore.img,即之前创建的镜像文件。
  • conv=notrunc:指定不截断输出文件,即保留 ucore.img 文件中超出 bin/bootblock 大小的部分。这条命令会将 bootblock 文件的内容写入到 ucore.img 的开头,而不改变 ucore.img 的其余部分。
dd if=bin/kernel of=bin/ucore.img seek=1 conv=notrunc
  • if=bin/kernel:指定输入文件为当前目录下的bin/kernel,这通常是操作系统的内核映像。
  • of=bin/ucore.img:同上,输出文件是bin/ucore.img。
    seek=1:这个选项告诉dd在输出文件中跳过1块(通常是512字节),从而开始写入的位置不是文件的开始处,而是从第二个块开始。
  • conv=notrunc:同上,保持输出文件的原有大小,不截断。
    这些命令通常用于构建一个包含引导扇区和内核的磁盘镜像文件,该文件可以被模拟器或者实际的硬件用来启动一个操作系统。在这个例子中,bin/ucore.img最终将包含一个引导块和内核,它们在磁盘上的位置分别是从起始处和第二个块开始。

2、被系统认为是符合规范的的硬盘主引导扇区的特征

sign.c负责将obj/bootblock.out加上主引导扇区特征(0x55,0x5A)后转化为bin/bootblock

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>

int main(int argc, char *argv[])
{
	// 结构体 stat:用于存储通过 stat 系统调用获取的文件状态信息
    struct stat st;

    // 确保能够正确地提供了所需的两个文件名参数!
    if (argc != 3) 
    {
        fprintf(stderr, "Usage: <input filename> <output filename>\n");
        return -1;
    }

    // 使用 stat 函数获取输入文件的状态信息,并检查文件是否存在以及是否可以访问
    if (stat(argv[1], &st) != 0)
    {
        fprintf(stderr, "Error opening file '%s': %s\n", argv[1], strerror(errno));
        return -1;
    }

    // 'obj/bootblock.out' size: 472 bytes
    printf("'%s' size: %lld bytes\n", argv[1], (long long)st.st_size);

    // 如果输入文件的大小超过 510 字节,打印错误消息并退出。
    if (st.st_size > 510)
    {
        fprintf(stderr, "%lld >> 510!!\n", (long long)st.st_size);
        return -1;
    }

    // 分配一个 512 字节的缓冲区,并用 0 填充它
    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);

    // 主引导记录的签名(0x55和0xAA) 在缓冲区的第 510 和 511 个字节位置分别设置值为 0x55 和 0xAA。
    buf[510] = 0x55;
    buf[511] = 0xAA;

    // 打开输出文件进行二进制写入,并将缓冲区(512 字节)写入到输出文件中。
    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;
}


<sys/stat.h> 和 系统调用stat()

<sys/stat.h> 是一个在 Unix 和类 Unix 操作系统中常见的头文件,它定义了用于操作文件系统信息的结构和函数。

系统调用stat()用于获取文件或文件系统状态信息来填充结构体stat。

//如果成功,返回 0;如果出错,返回 -1 并设置 errno。
int stat(const char *path, struct stat *buf);

以下是 sys/stat.h 中常见的结构和宏定义的简要介绍:

// 结构体 stat:用于存储通过 stat 系统调用获取的文件状态信息
struct stat {
    dev_t     st_dev;         // 文件的设备号
    ino_t     st_ino;         // 文件的 i-node 号
    mode_t    st_mode;        // 文件的保护模式
    nlink_t   st_nlink;       // 文件的链接数
    uid_t     st_uid;         // 文件所有者的用户 ID
    gid_t     st_gid;         // 文件所有者的组 ID
    dev_t     st_rdev;        // 设备文件的设备号,如果是普通文件则为 0
    off_t     st_size;        // 文件大小,字节数
    blksize_t st_blksize;     // 块大小
    blkcnt_t  st_blocks;      // 块数量
    time_t    st_atime;       // 最后访问时间
    time_t    st_mtime;       // 最后修改时间
    time_t    st_ctime;       // 最后状态改变时间
};

// 宏定义:sys/stat.h 还定义了一些宏,用于检查文件类型。
#define S_ISDIR(m)  ((m) & S_IFDIR)  // 判断是否为目录
#define S_ISCHR(m)  ((m) & S_IFCHR)  // 判断是否为字符设备
#define S_ISBLK(m)  ((m) & S_IFBLK)  // 判断是否为块设备
#define S_ISREG(m)  ((m) & S_IFREG)  // 判断是否为普通文件
#define S_ISFIFO(m) ((m) & S_IFIFO)  // 判断是否为管道
#define S_ISLNK(m)  ((m) & S_IFLNK)  // 判断是否为符号链接
#define S_ISSOCK(m) ((m) & S_IFSOCK) // 判断是否为套接字

下面是一个使用 sys/stat.h 和 stat 函数的简单示例代码:

#include <stdio.h>
#include <sys/stat.h>

int main() {
    struct stat st;
    if (stat("example.txt", &st) == -1) {
        perror("stat error");
        return 1;
    }

    printf("File size: %ld bytes\\n", st.st_size);
    printf("Last modified time: %s", ctime(&st.st_mtime));
    return 0;
}

这段代码会尝试获取名为 “example.txt” 的文件状态信息,并打印文件大小和最后修改时间。如果获取失败,它会打印错误信息。

拓展

比较 ISO、BIN/CUE 和 IMG,常见磁盘映像文件解析
关于int main(int argc,char* argv[])详解
聊聊x86计算机启动发生的事?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1957176.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

搭建AI无人直播插件

在当今的数字时代&#xff0c;直播已成为一种极为流行的内容传播方式&#xff0c;而人工智能(AI)技术的飞速发展更是为直播行业注入了新的活力。 AI无人直播插件&#xff0c;作为这一趋势下的产物&#xff0c;不仅能够实现24小时不间断的直播内容生成&#xff0c;还能根据观众…

SpringCloud Alibaba 微服务(四):Sentinel

目录 前言 一、什么是Sentinel&#xff1f; Sentinel 的主要特性 Sentinel 的开源生态 二、Sentinel的核心功能 三、Sentinel 的主要优势与特性 1、丰富的流控规则 2、完善的熔断降级机制 3、实时监控和控制台 4、多数据源支持 5、扩展性强 四、Sentinel 与 Hystrix…

Redis 序列化 GenericJackson2JsonRedisSerializer和Jackson2JsonRedisSerializer的区别

GenericJackson2JsonRedisSerializer 和 Jackson2JsonRedisSerializer 是 Spring Data Redis 提供的两种基于 Jackson 的 Redis 序列化器。 它们的主要区别在于序列化和反序列化的方式以及适用的场景。 GenericJackson2JsonRedisSerializer 序列化方式&#xff1a;在序列化对…

为Mac配置Alfred

参考资料&#xff1a; Alfred神器使用手册 | louis blogMacOS神器之Alfred workflow概览GitHub - arpir/Alfred-Workflows-Collection: 一些好用的 Alfred Workflow 一、修改快捷键 Spotlight的默认快捷键是Command Space Alfred的默认快捷键是Option Space 可以将Alfred和…

[网络编程】网络编程的基础使用

系列文章目录 1、 初识网络 网络编程套接字 系列文章目录前言一、TCP和UDP协议的引入二、UDP网络编程1.Java中的UDP2.UDP回显代码案例3.UDP网络编程的注意事项 三、TCP网络编程1.TCP回显代码案例2.TCP多线程使用 总结 前言 在学习完基础的网络知识后&#xff0c;完成跨主机通…

关于 OSPF LSA 序列号范围 0x80000001-0x7FFFFFFF 释疑正本清源

注&#xff1a;机翻&#xff0c;未校对。 正本&#xff1a;RFC 2328 OSPF Version 2 中相关解释 April 1998 12.1.6. LS sequence number 12.1.6. 序列号 The sequence number field is a signed 32-bit integer. It is used to detect old and duplicate LSAs. The space …

set,map(java)

前言&#xff1a;要了解set和map&#xff0c;首先需要对搜索树和哈希有一定的了解&#xff0c;才能进一步深入的了解set和map。 1.搜索树 &#xff08;1&#xff09;性质&#xff1a; 若它的左子树不为空&#xff0c;则左子树上所有节点值都小于根节点的值。 若它的右子树不…

事件如何驱动图表运行

状态流图如何响应事件 Stateflow图表仅在以循环方式响应事件时执行。 由于图表在单个线程上运行&#xff0c;因此基于事件发生的操作对该事件是原子性的。图表中由事件引起的所有活动都在执行返回到接收事件之前发生的活动之前完成。一旦事件启动了一个操作&#xff0c;除非被…

全网最全程序员接单网站

程序员客栈-领先的程序员自由工作平台-程序员兼职 (proginn.com) 闲鱼 - 闲不住&#xff0c;上闲鱼&#xff01; (goofish.com) 猪八戒网-品质企业服务 就找猪八戒 (zbj.com) 电鸭社区-专注远程工作招聘交流-远程工作&#xff0c;从电鸭开始 (eleduck.com) 开源众包-百万开发者…

Java台球厅助教教练预约上门到店系统源码

&#x1f3b1;一杆在手&#xff0c;天下我有&#xff01;台球助教教练预约系统&#xff0c;让球技飙升不是梦&#x1f680; &#x1f3af;【开篇&#xff1a;台球爱好者的福音来啦&#xff01;】&#x1f3af; 还在为找不到合适的台球教练而烦恼吗&#xff1f;或是想要在家就…

代码实践思考:C++和Python

起因 在人工智能工具日益强大的今天 如何更高效的进行代码学习 如何借助智能工具实现代码转换&#xff1f; 是否直接可以使用&#xff1f;为何&#xff1f; 如何实现不同的编程语言之间代码的无损转换&#xff1f; x86与arm C 云课五分钟-02第一个代码复现-终端甜甜圈C-CS…

GEE错误——文件导出的时候出现Error: User memory limit exceeded. (Error code: 3)

错误简介 在试图将我的表导出到资产文件夹,但出现了内存错误。我不知道我做错了什么。相同的脚本适用于其他年份。文件导出的时候出现Error: User memory limit exceeded. (Error code: 3) 函数 reduceToVectors(reducer, geometry, scale, geometryType, eightConnected,…

雪花算法的一些问题解析

前言 最近做项目&#xff0c;有些老旧项目&#xff0c;需要生成分布式唯一ID&#xff0c;不允许重复&#xff0c;此时如果要对其他中间件和数据库依赖小&#xff0c;那么就需要一套固定的ID生成规则&#xff0c;雪花算法就正当合适&#xff0c;当时Twitter就是用来存储数据库I…

服务器主机安全有多重要

一、什么是主机安全 主机安全&#xff0c;作为维护计算机系统核心安全的基石&#xff0c;旨在全面捍卫硬件与软件免受任何未经授权的侵扰、篡改、数据泄露等安全挑战。这一过程不仅聚焦于数据存储与处理的保密性、完整性及可用性&#xff0c;还深入至硬件构造、固件层、以及系…

利用C++11的异步操作实现一个线程池

利用C11的异步操作实现一个线程池 利用C11的异步操作实现一个线程池 介绍关于一些代码细节的解释测试 介绍 基于线程池执行任务的时候&#xff0c;入口函数内部执行逻辑是固定的&#xff0c;因此选择std::packaged_task加上std::future的组合来实现。 具体使用可以见我上一…

2025年第7届图像处理和机器视觉国际会议 (IPMV 2025)即将召开!

2025年第7届图像处理和机器视觉国际会议 (IPMV 2025)将于2025年1月10日-12日在中国香港举行。图像处理和机器视觉作为当代信息技术领域的重要分支&#xff0c;不仅推动了人工智能技术的飞速发展&#xff0c;也为各行各业带来了革命性的变革。本次会议旨在汇聚全球图像处理和机器…

极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图

目录 极致的灵活度满足工程美学&#xff1a;用Vue Flow绘制一个完美流程图 一、环境要求 二、初识Vue Flow 2.1、安装Vue Flow 2.2、Vue Flow构成 2.3、一个小坑 2.4、入门案例 三、Vue Flow优秀的自定义功能 3.1、引入 3.2、节点与连线的自定义 ①打样&#xff08;…

MySQL - 通过SQL语句导出数据到CSV文件

在 MySQL 中&#xff0c;可以使用 SELECT ... INTO OUTFILE 语句将查询结果导出为 CSV 文件&#xff0c;然后再将 CSV 文件转换为 Excel 格式。以下是一个示例&#xff1a; SELECT column1, column2, column3 INTO OUTFILE /path/to/file.csv FIELDS TERMINATED BY , ENCLO…

git 迁移仓库的方法

git Git是一个开源的分布式版本控制系统&#xff0c;由Linus Torvalds在2005年创建&#xff0c;用于有效、高速地处理从小到大的项目管理。它最初是为Linux内核开发而设计的&#xff0c;但很快被广泛用于各种项目。 以下是Git的一些主要特性&#xff1a; 分布式架构&#xff…

接近传感器 - 从零开始认识各种传感器【第十七期】

1、什么是接近传感器 接近传感器常被用于检测物体的距离或者是否有物体靠近。它通常发射电磁场或电磁波&#xff08;例如红外线&#xff09;来探测物体的位置。当有物体靠近时&#xff0c;传感器会接收到反射的电磁波信号&#xff0c;从而触发相应的电路或者控制系统。它广泛应…