文章目录

  • 一、linux 系统概要
    • 1. 程序
      • 1.1 进程
      • 1.2 应用程序与外部设备
    • 2. 设备驱动程序
    • 3. linux 的工作模式
    • 4. linux 系统调用(system call)
      • 4.1 深入理解系统调用
      • 4.2 strace
      • 4.3 track 常用选项

linux 系统相关知识, 文章内容来自狄泰软件学院, 如有需要淘宝执自行购买学习.

作者: baron

一、linux 系统概要

计算机系统由 “躯体” 和 “灵魂” 两部分组成

  • 躯体:构成计算机系统的电子设备(硬件) --> 中央处理器(CPU)
  • 灵魂:指挥躯体完成动作的指令序列       --> 操作系统(OS)

计算任务执行流程

  • 通过交互设备或网络像计算机系统发起计算请求
  • 根据请求将任务指令加载进入内存
  • cpu 从内存中取指令,并逐条执行
  • 计算任务的最终结果暂存入内存
  • 内存数据通过交互设备或网络进行反馈(也可直接写入外存)

1. 程序

程序的本质是指令和数据的集合。指令是指示 cpu 执行动作的命令, 数据是 cpu 执行动作的目标. 程序的分类:

  • 应用程序:用户可以直接使用,为用户提供直接帮助的程序
  • 程序中间件:多数应用程序的通过功能,用于辅助应用程序的运行
  • 操作系统:直接操作硬件设备,并为应用程序与程序中间件提供运行环境

1.1 进程

进程是程序的执行. 通常情况下, 程序在操作系统上以进程为单位运行. 每个程序运行后由一个或者多个进程构成. 进程是操作系统任务的基本单元, 也是系统资源的基本分配单元. 程序是"死的", 进程是活的. 程序的本质只是二进制数据, 不加载执行就没有任何价值. 进程是计算机系统对程序的一次加载执行, 即:执行计算任务的过程.

1.2 应用程序与外部设备

多数情况下,应用程序需要借助外部设备才能外层计算任务. 外部设备是处cpu与内存之外的其他计算机硬件(如: 硬盘, 网卡, 显卡). 直接访问, 开发成本高, 应用开发者必须熟悉各类外设的硬件特性. 开发周期长, 业务逻辑加设备逻辑. 应用场景难, 其他应用程序可能同事访问外设. 间接访问, 应用程序通过某软件层(驱动程序)接口以统一的方式访问外设.

2. 设备驱动程序

设备驱动程序是外设访问接口, 对应用程序提供统一的外设访问方式. 它象各种外设的共性, 简化设备驱动开发方式. 设备类型有字符设备, 块设备, 网络设备, 等. 对于同一类型的设备, 可以通过统一接口进行访问. 设备驱动程序并非唯一的访问外设的方式. 如何限制进程必须按照规则通过驱动程序访问外部设备? 可以通过工作模式进行限制.

3. linux 的工作模式

linux 系统的工作模式有用户模式和内核模式两种:

  • 用户模式(user mode)执行应用程序私有代码, 受限制的访问内存, 无法直接访问外部设备.
  • 内核模式执行内核代码,可以访问所有的硬件资源, 可立即暂停进程的执行.对大多数设备驱动程序属于内核模式.

内核职责: 以统一的方式有序的分配硬件资源, 保证用户任务按照预期的方式执行.

4. linux 系统调用(system call)

应用程序与操作系统内核直接的接口(表现形式为函数). 系统调用决定了应用程序如何与内核打交道.它解决了以下问题

  1. 系统资源有限, 需要统一有序的调配.
  2. 多个进程可能同时访问同一资源, 进而产生冲突.
  3. 一些特定的功能必须由操作系统内核完成(如: 精确延时).

进程系统调用后, 由用户模式切换到内核模式(执行内核代码). 工作模式的转变通常由中断触发(不同于普通的函数调用). 用户进程通过系统调用请求内核完成资源分配, 硬件访问等操作. 所有进程请求集中到内核, 内核可以统一调度处理, 协调进程的执行.

