码迷,mamicode.com
首页 > Windows程序 > 详细

API和系统调用实现同一方法

时间:2015-03-27 23:46:52      阅读:326      评论:0      收藏:0      [点我收藏+]

标签:

“平安的祝福 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ”

一、基本概念

1.1API和系统调用区别:

API只是一个函数定义;系统调用通过软中断向内核发出一个明确的请求。

Libc库定义的一些API引用了封装例程(wrapper routine,唯一目的就是发布系统调用):一般每个系统调用对应一个封装例程;库再用这些封装例程定义出给用户的API

1.2大部分封装例程返回一个整数,其值的含义依赖于相应的系统调用:

-1在多数情况下表示内核不能满足进程的请求;

Libc中定义的errno变量包含特定的出错码;

1.3应用程序、封装例程、系统调用处理程序及系统调用服务例程之间的关系

技术分享

1.4当用户态进程调用一个系统调用时,CPU切换到内核态并开始执行一个内核函数。

在Linux中是通过执行int $0x80来执行系统调用的,这条汇编指令产生向量为128的编程异常

1.5传参:

内核实现了很多不同的系统调用,进程必须指明需要哪个系统调用,这需要传递一个名为系统调用号的参数,使用eax寄存器

1.6系统调用也需要输入输出参数,例如

实际的值,用户态进程地址空间的变量的地址,甚至是包含指向用户态函数的指针的数据结构的地址

1.7system_call是linux中所有系统调用的入口点,每个系统调用至少有一个参数,即由eax传递的系统调用号

步骤:1.一个应用程序调用fork()封装例程,那么在执行int $0x80之前就把eax寄存器的值置为2(即__NR_fork)。这个寄存器的设置是libc库中的封装例程进行的,因此用户一般不关心系统调用号。

2.进入sys_call之后,立即将eax的值压入内核堆栈。

二、具体例子

2.1系统调用函数getpid编写的程序:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(void)
{
    printf("The current process ID is %d\n",getpid());
    return 0;
}

2.2使用嵌入式汇编实现的getpid程序:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(void)
{
    int t;
    asm volatile(
                "mov $0,%%ebx\n\t"
                "mov $0x14,%%eax\n\t"  //其中getpid的系统调用数是20
                "int $0x80\n\t"
                "mov %%eax,%0"
                :"=m"(t)
                );
    printf("The current process ID is %d\n",t);
    return 0;
}

2.3分析汇编代码系统调用工作过程:

首先将ebx寄存器清空,将getpid的系统调用号传入寄存器eax,然后调用系统软中断。系统中断处理完成后,eax寄存器存储的是系统调用getpid的返回值,将eax寄存器的值赋值给用户空间的参数。

2.4程序的输出结果一样:

技术分享

三、总结:

通过这次实验,大致了解用户程序如何执行系统调用的。流程:用户程序调用API——》封装例程——》中断向量实现系统程序的切换——》系统调用具体的汇编程序。

API和系统调用实现同一方法

标签:

原文地址:http://www.cnblogs.com/pingandezhufu/p/4373142.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!