操作系统是如何工作的

1. 小结:计算机是怎样工作的

三个法宝

存储程序计算机、函数调用堆栈、中断机制

两把宝剑

中断上下文、进程上下文的切换

2. 堆栈

  • 堆栈是C语言程序运行时必须的一个记录调用路径和参数的空间。

    • 函数条用框架
    • 传递参数
    • 保存返回地址
    • 提供局部变量空间...
  • 堆栈相关寄存器:

    esp:堆栈指针——指向系统栈最上面一个栈帧的栈顶
    ebp: 基址指针——指向系统栈最上面一个栈帧的底部
    cs:eip:指令寄存器——指向下一条等待执行的指令地址
  • 堆栈相关操作:
    • push :栈顶地址减少4个字节
    • pop: 栈顶地址增加4个字节
    • call:将当前cs:eip值压栈,cs:eip指向被调函数入口地址。
    • ret:从栈顶弹出原来保存在此的cs:eip值,放入cs:eip中。
    • leave:当调用函数调用时,一般都有这两条指令pushl %ebpmovl %esp,%ebp,leave是这两条指令的反操作。

3. 函数调用约定

函数调用约定 参数传递顺序 负责清理参数占用的堆栈
__pascal 从左到右 调用者
__stdcall 从右到左 被调函数
__cdecl 从右到左 调用者
      • 调用函数的代码和被调函数必须采用相同的函数的调用约定,程序才能正常运行。

        Windows中C/C++程序的缺省函数调用约定是__cdecl
        linux中gcc默认用的规则是__stdcall

4、C代码中嵌入汇编代码的写法

__asm__(汇编语句模板: 输出部分: 输入部分: 破坏描述部分)
  • 汇编语句模板
       汇编语句模板由汇编语句序列组成,语句之间使用“;”、“\n”或“\n\t”分开。指令中的操作数可以使用占位符引用C语言变量,操作数占位符最多10个,名称如下:%0,%1,…,%9。
  • 输出部分
       输出部分描述输出操作数,不同的操作数描述符之间用逗号格开,每个操作数描述符由限定字符串和C语言变量组成。
  • 输入部分
       输入部分描述输入操作数,不同的操作数描述符之间使用逗号格开,每个操作数描述符由限定字符串和C语言表达式或者C语言变量组成。
  • 破坏描述部分
       破坏描述符用于通知编译器我们使用了哪些寄存器或内存,由逗号格开的字符串组成,每个字符串描述一种情况,一般是寄存器名;除寄存器外还有“memory”。
  • 限制字符
       限制字符有很多种,有些是与特定体系结构相关,它们的作用是指示编译器如何处理其后的C语言变量与指令操作数之间的关系。 
常用限制字符
分类 限定符 描述
通用寄存器 “a” 将输入变量放入eax
“b” 将输入变量放入ebx
“c” 将输入变量放入ecx
“d” 将输入变量放入edx
“s” 将输入变量放入esi
“d” 将输入变量放入edi
“q” 将输入变量放入eax,ebx,ecx,edx中的一个
“r” 将输入变量放入通用寄存器,也就是eax,ebx,ecx,edx,esi,edi中的一个
“A” 把eax和edx合成一个64 位的寄存器(use long longs)
内存 “m” 内存变量
“o” 操作数为内存变量,但是其寻址方式是偏移量类型,也即是基址寻址,或者是基址加变址寻址
“V” 操作数为内存变量,但寻址方式不是偏移量类型
“ ” 操作数为内存变量,但寻址方式为自动增量
“p” 操作数是一个合法的内存地址(指针)
寄存器或内存 “g” 将输入变量放入eax,ebx,ecx,edx中的一个或者作为内存变量
“X” 操作数可以是任何类型
立即数 “I” 0-31之间的立即数(用于32位移位指令)
“J” 0-63之间的立即数(用于64位移位指令)
“N” 0-255之间的立即数(用于out指令)
“n” 立即数
“p” 立即数,有些系统不支持除字以外的立即数,这些系统应该使用“n”而不是“i”
匹配 & 该输出操作数不能使用过和输入操作数相同的寄存器
操作数类型 “=” 操作数在指令中是只写的(输出操作数)
“+” 操作数在指令中是读写类型的(输入输出操作数)
浮点数 “f” 浮点寄存器
“t” 第一个浮点寄存器
“u” 第二个浮点寄存器
“G” 标准的80387浮点常数
其它 % 该操作数可以和下一个操作数交换位置
# 部分注释,从该字符到其后的逗号之间所有字母被忽略
* 表示如果选用寄存器,则其后的字母被忽略

