linux0.11系统调用(要分清中断调用和系统调用:0x80号中断的处理程序是system-call.s。用户使用中断调用int 0x80和放在寄存器eax中的功能号来使用内核提供的各种 )

续标题:用户使用中断调用int 0x80和放在寄存器eax中的功能号来使用内核提供的各种功能服务。这些操作系统提供的功能被称之为系统调用功能。

一、角度1--------开凿运河-----以(0x80号)128号中断为运河源头

1

区分内核态和用户态:是一种处理器“硬件设计”,应该涉及段寄存器,即硬件设计段寄存器的那两位特权级位。cpu在取指执行时,若将要取操作的段的特权级大于当前特权级。则无法取指执行。

  2

(1)宏定义

#define _syscall3(type,name,atype,a,btype,b,ctype,c) 

type name(atype a, btype b, ctype c)

{

long  _ _res;

_ _asm_ _volatile(“int0x80”

:”=a”(_ _res)

:””(_ _NR_##name), ”b”((long)(a)),”c”((long)(b)),“d”((long)(c))));

if(_ _res>=0)

return (type)__res;

 errno=-_ _res;

return -1;

}

(2)宏展开sysca113 (int, write,int, fd, const char *,buf, off t, count)

输入Mov ebx,a

Mov ecx,b

Mov edx,c

输出Mov eax,_NR_write

展开后,只是明确了int 0x80的输入输出,int指令执行完后返回一个值,但问题是不知道int 0x80到底干什么?

(3)int 0x80中断干什么,需要预先初始化

  初始化时

在linux/init/main.c中函数void main(void)调用void sched_init(void)

void sched_init(void)

{

……..

……..

set_system_gate(0x80,&system_call);

}

在linux/include/asm/system.h中

#define set_system_gate(n, addr)

_set_gate(&idt[n],15,3,addr);             //idt是中断向量表基址

#define _set_gate(gate_addr, type, dpl, addr)

__asm__(“movw %%dx,%%ax”

“movw %0,%%dx”

“movl %%eax,%1”

“movl %%edx,%2”

:

:”i”((short)(0x8000+(dpl<<13)+type<<8))),

“o”(*(( char*)(gate_addr))),

”o”(*(4+(char*)(gate_addr))),

“d”((char*)(addr),

”a”(0x00080000))

set_system_gate(0x80,&system_call);即_set_gate(&idt[0x80], 15, 3, &system_call)

宏展开:

__asm__(“movw %%dx,%%ax”

“movw %0,%%dx”

“movl %%eax,%1”

“movl %%edx,%2”:

:”i”((short)(0x8000+(3 <<13)+15 <<8))),

“o”(*(( char*)(&idt[0x80]))),          //局部第0x80段

”o”(*(4+(char*)(&idt[0x80]))),

“d”((char*)(&system_call),

”a”(0x00080000))

  内嵌汇编转变一下

movl $0x00080000,%%eax

movl $&system_call,%%edx

movw %%dx,%%ax

movw $0xef00,%%dx

movl %%eax,地址位局部段第一个字节

movl %%edx,地址位局部段第四个字节

这样DPL变成3,用户可以进来。进来后RPL就成了0,就可以在内核逛了。

1)DPL=3
2)RPL=0
3)这个0x80中断的处理程序是system-call.s。对于0x80中断system-call.s是系统调用入口。

所以汇编语句int 0x80的作用是中断进入系统调用入口(系统调用入口system-call.s是初始化时设置的跳转函数,中断可以说是跳转)。接口函数API是包装一下语句int 0x80

3

system-call.s代码刨析

