在OS Lab Couse 1中我们已经构建了一个最小的hello world程序

#include<sys/syscall.h>
#include<unistd.h>
int main() {
syscall(SYS_exit, 42);
}

用一种比较特殊的编译方式 (-Wl,会把后面的东西传给连接器)

$ gcc a.c -static -Wl,--entry=main

编译生成可执行文件,然后用readelf查看ELF文件, 可以看到Entry point address是0x401ce5

img

objdump反汇编查看改地址对应的位置,确实是以main函数entry point

img

运行程序,程序依然能够正常执行

$ ./a.out; echo $?
42

img

回到程序=状态机

是谁创建了状态机

必然是操作系统,操作系统加载了上述程序

但是操作系统也是个程序,他又由谁加载?

Bare-Metal 与程序员的约定

为了让计算机能运行任何我们的程序,一定存在一些软件/硬件的约定

CPU Reset

  • CPU reset后,处理器处于某个确定的状态

    • PC指针一般指向一段memory-mapped ROM
      • ROM存储了厂商提供的firmware(固件)
    • 处理器的大部分特性处于关闭状态
      • 缓存,虚拟存储,…

老式的计算机有一个电源按钮,还有一个小的reset按钮。之前电脑启动有冷启动和热启动的概念。冷启动,按电源按钮,此时也会包含一个reset过程。热启动,电脑死机,按reset。

Fireware

    • 将用户数据加载到内存
      • 例如存储介质上的第二级loader
      • 或者直接加载操作系统(嵌入式系统)

CPU Reset行为

寄存器会有初始状态

  • EIP = 0x000ffff0

  • CR0 = 0x60000010 (表明16 bit模式)

  • EFLAGS = 0x00000002

    • interrupt disabled
img

CPU Reset之后,发生了什么

从 PC(CS:IP)指针处取指令,译码,执行

从firware开始执行

  • CPU Reset后EIP指向的ffff0通常是一条向firmware跳转的Jump指令

Firmware: BIOS vs. UEFI

  • 都是主板/主板上外插设备的软件抽象

    • 支持系统管理程序运行
  • Legacy BIOS (Basic I/O System)

  • UEFI (Unified Extensible Firmware Interface)

img

调试qemu, 确认Firmware的行为

提供了两个文件

  • run_qemu.sh
  • hello.img

run_qemu.sh的内容

#!/bin/bash

qemu-system-i386 -s -S -drive format=raw,file=$1 &
pid=$!
gdb \
-ex "target remote localhost:1234" \
-ex "set confirm off"

kill -9 $!

hello.img的内容

$ xxd hello.img

img

img

最后有一个55aa, 表明可启动,不是55aa则不可启动

img

  1. 开始调试
$ bash run-qemu.sh hello.img

CPU Reset

查看寄存器,发现此时eip是0xfff0, cs是0xf000

(gdb) info registers
eax 0x0 0
ecx 0x0 0
edx 0x663 1635
ebx 0x0 0
esp 0x0 0x0
ebp 0x0 0x0
esi 0x0 0
edi 0x0 0
eip 0xfff0 0xfff0
eflags 0x2 [ ]
cs 0xf000 61440
ss 0x0 0
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0

x/i ($cs * 16 + $eip)打印当前指令,这是一条jump指令

img

x/10i ($cs * 16 + $eip)打印当前开始的10条指令

img

  1. firmware会把磁盘的前512字节搬到内存0x7c00的位置,查看这个过程

x/16xb 0x7c00打印内存

img

通过watch *0x7c00在0x7c00出打一个监视点,然后继续执行

(gdb watch 借助观察断点可以监控程序中某个变量或者表达式的值,只要发生改变,程序就会停止执行)

img

程序停止,查看当前指令

img

查看0x7c00处内存

img

单步执行,随着程序的不断运行,越来越多的字节被搬运到0x7c00

img

对比hello.img,搬运进去的正是hello.img的内容

img

firmware完成任务之后,寄存器cs=0, ip=7c00

img

Firmware的另一些用处

放置一些 “绝对安全的代码”

  • BIOS 中断 (Hello World 是如何被打印的)

  • ARM TrustZone

  • Intel ME (不太正确的 “Ring -3”)

    • 据说 “每个 Intel 芯片组里都藏着一个 Minix3 操作系统”

Firmware病毒

Intel 430TX (Pentium) 芯片组允许写入 Flash ROM

  • 只要向 Flash BIOS 写入特定序列,Flash ROM 就变为可写

    • 留给 firmware 更新的通道
  • 要得到这个序列其实并不困难

    • 似乎文档里就有,还可以解析 BIOS 的更新程序
    • Boom…… (CPU RESET 之后就……了)

计算机系统=状态机

img