5.mykernel实验

  1. cd LinuxKernel/linux-3.9.4
  2. qemu -kernel arch/x86/boot/bzImage

然后cd mykernel 可以看到qemu窗口输出的内容的代码mymain.c和myinterrupt.c

  • 进程的启动
/*mymain.c*/
/* start process 0 by task[0] */
pid = 0;
my_current_task = &task[pid];
asm volatile(
"movl %1,%%esp\n\t" /* 将进程的sp赋给esp寄存器 */
"pushl %1\n\t" /* ebp入栈:因为在这里栈为空,esp=ebp,所以push的%1就是esp就是ebp。*/
"pushl %0\n\t" /* 进程入口ip入栈 */
"ret\n\t" /* 把进程入口ip赋给eip,即从这之后0号进程启动。*/
"popl %%ebp\n\t"
:
: "c" (task[pid].thread.ip),"d" (task[pid].thread.sp) /* input c or d mean %ecx/%edx*/
);
  • 进程的切换:
(1).下一个进程next->state == 0 即正在执行时
/*myinterrupt.c*/
//两个正在运行的进程之间做进程上下文切换 if(next->state == 0)
/* state值的含义:-1表示没有执行,0表示正在执行,>0表示停止,这里为0,即进程正在执行 */
{
/* 以下是进程切换关键代码 */
asm volatile(
"pushl %%ebp\n\t" /* 把当前进程的ebp保存*/
"movl %%esp,%0\n\t" /* 把当前进程的esp赋值到sp中保存下来*/
"movl %2,%%esp\n\t" /* 把下一个进程的sp放到esp中*/
"movl $1f,%1\n\t" /* 把eip保存起来,$1f指接下来的标号1:的位置*/
"pushl %3\n\t" /*把下一个进程的eip保存起来*/
"ret\n\t" /* 还原eip */
"1:\t" /* 标号1,下一进程从此开始 */
"popl %%ebp\n\t"
: "=m" (prev->thread.sp),"=m" (prev->thread.ip)
: "m" (next->thread.sp),"m" (next->thread.ip)
);
my_current_task = next;
printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);
}
(2).进程是一个新进程,还从未执行过
/*myinterrupt.c*/
/*这段代码是当进程从未执行过时,所执行的动作,即启动一个进程 next->state = 0; /* 首先要把进程置为运行时状态,作为当前正在执行的进程 */
my_current_task = next;
printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);
/* 进程切换时的提示,从当前进程切换至下一进程*/
asm volatile( //混合编程
"pushl %%ebp\n\t" /* 保存ebp */
"movl %%esp,%0\n\t" /* 保存esp */
"movl %2,%%esp\n\t" /* 将下一进程的sp存入esp */
"movl %2,%%ebp\n\t" /* 将下一进程的bp存入ebp,因为栈空,所以esp和ebp指向同一位置 */
"movl $1f,%1\n\t" /* 保存eip */
"pushl %3\n\t" /*保存当前进程入口 */
"ret\n\t" /* 还原eip */
: "=m" (prev->thread.sp),"=m" (prev->thread.ip)
: "m" (next->thread.sp),"m" (next->thread.ip)
);
  • 实验截图

