Exercise 9. Determine where the kernel initializes its stack, and exactly where in memory its stack is located. How does the kernel reserve space for its stack? And at which “end” of this reserved area is the stack pointer initialized to point to?

answer:
Determine where the kernel initializes its stack
重新梳理开机启动的流程:
BIOS 带电自检,设置中断向量表,在完成地址检查,将boot loader 读入磁盘
boot loader 从实模式转换为保护模式,在 bootmain 函数当中读入第一个磁盘,并且将控制权转交给内核。
在 bootmain 当中并没有设置内核栈的函数。
之后进入 entry.S,并且通过 entry.S 进入 i386_init() 函数来完成一些初始化的函数。
必然在进入函数之前完成栈的初始化,毕竟函数调用前都需要将参入和寄存器的内容入栈什么的。
设置栈顶指针在 /lab/kern/entry.S 当中,代码如下:

在 /lab/kern/entry.S 当中完成了栈的初始化。

kernel stack 的大小的定义。
KSTKSIZE = 8 * PGSIZE = 8 * 4096 = 32KB

exactly where in memory its stack is located
没有想好断点应该设置在哪里,一直在死循环。

设置栈之前开启了内存分页和虚拟地址映射,将断点打到虚拟地址映射之前就好。打在 0x10002d 最后一次使用物理地址,或者是打在 0x10000c 。

设置栈顶指针在 entry.S 的 77 段。之后便进入 i386_init()。
(内核函数调用的顺序为 entry.S 到 init.c )
其中 bootstacktop = 0xf0110000,
再根据 KSTKSIZE = 32KB 可知,留给栈空间的范围为 0xf0108000-0xf0110000 。

How does the kernel reserve space for its stack?
通过确定栈顶指针 + 确定栈的大小 来预留空间给未来要使用的栈。

at which “end” of this reserved area is the stack pointer initialized to point to?
一开始当然要指向栈顶啦,由于栈是从高地址向低地址增长的,所以一开始的指向是 0xf0110000。

Exercise 10. To become familiar with the C calling conventions on the x86, find the address of the test_backtrace function in obj/kern/kernel.asm, set a breakpoint there, and examine what happens each time it gets called after the kernel starts. How many 32-bit words does each recursive nesting level of test_backtrace push on the stack, and what are those words?

Note that, for this exercise to work properly, you should be using the patched version of QEMU available on the tools page or on Athena. Otherwise, you’ll have to manually translate all breakpoint and memory addresses to linear addresses.

test_backtrace () 函数



在内核中 栈 空间的大小为 0xf0108000-0xf0110000。
若 esp 的内容为 0xf0110000 ,则表明堆栈尚未使用。

(每次执行完后下面的语句是要执行的下一行)
在调用 i386_init () 之前,先初始化堆栈。把原来函数的 栈底指针的所指向的地址 压入栈中。

在执行 test_traceback()之前 esp 和 ebp 的值如下。i386_init () 函数栈的位置从 0xf010ffe0 ~ 0xf010fff8 。

call 指令先将 test_traceback () 的返回地址压入栈中,栈顶指针向低地址增长 4 个字节,从 0xf010ffe0 变成了 0xf010ffdc。

再将 i386_init ()的栈底指针压入栈当中,此时栈顶指针 esp 继续向下移动 4个字节,从 0xf010ffdc 变成了 0xf010ffd8。

将原来的栈底指针的位置移动到现在栈顶指针的位置,此时都是 0xf010ffd8,表示为 test_traceback(5)开辟新的函数栈空间。

通过 sub $0x10 ,%esp 将栈顶指针移动 0x10,为 test_traceback(5) 的参数预留一部分空间。

猜测 test_traceback(5) 函数栈的栈顶在 0xf010ffd0
开始 调用 test_traceback(4) ebp = 0xf010ffb8

参考文章:函数调用过程中函数栈详解
看完之后恍然大悟
根据文章画的图

The listed eip value is the function’s return instruction pointer: the instruction address to which control will return when the function returns. The return instruction pointer typically points to the instruction after the call instruction (why?).

为了方便函数返回之后迅速执行下一行。

Finally, the five hex values listed after args are the first five arguments to the function in question, which would have been pushed on the stack just before the function was called. If the function was called with fewer than five arguments, of course, then not all five of these values will be useful. (Why can’t the backtrace code detect how many arguments there actually are? How could this limitation be fixed?)

p[i] == *(p+i)
&p[i] == (p+i)

Exercise 11. Implement the backtrace function as specified above. Use the same format as in the example, since otherwise the grading script will be confused. When you think you have it working right, run make grade to see if its output conforms to what our grading script expects, and fix it if it doesn’t. After you have handed in your Lab 1 code, you are welcome to change the output format of the backtrace function any way you like.

If you use read_ebp(), note that GCC may generate “optimized” code that calls read_ebp() before mon_backtrace()'s function prologue, which results in an incomplete stack trace (the stack frame of the most recent function call is missing). While we have tried to disable optimizations that cause this reordering, you may want to examine the assembly of mon_backtrace() and make sure the call to read_ebp() is happening after the function prologue.

补充代码:
(我不会写,上网找了一个)