简单的说:system_call.s本程序主要实现系统调用(system_call)中断intOxSO的入口处理过程以及信号检测处理(从代码第80行开始同时给出了两个系统功能的底层接口,分别是sys_execve和sys_fork。还列出了处理过程类似 的协处理器出错(intl6)、设备不存在(int7)、时钟中断(int32)、硬盘中断(int46)、软盘中断(int38)的中断处理程序

 更细节的看源代码

二、角度2-------建造码头------用宏包裹int 0x80指令
1

接口函数API(Application Programming Interface)(.v申请;.n程序;.n接口)
(1)把系统调用的编号存入 EAX;
(2)把函数参数存入其它通用寄存器;
(3)触发 0x80 号中断(int 0x80),int 是汇编指令,编译后就是一段明确的二进制指令。就像pop,push。具体再往下延申就于系统调用远了些。

2

接口函数API的宏

内核接口函数的实现:0~3个参数的接口函数例子:
(1)0个参数
①0个参数类的接口函数的所需指令和所需指令的执行序列一样,做宏减少代码量。
#define syscallO(type, name) type name(void)
{
long _ _res;
_ asm volatile ( int $0x80"
:"=a〃 (res)
:”0”(NR##name)) ;
if ( res〉= 0)
return (type) res;
errno = - _res;
return -1;
}
(2)1个参数
①1个参数类的接口函数的所需指令和所需指令的执行序列一样,做宏减少代码量。
#define _syscalll (type, name, atype, a)
type name(atype a)
{
long _ res;
_ asm volatile ( int $0x80"
:"=a〃 (res)
:〃0〃 (NR##name), 〃b" ((long) (a))) ;
if ( res >= 0)
return (type) res;
errno = - _res;
return -1;
}
(3)2个参数
①2个参数类的接口函数的所需指令和所需指令的执行序列一样,做宏减少代码量。
#define sysca112(type, name, atype, a, btype, b)
type name(atype a, btype b)
{
long _ res;
_ asm _ volatile {“int $0x80〃
:”=a〃 (res)
:〃0〃 (NR##name), 〃b〃 ((long) (a)), “c” ((long) (b))) ;
if ( res >= 0)
return (type) res;
errno = - _res;
return -1;
}
(4)3个参数
1在linux/include/unistd.h中
#ifdef LIBRARY
①系统调用的编号的定义
宏定义系统调用符号常数,用作系统调用函数表中的索引值。
#define _ _NR_write 4
②3个参数类的接口函数的所需指令和所需指令的执行序列一样,做宏减少代码量。
#define _syscall3(type,name,atype,a,btype,b,ctype,c)
type name(atype a, btype b, ctype c)
{
long _ res;
_ asm volatile(“int0x80”
:”=a”( res)
:””( NR##name), ”b”((long)(a)),”c”((long)(b)),“d”((long)©)));
if( _res>=0)
return (type)_res;
errno=- _res;
return -1;
}
#endif
③系统调用的函数原型定义int write(int fildes, const char * buf, off_t count);


3、利用上诉的4个宏定义接口函数API

(1)在linux/lib/write.c中只有三句
#define LIBRARY
include <unistd. h>
sysca113 (int, write,int, fd, const char *,buf, off_t, count)


(2)要理解嵌入式汇编宏函数,就要先了解宏函数
sysca113 (int, write,int, fd, const char *,buf, off_t, count)

宏展开为

int write(int fd, const char *buf, off_t count)
{
long _ res;
_ asm volatile(“int0x80”
:”=a”( res)
:””( NR##write), ”b”((long)(fd)),”c”((long)(buf)),“d”((long)(count)));
if( _res>=0)
    return (int)_res;
errno=- _res;
return -1;
}

在实际情形中,带参数的宏得到参数,一般会做两件事,一执行汇编指令int的操作,二返回一个值。

4、当然系统调用接口函数原型可以是利用宏定义:

sysca113 (int, write,int, fd, const char *,buf, off_t, count)

也可以是直接定义:

int open(const char * filename, int flag, ...)
{
    register int res;
    va_list arg;

    va_start(arg,flag);
    __asm__("int $0x80"
        :"=a" (res)
        :"0" (__NR_open),"b" (filename),"c" (flag),
        "d" (va_arg(arg,int)));
    if (res>=0)
        return res;
    errno = -res;
    return -1;
}
因为sys_open有:(1)把系统调用的编号存入 EAX; (2)把函数参数存入其它通用寄存器;
                             (3)触发 0x80 号中断(int 0x80)

这三个接口函数必有要素外,还使用了可变参数

可变参数可以看看我的:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值