⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 interrupt-sys_call_6.htm

📁 编写自己的操作系统
💻 HTM
📖 第 1 页 / 共 2 页
字号:
\<BR>&nbsp;if ((unsigned long)(res) &gt;= (unsigned long)(-125)) { \<BR>&nbsp; 
errno = -(res); \<BR>&nbsp; res = -1; \<BR>&nbsp;} \<BR>&nbsp;return (type) 
(res); \<BR>} while (0)</FONT></P>
<P><FONT face="Courier New" size=2>/* 没有参数的系统调用使用此Macro进行定义 */<BR>#define 
_syscall0(type,name) \<BR>type name(void) \<BR>{ \<BR>long __res; \<BR>__asm__ 
volatile ("int $0x80" \<BR>&nbsp;: "=a" (__res) \<BR>&nbsp;: "0" (__NR_##name)); 
\<BR>__syscall_return(type,__res); \<BR>}</FONT></P>
<P><FONT face="Courier New" size=2>/* 具有1个参数的系统调用使用此Macro进行定义 */</FONT></P>
<P><FONT face="Courier New" size=2>#define _syscall1(type,name,type1,arg1) 
\<BR>type name(type1 arg1) \<BR>{ \<BR>long __res; \<BR>__asm__ volatile ("int 
$0x80" \<BR>&nbsp;: "=a" (__res) \<BR>&nbsp;: "0" (__NR_##name),"b" 
((long)(arg1))); \<BR>__syscall_return(type,__res); \<BR>}</FONT></P>
<P><FONT face="Courier New" size=2>/* 具有2个参数的系统调用使用此Macro进行定义 */</FONT></P>
<P><FONT face="Courier New" size=2>#define 
_syscall2(type,name,type1,arg1,type2,arg2) \<BR>type name(type1 arg1,type2 arg2) 
\<BR>{ \<BR>long __res; \<BR>__asm__ volatile ("int $0x80" \<BR>&nbsp;: "=a" 
(__res) \<BR>&nbsp;: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); 
\<BR>__syscall_return(type,__res); \<BR>}</FONT></P>
<P><FONT face="Courier New" size=2>/* 具有3个参数的系统调用使用此Macro进行定义 */</FONT></P>
<P><FONT face="Courier New" size=2>#define 
_syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \<BR>type name(type1 
arg1,type2 arg2,type3 arg3) \<BR>{ \<BR>long __res; \<BR>__asm__ volatile ("int 
$0x80" \<BR>&nbsp;: "=a" (__res) \<BR>&nbsp;: "0" (__NR_##name),"b" 
((long)(arg1)),"c" ((long)(arg2)), \<BR>&nbsp;&nbsp;&nbsp; "d" ((long)(arg3))); 
\<BR>__syscall_return(type,__res); \<BR>}</FONT></P>
<P><FONT face="Courier New" size=2>/* 具有4个参数的系统调用使用此Macro进行定义 */</FONT></P>
<P><FONT face="Courier New" size=2>#define 
_syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \<BR>type name 
(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \<BR>{ \<BR>long __res; 
\<BR>__asm__ volatile ("int $0x80" \<BR>&nbsp;: "=a" (__res) \<BR>&nbsp;: "0" 
(__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \<BR>&nbsp;&nbsp; "d" 
((long)(arg3)),"S" ((long)(arg4))); \<BR>__syscall_return(type,__res); \<BR>} 
</FONT></P>
<P><FONT face="Courier New" size=2>/* 具有5个参数的系统调用使用此Macro进行定义 */</FONT></P>
<P><FONT face="Courier New" size=2>#define 
_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, 
\<BR>&nbsp;&nbsp; type5,arg5) \<BR>type name (type1 arg1,type2 arg2,type3 
arg3,type4 arg4,type5 arg5) \<BR>{ \<BR>long __res; \<BR>__asm__ volatile ("int 
$0x80" \<BR>&nbsp;: "=a" (__res) \<BR>&nbsp;: "0" (__NR_##name),"b" 
((long)(arg1)),"c" ((long)(arg2)), \<BR>&nbsp;&nbsp; "d" ((long)(arg3)),"S" 
((long)(arg4)),"D" ((long)(arg5))); \<BR>__syscall_return(type,__res); 
\<BR>}</FONT></P>
<P><FONT face="Courier New" size=2>/* 具有6个参数的系统调用使用此Macro进行定义 */</FONT></P>
<P><FONT face="Courier New" size=2>#define 
_syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, 
\<BR>&nbsp;&nbsp; type5,arg5,type6,arg6) \<BR>type name (type1 arg1,type2 
arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \<BR>{ \<BR>long __res; 
\<BR>__asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; int 
$0x80 ; pop %%ebp" \<BR>&nbsp;: "=a" (__res) \<BR>&nbsp;: "i" (__NR_##name),"b" 
((long)(arg1)),"c" ((long)(arg2)), \<BR>&nbsp;&nbsp; "d" ((long)(arg3)),"S" 
((long)(arg4)),"D" ((long)(arg5)), \<BR>&nbsp;&nbsp; "0" ((long)(arg6))); 
\<BR>__syscall_return(type,__res); \<BR>}</FONT></P>
<P><FONT face="Courier New" size=2>/* 下面是几个通过上述Macro进行定义的系统调用的例子 */</FONT></P>
<P><FONT face="Courier New" size=2>static inline 
_syscall0(pid_t,setsid)<BR>static inline _syscall1(int,dup,int,fd)<BR>static 
inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)<BR>static inline 
_syscall3(int,read,int,fd,char *,buf,off_t,count)<BR>static inline 
_syscall3(off_t,lseek,int,fd,off_t,offset,int,count)</FONT></P>
<P><FONT face="Courier New" 
size=2>Linux捕获到这个中断后,将执行其对应的中断服务程序(system_call),system_call首先将必要的寄存器(包括这6个通用寄存器)push到栈中,然后以%eax中的值作为索引到其所维护的系统调用功能函数入口表(sys_call_table)中查找并调用相应函数。等系统调用完成后,Linux内核将返回值装入EAX寄存器(如果不是void的话),但不用其它寄存器来返回执行结果。下面是Linux 
2.4相关代码。</FONT></P>
<P><FONT face="Courier New" size=2>/* 这里定义的是Stack中各个寄存器距离栈顶的字节数 */</FONT></P>
<P><FONT face="Courier New" size=2>EBX = 0x00<BR>ECX = 0x04<BR>EDX = 
0x08<BR>ESI = 0x0C<BR>EDI = 0x10<BR>EBP = 0x14<BR>EAX = 0x18<BR>DS  = 
0x1C<BR>ES  = 0x20<BR>ORIG_EAX = 0x24<BR>EIP = 0x28<BR>CS = 0x2C<BR>EFLAGS = 
0x30<BR>OLDESP = 0x34<BR>OLDSS = 0x38</FONT></P>
<P><FONT face="Courier New" size=2>/* 此Macro用来保存和设置所有相关寄存器*/</FONT></P>
<P><FONT face="Courier New" size=2>#define SAVE_ALL \<BR>&nbsp;cld; 
\<BR>&nbsp;pushl %es; \<BR>&nbsp;pushl %ds; \<BR>&nbsp;pushl %eax; 
\<BR>&nbsp;pushl %ebp; \<BR>&nbsp;pushl %edi; \<BR>&nbsp;pushl %esi; 
\<BR>&nbsp;pushl %edx; \<BR>&nbsp;pushl %ecx; \<BR>&nbsp;pushl %ebx; 
\<BR>&nbsp;movl $(__KERNEL_DS),%edx; \<BR>&nbsp;movl %edx,%ds; \<BR>&nbsp;movl 
%edx,%es;</FONT></P>
<P><FONT face="Courier New" size=2>/* 为了便于理解,system_call中几条与此关键机制无关的指令被删去 
*/</FONT></P>
<P><FONT face="Courier New" size=2>ENTRY(system_call)<BR>&nbsp;pushl 
%eax&nbsp;&nbsp; # save orig_eax<BR>&nbsp;SAVE_ALL <BR>&nbsp;cmpl 
$(NR_syscalls),%eax # %eax中存放的系统调用号必须为一个存在的号<BR>&nbsp;jae 
badsys&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
# 否则返回-ENOSYS错误<BR>&nbsp;call 
*SYMBOL_NAME(sys_call_table)(,%eax,4) # 以%eax为索引,调用相应系统调用函数<BR>&nbsp;movl 
%eax,EAX(%esp)&nbsp;    # save the return value</FONT></P>
<P><FONT face="Courier New" size=2>badsys:<BR>&nbsp;movl 
$-ENOSYS,EAX(%esp)<BR>&nbsp;jmp ret_from_sys_call</FONT></P>
<P><FONT face="Courier New" 
size=2>需要注意的是,由于函数参数传递的方式是将参数Push到Stack中,被调用函数执行时到Stack中访问相关参数,所以SAVE_ALL中将各个寄存器压栈的顺序是经过精心安排的,不能够随意更改。我们看栈顶的6个寄存器依次为%ebx,%ecx,%edx,%esi,%edi,%ebp,对于不需要参数的系统调用功能函数来说,它不需要访问任何保存在栈中的寄存器的值;对于需要1个参数的寄存器来说,栈顶%ebx寄存器的内容就是它所需的参数的值;对于需要2个参数的寄存器来说,栈顶的%ebx,%ecx寄存器的内容就是它所需的2个参数的值,其中%ebx对应第一个参数,%ecx对应第2个参数……依次类推,对于需要6个参数的寄存器来说,栈顶的6个寄存器的内容就依次是它所需的6个参数的值。</FONT></P>
<P><FONT face="Courier New" 
size=2>另外,假如系统只提供了100个系统调用功能函数(0至99),而应用程序通过%eax寄存器传入的系统调用功能号为100以上的值,这很显然是一个非法调用,直接返回-ENOSYS错误。</FONT></P>
<P><FONT size=2><FONT size=+0><FONT face="Courier New" 
size=2>当系统调用表(sys_call_table)中的某个系统调用功能函数被执行后,由于此函数运行在内核态,内核当然应该信任自身的任何代码,所以它可以访问任何资源,可以调用任何操作系统内核中的函数。此时我们认为用户应用程序运行在内核态。</FONT></P></FONT></FONT></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -