OS:lab4课下基础

OS:lab4课下基础 1.系统调用 1.1 系统调用相关概念 ​ 在MIPS中,syscall是用于执行系统调用的自陷指令,它使得进程陷入到内核的异常处理程序中,由内核根据系统调用时的上下文执行相应的内核函数,完成相应的功能,并最终返回到syscall的后一条指令。 存在只能由内核来完成的操作(读写设备、创建进程、IO等) C标准库中的一些函数的实现依赖于操作系统 通过执行syscall指令,用户进程可以陷入到内核态,请求内核提供的服务 通过系统调用陷入到内核态时,需要在用户态与内核态之间进行数据传递与保护 ​ 系统调用保证了系统的安全性:内核将自己能够提供的服务以系统调用的方式提供给用户空间,用户程序只能将服务相关的参数交予操作系统执行 API : Application Programming Interface,程序之间的接口 ​ 直接使用系统调用较为麻烦,于是产生了一系列用户空间的API定义,他们在系统的调用的基础上,实现了更多更高级的常用功能。用户在编写程序时可以直接调用高层次的API来实现各种功能。 ​ 通过层级划分使得程序具有更好的可移植性,只要程序以来的API不变,无论底层的系统调用如何变化,都不会影响 1.2 系统调用机制的实现 ​ 异常分发向量组(exception_handlers)中的8号异常,即为操作系统处理系统调用时的异常。 MOS实验代码中,kern目录下即为内核态代码,user目录下即为用户态代码 ​ 以user/lib/debugf.c中的debugf函数来学习处理系统调用的流程(debugf函数是一个debug信息输出函数,进行了IO方面的系统调用) ​ debugf函数的调用链为(系统调用请求从用户态向内核态传递) debugf调用字符串输出函数debug_output debug_output调用了用户空间的syscall_*函数(这里的*为通配符,代表着用户空间进行系统调用的一组操作,都定义在用户态代码syscall_lab.c中,这里调用的是syscall_print_cons) syscall_*函数调用msyscall函数,系统陷入内核态(msyscall是汇编代码,直接调用syscall)。 内核态中将异常分发到handle_sys函数,将系统所需信息传递进内核(输出字符串s) 内核取得信息,执行对应的内核空间的系统调用函数sys_*(kern/syscall_all.c) 系统调用完成,返回值传递回用户态 从系统调用函数返回,回到debugf调用处 通过上述描述,对于系统调用的处理实际上是从用户空间向系统空间进行传递的,用户空间中的syscall_*函数与内核中的sys_*是一一对应的,syscall_*函数是用户空间中最接近内核的函数,他调用msyscall中的汇编代码syscall直接陷入内核态,sys_*函数是内核中系统调用的具体实现。 ​ 直接调用syscall陷入内核的msyscall函数具有六个参数,其中第一个参数是与调用名相似的宏,例如SYS_print_cons,被称为系统调用号(include/syscall.h),用来区分不同的系统调用,其余还有五个参数,即为系统调用时需要传递给内核的参数。 回忆MIPS函数调用规范中的参数传递,前四个参数保存在寄存器中 Exercise 4.1 msyscall 进行系统调用(syscall),并返回到msyscall的调用者处(jr),syscall_* #include <asm/asm.h> LEAF(msyscall) // Just use 'syscall' instruction and return. /* Exercise 4.1: Your code here. */ syscall #陷入内核 jr ra #返回调用者 syscall_* END(msyscall) ​ 通过汇编指令syscall陷入内核态后,处理器将PC寄存器指向一个内核中固定的异常处理入口(见lab3中不同异常处理跳转到的地址) ...

May 6, 2024 · 15 min · sudo

OS:lab3实验报告

