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

📄 system_call.s

📁 LINUX 0.11版内核代码。 并有代码分析说明。
💻 S
📖 第 1 页 / 共 2 页
字号:
;/* passed;* linux/kernel/system_call.s;*;* (C) 1991 Linus Torvalds;*/.386p
.model flat
;/*;* system_call.s contains the system-call low-level handling routines.;* This also contains the timer-interrupt handler, as some of the code is;* the same. The hd- and flopppy-interrupts are also here.;*;* NOTE: This code handles signal-recognition, which happens every time;* after a timer-interrupt and after each system call. Ordinary interrupts;* don't handle signal-recognition, as that would clutter them up totally;* unnecessarily.;*;* Stack layout in 'ret_from_system_call':;*;* 0(%esp) - %eax;* 4(%esp) - %ebx;* 8(%esp) - %ecx;* C(%esp) - %edx;* 10(%esp) - %fs;* 14(%esp) - %es;* 18(%esp) - %ds;* 1C(%esp) - %eip;* 20(%esp) - %cs;* 24(%esp) - %eflags;* 28(%esp) - %oldesp;* 2C(%esp) - %oldss;*/;/*;* system_call.s 文件包含系统调用(system-call)底层处理子程序。由于有些代码比较类似,所以;* 同时也包括时钟中断处理(timer-interrupt)句柄。硬盘和软盘的中断处理程序也在这里。;*;* 注意:这段代码处理信号(signal)识别,在每次时钟中断和系统调用之后都会进行识别。一般;* 中断信号并不处理信号识别,因为会给系统造成混乱。;*;* 从系统调用返回('ret_from_system_call')时堆栈的内容见上面19-30 行。;*/SIG_CHLD = 17 ;// 定义SIG_CHLD 信号(子进程停止或结束)。R_EAX = 00h ;// 堆栈中各个寄存器的偏移位置。R_EBX = 04hR_ECX = 08hR_EDX = 0ChR_FS = 10hR_ES = 14hR_DS = 18hR_EIP = 1ChR_CS = 20hEFLAGS = 24hOLDR_ESP = 28h ;// 当有特权级变化时。OLR_DSS = 2Ch;// 以下这些是任务结构(task_struct)中变量的偏移值,参见include/linux/sched.h,77 行开始。state = 0 ;// these are offsets into the task-struct. ;// 进程状态码counter = 4 ;// 任务运行时间计数(递减)(滴答数),运行时间片。priority = 8 ;// 运行优先数。任务开始运行时counter=priority,越大则运行时间越长。signal = 12 ;// 是信号位图,每个比特位代表一种信号,信号值=位偏移值+1。sigaction = 16 ;// MUST be 16 (=len of sigaction) // sigaction 结构长度必须是16 字节。;// 信号执行属性结构数组的偏移值,对应信号将要执行的操作和标志信息。blocked = (33*16) ;// 受阻塞信号位图的偏移量。;// 以下定义在sigaction 结构中的偏移量,参见include/signal.h,第48 行开始。;// offsets within sigactionsa_handler = 0 ;// 信号处理过程的句柄(描述符)。sa_mask = 4 ;// 信号量屏蔽码sa_flags = 8 ;// 信号集。sa_restorer = 12 ;// 返回恢复执行的地址位置。nr_system_calls = 72 ;// Linux 0.11 版内核中的系统调用总数。;/*;* Ok, I get parallel printer interrupts while using the floppy for some;* strange reason. Urgel. Now I just ignore them.;*/;/*;* 好了,在使用软驱时我收到了并行打印机中断,很奇怪。呵,现在不管它。;*/;// 定义入口点。
extrn _schedule:proc,_do_signal:proc,_math_error:proc
extrn _math_state_restore:proc,_math_emulate:proc,_jiffies:proc
extrn _do_timer:proc,_do_execve:proc
extrn _find_empty_process:proc,_copy_process:proc
extrn _do_floppy:proc,_unexpected_floppy_interrupt:proc
extrn _do_hd:proc,_unexpected_hd_interrupt:proc

extrn _current:dword,_task:dword,_sys_call_table:dword
public _system_call,_sys_fork,_timer_interrupt,_sys_execvepublic _hd_interrupt,_floppy_interrupt,_parallel_interruptpublic _device_not_available, _coprocessor_error

.code

;// 错误的系统调用号。align 4 ;// 内存4 字节对齐。bad_sys_call:	mov eax,-1 ;// eax 中置-1,退出中断。	iretd;// 重新执行调度程序入口。调度程序schedule 在(kernel/sched.c,104)。align 4reschedule:	push ret_from_sys_call ;// 将ret_from_sys_call 的地址入栈(101 行)。	jmp _schedule;//// int 0x80 --linux 系统调用入口点(调用中断int 0x80,eax 中是调用号)。align 4_system_call:	cmp eax,nr_system_calls-1 ;// 调用号如果超出范围的话就在eax 中置-1 并退出。	ja bad_sys_call	push ds ;// 保存原段寄存器值。	push es	push fs	push edx ;// ebx,ecx,edx 中放着系统调用相应的C 语言函数的调用参数。	push ecx ;// push %ebx,%ecx,%edx as parameters	push ebx ;// to the system call	mov edx,10h ;// set up ds,es to kernel space	mov ds,dx ;// ds,es 指向内核数据段(全局描述符表中数据段描述符)。	mov es,dx	mov edx,17h ;// fs points to local data space	mov fs,dx ;// fs 指向局部数据段(局部描述符表中数据段描述符)。;// 下面这句操作数的含义是:调用地址 = _sys_call_table + %eax * 4。参见列表后的说明。;// 对应的C 程序中的sys_call_table 在include/linux/sys.h 中,其中定义了一个包括72 个;// 系统调用C 处理函数的地址数组表。	call [_sys_call_table+eax*4]	push eax ;// 把系统调用号入栈。	mov eax,_current ;// 取当前任务(进程)数据结构地址??eax。;// 下面97-100 行查看当前任务的运行状态。如果不在就绪状态(state 不等于0)就去执行调度程序。;// 如果该任务在就绪状态但counter[??]值等于0,则也去执行调度程序。	cmp dword ptr [state+eax],0 ;// state	jne reschedule	cmp dword ptr [counter+eax],0 ;// counter	je reschedule;// 以下这段代码执行从系统调用C 函数返回后,对信号量进行识别处理。ret_from_sys_call:;// 首先判别当前任务是否是初始任务task0,如果是则不必对其进行信号量方面的处理,直接返回。;// 103 行上的_task 对应C 程序中的task[]数组,直接引用task 相当于引用task[0]。	mov eax,_current ;// task[0] cannot have signals	cmp eax,_task	je l1 ;// 向前(forward)跳转到标号l1。;// 通过对原调用程序代码选择符的检查来判断调用程序是否是超级用户。如果是超级用户就直接;// 退出中断,否则需进行信号量的处理。这里比较选择符是否为普通用户代码段的选择符0x000f;// (RPL=3,局部表,第1 个段(代码段)),如果不是则跳转退出中断程序。	cmp word ptr [R_CS+esp],0fh ;// was old code segment supervisor ?	jne l1;// 如果原堆栈段选择符不为0x17(也即原堆栈不在用户数据段中),则也退出。	cmp word ptr [OLR_DSS+esp],17h ;// was stack segment = 0x17 ?	jne l1;// 下面这段代码(109-120)的用途是首先取当前任务结构中的信号位图(32 位,每位代表1 种信号),;// 然后用任务结构中的信号阻塞(屏蔽)码,阻塞不允许的信号位,取得数值最小的信号值,再把;// 原信号位图中该信号对应的位复位(置0),最后将该信号值作为参数之一调用do_signal()。;// do_signal()在(kernel/signal.c,82)中,其参数包括13 个入栈的信息。	mov ebx,[signal+eax] ;// 取信号位图??ebx,每1 位代表1 种信号,共32 个信号。	mov ecx,[blocked+eax] ;// 取阻塞(屏蔽)信号位图??ecx。	not ecx ;// 每位取反。	and ecx,ebx ;// 获得许可的信号位图。	bsf ecx,ecx ;// 从低位(位0)开始扫描位图,看是否有1 的位,;// 若有,则ecx 保留该位的偏移值(即第几位0-31)。	je l1 ;// 如果没有信号则向前跳转退出。	btr ebx,ecx ;// 复位该信号(ebx 含有原signal 位图)。	mov dword ptr [signal+eax],ebx ;// 重新保存signal 位图信息??current->signal。	inc ecx ;// 将信号调整为从1 开始的数(1-32)。	push ecx ;// 信号值入栈作为调用do_signal 的参数之一。	call _do_signal ;// 调用C 函数信号处理程序(kernel/signal.c,82)	pop eax ;// 弹出信号值。l1: pop eax	pop ebx	pop ecx	pop edx	pop fs	pop es	pop ds	iretd;//// int16 -- 下面这段代码处理协处理器发出的出错信号。跳转执行C 函数math_error();// (kernel/math/math_emulate.c,82),返回后将跳转到ret_from_sys_call 处继续执行。align 4_coprocessor_error:	push ds	push es	push fs	push edx	push ecx	push ebx	push eax

⌨️ 快捷键说明

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