MIT XV6 - 1.1 Lab: Xv6 and Unix utilities - user/_sleep 是什么?做什么?

接上文 MIT XV6 - 1.1 Lab: Xv6 and Unix utilities - sleep 是怎样练成的?

user/_sleep 是什么?

book-riscv-rev3.pdf 3.8节有对Xv6 binary文件的格式描述

Xv6 binaries are formatted in the widely-used ELF format, defined in (kernel/elf.h). An ELF binary
consists of an ELF header, struct elfhdr (kernel/elf.h:6), followed by a sequence of program
section headers, struct proghdr (kernel/elf.h:25). Each progvhdr describes a section of the
application that must be loaded into memory; xv6 programs have two program section headers:
one for instructions and one for data.

  • 让我们验证一下他的文件格式
    riscv64-unknown-elf-readelf -h user/_sleep  
    ELF Header:                                 
      Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00          # ELF 文件的魔数,用于标识文件类型
      Class:                             ELF64                          # 64 位 ELF 文件
      Data:                              2's complement, little endian  # 使用 2 的补码表示数字,小端序存储
      Version:                           1 (current)                    # ELF 格式的当前版本
      OS/ABI:                            UNIX - System V                # 目标操作系统为 UNIX System V
      ABI Version:                       0                              # ABI 版本号
      Type:                              EXEC (Executable file)         # 这是一个可执行文件
      Machine:                           RISC-V                         # 目标架构为 RISC-V
      Version:                           0x1                            # ELF 文件版本
      Entry point address:               0x64                           # 程序入口点的虚拟地址
      Start of program headers:          64 (bytes into file)           # 程序头表在文件中的偏移量
      Start of section headers:          31008 (bytes into file)        # 节头表在文件中的偏移量
      Flags:                             0x5, RVC, double-float ABI     # 标志位:RISC-V 压缩指令集,双精度浮点数 ABI
      Size of this header:               64 (bytes)                     # ELF 头的大小
      Size of program headers:           56 (bytes)                     # 每个程序头的大小
      Number of program headers:         4                              # 程序头的数量
      Size of section headers:           64 (bytes)                     # 每个节头的大小
      Number of section headers:         18                             # 节头的数量
      Section header string table index: 17                             # 节头字符串表的索引
    

我们知道,在Unix系统中,一个新进程的诞生是通过forkexec配合得来的,通过fork创建一个副本,然后通过exec将指定的binary加载进内存空间中并开始执行,教材中也对此有所讲解,依然是book-riscv-rev3.pdf 3.8节,简单看一眼

