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

黄二玉+原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

预备知识

系统调用(System call)

The architecture of most modern processors, with the exception of some embedded systems, involves a security model. For example, the rings model specifies multiple privilege levels under which software may be executed: a program is usually limited to its own address space so that it cannot access or modify other running programs or the operating system itself, and is usually prevented from directly manipulating hardware devices (e.g. the frame buffer or network devices).
However, many normal applications obviously need access to these components, so system calls are made available by the operating system to provide well defined, safe implementations for such operations. The operating system executes at the highest level of privilege, and allows applications to request services via system calls, which are often initiated via interrupts. An interrupt automatically puts the CPU into some elevated privilege level, and then passes control to the kernel, which determines whether the calling program should be granted the requested service. If the service is granted, the kernel executes a specific set of instructions over which the calling program has no direct control, returns the privilege level to that of the calling program, and then returns control to the calling program.

上面是维基百科关于为何要设置系统调用及程序是如何获得较高特权的

  • 出于安全方面的原因,应用程序不允许直接访问或者修改某些资源,但是系统调用是可以让应用程序能够获得它所需的服务或操作的.
  • 系统调用主要是通过中断(interrupt)实现的,中断可以使运用程序获得更好的优先级。

用户态(user space)与内核态 (kernel space)

用户态:cpu的访问受到了限制,不允许访问硬件资源;
内核态:可以访问所用的资源

API与系统调用

为了实现系统调用需要从用户态切换到内核态,一种经常使用的方法是使用软中断(software)或者陷入(trap),中断把控制转移到操作系统内核,因此运用程序只需要在寄存器中设置系统调用号,然后简单的执行软中断。通常,系统提供了已经封装好系统调用的API,一个API中可能封装了多个系统调用,当然一个系统调用也可能被多个API封装。

如何实现系统调用

通常系统调用总是在我们不知不觉中被使用,比如说调用c语言中的read函数,open函数等;为了更好的理解系统调用,可以在c代码中嵌入汇编代码的方式来实现一个系统调用。
在X86中,把系统调用号放在寄存器ax中,然后执行int $128或者int $0x80语句便可以实现一个系统调用。

例子

获取时间

#include <stdio.h>
#include <time.h>
int main()
{
   time_t tt;
   struct tm *t;
   asm volatile(
        "mov $0,%%ebx\n\t"
        "mov $0xd,%%eax\n\t" /*获取系统时间的系统调用号是13*/
        "int $0x80\n\t"   /*执行系统调用*/
        "mov %%eax,%0\n\t"  /*把返回值放到tt中*/
        :"=m"(tt)
    );
    t=localtime(&tt);
    printf("time:%d:%d:%d:%d:%d\n",t->tm_year+1900,t->tm_mon,t->tm_hour,t->tm_min,t->tm_sec);
    return 0;
}

把上面的代码反正time.c中,使用gcc time.c -o time -m32命令编译
结果如下:
time

退出程序

#include<stdio.h>
int main()
{
    int a=10;
    asm volatile(
    "mov $0x01,%%eax\n\t"
    "int $0x80\n\t"
    "mov %%eax,%0\n\t"
    :"=m"(a)
    );
    printf("a=%d\n",a);//该语句不会被执行
    return 0;
}

获得pid

#include<stdio.h>
int main()
{
    printf("%d\n",getpid());
    return 0;
}

使用嵌入汇编的方式:

#include<stdio.h>
int main()
{
    int a=0;
    asm volatile(
        "mov $20,%%eax\n\t"
        "int $128\n\t"
        "mov %%eax,%0\n\t" //eax存放了系统调用的返回值
        :"=m"(a)
   );
    printf("%d\n",a);
    return 0;
}

总结

运用程序为了获得受限的服务或者操作,需要使用系统调用,而系统调用主要是通过中断来实现的,通过中断可以使cpu获得更高的优先级,从而完成由用户态到内核态的切换。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值