MIT 6.828 操作系统基础知识

1,067 阅读4分钟

1. 工具

1.1 QEMU

MIT 6.828课程用到的模拟器为:QEMU,主要提供guest->host指令集的映射功能,通过动态二进制转换来模拟CPU,并提供硬件模型来让CPU进行交互;

image-20210728163934597

1.2 KVM

Kernel-based Virtual Machine(KVM) is a virtualization infrastructure for the Linux kernel that it into a hypervisor.

KVM包含一个内核模块kvm.ko用来实现核心虚拟化功能,以及一个和处理器强相关的模块如kvm-intel.ko或kvm-amd.ko。 有了KVM以后,guest os的CPU指令不用再经过QEMU来转译便可直接运行,大大提高了运行速度。但KVM的kvm.ko本身只提供了CPU和内存的虚拟化,所以它必须结合QEMU才能构成一个完整的虚拟化技术。

img

1.3 GDB

gdb主要命令如下所示

  • 单步调试使用si执行
  • 断点相关

    • b设置断点,b *addr,b function
    • c执行至断点
  • 信息查看

    • 寄存器,info registers
    • 数据,例如:x/4i 0xffff0
    • 指令,例如:x/4x 0xfff0

image-20210726152937266

image-20210722104840306

参考资料:QEMU,KVM及QEMU-KVM介绍

2. 汇编语言

2.1 指令

MIT 6.828中gcc产生的汇编语言格式为AT&T格式,其中汇编语言格式如下:

[<label>:][<instruction or directive or pseudo-instruction>} @comment
# 分别对应:[<标号>:][<指令 or 伪操作 or 伪指令>} @注释

img

gcc生成的汇编语言代码在.asm中

image-20210722192504630

2.2 Emu8086

汇编语言的体验可通过Emu8086进行,以下为Emu8086自带的例子,可以看到汇编语言的使用场景:

  • HelloWorld

img

  • 写LED

img

  • 步进电机,stepper-motor

img

2.2 伪指令

常见伪指令如下:

# 汇编程序的缺省入口是_start标号,用户也可以在连接脚本文件中用ENTRY标志指明其它入口点。
_start = RELOC(entry)
# .long 定义4字节数据
.long 0x12345678,23876565
# .global/ .globl :用来定义一个全局的符号
.globl entry
# .text @代码段
.text
# .data @初始化数据段 .data Read-write initialized long data.
.data
# .align 对齐方式伪操作 
.align 4
# .space <number_of_bytes> {,<fill_byte>},分配number_of_bytes字节的数据空间,并填充其值为fill_byte,若未指定该值,缺省填充0。
.space      KSTKSIZE

2.3 内联汇编

在操作系统的代码中,内联汇编在CPU与操作系统之间起着桥梁作用,如获取寄存器值,读写端口等操作,格式如下:

asm ( "statements" : output_registers : input_registers : clobbered_registers);

其中 clobbered_registers ,易失寄存器,volatile;

如下的内联汇编代码可以在一个周期内完成乘以9的操作:

#define times9(arg1, arg2) \
__asm__ ( \
  "leal (%0,%0,8),%0" \
  : "=r" (arg2) \
  : "0" (arg1) );
  • 参数:(arg1),前面的0代表,入参传入由编译器决定的以0为标识的寄存器中
  • 返回值:(arg2),=r代表,结果传入编译器决定的以r为标识的寄存器中
  • 寄存器标识映射
a        eax
b        ebx
c        ecx
d        edx
S        esi
D        edi
I        constant value (0 to 31)
q,r      dynamically allocated register (see below)
g        eax, ebx, ecx, edx or variable in memory
A        eax and edx combined into a 64-bit integer (use long longs)
r        edi,esi
number   [0,1,2,etc]
cc       condition code

参考资料:

3. C语言指针

指针操作中:*p+i=p+sizeof(p)i

#include <stdio.h>
#include <stdlib.h>
void
f(void)
{
    int a[4];
    int *b = malloc(16);
    int *c;
    int i;
    printf("1: a = %p, b = %p, c = %p\n", a, b, c);
    c = a;
    for (i = 0; i < 4; i++)
    a[i] = 100 + i;
    c[0] = 200;
    printf("2: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
       a[0], a[1], a[2], a[3]);
    c[1] = 300;
    *(c + 2) = 301;
    3[c] = 302;
    printf("3: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
       a[0], a[1], a[2], a[3]);
    c = c + 1;
    *c = 400;
    printf("4: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
       a[0], a[1], a[2], a[3]);
    //1.指针类型不同导致的异常
    c = (int *) ((char *) c + 1);
    *c = 500;
    printf("5: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
       a[0], a[1], a[2], a[3]);
    b = (int *) a + 1;
    c = (int *) ((char *) a + 1);
    printf("6: a = %p, b = %p, c = %p\n", a, b, c);
}
int
main(int ac, char **av)
{
    f();
    return 0;
}

其中第5部分,指针类型不同导致的异常部分,400的二进制表示为:0x00000190,301的二进制表示为:0x0000012d,500的二进制:0x000001f4

第5步的指针运算后,布局为:

image-20210722163835356

最终a[1]为:0x0001f490,a[2]为:0x00000100