在这里插入图片描述

  • 让我们看看我们的 user/_sleep

    riscv64-unknown-elf-objdump -p user/_sleep 
    
    user/_sleep:     file format elf64-littleriscv
    
    Program Header:
    0x70000003 off    0x0000000000006af8 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**0
        filesz 0x000000000000005a memsz 0x0000000000000000 flags r--
    LOAD off    0x0000000000001000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**12
        filesz 0x0000000000001000 memsz 0x0000000000001000 flags r-x
    LOAD off    0x0000000000002000 vaddr 0x0000000000001000 paddr 0x0000000000001000 align 2**12
        filesz 0x0000000000000000 memsz 0x0000000000000020 flags rw-
    STACK off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4
        filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-
    
  • 让我们来看看AI是怎么解释的
    在这里插入图片描述

  • 当然我们的 user/_sleep 里面还有更多东西

    riscv64-unknown-elf-objdump -h user/_sleep  
    Sections:                                                                        
    Idx Name          Size      VMA               LMA               File off  Algn   # 列标题:索引、名称、大小、虚拟地址、加载地址、文件偏移、对齐
      0 .text         0000082a  0000000000000000  0000000000000000  00001000  2**1   # 代码段:包含可执行指令
                      CONTENTS, ALLOC, LOAD, READONLY, CODE                           # 属性:有内容、已分配、可加载、只读、代码
      1 .rodata       000007d0  0000000000000830  0000000000000830  00001830  2**3   # 只读数据段:包含常量数据(如字符串常量)
                      CONTENTS, ALLOC, LOAD, READONLY, DATA                           # 属性:有内容、已分配、可加载、只读、数据
      2 .data         00000000  0000000000001000  0000000000001000  00002000  2**0   # 数据段:包含已初始化的全局变量
                      CONTENTS, ALLOC, LOAD, DATA                                      # 属性:有内容、已分配、可加载、数据
      3 .bss          00000020  0000000000001000  0000000000001000  00002000  2**3   # BSS段:包含未初始化的全局变量
                      ALLOC                                                           # 属性:已分配
      4 .debug_info   00000ff8  0000000000000000  0000000000000000  00002000  2**0   # 调试信息段:包含DWARF调试信息
                      CONTENTS, READONLY, DEBUGGING, OCTETS                           # 属性:有内容、只读、调试用、字节数据
      5 .debug_abbrev 00000643  0000000000000000  0000000000000000  00002ff8  2**0   # 调试缩写表:DWARF调试信息的缩写表
                      CONTENTS, READONLY, DEBUGGING, OCTETS                           # 属性:有内容、只读、调试用、字节数据
      6 .debug_loc    00001f21  0000000000000000  0000000000000000  0000363b  2**0   # 调试位置信息:变量位置信息
                      CONTENTS, READONLY, DEBUGGING, OCTETS                           # 属性:有内容、只读、调试用、字节数据
      7 .debug_aranges 000000f0  0000000000000000  0000000000000000  00005560  2**4  # 调试地址范围:用于快速定位调试信息
                      CONTENTS, READONLY, DEBUGGING, OCTETS                           # 属性:有内容、只读、调试用、字节数据
      8 .debug_line   000011ab  0000000000000000  0000000000000000  00005650  2**0   # 调试行号信息:源代码行号映射
                      CONTENTS, READONLY, DEBUGGING, OCTETS                           # 属性:有内容、只读、调试用、字节数据
      9 .debug_str    000002e4  0000000000000000  0000000000000000  000067fb  2**0   # 调试字符串表:调试信息中的字符串
                      CONTENTS, READONLY, DEBUGGING, OCTETS                           # 属性:有内容、只读、调试用、字节数据
    10 .comment      00000019  0000000000000000  0000000000000000  00006adf  2**0   # 注释段:包含编译器版本等信息
                      CONTENTS, READONLY                                              # 属性:有内容、只读
    11 .riscv.attributes 0000005a  0000000000000000  0000000000000000  00006af8  2**0 # RISC-V特定属性段
                      CONTENTS, READONLY                                              # 属性:有内容、只读
    12 .debug_frame  000004e0  0000000000000000  0000000000000000  00006b58  2**3   # 调试帧信息:用于栈回溯
                      CONTENTS, READONLY, DEBUGGING, OCTETS                           # 属性:有内容、只读、调试用、字节数据
    13 .debug_ranges 00000050  0000000000000000  0000000000000000  00007038  2**0   # 调试范围信息:用于描述变量范围
                      CONTENTS, READONLY, DEBUGGING, OCTETS                           # 属性:有内容、只读、调试用、字节数据
    

    我就不解释了,这个东西给我一天也解释不清楚,解释不完全(是真的不清楚)

user/_sleep 做什么?

让我们打开 user/sleep.asm 看一下汇编代码

   0:	1141                	addi	sp,sp,-16
   2:	e406                	sd	ra,8(sp)
   4:	e022                	sd	s0,0(sp)
   6:	0800                	addi	s0,sp,16
    if (argc != 2)
   8:	4789                	li	a5,2
   a:	02f50063          	beq	a0,a5,2a <main+0x2a>
    {
        fprintf(2, "Usage: sleep <seconds>\n");
   e:	00001597          	auipc	a1,0x1
  12:	82258593          	addi	a1,a1,-2014 # 830 <malloc+0x100>
  16:	853e                	mv	a0,a5
  18:	00000097          	auipc	ra,0x0
  1c:	62e080e7          	jalr	1582(ra) # 646 <fprintf>
        exit(1);
  20:	4505                	li	a0,1
  22:	00000097          	auipc	ra,0x0
  26:	2fc080e7          	jalr	764(ra) # 31e <exit>
    }

    if (sleep(atoi(argv[1])) != 0)
  2a:	6588                	ld	a0,8(a1)
  2c:	00000097          	auipc	ra,0x0
  30:	1ec080e7          	jalr	492(ra) # 218 <atoi>
  34:	00000097          	auipc	ra,0x0
  38:	37a080e7          	jalr	890(ra) # 3ae <sleep>
  3c:	cd19                	beqz	a0,5a <main+0x5a>
    {
        fprintf(2, "sleep: failed to sleep\n");
  3e:	00001597          	auipc	a1,0x1
  42:	80a58593          	addi	a1,a1,-2038 # 848 <malloc+0x118>
  46:	4509                	li	a0,2
  48:	00000097          	auipc	ra,0x0
  4c:	5fe080e7          	jalr	1534(ra) # 646 <fprintf>
        exit(1);
  50:	4505                	li	a0,1
  52:	00000097          	auipc	ra,0x0
  56:	2cc080e7          	jalr	716(ra) # 31e <exit>
    }

    exit(0);
  5a:	4501                	li	a0,0
  5c:	00000097          	auipc	ra,0x0
  60:	2c2080e7          	jalr	706(ra) # 31e <exit>

注意这一条指令

  38:	37a080e7          	jalr	890(ra) # 3ae <sleep>