OS:lab3实验报告 Thinking 3.1 请结合 MOS 中的页目录自映射应用解释代码中 e->env_pgdir[PDX(UVPT)] = PADDR(e->env_pgdir) | PTE_V 的含义。 UVPT是用户地址空间中页表项的起始地址 结合页目录自映射我们知道,只要给定了二级页表项的起始地址,我们就能通过自映射机制计算出页目录的起始虚拟地址 UVPT为二级页表基地址 则页目录基地址为$UVPT + (UVPT»12)*4 = UVPT+UVPT»10$ 映射到页目录的页表项的地址为$UVPT + ((UVPT+UVPT»10)»12)*4 = UVPT + UVPT»10 + UVPT»20$ 该项相对于页目录的index:或者说该项相对于页目录的地址偏移为$UVPT»20$,对应的偏移量为UVPT»22,即为PDX(UVPT) PDX(UVPT)可以得到二级页表起始虚拟地址UVPT的页目录号 e->env_pgdir[PDX(UVPT)]即为指向页目录中指向页目录自身的页目录项 PADDR(e->env_pgdir)得到页目录的物理地址并赋予有效位PTE_V Thinking 3.2 elf_load_seg 以函数指针的形式,接受外部自定义的回调函数 map_page。请你找到与之相关的 data 这一参数在此处的来源,并思考它的作用。没有这个参数可不可以?为什么? data是传入的进程控制块指针 作用:在增加虚拟地址到物理地址的映射时提供当前进程地址空间的页目录基地址pg_dir和asid(load_icode_mapper),所有这个参数是必要的 Thinking 3.3 结合 elf_load_seg 的参数和实现,考虑该函数需要处理哪些页面加载的情况 elf_load_seg函数的实现(elfloader.c) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 int elf_load_seg(Elf32_Phdr *ph, const void *bin, elf_mapper_t map_page, void *data) { u_long va = ph->p_vaddr; size_t bin_size = ph->p_filesz; size_t sgsize = ph->p_memsz; u_int perm = PTE_V; if (ph->p_flags & PF_W) { perm |= PTE_D; } int r; size_t i; u_long offset = va - ROUNDDOWN(va, PAGE_SIZE); if (offset != 0) { if ((r = map_page(data, va, offset, perm, bin, MIN(bin_size, PAGE_SIZE - offset))) != 0) { return r; } } /* Step 1: load all content of bin into memory. */ for (i = offset ? MIN(bin_size, PAGE_SIZE - offset) : 0; i < bin_size; i += PAGE_SIZE) { if ((r = map_page(data, va + i, 0, perm, bin + i, MIN(bin_size - i, PAGE_SIZE))) != 0) { return r; } } /* Step 2: alloc pages to reach `sgsize` when `bin_size` < `sgsize`. */ while (i < sgsize) { if ((r = map_page(data, va + i, 0, perm, NULL, MIN(sgsize - i, PAGE_SIZE))) != 0) { return r; } i += PAGE_SIZE; } return 0; } ...

April 21, 2024 · 2 min · sudo

OS理论期中考试复习

OS理论期中考试复习 一.引论 1. 操作系统定义 操作系统是一组管理计算机硬件资源的软件集合,他向计算机程序提供共性的服务 2. 操作系统发展史 电子管时期:软件:手工修改硬件逻辑单元连接 解决人和CPU的矛盾:软件和硬件分离 2.1 批处理系统 加载在计算机上的一个系统软件,在他的控制下,计算机能够自动地、成批地处理一个或多个用户的作业 用户将一批作业提交给操作系统后就不再干预 2.1.1 联机批处理系统 在主机和输入机之间增加一个存储设备——磁带,在运行于主机的监督程序(OS)的自动控制下,计算机可自动完成:成批地把输入机上的用户作业读入磁带,依次把磁带上的用户作业读入主机内存并执行,然后把计算结果向输出机输出。完成了上一批作业后,监督程序又从输入机上输入另一批作业,保存在磁带上,重复处理 优点:监督程序不停地处理各个作业,实现了作业到作业的自动转接,减少了作业建立时间和手工操作时间,克服了人机矛盾。 缺点:CPU与慢速的外设之间的矛盾:在作业输入和结果输出时,主机的高速CPU需要等待慢速的输入输出设备完成工作,主机处于“忙等”状态 2.1.2 脱机批处理系统 增加一台不与初级直接相连而是与输入输出设备打交道的卫星机 优点:主机不直接与慢速的输入输出设备打交道,而是与速度相对较快的磁带机发生关系,主机与卫星机并行工作,发挥主机的高速计算能力 缺点:主机内存中仅存放一道作业,每当该作业运行期间发生输入输出请求后,高速的CPU便处于等待低速的IO完成状态,COU空闲 2.2 多道程序系统 多道程序设计技术,指允许多个程序同时进入内存并运行。即同时把多个程序放入内存中,并允许他们交替在CPU中运行,共享系统中的各种硬软件资源 当一道程序因为IO请求而暂停运行时,CPU便立即转去运行另一道程序,不同程序间的切换运行 使CPU得到充分利用,同时改善IO设备和内存的利用率,提高整个系统的资源利用率和系统吞吐量 宏观上并行:进入系统的几道程序都处于运行过程中,都开始了各自的运行,但都未运行完毕 微观上串行:各道程序轮流地使用CPU,并交替运行 2.3 单道程序系统 内存中只有一道程序,存在计算时IO设备空闲或进行IO操作时CPU空闲 2.4 多道批处理系统 多道:系统内可同时容纳多个作业 成批:在系统运行过程中,不允许用户与其作业发生交互 优点:系统吞吐量大,资源利用率高 缺点:平均周转时间长,单个用户不能交互,多用户使用和单独控制的矛盾 2.5 分时系统 分时技术:把处理机的运行时间分成很短的时间片,按时间片轮流把CPU分配给各联机作业/程序使用,给不同的用户提供程序的使用 一台计算机同时连接多个用户终端 特点 多路性:宏观上看多个用户并行工作,微观上看是各用户轮流使用计算机 交互性:用户可以根据系统对请求的响应结果,进一步向系统提出新的请求(交互式系统) 独立性:用户之间相互独立,互不干扰 及时性:系统对用户的输入及时作出响应 2.6 网络操作系统 传统单机OS上加单独软件层,提供联网功能和资源的远程访问,多机互联 2.7 分布式操作系统 多台机器统一管理形成单一系统 2.8 实时系统 在某个时间限制内及时完成某些及时任务不需要时间片排队 3. 操作系统的基本实现机制 用户态和内核态 用户态和内核态所在的内存空间不一样 CPU的运行状态不一样 指令的执行权限不一样 从用户态转入内核态 ...

April 16, 2024 · 4 min · sudo

OS第三次理论作业

OS第三次理论作业 一.第一题 (1) 答 32位虚拟地址空间,故整个的地址空间大小为4GB;页内偏移量为12位,故一页有4096字节 (2) 答 考察了二级页表的自映射机制,第一级页表所在的逻辑地址即为第一级页表中第一个页表项的逻辑地址,第一个页表项映射到第一个二级页表,第一个二级页表对应的虚拟页号为$0x80000000 » 12 = 0x00080000$,故该页表项为第$0x0008000$个页表项,相对于页表项起始地址的偏移量为$0x00080000 * 4$,故对应的逻辑地址为$PT_{base} + (PT_{base} «12) *4 = 0x80200000$ (3) 答 逻辑地址0x0:访问逻辑地址0x0时,对应的页目录偏移量为0,对应的有效位为0,引发了缺页中断,需要进行重填 逻辑地址0x00803004:访问逻辑地址0x00803004时,对应的页目录偏移量为2,有效位为1,对应的物理地址为0x5000,逻辑地址对应的二级页表偏移量为3,对应的页表项有效位为1,对应的物理地址为0x20000,页内偏移量为4字节, 若系统为小端存储(数据的低字节放在低地址空间,大小端的顺序是以字节为单位的,而不是bit),则数据排布为0000_9000,0032_6001,则访问到的数据为0x1 若系统为大端存储(数据的高字节放在低地址空间),则数据排布为0090_0000,0160_3200,则访问到的数据为0x0 逻辑地址0x00402001:访问逻辑地址0x00402001时,对应的页目录偏移量为1,有效位为1,对应的物理地址为0x1000,逻辑地址对应的二级页表偏移量为2,对应的页表项有效位为1,对应的物理地址为0x5000,页内偏移量为1字节,访问到的数据为0x0 (4) 答 ​ 要想访问物理地址0x326028,先看他的物理页号,物理页号为$0x326028 » 12 = 0x326000$则对应起始物理地址为0x20000页表中偏移量为1的项,对应页目录中偏移量为3的页表项的映射,页内偏移量为$0x28$,故逻辑地址为$0x00c01028$ 二.第二题 前提:LOAD STORE操作的均为虚拟地址 大尾端为将数据的高位存在低地址端 0000430: e684 6c4e 0100 1800 53ef 0100 0100 0000 0000440: b484 6c4e 004e ed00 0000 0000 0100 0000 在大端模式下,前32位应该这样读: e6 84 6c 4e 在小端模式下,前32位应该这样读: 4e 6c 84 e6 ...

April 14, 2024 · 1 min · sudo

OS:lab3课下基础

