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

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

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

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

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

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

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

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

这里的Entry point address表示它第一条指令的起始地址。
3. 最简单的" Hello World"
1. 如果我们有一个下面这样的代码

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

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

  • 这里会提示我们没有定义puts,明明是调用了printf为什么会提示puts这是因为printf在底层实际上调用了puts
    这是因为gcc即便在没有设置优化的情况下。也就是- o0的情况下还是会做优化,把printf简化成了puts
  • 第二个问题是这里提示了warninng是我们没有制定代码的起始位置
2. 如果我们再尝试一次代码
int main() { }

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

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

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

因此在这里我们触发了段错误。这里我们不能访问地址为1的地方
3. 正确的尝试 这里jyy老师引入了一段汇编代码。让hello程序变得正确


这里单步执行到了系统调用
%eax 传递系统调用号
%rdi 传递第一个参数 ,以此类推
2. 应用程序怎么调用操作系统 1.首先看一下syscall的代码在哪里

objdump指令解释
Displays information about one or more object files.
这里可以发现我们所有的系统调用都是callq syscall@plt-动态链接来自于libc的代码
2. Main()之前发生了什么?
(面试题)一个普通的C程序第一条指令子啊哪里?
  • ? main的第一条指令
  • ? libc的_start

可以用gdb调试一下会发现。它的第一条指令会在lib64/ld-linux-x86-64.so这是操作系统自带的加载器
下面输入info inferiors看一下有什么问题
  1. 我们发现我们现在运行的这个程序进程号是12305。
  2. 我们使用pmap 12305输出这个进程的信息。

会发现os已经帮我们做了很多事情所以整个过程是
os自带的加载器---> 加载libc------> 加载a.out
看下面这个程序。

虽然main是空的。,但是这里的
Hello World Goodbye, Cruel OS World

还是可以正常输出
3. Trace的使用
使用strace可以追踪系统调用

这里跟随课上jyy老师的脚步分析一下a.out的系统调用
  1. 可以发现第一条系统调用是execve
  2. 然后libc执行了一堆系统调用
  3. 最后才会到我们自己写的程序
3. 应用眼中的操作系统
可以说所有的程序都是类似的,不断的调用系统调用。从开始到关闭
1. gcc的系统调用过程

  1. 这里的gcc确实是先利用as来做编译
  2. 然后用collect2来做链接

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

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

2. 其他的应用程序
【南京大学OS笔记(1)-应用眼中的操作系统】

    推荐阅读