4.1 深入理解系统调用

模式切换是系统调用的本质, 系统模式切换依赖于 cpu 提供的工作方式, 一般来说, 大部分 cpu 至少有两种工作方式.

  • 高特权级, 可以访问任意数据, 包括外围设备, 比如网卡, 硬盘等.
  • 低特权级, 只能首先访问内存, 并且不允许访问外围设备, 可被打断.

系统模式切换通过执行特殊的 cpu 指令发起(int 0x80). 应用程序(进程)无法直接切换 cpu 的工作方式. 系统调用是应用程序(进程)请求模式切换的唯一方式.下面实例使用系统调用打印字符串

void print(const char*s, int l);
void exit(int code);void program()
{print("Hello World!\n", 13);exit(0);
}// 使用系统调用打印字符串
void print(const char*s, int l)
{asm volatile ("movl $4, %%eax\n" // 制定编号为 4 的系统调用(sys_wirte)"movl $1, %%ebx\n" // 指定 sys_write 的输出目标, 1 为标准输出"movl %0, %%ecx\n" // 指定输出字符地址"movl %1, %%edx\n" // 指定输出字符串长度"int $0x80 \n"     // 执行系统调用:   : "r"(s), "r"(l)   // 参数: "eax", "ebx", "ecx", "edx"); // 保留寄存器, 不用于关联变量
}// 退出当前进程
void exit(int code)
{asm volatile ("movl $1, %%eax\n""movl %0, %%ebx\n""int $0x80     \n":   : "r"(code): "eax", "ebx");  }运行结果:
Hello World!

编译命令注释如下:

gcc -m32 -e program -fno-builtin -nostartfiles program.c
-m32 : 采用 32 位编译
-e program : 指定函数入口
-fno-builtin -nostartfiles : 不链接到 start 函数

4.2 strace

strace 是系统调用工具它具有以下功能:

  1. 用于判断应用程序是否触发系统调用.
  2. 用于监控进程与内核的交互(监控系统调用).
  3. 用于追踪进程内部状态(定位运行时的问题).
  4. 按序输出进程运行过程想通调用名称, 参数和返回值.

实例分析如下

strace -o ./program.log ./a.out // 使用 strace 工具查看 a.out 这个程序的系统调用.execve("./a.out", ["./a.out"], 0x7ffcc94c5760 /* 23 vars */) = 0  // 用来加载执行应用程序, 使其变成进程, 返回值为 0
/* ============> 参数分析  */
// pid : 进程号
// execve : 系统调用的名称, 用来加载执行应用程序, 使其变成进程
// ("./a.out", ["./a.out"], 0x7ffd160fcea0 /* 23 vars */) : 系统调用的参数
// = 0: 系统调用的返回值.
/* ============> 结束 */brk(NULL)                               = 0x56ca1000  // 创建应用程序所需的数据段
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf7f8e000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
set_thread_area({entry_number=-1, base_addr=0xf7f8e9c0, limit=0x0fffff, seg_32bit=1, contents=0, read_exec_only=0, limit_in_pages=1, seg_not_present=0, useable=1}) = 0 (entry_number=12)
mprotect(0x56581000, 4096, PROT_READ)   = 0
write(1, "Hello World!\n", 13)          = 13  // 往标准输出(屏幕), 写入字符串 "Hello World!\n" , 长度为13
exit(0)                                 = ?
+++ exited with 0 +++

使用标准方式打印 "Hello World!\n"

#include <stdio.h>int main()
{printf("Hello World\n");return 0;
}运行结果:
Hello World!

使用 strace 查看系统调用过程

execve("./a.out", ["./a.out"], 0x7ffdda4b7c80 /* 23 vars */) = 0  // 用来加载执行应用程序, 使其变成进程, 返回值为 0
brk(NULL)                               = 0x557d7ea3b000 // 创建应用程序所需的数据段
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=103208, ...}) = 0
mmap(NULL, 103208, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f5b96694000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240\35\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2030928, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5b96692000
mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f5b96094000
mprotect(0x7f5b9627b000, 2097152, PROT_NONE) = 0
mmap(0x7f5b9647b000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f5b9647b000
mmap(0x7f5b96481000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f5b96481000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7f5b966934c0) = 0
mprotect(0x7f5b9647b000, 16384, PROT_READ) = 0
mprotect(0x557d7d3f5000, 4096, PROT_READ) = 0
mprotect(0x7f5b966ae000, 4096, PROT_READ) = 0
munmap(0x7f5b96694000, 103208)          = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
brk(NULL)                               = 0x557d7ea3b000
brk(0x557d7ea5c000)                     = 0x557d7ea5c000
write(1, "Hello World\n", 12)           = 12  // 往标准输出(屏幕), 写入字符串 "Hello World!\n" , 长度为13
exit_group(0)                           = ?
+++ exited with 0 +++

为什么采用标准方式系统调用会多很多, 因为标准方式是基于 c 标准库来做的, 中间有很多复杂的调用是我们看不见的. 同理 c++ 的结果将更为复杂.

4.3 track 常用选项

  • -t在前面打印出调用的实时时间
  • -tt在前面, 更精确的打印出调用的实时时间
  • -T在后面打印出调用函数花费的时间
  • -c打印出调用的次数与总时间 ------ 最常用
  • -s更详细的展示数据内容, 后跟要展示的数据长度
  • -x涉及到的数据,优先以字符串的方式进行展示, 以16进制的数据进行展示
  • -xx涉及到的数据强制以16进制的数据进行展示
  • -e只关注某个系统调用, 后跟要关注的系统调用函数
  • -e trace=只关注 trace 后根的系统调用,例如trace=file,read,write
strace -c -o ./program.log ./program.out------ ----------- ----------- --------- --------- ----------------0.00    0.000000           0         1           execve
------ ----------- ----------- --------- --------- ----------------
100.00    0.000000                     1           total
System call usage summary for 32 bit mode:
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------0.00    0.000000           0         1           write0.00    0.000000           0         2         2 access0.00    0.000000           0         1           brk0.00    0.000000           0         1           mprotect0.00    0.000000           0         1           mmap20.00    0.000000           0         1           set_thread_area
------ ----------- ----------- --------- --------- ----------------
100.00    0.000000                     7         2 total

编译形语言的效率比解释行语言的效率高.

linux系统篇 -- 一、系统概要相关推荐

  1. Linux高级篇——IO系统编程

    1.文件IO 2.标准IO 3.动静态库的制作 4.目录IO 1.文件IO 文件IO简介 涉及哪些接口? Input ,Output 是从用户空间角度考虑的输入与输出: 从内核读取数据或从文件中读取数 ...

  2. windows制作docker镜像_电脑技术之Windows系统篇-PE系统的制作及GHO镜像系统恢复

    技术的道路,永无止步,没有了进步它就为退步! 如果您是大牛,这篇文章您可以略过! 首先我们先来了解下PE系统,以下是百度百科的介绍! Windows PE_百度百科​baike.baidu.com W ...

  3. 利用自己的电脑设置web服务器建网站_win7系统篇,win7系统利用iis搭建web服务器实现信息浏览资源共享的操作方法...

    很多小伙伴都遇到过对win7系统利用iis搭建web服务器实现信息浏览资源共享进行设置的困惑吧,一些朋友看过网上对win7系统利用iis搭建web服务器实现信息浏览资源共享设置的零散处理方法,并没有完 ...

  4. ESP32-C3入门教程 系统篇①——FreeRTOS系统时钟Tick

    文章目录 一.前言 二.延时函数 三.计时函数 四.源码详解 一.前言 本文基于VS Code IDE进行编程.编译.下载.运行等操作 基础入门章节请查阅:ESP32-C3入门教程 基础篇①--基于V ...

  5. 高通平台开发系列讲解(系统篇)系统关机流程

    文章目录 一.关机流程图 二.执行关机流程 2.1.kernel_shutdown_prepare流程 2.2.migrate_to_reboot_cpu流程 2.3.syscore_shutdown ...

  6. Linux系统篇-文件系统虚拟文件系统

    看了之前的关于Linux内存管理和进程调度的文章,相比读者们应该对Linux有了大致的了解,本文的主题是Linux虚拟文件系统.闲话少说,开始! 1.软链接和硬链接的区别 我们知道文件都有文件名与数据 ...

  7. NUC 折腾笔记 - Linux 系统篇

    NUC 折腾笔记 - Linux 系统篇 写一篇迟到的折腾笔记:NUC8 8i5beh .原本计划折腾 Hackintosh ,最后折腾了一台 Linux Homelab 设备. 本篇记录 NUC 基 ...

  8. Linux运维-服务器系统篇

    Linux运维-服务器系统篇 开篇导读: 本篇博文是此系列教程的第二课,在这一课中将大概的介绍一下服务器上的操作系统,了解一下它的基本概念和发展历程. 服务器系统的概念和作用 如何理解服务器操作系统? ...

  9. Ubuntu Linux环境搭建|系统篇

    说明:本篇以ubuntu Desktop 12.04 for 64位为例 同样适用与11.10等其他版本 一.准备镜像 1. 下载Ubuntu Desktop 12.04 LTS   (目前的最新版本 ...

  10. linux目录无法进入是磁盘坏,linux故障篇:MBR损坏导致无法正常启动系统

    由于MBR中包含磁盘分区表记录,如果MBR遭到破坏,系统将无法读取分区表,导致无法挂载分区,即使通过光盘引导的方式也无法挂载,所以必须对分区表进行正确备份并且必须备份到其他磁盘或U盘中.以保证能够读取 ...

最新文章

  1. Emojify - v2 吴恩达老师深度学习第五课第二周编程作业2
  2. 《LeetCode力扣练习》第16题 C语言版 (做出来就行,别问我效率。。。。)
  3. bzoj 1058: [ZJOI2007]报表统计 (Treap)
  4. 准备好跟机器人正面交锋了吗?
  5. 了解PostCSS原理
  6. 服务器 设置 将 Tomcat 注册 到系统服务 及使用方法
  7. 获取运行的class文件,所在的目录
  8. python requests库详解_python爬虫之路(一)-----requests库详解
  9. HDU-1013-Digital root
  10. java多线程下载美女图片
  11. 使用Git上传本地项目到GitHub
  12. 有了雀巢智能咖啡机,单身狗离“秀恩爱”还会远吗?
  13. 高数-----两个重要的极限
  14. Apache 安装虚拟主机
  15. Autodesk 2013 免费下载 及所有产品product Key(产品密匙)
  16. POJ3159 Candies(差分约束)
  17. 函数中arguments是什么?
  18. 成为JAVA(高级)工程师,该学什么?
  19. 从tushare获取场内ETF基金数据
  20. Ansi,UTF8,Unicode,ASCII编码的区别

热门文章

  1. 转载 解密蓝牙mesh系列 | 第五篇 【好友(Friend)和低功耗节点(LPN)】【友谊(Friendship)参数】【友谊建立】【友谊(Friendship)消息传送】【安全性】【友谊终止】
  2. 【内存泄露】LeakCanary常见问题
  3. 在数组中 找左边都比其小右边都比其大的元素
  4. 写乐100道练习题_写乐大型21K详细评测(文长慎入)
  5. 枸杞的功效与食用方法
  6. 一般纳税人企业如何合理避税?
  7. RabbitMQ消息确认机制和消息重发机制
  8. 结构体中元素引用—— “.“ 与 “->“
  9. UVA 1647 Computer Transformation
  10. [FAST 2009]Cumulus:File System Backup to the Cloud