(转)系统调用与API

来源:互联网 发布:asp网站怎么连接数据库 编辑:程序博客网 时间:2024/05/13 09:52

原文:http://www.cnblogs.com/zhuyp1015/archive/2012/05/11/2496730.html


系统调用接口往往是通过中断来实现,比如Linux使用0x80号中断作为系统调用的入口,Windows采用0x2E号中断作为系统调用的入口。

EAX

名字

C语言定义

含义

参数

1

exit

void _exit(int status)

退出进程

EBX表示退出码

2

fork

pid_t fork(void)

复制进程

EBX表示复制参数

3

read

ssize_t read( int fd,

void    *buf,

size_t  count)

读文件

EBX表示文件句柄,ECX表示读取缓冲地址,EDX表示读取的大小

4

write

ssize_t write( int fd,

const void *buf,

size_t   count);

写文件

同sys_read

5

open

Int open(

    Const char *path

    int flags,

    mode_t mode);

打开文件

EBX表示文件路径,ECX表示打开文件的模式,EDX也表示打开的模式

...

 

 

 

 

 

我们可以通过系统调用open()、read()和close()来绕过glibc的fopen()、fread()、fclose()。

 

/*sys_call_01.c*/

#include <unistd.h>

 

int main()

{

char buffer[64];

char buffer_r[64];

char *error_message = "open file error \n";

char *success_message = "open file success \n";

char *message = "please input something\n";

write(0,message,strlen(message));

int r_len = read(1,buffer_r,64);

buffer_r[r_len] = '\0';

printf("read_len = %d \t buffer_read = %s \n",r_len,buffer_r);

int fd = open("readme.txt",0,0);

if(fd == -1)

{

write(0, error_message, strlen(error_message));

return -1;

}

write(0,success_message, strlen(success_message));

read(fd, buffer,64);

printf("buffer: %s\n",buffer);

close(fd);

return 0;

}

注:stdin,stdout, stderr 的文件描述符分别为'0','1','2'

 

$ ./sys_call_01

please input something

read from stdin

read_len = 16    buffer_read = read from stdin

 

open file success

buffer: this is a test!

this is a test!

this is a test!

this is a tes/

 

在不同的系统中,系统调用是不相同的,为了统一,各种编程语言提供了运行库的接口来统一相同的功能。

比如,C语言里面的fread,用于读取文件,在Windows下这个函数的实现可能是调用ReadFile这个API,而如果在Linux下则很可能调用read这个系统调用。但不在管哪个平台,我们都可以使用C语言运行库的fread来读取文件。

 

运行时库将不同的操作系统的系统调用包装为统一固定的接口,使得同样的代码,在不同的操作系统下都可以直接编译,并产生一致的效果。这就是源代码级上的可移植性。

 

中断一般有两个属性,一个称为中断号(从0开始),一个称为中断处理程序(Interrupt Service Routine,ISR)。不同的中断具有不同的中断号,而同时一个中断处理程序一一对应一个中断号。在内核中,有一个数组称为中断向量表(Interrupt Vector Table),这个数组的第n项包含了指向第n个中断的中断处理程序的指针。

一个函数指针的数组:

(* ivt[])(int n) = { isr_01, isr-02, isr_03,...}

 

                                                       CPU中断过程

 

基于int的Linux的经典系统调用实现:

 

  1. 触发中断     2.    切换堆栈     3.    中断处理程序

在2.6的内核里面没有找到_syscall0

 

 

Windows API

一个普通的fwrite()的调用路径:

 

Windows API现在的数量很庞大,按照功能被划分为几大类:

 

 

所以不管内核如何改变接口,只要维持API层面的接口不变,理论上所有的应用程序都不用重新编译就可以正常运行,这也是Windows API存在的主要原因。