OS:lab3课下基础 1.进程 由于没有实现线程,本实验中进程既是基本的分配单元,也是基本的执行单元 1.1 进程控制块 ​ 进程控制块(Process Control Block)是用来管理进程的数据结构,可以记录进程的变化过程,记录进程的外部特征。PCB是系统感知进程存在的唯一标志,进程与PCB是一一对应的。在MOS中,PCB定义为一个Env结构体 1 2 3 4 5 6 7 8 9 10 11 struct Env { struct Trapframe env_tf; // saved context (registers) before switching LIST_ENTRY(Env) env_link; // intrusive entry in 'env_free_list' u_int env_id; // unique environment identifier u_int env_asid; // ASID of this env u_int env_parent_id; // env_id of this env's parent u_int env_status; // status of this env Pde *env_pgdir; // page directory TAILQ_ENTRY(Env) env_sched_link; // intrusive entry in 'env_sched_list' u_int env_pri; // schedule priority }; env_tf : 在发生进程调度,或当陷入内核时,会将当时的进程上下文环境保存在env_tf变量中 ...

April 8, 2024 · 13 min · sudo

OS:lab2实验报告

OS:lab2实验报告 Thinking 2.1 **在编写的C程序中,指针变量中存储的地址被视为虚拟地址,还是物理地址?MIPS汇编程序中lw和sw指令使用的地址被视为虚拟 地址,还是物理地址? ** 在编写的C程序中,指针变量中存储的地址为虚拟地址 汇编程序中lw,sw发送的也是虚拟地址 Thinking 2.2 请从可重用性的角度,阐述用宏来实现链表的好处 使用宏定义对链表操作进行封装,可以实现代码的复用,即减少了工作量,也提高了程序的可读性 请你查看实验环境中的 /usr/include/sys/queue.h,了解其中单向链表与循环链表的实现,比较它们与本实验中使用的双向链表,分析三者在插入与删除操作上的性能差异 对于单向链表,由于它只能获得每一项的后面一项,因此在删除时需要遍历整个链表;同样,如果是在某一项的前面插入,也需要从head开始遍历这个链表。但是如果是“在某一项之后插入”,单项链表可以直接进行该操作。 对于循环链表,因为它仍然是单向的,所以在“删除”、“某一项之前插入”、“某一项之后插入”三个操作的性能和单项链表相同。但是,由于循环链表首尾相连,同时维护了一个指向尾项的指针,因此它可以直接在尾部插入。 对于双向链表,因为它可以直接获得某一项的前后两项,所以无论是“删除”还是“在某一项前或后插入”都可以以O(1)的开销实现。但是,双向链表没有维护指向尾部的指针,因此无法直接将某一项插入链表尾部,如要实现该操作还需要遍历整个链表。 Thinking 2.3 选择Page_list正确的展开结构 C struct Page_list{ struct { struct { struct Page *le_next; struct Page **le_prev; } pp_link; u_short pp_ref; }* lh_first; } Thinking 2.4 请阅读上面有关TLB的描述,从虚拟内存和多进程操作系统的实现角度,阐述ASID的必要性。 操作系统会给每一个进程分配一个页表,每个页表都有自己的虚拟地址空间,而同一虚拟地址在不同地址空间中通常映射到不同的物理地址。如果没有ASID来区分当前虚拟地址是在哪个进程中使用,则可能会将该虚拟地址映射到错误的物理地址。(每一个进程都有自己的虚拟地址空间4G,ASID可以区分不同进程同一虚拟地址转换成物理地址的方法) 请阅读 MIPS 4Kc 文档《MIPS32® 4K™ Processor Core Family Software User’s Manual》的 Section 3.3.1 与 Section 3.4,结合 ASID 段的位数,说明 4Kc中可容纳不同的地址空间的最大数量 ASID有8位,即最多可以有$2^8$个地址空间(进程数量) Thinking 2.5 tlb_invalidate 和 tlb_out 的调用关系是怎样的? ...

March 31, 2024 · 2 min · sudo

OS:lab2课下基础

OS:lab2课下基础 一.物理内存管理 1.虚拟地址映射到物理地址 在MIPS-4Kc上,软件访存虚拟地址会先被MMU(Memory Management Unit) 映射到物理地址,随后使用物理地址来访问内存或其他外设 ​ 虚拟地址空间中的四个部分 kseg0:存放内核代码与数据 将虚拟地址的最高位清0得到物理地址 通过Cache访存 0x8000_0000 - 0x9fff_ffff kseg1:访问外设 将虚拟地址的最高三位清0得到物理地址 不通过Cache访存 0xa000_0000 - 0xbfff_ffff kuseg:用户程序代码与数据 通过TLB转换成物理地址 通过Cache访存 0x0000_0000 - 0x7fff_ffff 2.内核程序启动 lab1中内核启动后跳转到mips_init函数,lab2中在mips_init中增加三个函数 在建立内核管理机制时,实验中都通过kseg0访问内存 2.1 mips_detect_memory 探测硬件可用内存,并对一些和内存管理相关的变量进行初始化 void mips_detect_memory(u_int _memsize) { /* Step 1: Initialize memsize. */ memsize = _memsize; /* Step 2: Calculate the corresponding 'npage' value. */ /* Exercise 2.1: Your code here. */ npage = memsize / PAGE_SIZE; printk("Memory size: %lu KiB, number of pages: %lu\n", memsize / 1024, npage); } memsize对应总物理内存对应的字节数 npage对应总物理页数 PAGE_SIZE是mmu.h中定义的宏,大小是4096,即每个物理页面的大小为4096字节 2.2 mips_vm_init alloc 在建立起页式内存管理机制之前,使用alloc进行内存空间的分配 ...

March 31, 2024 · 10 min · sudo

OS第二次理论作业

OS第二次理论作业 1.多道程序的存储管理 空间的分配:分区式分配,将内存分为一些大小相等或不等的分区,每个应用程序占用一个或几个分区,操作系统占用其中一个分区 1.1 固定(静态)式分区分配 当系统初始化时,把存储空间划分为若干个任意大小的区域,然后将这些区域分配给每个用户作业 将内存划分为若干个固定大小的连续分区 分区大小相等:多个相同程序的并发执行 分区大小不等:多个小分区,适量的中等分区,少量的大分区 优点:易于实现,开销小 缺点:内碎片造成浪费,分区总数固定,限制了并发执行的程序数目 采用的数据结构:分区表——记录分区的大小和使用情况 1.1.1 单一队列分配方式 ​ 需要加载程序时,选择一个当前闲置且容量足够大的分区进行加载,即多个用户程序排在一个共同的队列中等待分区 1.1.2 多队列分配方式 ​ 防止单一队列造成的小程序占用大分区的情况,采用多个队列,每个分区一个队列,程序按照大小排在相应的队列中,即小分区排队的都是小程序,大分区排队的都是大程序 1.2 可变(动态)式分区分配 可变式分区:分区的边界可以移动,即分区的大小可变 优点:没有内碎片 缺点:有外碎片 1.2.0 内碎片与外碎片 内碎片:分配给作业的存储空间中未被利用的部分,如固定分区中存在的碎片 内碎片其实已经被分配出去了,只是没有被利用,在作业完成后会得到释放 外碎片:系统中无法利用的小的空闲分区,如分区与分区之间存在的碎片,动态分区管理会产生外部碎片 消除外部碎片的方法:紧凑技术 1.2.1 位图表示法 给每个分配单元赋予一个字位,用来记录该分配单元是否闲置。字位取值为0表示单元闲置,取值为1表示已被占用 空间成本固定,不依赖于程序中的程序数量 时间成本低,操作简单,直接修改位图值 没有容错能力:无法确定是为1还是因错误变为1 1.2.2 链表表示法 将分配单元按照是否闲置链接起来 空间成本取决于程序的数量 例如空闲链表,将内存中空闲的区域以链表的形式穿起来 时间成本:链表扫描速度较慢,还要进行链表项的插入删除和修改 有一定容错能力,链表有被占空间和闲置空间的表项,可相互验证 1.3 基于顺序搜索的分配算法 First Fit:每个空白区按其在存储空间中地址递增的顺序连载一起,在为作业分配存储区域时,从这个空白区域链的始端开始查找,选择第一个足以满足请求(够大)的空白块 Next Fit:把存储空间中的空白区构成一个循环链,每次为存储请求查找合适的分区时,总是从上次查找结束的地方开始,只要找到一个足够大的空白区,就将他划分后分配出去 Best Fit:为一个作业选择分区时,总是寻找其大小最接近于作业所要求的存储区域 Worst Fit:为作业选择存储区域时,总是寻找最大的空白区 2.页式内存管理 从方便管理物理内存的角度考虑 2.1 程序、进程和作业 程序:程序是静止的,是存放在磁盘上的可执行文件 进程:进程是动态的,进程包括程序的程序处理对象(数据),是系统分配资源的基本单位,分为系统进程和用户进程,进程有生命周期 作业:作业是用户需要计算机完成的某项任务,是要求计算机所做工作的集合,一个作业可以有多个进程 2.2 分页式存储管理 把一个逻辑地址连续的程序分散存放到若干不连续的内存区域内,充分利用内存空间,逻辑上相邻的页,物理上不一定相邻 页:在页式存储管理系统中,把每个作业的地址空间分成一些大小相等的片,称之为页 存储块(页框):把主存的存储空间也分成与页面大小相同的片,这些片称为存储块或页框 ...

March 25, 2024 · 1 min · sudo

OS:lab1实验报告

OS : lab1 实验报告 Thinking 1.1 **尝试分别使用实验环境中的原生x86工具链(gcc、ld、readelf、objdump 等)和 MIPS 交叉编译工具链(带有 mips-linux-gnu 前缀),重复其中的编译和解析过程,观察相应的结果,并解释其中向objdump传入的参数 的含义。 ** objdump传入参数的含义 参数 含义 -d 将代码段反汇编 反汇编那些应该还有指令机器码的section -D 与 -d 类似,但反汇编所有section -S 将代码段反汇编的同时,将反汇编代码和源代码交替显示,源码编译时需要加-g参数,即需要调试信息 -C 将C++符号名逆向解析 -l 反汇编代码中插入源代码的文件名和行号 -j section: 仅反编译所指定的section,可以有多个-j参数来选择多个section objdump-DS 要反汇编的目标文件名 > 导出文本文件名 -DS表示反汇编并将反汇编代码和源代码交替显示 使用原生x86工具链进行编译并查看反汇编 git@22373362:~/compile $ gcc -c hello.c -o hello.o git@22373362:~/compile $ objdump -DS hello.o > x86_log 如下图(部分) 使用MIPS交叉编译工具链进行编译 git@22373362:~/compile $ mips-linux-gnu-gcc -c hello.c -o mips_hello.o git@22373362:~/compile $ mips-linux-gnu-objdump -DS mips_hello.o > mips_log Thinking1.2 **尝试使用我们编写的readelf程序,解析之前在target目录下生成的内核ELF文件。 ** ...

March 24, 2024 · 2 min · sudo

OS-lab1课下基础

OS :lab1课下基础 1. 操作系统的启动 : boot 1.1 概述 ​ 将硬件初始化的相关工作称为bootloader程序,将bootloader程序放在非易失存储器中(ROM/FLASH),将操作系统内核放在磁盘中。 将硬件初始化相关工作从操作系统中抽离出来放在bootloader中实现。实现了硬件启动和软件启动的分离。即由bootloader实现硬件启动,操作系统内核实现软件启动,这样负责硬件启动的指令不多,需要的存储空间不大,可以存在容量较小的ROM或FLASH中 bootloader在硬件初始化之后,需要为软件启动(操作系统内核的功能)做准备,将内核镜像从存放他的存储器(例如磁盘)中读到RAM中。bootloader需要将内核镜像加载到内存中,就可以选择用哪一个内核镜像进行加载,实现多重开机的功能,在一个硬件上选择运行不同的操作系统。 bootloader划分了硬件启动和软件启动的边界,bootloader主要负责硬件启动相关工作,操作系统内核专注于软件启动以及对用户提供服务的工作。简化操作系统的开发和移植。 1.2 bootloader ​ bootloader需要正确地找到内核并加载执行。bootloader的实现依赖于CPU的体系结构,分为stage1,stage2两个部分。 1.3 QEMU中操作系统的启动 ​ QEMU已经提供了bootloader的引导功能,支持加载ELF格式的内核。启动流程被简化为加载内核到内存,之后跳转到内核的入口。 2. ELF 2.1 编译链接 ​ 我们知道源代码文件需要经过编译链接两个阶段才能变成可执行文件来运行。 编译-c:源代码被翻译为二进制指令,得到目标文件 链接:将多个目标文件链接为可执行文件 将编译好的目标文件反汇编:objdump指令 objdump -DS <要反汇编的目标文件名> > <导出文本文件名> ​ 以简单的代码为示例 #include<stdio.h> int main() { printf("hello,world!\n"); return 0; } ​ 这里我们知道,头文件中只包含函数的声明,而不包括函数的定义,因此在预处理阶段(替换头文件、宏定义过程)只会将printf替换为他的声明。最后在链接阶段才会替换为printf的实现。即在编译的最后,链接器将所有的目标文件链接在一起,将 之前未填写的地址等信息填上,形成最终的可执行文件,这就是链接的过程 2.2 ELF ​ ELF是一种文件格式,即Executable and Linkable Format。ELF是Unix系统中一种常见的文件格式,包括可重定位文件(relocatable),可执行文件(executable),共享对象文件(shared object)。其中可重定位文件即为我们熟悉的.o文件,后两种文件都需要对.o文件进行链接才能产生。 2.2.1 段和节 段:segment 节:section ELF 官方文档中对于section segment的解释 所谓section与segment是同一数据的两种视图 左侧是链接视图:使用section进行链接 右侧是执行视图:使用segment运行 每个segment中包含一个或多个section 节头表(Section header table):包含程序中各个节(section)的信息,在程序编译链接时使用 ...

March 18, 2024 · 7 min · sudo