这是一条跳转指令,地址是 3ae,经过搜索可以看到 sleep 函数的汇编代码

00000000000003ae <sleep>:                      # 函数入口点,地址为 0x3ae
.global sleep                                  # 声明 sleep 为全局符号
sleep:                                         # 函数标签
 li a7, SYS_sleep                              # 将系统调用号 13 (SYS_sleep) 加载到寄存器 a7
 3ae:	48b5                li	a7,13          # 机器码:48b5 表示 li a7,13
 ecall                                         # 执行系统调用指令
 3b0:	00000073          	ecall              # 机器码:00000073 表示 ecall
 ret                                           # 从函数返回
 3b4:	8082                ret                # 机器码:8082 表示 ret

我们忽略其他各种分支判断以及错误码打印,exit调用等等, 可以看到sleep.c的核心就是在条件达成时,调用函数sleep,而 sleep函数内的实现就是利用 ecall 指令触发系统调用,当系统调用完成后,函数返回。

瞎谈

有大佬说过 Algorithms + Data Structures = Programs

那么从操作系统的角度来看,是不是 Data + SysCall = Programs 也是成立的?因为程序的一切的一切最终都是要把你想做的事情组织成一条条数据,通过系统调用的方式来达成目的?比如播放音乐、播放视频、玩video game,毕竟系统调用应该是应用程序控制硬件资源的唯一途径(吧?)。

### 回答1:xv6是一个基于Unix操作系统,它是一个教学用途的操作系统,旨在教授操作系统的基本概念和实现。它是在MIT的x86架构上开发的,包括了Unix的一些基本功能,如进程管理、文件系统、内存管理等。xv6的源代码是公开的,可以用于学习和研究。 Unix utilitiesUnix操作系统中的一些基本工具,如ls、cd、cp、mv、rm等。这些工具可以帮助用户管理文件和目录,执行各种操作。这些工具的实现是基于Unix的系统调用,可以通过编写C程序来调用这些系统调用实现相应的功能。这些工具是Unix操作系统的基础,也是其他操作系统的参考。 ### 回答2: lab: xv6 and unix utilities 实验是一项旨在帮助学生深入理解操作系统Unix 工具使用的实验。该实验分为两个部分,第一部分教授学生如何构建和运行 xv6 操作系统;第二部分则重点教授 Unix 工具的使用。 在 xv6 操作系统部分,学生将学习到操作系统内核的基本结构和实现原理。实验将引导学生理解内存管理、进程调度、系统调用等关键操作系统概念。此外,学生还将学习如何编写简单的 shell 以及如何通过修改 xv6 内核代码来实现新的系统调用和功能。 在 Unix 工具部分,学生将探索 Unix 系统中广泛使用的常见工具。这些工具包括 vi 编辑器、grep、awk、sed 等。实验将介绍这些工具的基本使用方法以及它们在处理文本和数据时的实际应用。这部分实验还将让学生深入了解 shell 和 shell 脚本的编写,帮助他们在 Unix 环境中轻松地编写脚本和自动化任务。 lab: xv6 and unix utilities 实验对计算机科学专业的学生具有重要意义。通过完成这个实验,学生将建立起对操作系统Unix 工具的深入理解,为他们成为一名优秀的软件工程师奠定坚实的基础。同时,这个实验还将为学生提供实践经验,让他们能够将所学知识应用到真实的软件开发和运维中。 ### 回答3: Lab: xv6 and Unix Utilities是一个计算机科学领域的实验,旨在让学生深入了解Unix操作系统以及操作系统本身的自我管理机制。在这个实验中,学生需要从零开始构建一个类似于Unix操作系统,在这个操作系统中,学生需要设计一些基本命令,例如ls,cat,grep等等,并且将它们与系统的底层API结合起来,以实现各种功能。此外,学生还需要了解和探索xv6这个开发工具,它是一个轻量级基于Unix操作系统实现,具有一定的可移植性和简洁性,因此,它可以作为一个基础框架来实现一个完整的Unix操作系统。 这个实验的目标是让学生了解Unix的基本命令结构和API,以及操作系统内部的一些基本机制,例如进程管理,文件系统交互以及进程通信等等。此外,通过实现这些命令,学生还可以学到一些基本的C语言编程技能,例如文件操作,字符串处理以及进程管理等等。还可以学习到如何使用Git等版本控制工具,以及如何进行调试和测试代码的技巧。 在整个实验过程中,学生需要有较强的自我管理能力和综合运用能力,因为在实现这些命令的同时,他们还需要和其他团队成员进行交流和合作,以及不断改进和完善他们的代码。总之,这个实验是一个非常有趣且富有挑战性的计算机科学课程,通过完成这个实验,学生可以更好地了解操作系统的构造和运作机制,以及如何设计和开发高效的系统级应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值