?? system_call.s
字號:
/** linux/kernel/system_call.s** (C) 1991 Linus Torvalds*//** 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 信號(子進程停止或結束)。EAX = 0x00 # 堆棧中各個寄存器的偏移位置。EBX = 0x04ECX = 0x08EDX = 0x0CFS = 0x105.5 system_call.s 程序ES = 0x14DS = 0x18EIP = 0x1CCS = 0x20EFLAGS = 0x24OLDESP = 0x28 # 當有特權級變化時。OLDSS = 0x2C# 以下這些是任務結構(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.*//** 好了,在使用軟驅時我收到了并行打印機中斷,很奇怪。呵,現在不管它。*/# 定義入口點。.globl _system_call,_sys_fork,_timer_interrupt,_sys_execve.globl _hd_interrupt,_floppy_interrupt,_parallel_interrupt.globl _device_not_available, _coprocessor_error# 錯誤的系統調用號。.align 2 # 內存4 字節對齊。bad_sys_call:movl $-1,%eax # eax 中置-1,退出中斷。iret# 重新執行調度程序入口。調度程序schedule 在(kernel/sched.c,104)。.align 2reschedule:pushl $ret_from_sys_call # 將ret_from_sys_call 的地址入棧(101 行)。jmp _schedule#### int 0x80 --linux 系統調用入口點(調用中斷int 0x80,eax 中是調用號)。.align 2_system_call:cmpl $nr_system_calls-1,%eax # 調用號如果超出范圍的話就在eax 中置-1 并退出。ja bad_sys_call5.5 system_call.s 程序push %ds # 保存原段寄存器值。push %espush %fspushl %edx # ebx,ecx,edx 中放著系統調用相應的C 語言函數的調用參數。pushl %ecx # push %ebx,%ecx,%edx as parameterspushl %ebx # to the system callmovl $0x10,%edx # set up ds,es to kernel spacemov %dx,%ds # ds,es 指向內核數據段(全局描述符表中數據段描述符)。mov %dx,%esmovl $0x17,%edx # fs points to local data spacemov %dx,%fs # fs 指向局部數據段(局部描述符表中數據段描述符)。# 下面這句操作數的含義是:調用地址 = _sys_call_table + %eax * 4。參見列表后的說明。# 對應的C 程序中的sys_call_table 在include/linux/sys.h 中,其中定義了一個包括72 個# 系統調用C 處理函數的地址數組表。call _sys_call_table(,%eax,4)pushl %eax # 把系統調用號入棧。movl _current,%eax # 取當前任務(進程)數據結構地址??eax。# 下面97-100 行查看當前任務的運行狀態。如果不在就緒狀態(state 不等于0)就去執行調度程序。# 如果該任務在就緒狀態但counter[??]值等于0,則也去執行調度程序。cmpl $0,state(%eax) # statejne reschedulecmpl $0,counter(%eax) # counterje reschedule# 以下這段代碼執行從系統調用C 函數返回后,對信號量進行識別處理。ret_from_sys_call:# 首先判別當前任務是否是初始任務task0,如果是則不必對其進行信號量方面的處理,直接返回。# 103 行上的_task 對應C 程序中的task[]數組,直接引用task 相當于引用task[0]。movl _current,%eax # task[0] cannot have signalscmpl _task,%eaxje 3f # 向前(forward)跳轉到標號3。# 通過對原調用程序代碼選擇符的檢查來判斷調用程序是否是超級用戶。如果是超級用戶就直接# 退出中斷,否則需進行信號量的處理。這里比較選擇符是否為普通用戶代碼段的選擇符0x000f# (RPL=3,局部表,第1 個段(代碼段)),如果不是則跳轉退出中斷程序。cmpw $0x0f,CS(%esp) # was old code segment supervisor ?jne 3f# 如果原堆棧段選擇符不為0x17(也即原堆棧不在用戶數據段中),則也退出。cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ?jne 3f# 下面這段代碼(109-120)的用途是首先取當前任務結構中的信號位圖(32 位,每位代表1 種信號),# 然后用任務結構中的信號阻塞(屏蔽)碼,阻塞不允許的信號位,取得數值最小的信號值,再把# 原信號位圖中該信號對應的位復位(置0),最后將該信號值作為參數之一調用do_signal()。# do_signal()在(kernel/signal.c,82)中,其參數包括13 個入棧的信息。movl signal(%eax),%ebx # 取信號位圖??ebx,每1 位代表1 種信號,共32 個信號。movl blocked(%eax),%ecx # 取阻塞(屏蔽)信號位圖??ecx。notl %ecx # 每位取反。andl %ebx,%ecx # 獲得許可的信號位圖。bsfl %ecx,%ecx # 從低位(位0)開始掃描位圖,看是否有1 的位,# 若有,則ecx 保留該位的偏移值(即第幾位0-31)。je 3f # 如果沒有信號則向前跳轉退出。btrl %ecx,%ebx # 復位該信號(ebx 含有原signal 位圖)。movl %ebx,signal(%eax) # 重新保存signal 位圖信息??current->signal。incl %ecx # 將信號調整為從1 開始的數(1-32)。pushl %ecx # 信號值入棧作為調用do_signal 的參數之一。5.5 system_call.s 程序call _do_signal # 調用C 函數信號處理程序(kernel/signal.c,82)popl %eax # 彈出信號值。3: popl %eaxpopl %ebxpopl %ecxpopl %edxpop %fspop %espop %dsiret#### int16 -- 下面這段代碼處理協處理器發出的出錯信號。跳轉執行C 函數math_error()# (kernel/math/math_emulate.c,82),返回后將跳轉到ret_from_sys_call 處繼續執行。.align 2_coprocessor_error:push %dspush %espush %fspushl %edxpushl %ecxpushl %ebxpushl %eaxmovl $0x10,%eax # ds,es 置為指向內核數據段。mov %ax,%dsmov %ax,%esmovl $0x17,%eax # fs 置為指向局部數據段(出錯程序的數據段)。mov %ax,%fs
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -