在分析了中断和异常之后,对于系统调用的过程应该是很容易理解的,这篇博文中除了介绍系统调用,还会涉及到一个比较重要的知识点——异常修正。
int sethostname(const char* name, size_t size)
参数name是要设置的主机名;len是name的长度;调用后返回0表示成功,返回-1表示失败。失败时用户程序中的全局变量errno和iu含有具体的出错代码。
sethostname()是一个库函数,反汇编的到其汇编代码如下:
0:movl %ebx, %edx #保存ebx
2:movl 0x8(%esp, 1), %ecx #len(主机名长度)
6:movl 0x4(%esp, 1), %ebx #name(指向用户名)
a:movl $0x4a, %eax #系统调用号
f:int $0x80 #中断
11:movl %edx, %ebx
13:compl $0xfffff001, %eax #检查系统调用的返回值,如果%eax实在0xfffff001和0xffffffff则说明出错了,则转向__syscall_error并从那里返回。
18:jae 1a <sethostname+0x1a>#
1d
1a:__syscall_error
1e:ret
我们看到,系统调用是通过寄存器传递参数的,避免了因为参数问题反复的在用户空间和内核空间进行切换。
__syscall_error完成的工作主要是将保存在eax中的出错码取负之后存入errorno,之后将-1写入eax,作为返回值,通知用户系统调用出错。
CPU穿过陷阱门的过程与发生中断时穿过中断门的过程相同,不过后者不需要进行特权级别的检查,而前者则需要核对规定的转入级别与CPU的昂钱运行级别(系统调用的准入级别是3)。IDT表对应于0x80的表项对应的函数指针是system_call():
/*
* syscall stub including irq exit should be protected against kprobes
*/
.pushsection .kprobes.text, "ax"
#