// 获取寄存器ebp本身的位置int regebp = read_ebp();// 获取ebp指向的位置,即ebp中的内容regebp = *((int *)regebp);// ebp 最终指向栈的某个位置int *ebp = (int *)regebp;cprintf("Stack backtrace:\n");//If only we haven't pass the stack frame of i386_initwhile((int)ebp != 0x0) {cprintf("  ebp %08x", (int)ebp);// 返回地址cprintf("  eip %08x", *(ebp+1));cprintf("  args");cprintf(" %08x", *(ebp+2));cprintf(" %08x", *(ebp+3));cprintf(" %08x", *(ebp+4));cprintf(" %08x", *(ebp+5));cprintf(" %08x\n", *(ebp+6));// 上一层函数的ebp指针ebp = (int *)(*ebp);}

read_ebp ()在 x86.h 当中:

运行的结果,发现调用的相邻两个函数栈的距离是 0x10,自己之前的推测是错误的。当前函数 ebp 的值属于自己的函数栈。

2022-2-27 MIT 6.828 Lab 1: Booting a PC | Part 3: The Kernel | The Stack |exercise 9 - 11相关推荐

  1. 2022-2-16 MIT 6.828 Lab1:Booting a PC part1-part2

    Part 1: PC Bootstrap Getting Started with x86 assembly Exercise 1. Familiarize yourself with the ass ...

  2. 《MIT 6.828 Lab 1 Exercise 10》实验报告

    本实验的网站链接:MIT 6.828 Lab 1 Exercise 10. 题目 Exercise 10. To become familiar with the C calling conventi ...

  3. Lab 1: Booting a PC

    这个实验是基于MIT的2017的6.826课程,搭建环境的时候踩了几个坑,但是当时没有记录下来,可惜~ Part 1: PC Bootstrap 介绍了如何安装qemu以及如同通过qemu来模拟操作系 ...

  4. MIT6.828——LAB1:Booting a PC

    MIT6.828--LAB1:Booting a PC Part1:PC Bootstrap 练习1: 熟悉X86汇编语言 The PC's Physical Address Space 电脑的物理地 ...

  5. 2022-3-17 MIT 6.828 Lab 3: User Environments | Part A: User Environments and Exception Handling

    补充一个知识点:MMU (一) 从 lab2 切换到 lab3 的方法 Lab 3 是为了设置用户在运行的时候适应的上下文环境 Allocating the Environments Array Li ...

  6. 2022-3-16 MIT 6.828 Lab 2: Memory Management | Part 3: Kernel Address Space | Exercise 5

    Exercise 5. Fill in the missing code in mem_init() after the call to check_page(). Your code should ...

  7. MIT 6.828 lab1 part2

    Part 2: The Boot Loader 加载内核 为了理解boot/main.c,你需要知道ELF二进制文件是什么.当你编译和链接一个C程序(如JOS内核)时,编译器将每个C源文件('. C ...

  8. MIT 6.828 操作系统工程 lab4A:多处理器支持和协作多任务

    MIT 6.828 操作系统工程 lab4A:多处理器支持和协作多任务 这篇是我自己探索实现 MIT 6.828 lab 的笔记记录,会包含一部分代码注释和要求的翻译记录,以及踩过的坑/个人的解决方案 ...

  9. 问卷量表调研结果 - data 2022.2.27周五

    问卷量表调研结果 - data 2022.2.27周五 调研要求: 找接口asp类型的,寻找其方法 退而求其次!在网站上找链接,做完以后找到它的答案页面,记录链接以后反馈给用户,或者从她的源代码找到代 ...

最新文章

  1. React+Reflux博客实践
  2. 详解:UML类图符号、各种关系说明以及举例
  3. Java设计模式学习之工厂模式
  4. 朋友圈 H5 进化简史
  5. 计算机专业人大学排名,计算机专业学校排名哪些大学计算机专业比较好
  6. Metasploit 提权篇
  7. 【Linux网络编程】TCP三次握手和四次挥手
  8. linux内存管理策略,Glibc内存管理—ptmalloc内存分配策略(1)
  9. java依赖_java 依赖、组合、聚合与继承
  10. 使用SpringData出现java.lang.AbstractMethodError
  11. Asp.net输出Excel文件并且下载该文件以及某些细节问题解决
  12. 深度学习笔记(五):LSTM
  13. 计算机多媒体技术的内容有哪些方面,多媒体技术是什么_多媒体技术知识点总结...
  14. 多指标综合评价方法汇总
  15. GSM网络结构及主要接口标注(附中英翻译)
  16. 做个坚强的逆行者,献给终日奋斗的你我——《当幸福来敲门》
  17. 微信小程序组件开发——可视化电影选座
  18. 413 Arithmetic Slices
  19. 盘点2020年受影响最大的十大行业和10大职业
  20. Blackhat2017:如何利用PostScript语言入侵打印机

热门文章

  1. 嵌入式机载软件安全性分析
  2. erp二次开发与java web_什么是erp系统的二次开发?
  3. Virbox Protector Java 虚拟化上线!支持jar包二次调用!
  4. Patching more than once will result in the union of all True param eters being patched monkey.pat
  5. 使用Redshift渲染器,怎么选电脑配置!
  6. 在线驾考 HTML5,驾考科目一app哪个好_预约科目一考试app_科目一练题哪个软件好...
  7. photoshop图像处理用钱吗_PS图像处理的流程与方法
  8. 办公套件新选择 WPS Office for Mac vs. 微软 Office 2019
  9. python编写操作系统实验_6.828 操作系统 lab2 实验报告
  10. 从零开始学Unity游戏开发