mykernel的运行与初步分析

黄二玉+《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

预备知识
内嵌汇编

内嵌汇编语法:
_asm_(
  汇编语句模板:
  输出部分:
  输入部分:
  破坏描述部分);

同时”asm”也可以由“asm”来代替,“asm”是”asm“的别名。在”asm”后面有时也会加上”volatile“表示编译器不要优化代码,后面的指令保留原样,“volatile”是它的别名,在这里值得注意的是无论“asm“还是“volatile”中的每个下划线都不是一个单独的下划线拼成的,在括号里面的便是汇编指令。
例如,有如下一段程序:


int main(void)
{
  int input,output,temp;
  input=temp=1;
  _asm_ _volatile_(
    "movl $0,%%eax\n\t"    /* eax=0*/
    "movl %2,%%eax\n\t"      /* eax=input */
    "movl %%eax,%0\n\t "    /* output=eax*/
    :"=m"(output),"=m"(temp)
     :"r"(input)
    :"eax");
  printf("%d %d\n",temp,output);
  return 0;
}

这段会输出什么?标号6中的$0表示立即数0,把输出部分,输入部分中的变量进行编号依次为0,1,2,…,因此%0表示标号9的output,%1表示temp,%2表示input。


指令的跳转

cup中的ip寄存器总是存放了下一条要执行的指令,更重要的是ip寄存器的内容无法直接修改,但是可以间接的被修改,比如使用jmp,ret指令,如果要在c语言中实现跳转到指定的位置,可以借助栈和ret指令来实现,先看ret指令的作用:

  • ret指令:想当于pop ip,把栈顶元素放到ip寄存器中。

为了实现跳转到指定位置(i.e 地址a),可以把a压栈,然后利用ret指令,push a; ret,在ret指令执行完后ip寄存器指向的位置就是a了。

保存和恢复

当一个函数切换到另一个函数时需要保存前一个函数的信息,比如说临时变量,全局变量,因此需要在另一个函数开始执行的时候保存前一个函数的sp,bp中的数值,需要注意的是为什么不是进程而是函数?因为一个进程可以分为代码段,数据段,堆栈段等,而每个进程分配的堆栈段是不同的,因此进程切换时不仅仅保存sp,bp,还需要保存ss,cs,flag等等状态的信息,而在一个程序的函数间进行切换,代码段,数据段,和堆栈段都是一样的,只是从堆栈区分配给函数的栈不同,因此要保留每个函数自己的栈基址。
保存:
 push bp; //bp入栈
  mov sp,bp; //开始一个新的栈

恢复:
mov bp,sp; //使sp指向存储了前一个bp的单元
pop bp; // 把前一个基址恢复

例子

这个例子是借助Linux内核部分源代码模拟存储程序计算机工作模型及时钟中断,里面的汇编代码如下:

  • mymain.c

    这里写图片描述
    上面的汇编代码主要是实现ip的转移

  • myinterrupt.c

    这里写图片描述
    模拟进程之间的切换

运行程序输出如下:
这里写图片描述

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值