2019-2020-1 20199315《Linux内核原理与分析》第六周作业

实验楼实验五

实验楼环境研究MenuOS

1.在MenuOS中添加并运行getpid命令

进入LinuxKernel目录,删除menu目录


$cd LinuxKernel
$ls
$rm -rf menu
$ls

从github上克隆一个menu,该版本中已经写了time和time_asm两个系统调用


$git clone https://github.com/mengning/menu.git

运行make rootfs对menu内文件进行编译,打开MenuOS输入help查询系统调用函数


$cd menu
$make rootfs

输入help命令,测试新加入的time以及time-asm

在menu目录中找到test.c文件打开(vim或gedit test.c),添加并写入getPid()方法,函数名应该避免与系统调用函数getpid()重复。


int getPid(int argc,char *argv[]){
    int pid;
    pid=getpid();
    printf("pid=%d\n",pid);
    return 0;
}

查看一下新扩展的两个函数,如橙色框所示;写入getPid()方法,如红色框所示

再次使用make rootfs对menu内文件进行编译,由于test.c中通过MenuConfig()定义了调用函数名,在MenuOS中直接输入getPid可以调用,获得当前进程号,该进程也叫根进程。它负责产生其他所有用户进程。所有的进程都会被挂在这个进程下。

实验中,发现不知道为什么,我的进程号大到如此惊人……

一看原来是函数里面写错了:


int getPid(int argc,char *argv[]){
    int pid;
    pid-getpid();  /* 是的,下面的printf中等号写成短横线就算了,这里都写错了2333 */
    printf("pid-%d\n",pid);
    return 0;
}

改完之后又出现了新的问题……

不知道咋搞= =,问了娄君也不得而知,索性关了重新编译了一次,没问题了……希望如果老师看到的话可以解疑QAQ

  1. gdb跟踪调用time函数的过程

退回LinuxKernel目录,


$cd ..

shift+ctrl+o切换横屏,然后在终端1将QEMU挂起


$qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -S -s

在终端2打开gdb,在start_kernel设置断点


$gdb
$file linux-3.18.6/vmlinux        /* 在gdb界面中targe remote之前加载符号表 */
$target remote:1234           /* 建立gdb和gdbserver之间的连接,按c让qemu上的Linux继续运行 */
$b start_kernel               /* 断点的设置可以在target remote之前,也可以在之后 */

又连接超时了……

过了会重启gdb又好了……

设置断点

程序执行到断点处

继续执行,执行time命令,可发现此命令执行到一半卡住了,出现了一个断点。继续执行,直到出现return i

设置断点(system_call),继续执行可发现time有返回

实验分析

system_call的代码:


ENTRY(system_call)
    RING0_INT_FRAME    
    ASM_CLAC        
    pushl_cfi %eax                /* 保存系统调用号 */
    SAVE_ALL                      /* 可以用到的所有CPU寄存器保存到栈中 */
    GET_THREAD_INFO(%ebp)               /* ebp用于存放当前进程thread_info结构的地址 */
    testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
    jnz syscall_trace_entry
    cmpl $(nr_syscalls), %eax           /* 检查系统调用号(系统调用号应小于NR_syscalls) */
    jae syscall_badsys               /* 不合法,跳入到异常处理 */
syscall_call:
    call *sys_call_table(,%eax,4)           /* 合法,对照系统调用号在系统调用表中寻找相应服务例程 */
    movl %eax,PT_EAX(%esp)             /* 保存返回值到栈中 */
syscall_exit:  
    testl $_TIF_ALLWORK_MASK, %ecx   /* 检查是否需要处理信号 */
    jne syscall_exit_work             /* 需要,进入 syscall_exit_work */
restore_all: 
    TRACE_IRQS_IRET                   /* 不需要,执行restore_all恢复,返回用户态 */
irq_return:
    INTERRUPT_RETURN                /* 相当于iret */

给MenuOS增加time和time-asm命令

命令:1、强制删除:rm menu -rf

   2、克隆:git clone (后跟需要克隆数据所在的位置)

   3、自动编译,自动生成根文件系统,并自动启动:make rootfs

给MenuOS增加time和time-asm命令步骤:

1、更新menu代码到最新版

2、在main函数中增加MenuCongfig

3、增加对应的time和time-asm函数

4、make rootfs

使用gdb跟踪调用内核函数sys-time

跟踪方法和上次所学内容一样:

注:sys_time返回后进入汇编代码处理,gdb无法继续进行追踪

  执行int 0x80之后执行system_call对应的代码

系统调用在内核代码中的处理过程

1、系统调用机制的初始化


\init\main.c start_kernel

      trap_init()

\arch\x86\kernel\traps.c

      #fdef CONFIG_x86_32

      set_system_trap_gate(SYSTALL_VECTOR,&system_call)(SYSTALL_VECTOR:系统调用的工作向量,&system_call:汇编代码的入口,系统执行int 0x80就跳转到该处执行)

      set_bit(SYSCALL_VECTOR,used_vectors)

      #endif

2、system_call伪代码:

system_call位置:/ arch/x86/kernel/entry_32.S中

系统调用是特殊的中断:存在保存现场和恢复现场

SAVE_ALL保存现场

restore_all恢复现场
call *sys_call_table(,%eax,4)调用系统调用函数:eax存的是系统调用号,根据系统调用号去找sys_call_table中的中断处理。
INTERRUPT_RETURN,就是iret。

分析system_call代码,系统调用的流程大致为:

总结:

发生中断时,CPU暂停执行当前程序,产生中断响应。中断响应主要工作是:
(1)中止当前程序的执行;
(2)保存原程断点现场
(3)转到相应的处理程序。
接着中断处理程序进行相应处理:
(1)保存中断程序现场
(2)分析中断原因,转入相应处理程序
(3)调用中断处理程序
(4)中断返回。

此为本人Linux学习第六周的内容,如有不足,还请批评指正,不胜感激。

以上

猜你喜欢

转载自www.cnblogs.com/qianxiaoxu/p/11742083.html
今日推荐