20135302魏静静Linux内核分析第二周学习总结的更多相关文章

  1. LINUX内核分析第二周学习总结——操作系统是如何工作的

    LINUX内核分析第二周学习总结——操作系统是如何工作的 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/course ...

  2. Linux内核分析第二周学习笔记

    linux内核分析第二周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...

  3. Linux内核分析第二周学习博客——完成一个简单的时间片轮转多道程序内核代码

    Linux内核分析第二周学习博客 本周,通过实现一个简单的操作系统内核,我大致了解了操作系统运行的过程. 实验主要步骤如下: 代码分析: void my_process(void) { int i = ...

  4. Linux内核分析第二周学习总结:操作系统是如何工作的?

    韩玉琪 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.函数调用堆栈 ...

  5. Linux内核分析——第二周学习笔记

    20135313吴子怡.北京电子科技学院 chapter 1 知识点梳理 (一)计算机是如何工作的?(总结)——三个法宝 ①存储程序计算机工作模型,计算机系统最最基础性的逻辑结构: ②函数调用堆栈,高 ...

  6. 三20135320赵瀚青LINUX内核分析第二周学习笔记

    赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.计算机的三个法宝 存储程 ...

  7. Linux内核分析——第二周学习笔记20135308

    第二周 操作系统是如何工作的 第一节 函数调用堆栈 存储程序计算机:是所有计算机基础的框架 堆栈:计算机中基础的部分,在计算机只有机器语言.汇编语言时,就有了堆栈.堆栈机制是高级语言可以运行的基础. ...

  8. linux内核分析第二周

    网易云课堂linux内核分析第二周 20135103                王海宁 <Linux内核分析>MOOC课程http://mooc.study.163.com/cours ...

  9. Linux内核分析第二周--操作系统是如何工作的

    Linux内核分析第二周--操作系统是如何工作的 李雪琦 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course ...

随机推荐

  1. mysql如何用sql添加字段如何设置字符集和排序规则

    alter table pay_company add sms_code2 varchar(16) CHARACTER SET UTF8 COLLATE utf8_general_ci DEFAULT ...

  2. 170410、java Socket通信的简单例子(TCP)

    服务端代码: package com.bobohe.socket; import java.io.*; import java.net.*; import java.applet.Applet; pu ...

  3. 160520、MyBatis的几种批量操作

    MyBatis中批量插入 方法一: <insert id="insertbatch" parameterType="Java.util.List"> ...

  4. jstree的checkbox实例+详解

    jstree的checkbox实例较少,思索后决定进行一下整理,先上代码 $("#filtrate_row").on("loaded.jstree",funct ...

  5. ubuntu下安装myeclipse+破解

    1.给myeclipseInstaller.run权限 chmod myeclipseInstaller.run 2.安装(结束时不启动,去掉√) ./myeclipseInstaller.run 3 ...

  6. 读取properties文件------servletcontext及dao层读取

    用servletcontext读取properties文件-------1) 重点在于:InputStream in=this.getServletContext().getResourceAsStr ...

  7. Spring Data CrudRepository增删改查方法(八)

    CrudRepository   的主要方法 long count(); boolean exists(Integer arg0); <S extends StudentPO> S sav ...

  8. 转:JAVA.NET.SOCKETEXCEPTION: TOO MANY OPEN FILES解决方法

    最近随着网站访问量的提高把web服务器移到linux下了,在移服务器的第二天,tomcat频繁的报 java.net.SocketException: Too many open files错误,错误 ...

  9. JSP学习(第二课)

    把GET方式改为POST在地址栏上就不会显示. 发现乱码了,设置编码格式(这个必须和reg.jsp中page的charset一致):  但是注意了!我们传中文名,就会乱码: 通过get方式提交的请求无 ...

  10. 算法总结之动态规划(DP)

    适用动态规划的特点 所解决的问题是最优化问题. 所解决的问题具有"最优子结构".可以建立一个递推关系,使得n阶段的问题,可以通过几个k<n阶段的低阶子问题的最优解来求解. 具 ...