Linux内核分析第四周作业

使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

首先从系统调用表中选择一个系统调用,我选择了122号系统调用——uname

122	i386	uname			sys_newuname

先用man查一下api是怎么使用的

man 2 api

这里的2表示查询系统调用uname(2),否则默认查的是uname(1),也就是在shell中运行的uname程序。

可以看到,要使用uname,首先要include头文件sys/utsname.h。然后定义一个utsname结构体的变量,将这个变量的指针作为参数传递给uname。系统就会在结构体中填充信息,都是字符串,可以直接打印。

于是写下最简单的代码:

#include <stdio.h>
#include <sys/utsname.h>

int main()
{
    struct utsname name;
    uname(&name);
    printf("--API--\n");
    printf("%s\n", name.sysname);
    printf("%s\n", name.nodename);
    printf("%s\n", name.release);
    printf("%s\n", name.version);
    printf("%s\n", name.machine);
    return 0;
}

编译以后看一下运行结果

然后考虑用内联汇编实现系统调用。将代码修改一下

 1 #include <stdio.h>
 2 #include <sys/utsname.h>
 3
 4 int main()
 5 {
 6     struct utsname name;
 7
 8     asm volatile(
 9         "mov %0, %%ebx\n\t"
10         "mov $122, %%eax\n\t"
11         "int $0x80\n\t"
12         :
13         :"r"(&name)
14     );
15
16     printf("--ASM--\n");
17     printf("%s\n", name.sysname);
18     printf("%s\n", name.nodename);
19     printf("%s\n", name.release);
20     printf("%s\n", name.version);
21     printf("%s\n", name.machine);
22     return 0;
23 }

编译以后看一下运行结果

和API的调用方式结果一样。

下面分析一下汇编代码调用的细节。

第9行向EBX写入参数,即name结构体的地址

第10行将系统调用号122写入EAX

第11行引发0x80的中断。中断会立刻运行IRQ。

Linux内核在启动之初的trap_init函数中就将0x80的IRQ固定为系统调用的处理函数

其中SYSCALL_VECTOR的值就是0x80

因为中断是内核处理的,所以此时已经进入内核态。

0x80的IRQ——system_call是用汇编写的

一开始保存了现场

然后根据EAX中的系统调用号,去调用对应的系统调用。最后将调用结果保存起来,退出IRQ的时候通过EAX返回给用户程序。

顺便看一眼这次选择的系统调用代码。根据系统调用表,112对应的系统调用名字叫做newuname(居然还有olduname和oldolduname。。。)

很简单,uname的内容一直在内核中保存着,每次系统调用只要将内容从内核态复制到用户态即可,并且复制的时候用锁保护了一下。

总结

Linux为了系统的稳定性,分为用户态和内核态。用户态的程序无法使用系统的底层功能,因此需要系统调用临时地让内核替用户程序去完成一些底层功能。

无论是API还是汇编的方式,都是通过0x80中断进入内核态,然后内核根据EAX中的系统调用号去调用对应的系统调用函数,最后将返回值通过EAX返回给用户态程序。

此外,系统调用是进程调度切换的时机,因为此时控制交给了内核。对于用户程序来说仅仅是调用了系统调用,然后从系统调用返回。在系统调用中发生的进程切换对于用户程序是透明的。

王岩

原创作品转载请注明出处

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

时间: 2024-08-09 16:24:13

Linux内核分析第四周作业的相关文章

LINUX内核分析第四周学习总结——扒开应用系统的三层皮(上)

LINUX内核分析第四周学习总结——扒开应用系统的三层皮(上) 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.知识概要 (一)用户态.内核态和中断处理过程 (二)系统调用概述 系统调用概述和系统调用的三层皮 (三)使用库函数API和C代码中嵌入汇编代码触发同一个系统调用 使用库函数API获取系统当前时间 C代码中嵌入汇编代码的方法(复习) 使用C代码中嵌入汇编代码触发系统调

20135327郭皓--Linux内核分析第四周 扒开系统调用的三层皮(上)

Linux内核分析第四周 扒开系统调用的三层皮(上) 郭皓 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 一.用户态.内核态和中断 用户态:当进程在执行用户自己的代码时,则称其处于用户态,即此时处理器在特权级最低的(3级)用户代码中运行. 内核态:当一个进程执行系统调用而陷入内核代码中执行时,我们就称进程处于内核态,此时处理器处于特权级最高的(0级)内核代码中执行. PS:CPU指令

《Linux内核分析》 week8作业-Linux加载和启动一个可执行程序

一.ELF文件格式 ELF(Executable and Linking Format)是x86 Linux系统下常用的目标文件格式,有三种主要类型: 适于连接的可重定位文件,可与其他目标文件一起创建可执行文件和共享目标文件. 适于执行的可执行文件,用于提供程序的进程映像,加载的内存执行. 共享目标文件,连接器可将它与其他可重定位文件和共享目标文件连接成其他目标文件. 文件格式 ELF header在文件开始处描述了整个文件的组织,Section提供了目标文件的各项信息,Program head

linux内核分析第四周-使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

本周作业的主要内容就是采用gcc嵌入汇编的方式调用system call.系统调用其实就是操作系统提供的服务.我们平时编写的程序,如果仅仅是数值计算,那么所有的过程都是在用户态完成的,但是我们想将变量打印在屏幕上,就必须调用printf,而printf这个函数内部就使用了write这个系统调用.操作系统之所以以system call的方式提供服务,是因为如果程序员能够任意操作OS所有的资源,那么将无比危险,所以OS设计出了内核态和用户态. 我们平时编程都是在用户态下,如果我们想要调用系统资源,那

《Linux内核分析》 week6作业-Linux内核fork()系统调用的创建过程

一.进程控制块PCB-stack_struct 进程在操作系统中都有一个结构,用于表示这个进程.这就是进程控制块(PCB),在Linux中具体实现是task_struct数据结构,它主要记录了以下信息: 状态信息,例如可执行状态.就绪状态.阻塞状态等. 性质,由于unix有很多变种,进行有自己独特的性质. 资源,资源的链接比如内存,还有资源的限制和权限等. 组织,例如按照家族关系建立起来的树(父进程.子进程等). task_struct结构体内容非常庞大,暂时没有去分析源代码,以后有时间再去研究

《Linux内核分析》 week5作业-system call中断处理过程

一.使用gdb跟踪分析一个系统调用内核函数 1.在test.c文件中添加time函数与采用c语言内嵌汇编的time函数.具体实现请看下图. 2.然后在main函数中添加MenuConfig函数,进行注册.这样当Menuos运行起来时,界面就会多出time与time-asm选项. 3.通过make rootfs命令运行 采用gdb调试的过程 qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S gdb fi

《Linux内核分析》 week2作业-时间片轮转

一.基于时间片轮转调度代码的解读 代码结构主要由三个文件组成: 1.mypcb.h 2.myinterrupt.c 3.mymain.c 1.进程控制块(mypcb.h) /* CPU-specific state of this task */ struct Thread{ unsigned long ip; //eip,程序入口地址 unsigned long sp; //堆栈esp栈顶地址 }; typedef struct PCB{ int pid; //进程pid号 volatile

《Linux内核分析》 week4作业-使用嵌入式汇编调用一个系统调用

一.fork的嵌入式汇编执行 #include <stdio.h> #include <unistd.h> int main(){ pid_t pid; asm volatile( "mov $0,%%ebx\n\t" "mov $0x2,%eax\n\t" "int 0x80\n\t" "mov %%eax,%0\n\t" :"=m"(tt) ); if(pid==0){ prin

Linux内核分析期末总结

<Linux内核分析>期末总结 20135313吴子怡.北京电子科技学院 Chapter1 往期博客传送门 (1)计算机是如何工作的:Linux内核分析——第一周学习笔记 (2)操作系统是如何工作的:Linux内核分析——第二周学习笔记 (3)Linux系统启动过程:Linux内核分析——第三周学习笔记 (4)系统调用的方法: Linux内核分析——第四周学习笔记 Linux内核实验作业四 (5)分析system_call中断处理过程: Linux内核分析——第五周学习笔记 实验作业:使gdb