JayL-zxl

南京大学OS笔记(1)-应用眼中的操作系统

早就想刷一刷南大JYY老师的os课。之前稍微看过几节,果然讲的风趣幽默,而且现场写代码展示水平确实很高,这次准备认真刷一刷然后好好记一下笔记。当然lab就不做了,因为已经做过mit的lab了。刷课主要是为了复习基础知识和学的更深入一点。第一节操作系统历史就不记笔记了,直接从第二节开始

1. 什么是应用程序

1. (应用)程序

image-20211112143459540

这里学到和csapp里的一致的。下面看一系列代码演示

image-20211112143348929

当我gcc -c a.c的时候会生成一个a.o。注意-c表示编译。这里的a.o是可重定位目标文件。而不是可执行目标文件。

image-20211112143543776

而在执行gcc a.o就会把它变成一个可执行目标文件。这里我在我自己的Linux机器上报错了。

image-20211112143628549

总结一下,程序就是可执行的二进制文件,无论什么程序在Linux系统下都是如此的。

2. ELF二进制文件

image-20211112144054315

正因如此,我们可以用vim直接打开/bin/ls

image-20211112144225135

这是一个二进制文件,所以这里直接显示乱码。

xxd可以用来读二进制文件

image-20211112144930616

这里的Entry point address表示它第一条指令的起始地址。

3. 最简单的" Hello World"

1. 如果我们有一个下面这样的代码

int main () {
	printf("Hello World\n");
}

可以直接运行吗。看起来没什么问题,但我们试试

image-20211112150432653

  • 这里会提示我们没有定义puts,明明是调用了printf为什么会提示puts这是因为printf在底层实际上调用了puts

    这是因为gcc即便在没有设置优化的情况下。也就是- o0的情况下还是会做优化,把printf简化成了puts

  • 第二个问题是这里提示了warninng是我们没有制定代码的起始位置

2. 如果我们再尝试一次代码

int main() {
	
}

这是一个完全空的代码。但是它还是会报错

image-20211112151551354

我们需要用gdb调试一下,看看到底为什么出错了

image-20211112151741453

我们需要单步执行,执行到retrun这里。return指令就是调用main函数的地方。

image-20211112151816072

因此在这里我们触发了段错误。这里我们不能访问地址为1的地方

3. 正确的尝试

这里jyy老师引入了一段汇编代码。让hello程序变得正确

image-20211112152649823


image-20211112152538586

这里单步执行到了系统调用

%eax 传递系统调用号

%rdi 传递第一个参数 ,以此类推

2. 应用程序怎么调用操作系统

1.首先看一下syscall的代码在哪里

image-20211112224001531

objdump指令解释

Displays information about one or more object files.

这里可以发现我们所有的系统调用都是callq syscall@plt-动态链接来自于libc的代码

2. Main()之前发生了什么?

(面试题)一个普通的C程序第一条指令子啊哪里?

  • ❌ main的第一条指令
  • ❌ libc的_start

image-20211112224757971

可以用gdb调试一下会发现。它的第一条指令会在lib64/ld-linux-x86-64.so这是操作系统自带的加载器

下面输入info inferiors看一下有什么问题

  1. 我们发现我们现在运行的这个程序进程号是12305。
  2. 我们使用pmap 12305输出这个进程的信息。

image-20211112224915863

会发现os已经帮我们做了很多事情所以整个过程是

os自带的加载器---> 加载libc------> 加载a.out

看下面这个程序。

image-20211112225224690

虽然main是空的。,但是这里的

Hello World
Goodbye, Cruel OS World

还是可以正常输出

3. Trace的使用

使用strace可以追踪系统调用

image-20211112225616565

这里跟随课上jyy老师的脚步分析一下a.out的系统调用

  1. 可以发现第一条系统调用是execve
  2. 然后libc执行了一堆系统调用
  3. 最后才会到我们自己写的程序

3. 应用眼中的操作系统

image-20211112230110029

可以说所有的程序都是类似的,不断的调用系统调用。从开始到关闭

1. gcc的系统调用过程

image-20211112230438185

  1. 这里的gcc确实是先利用as来做编译

  2. 然后用collect2来做链接

    image-20211112230829979

    collect2主要用来做合成,会把构造器和析构器的代码生成出来

image-20211112230917583

  1. 在gcc的最后会调用ld。

image-20211112231510595

2. 其他的应用程序

image-20211112232047854

相关文章:

猜你喜欢