文章目錄
  1. 1. 引言
  2. 2. ELF文件
  3. 3. 引导
  4. 4. 总结
  5. 5. 引用

引言

本来自己查了很多资料,想自己写出来,结果下笔的时候发现别人已经把我想写的部分全部写出来了,而且比我想的还要具体,所以我就不写了,把链接放出了,顺便我补充一些

http://leenjewel.github.io/blog/2014/07/29/%5B%28xue-xi-xv6%29%5D-cong-shi-mo-shi-dao-bao-hu-mo-shi/

http://leenjewel.github.io/blog/2015/05/26/%5B%28xue-xi-xv6%29%5D-jia-zai-bing-yun-xing-nei-he/

ELF文件

首先你要知道什么是ELF,可以看一下这篇博客,简单来说就是编译完C后的机器码,前面加了一些数据表记录程序的分布情况

为了帮助我们逆向分析这些代码有什么,我们必须要借助两个工具

  • objdump
  • readelf

我们接下来就用实际例子解读mit6.828里面的引导和核心

引导

首先我们查看一下引导文件,在boot/目录下有两个文件

  • boot.S
  • main.c

两者是通过gcc编译器将汇编和C编译成为一个elf文件,具体在Makefile文件中(boot/Makefrag),我将它简单翻译一下

gcc -N -e start -Ttext 0x7C00 -o boot.out boot.o main.o

boot.omain.o就是boot.Smain.c编译后的文件,-e start意思程序从boot.Sstart中开始运行(这样就能从汇编开始执行),-Ttexttext代表代码段,也就是说直接指定代码入口地址为0x7C00,我们可以用readelf验证一下

mit-6.828-2014 ➤ readelf -h obj/boot/boot.out                         git:lab1*
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x7c00
  Start of program headers:          52 (bytes into file)
  Start of section headers:          4868 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         2
  Size of section headers:           40 (bytes)
  Number of section headers:         9
  Section header string table index: 6

我们读取了一下生成的elf文件头部,我们可以看到Entry point address这个字段,就是我们设定的0x7c00,要了解这个地址的含义我们必须知道虚拟地址和物理地址的区别,可以看一下这篇博客,接着我们看一下反汇编的汇编代码obj/boot/boot.asm中,我们知道现在0x7c00代表程序把自己当做在内存上的真实内存上面,但是不一定会真的存在这块上,所以我们称它为虚拟的

首先我们了解一个系统知识,因为电脑启动后会按照启动盘顺序,把每个盘第一个扇形区512B取出来,如果最后两个字节为0xAA55的话就把它放到内存上面的0x7c00上去,我们看一下我们生成的obj/boot/boot

使用hexdump obj/boot/boo可以看到(我把最后一行复制出来)

00001f0 0000 0000 0000 0000 0000 0000 0000 aa55

最后连个字节为0xaa55,且文件大小刚刚好512B,这时候你可以有一个疑惑了,我们知道gcc我们生成的boot.out的elf文件,但是这个文件还有头部存贮数据,我们如果把整个文件放到磁盘上,当程序在内存0x7c00处执行时,那么文件头部碰到的就是elf头了,所以
为了把机器码提取出来并生成合适文件(512B尾部为0xaa55),程序干了两件事

  • 用objcopy将elf文件中执行代码提取出来(相当于去掉elf头部)
  • 用脚本修改尾部两字节(在boot/sign.pl用了perl程序来将生成512B且尾部为0xaa55boot文件)

总结

后面将核心加载到内存,上面的给出资料写的很详细,我就不多说,只不过由于当前2014的版本同资料有点不同,这里我提一下

当前版本是将内核头加载在0x10000上,然后在把内核代码加载到0x100000上(前面4个0,后面5个0,我当初看错了,百思不得其解),并将内核地址映射到f0100000上。

由于资料给的操作系统与2016的操作系统实现细节有点不同,其中最主要的就是一个很重要的KERNBASE常量值由0x80000000变成0xf0000000,这个变量牵扯到了在给出的book-rev8.pdf资料中第一章的最后一个问题,我就把我对这个问题的思考放到这篇文章中。

引用

http://leenjewel.github.io/blog/2014/07/29/%5B%28xue-xi-xv6%29%5D-cong-shi-mo-shi-dao-bao-hu-mo-shi/

https://my.oschina.net/u/864891/blog/87965

端口信息

文章目錄
  1. 1. 引言
  2. 2. ELF文件
  3. 3. 引导
  4. 4. 总结
  5. 5. 引用