日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux0.11内核--系统中断处理程序int 0x80实现原理

發(fā)布時間:2025/3/15 linux 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux0.11内核--系统中断处理程序int 0x80实现原理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

系統(tǒng)調(diào)用是一個軟中斷,中斷號是0x80,它是上層應(yīng)用程序與Linux系統(tǒng)內(nèi)核進(jìn)行交互通信的唯一接口。

這個中斷的設(shè)置在kernel/sched.c中441行函數(shù)中

void sched_init(void) {int i;struct desc_struct * p;if (sizeof(struct sigaction) != 16)panic("Struct sigaction MUST be 16 bytes");set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));p = gdt+2+FIRST_TSS_ENTRY;for(i=1;i<NR_TASKS;i++) {task[i] = NULL;p->a=p->b=0;p++;p->a=p->b=0;p++;} /* Clear NT, so that we won't have troubles with that later on */__asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");ltr(0);lldt(0);outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */outb_p(LATCH & 0xff , 0x40); /* LSB */outb(LATCH >> 8 , 0x40); /* MSB */set_intr_gate(0x20,&timer_interrupt);outb(inb_p(0x21)&~0x01,0x21);set_system_gate(0x80,&system_call); }
最后一句就將0x80中斷與system_call(系統(tǒng)調(diào)用)聯(lián)系起來。

通過int 0x80,就可使用內(nèi)核資源。不過,通常應(yīng)用程序都是使用具有標(biāo)準(zhǔn)接口定義的C函數(shù)庫間接的使用內(nèi)核的系統(tǒng)調(diào)用,即應(yīng)用程序調(diào)用C函數(shù)庫中的函數(shù),C函數(shù)庫中再通過int 0x80進(jìn)行系統(tǒng)調(diào)用。
????所以,系統(tǒng)調(diào)用過程是這樣的:
????應(yīng)用程序調(diào)用libc中的函數(shù)->libc中的函數(shù)引用系統(tǒng)調(diào)用宏->系統(tǒng)調(diào)用宏中使用int 0x80完成系統(tǒng)調(diào)用并返回

下面是sys_call_table的定義文件

位于./include/sys.h

extern int sys_setup (); // 系統(tǒng)啟動初始化設(shè)置函數(shù)。 (kernel/blk_drv/hd.c,71) extern int sys_exit (); // 程序退出。 (kernel/exit.c, 137) extern int sys_fork (); // 創(chuàng)建進(jìn)程。 (kernel/system_call.s, 208) extern int sys_read (); // 讀文件。 (fs/read_write.c, 55) extern int sys_write (); // 寫文件。 (fs/read_write.c, 83) extern int sys_open (); // 打開文件。 (fs/open.c, 138) extern int sys_close (); // 關(guān)閉文件。 (fs/open.c, 192) extern int sys_waitpid (); // 等待進(jìn)程終止。 (kernel/exit.c, 142) extern int sys_creat (); // 創(chuàng)建文件。 (fs/open.c, 187) extern int sys_link (); // 創(chuàng)建一個文件的硬連接。 (fs/namei.c, 721) extern int sys_unlink (); // 刪除一個文件名(或刪除文件)。 (fs/namei.c, 663) extern int sys_execve (); // 執(zhí)行程序。 (kernel/system_call.s, 200) extern int sys_chdir (); // 更改當(dāng)前目錄。 (fs/open.c, 75) extern int sys_time (); // 取當(dāng)前時間。 (kernel/sys.c, 102) extern int sys_mknod (); // 建立塊/字符特殊文件。 (fs/namei.c, 412) extern int sys_chmod (); // 修改文件屬性。 (fs/open.c, 105) extern int sys_chown (); // 修改文件宿主和所屬組。 (fs/open.c, 121) extern int sys_break (); // (-kernel/sys.c, 21) extern int sys_stat (); // 使用路徑名取文件的狀態(tài)信息。 (fs/stat.c, 36) extern int sys_lseek (); // 重新定位讀/寫文件偏移。 (fs/read_write.c, 25) extern int sys_getpid (); // 取進(jìn)程id。 (kernel/sched.c, 348) extern int sys_mount (); // 安裝文件系統(tǒng)。 (fs/super.c, 200) extern int sys_umount (); // 卸載文件系統(tǒng)。 (fs/super.c, 167) extern int sys_setuid (); // 設(shè)置進(jìn)程用戶id。 (kernel/sys.c, 143) extern int sys_getuid (); // 取進(jìn)程用戶id。 (kernel/sched.c, 358) extern int sys_stime (); // 設(shè)置系統(tǒng)時間日期。 (-kernel/sys.c, 148) extern int sys_ptrace (); // 程序調(diào)試。 (-kernel/sys.c, 26) extern int sys_alarm (); // 設(shè)置報(bào)警。 (kernel/sched.c, 338) extern int sys_fstat (); // 使用文件句柄取文件的狀態(tài)信息。(fs/stat.c, 47) extern int sys_pause (); // 暫停進(jìn)程運(yùn)行。 (kernel/sched.c, 144) extern int sys_utime (); // 改變文件的訪問和修改時間。 (fs/open.c, 24) extern int sys_stty (); // 修改終端行設(shè)置。 (-kernel/sys.c, 31) extern int sys_gtty (); // 取終端行設(shè)置信息。 (-kernel/sys.c, 36) extern int sys_access (); // 檢查用戶對一個文件的訪問權(quán)限。(fs/open.c, 47) extern int sys_nice (); // 設(shè)置進(jìn)程執(zhí)行優(yōu)先權(quán)。 (kernel/sched.c, 378) extern int sys_ftime (); // 取日期和時間。 (-kernel/sys.c,16) extern int sys_sync (); // 同步高速緩沖與設(shè)備中數(shù)據(jù)。 (fs/buffer.c, 44) extern int sys_kill (); // 終止一個進(jìn)程。 (kernel/exit.c, 60) extern int sys_rename (); // 更改文件名。 (-kernel/sys.c, 41) extern int sys_mkdir (); // 創(chuàng)建目錄。 (fs/namei.c, 463) extern int sys_rmdir (); // 刪除目錄。 (fs/namei.c, 587) extern int sys_dup (); // 復(fù)制文件句柄。 (fs/fcntl.c, 42) extern int sys_pipe (); // 創(chuàng)建管道。 (fs/pipe.c, 71) extern int sys_times (); // 取運(yùn)行時間。 (kernel/sys.c, 156) extern int sys_prof (); // 程序執(zhí)行時間區(qū)域。 (-kernel/sys.c, 46) extern int sys_brk (); // 修改數(shù)據(jù)段長度。 (kernel/sys.c, 168) extern int sys_setgid (); // 設(shè)置進(jìn)程組id。 (kernel/sys.c, 72) extern int sys_getgid (); // 取進(jìn)程組id。 (kernel/sched.c, 368) extern int sys_signal (); // 信號處理。 (kernel/signal.c, 48) extern int sys_geteuid (); // 取進(jìn)程有效用戶id。 (kenrl/sched.c, 363) extern int sys_getegid (); // 取進(jìn)程有效組id。 (kenrl/sched.c, 373) extern int sys_acct (); // 進(jìn)程記帳。 (-kernel/sys.c, 77) extern int sys_phys (); // (-kernel/sys.c, 82) extern int sys_lock (); // (-kernel/sys.c, 87) extern int sys_ioctl (); // 設(shè)備控制。 (fs/ioctl.c, 30) extern int sys_fcntl (); // 文件句柄操作。 (fs/fcntl.c, 47) extern int sys_mpx (); // (-kernel/sys.c, 92) extern int sys_setpgid (); // 設(shè)置進(jìn)程組id。 (kernel/sys.c, 181) extern int sys_ulimit (); // (-kernel/sys.c, 97) extern int sys_uname (); // 顯示系統(tǒng)信息。 (kernel/sys.c, 216) extern int sys_umask (); // 取默認(rèn)文件創(chuàng)建屬性碼。 (kernel/sys.c, 230) extern int sys_chroot (); // 改變根系統(tǒng)。 (fs/open.c, 90) extern int sys_ustat (); // 取文件系統(tǒng)信息。 (fs/open.c, 19) extern int sys_dup2 (); // 復(fù)制文件句柄。 (fs/fcntl.c, 36) extern int sys_getppid (); // 取父進(jìn)程id。 (kernel/sched.c, 353) extern int sys_getpgrp (); // 取進(jìn)程組id,等于getpgid(0)。(kernel/sys.c, 201) extern int sys_setsid (); // 在新會話中運(yùn)行程序。 (kernel/sys.c, 206) extern int sys_sigaction (); // 改變信號處理過程。 (kernel/signal.c, 63) extern int sys_sgetmask (); // 取信號屏蔽碼。 (kernel/signal.c, 15) extern int sys_ssetmask (); // 設(shè)置信號屏蔽碼。 (kernel/signal.c, 20) extern int sys_setreuid (); // 設(shè)置真實(shí)與/或有效用戶id。 (kernel/sys.c,118) extern int sys_setregid (); // 設(shè)置真實(shí)與/或有效組id。 (kernel/sys.c, 51) // 系統(tǒng)調(diào)用函數(shù)指針表。用于系統(tǒng)調(diào)用中斷處理程序(int 0x80),作為跳轉(zhuǎn)表。 fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod,sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount,sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm,sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access,sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir,sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid,sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,sys_setreuid, sys_setregid };

其中sys_call_table的類型是fn_ptr類型,其中sys_call_table[0]元素為sys_setup,它的類型是fn_ptr類型,它實(shí)際上是函數(shù)sys_setup的

入口地址。

它的定義如下:

typedef int (*fn_ptr) (); // 定義函數(shù)指針類型。

下面的實(shí)例代碼有助于理解函數(shù)指針:

#include<stdio.h> typedef int (*MyFunc)(); MyFunc Func1; int Func2() {printf("This is a sample output!/n");return 0; } int main() {Func1=Func2;//Func2();//(*Func1)();printf("%x/n",(*Func1));printf("%x/n",Func2);return 0; }

system_call系統(tǒng)調(diào)用入口函數(shù)

#### int 0x80 --linux 系統(tǒng)調(diào)用入口點(diǎn)(調(diào)用中斷int 0x80,eax 中是調(diào)用號)。 .align 2 _system_call: cmpl $nr_system_calls-1,%eax # 調(diào)用號如果超出范圍的話就在eax 中置-1 并退出。 ja bad_sys_call push %ds # 保存原段寄存器值。 push %es push %fs pushl %edx # ebx,ecx,edx 中放著系統(tǒng)調(diào)用相應(yīng)的C 語言函數(shù)的調(diào)用參數(shù)。 pushl %ecx # push %ebx,%ecx,%edx as parameters pushl %ebx # to the system call movl $0x10,%edx # set up ds,es to kernel space mov %dx,%ds # ds,es 指向內(nèi)核數(shù)據(jù)段(全局描述符表中數(shù)據(jù)段描述符)。 mov %dx,%es movl $0x17,%edx # fs points to local data space mov %dx,%fs # fs 指向局部數(shù)據(jù)段(局部描述符表中數(shù)據(jù)段描述符)。 # 下面這句操作數(shù)的含義是:調(diào)用地址 = _sys_call_table + %eax * 4。參見列表后的說明。 # 對應(yīng)的C 程序中的sys_call_table 在include/linux/sys.h 中,其中定義了一個包括72 個 # 系統(tǒng)調(diào)用C 處理函數(shù)的地址數(shù)組表。 call _sys_call_table(,%eax,4) pushl %eax # 把系統(tǒng)調(diào)用號入棧。 movl _current,%eax # 取當(dāng)前任務(wù)(進(jìn)程)數(shù)據(jù)結(jié)構(gòu)地址??eax。 # 下面97-100 行查看當(dāng)前任務(wù)的運(yùn)行狀態(tài)。如果不在就緒狀態(tài)(state 不等于0)就去執(zhí)行調(diào)度程序。 # 如果該任務(wù)在就緒狀態(tài)但counter[??]值等于0,則也去執(zhí)行調(diào)度程序。 cmpl $0,state(%eax) # state jne reschedule cmpl $0,counter(%eax) # counter je reschedule # 以下這段代碼執(zhí)行從系統(tǒng)調(diào)用C 函數(shù)返回后,對信號量進(jìn)行識別處理。 ret_from_sys_call: # 首先判別當(dāng)前任務(wù)是否是初始任務(wù)task0,如果是則不必對其進(jìn)行信號量方面的處理,直接返回。 # 103 行上的_task 對應(yīng)C 程序中的task[]數(shù)組,直接引用task 相當(dāng)于引用task[0]。 movl _current,%eax # task[0] cannot have signals cmpl _task,%eax je 3f # 向前(forward)跳轉(zhuǎn)到標(biāo)號3。 # 通過對原調(diào)用程序代碼選擇符的檢查來判斷調(diào)用程序是否是超級用戶。如果是超級用戶就直接 # 退出中斷,否則需進(jìn)行信號量的處理。這里比較選擇符是否為普通用戶代碼段的選擇符0x000f # (RPL=3,局部表,第1 個段(代碼段)),如果不是則跳轉(zhuǎn)退出中斷程序。 cmpw $0x0f,CS(%esp) # was old code segment supervisor ? jne 3f # 如果原堆棧段選擇符不為0x17(也即原堆棧不在用戶數(shù)據(jù)段中),則也退出。 cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ? jne 3f # 下面這段代碼(109-120)的用途是首先取當(dāng)前任務(wù)結(jié)構(gòu)中的信號位圖(32 位,每位代表1 種信號), # 然后用任務(wù)結(jié)構(gòu)中的信號阻塞(屏蔽)碼,阻塞不允許的信號位,取得數(shù)值最小的信號值,再把 # 原信號位圖中該信號對應(yīng)的位復(fù)位(置0),最后將該信號值作為參數(shù)之一調(diào)用do_signal()。 # do_signal()在(kernel/signal.c,82)中,其參數(shù)包括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 # 如果沒有信號則向前跳轉(zhuǎn)退出。 btrl %ecx,%ebx # 復(fù)位該信號(ebx 含有原signal 位圖)。 movl %ebx,signal(%eax) # 重新保存signal 位圖信息??current->signal。 incl %ecx # 將信號調(diào)整為從1 開始的數(shù)(1-32)。 pushl %ecx # 信號值入棧作為調(diào)用do_signal 的參數(shù)之一。 call _do_signal # 調(diào)用C 函數(shù)信號處理程序(kernel/signal.c,82) popl %eax # 彈出信號值。 3: popl %eax popl %ebx popl %ecx popl %edx pop %fs pop %es pop %ds iret

./include/unistd.h文件中系統(tǒng)調(diào)用符號和調(diào)用號的對應(yīng)定義

// 以下是內(nèi)核實(shí)現(xiàn)的系統(tǒng)調(diào)用符號常數(shù),用于作為系統(tǒng)調(diào)用函數(shù)表中的索引值。( include/linux/sys.h ) #define __NR_setup 0 /* used only by init, to get system going */ /* __NR_setup 僅用于初始化,以啟動系統(tǒng) */ #define __NR_exit 1 #define __NR_fork 2 #define __NR_read 3 #define __NR_write 4 #define __NR_open 5 #define __NR_close 6 #define __NR_waitpid 7 #define __NR_creat 8 #define __NR_link 9 #define __NR_unlink 10 #define __NR_execve 11 #define __NR_chdir 12 #define __NR_time 13 #define __NR_mknod 14 #define __NR_chmod 15 #define __NR_chown 16 #define __NR_break 17 #define __NR_stat 18 #define __NR_lseek 19 #define __NR_getpid 20 #define __NR_mount 21 #define __NR_umount 22 #define __NR_setuid 23 #define __NR_getuid 24 #define __NR_stime 25 #define __NR_ptrace 26 #define __NR_alarm 27 #define __NR_fstat 28 #define __NR_pause 29 #define __NR_utime 30 #define __NR_stty 31 #define __NR_gtty 32 #define __NR_access 33 #define __NR_nice 34 #define __NR_ftime 35 #define __NR_sync 36 #define __NR_kill 37 #define __NR_rename 38 #define __NR_mkdir 39 #define __NR_rmdir 40 #define __NR_dup 41 #define __NR_pipe 42 #define __NR_times 43 #define __NR_prof 44 #define __NR_brk 45 #define __NR_setgid 46 #define __NR_getgid 47 #define __NR_signal 48 #define __NR_geteuid 49 #define __NR_getegid 50 #define __NR_acct 51 #define __NR_phys 52 #define __NR_lock 53 #define __NR_ioctl 54 #define __NR_fcntl 55 #define __NR_mpx 56 #define __NR_setpgid 57 #define __NR_ulimit 58 #define __NR_uname 59 #define __NR_umask 60 #define __NR_chroot 61 #define __NR_ustat 62 #define __NR_dup2 63 #define __NR_getppid 64 #define __NR_getpgrp 65 #define __NR_setsid 66 #define __NR_sigaction 67 #define __NR_sgetmask 68 #define __NR_ssetmask 69 #define __NR_setreuid 70 #define __NR_setregid 71

這是一系列宏,它們的定義在unistd.h中,基本形式為#define _NR_name value,name為系統(tǒng)函數(shù)名字,value是一個整數(shù)值,是name所對應(yīng)的系統(tǒng)函數(shù)指針在sys_call_table中的偏移量。

?

系統(tǒng)調(diào)用宏也在本文件內(nèi)定義,采用內(nèi)聯(lián)匯編,如下:

// 以下定義系統(tǒng)調(diào)用嵌入式匯編宏函數(shù)。 // 不帶參數(shù)的系統(tǒng)調(diào)用宏函數(shù)。type name(void)。 // %0 - eax(__res),%1 - eax(__NR_##name)。其中name 是系統(tǒng)調(diào)用的名稱,與 __NR_ 組合形成上面 // 的系統(tǒng)調(diào)用符號常數(shù),從而用來對系統(tǒng)調(diào)用表中函數(shù)指針尋址。 // 返回:如果返回值大于等于0,則返回該值,否則置出錯號errno,并返回-1。 #define _syscall0(type,name) / type name(void) / { / long __res; / __asm__ volatile ( "int $0x80" / // 調(diào)用系統(tǒng)中斷0x80。 :"=a" (__res) / // 返回值??eax(__res)。 :"" (__NR_##name)); / // 輸入為系統(tǒng)中斷調(diào)用號__NR_name。if (__res >= 0) / // 如果返回值>=0,則直接返回該值。return (type) __res; errno = -__res; / // 否則置出錯號,并返回-1。return -1;} // 有1 個參數(shù)的系統(tǒng)調(diào)用宏函數(shù)。type name(atype a) // %0 - eax(__res),%1 - eax(__NR_name),%2 - ebx(a)。 #define _syscall1(type,name,atype,a) / type name(atype a) / { / long __res; / __asm__ volatile ( "int $0x80" / : "=a" (__res) / : "" (__NR_##name), "b" ((long)(a))); / if (__res >= 0) / return (type) __res; / errno = -__res; / return -1; / } // 有2 個參數(shù)的系統(tǒng)調(diào)用宏函數(shù)。type name(atype a, btype b) // %0 - eax(__res),%1 - eax(__NR_name),%2 - ebx(a),%3 - ecx(b)。 #define _syscall2(type,name,atype,a,btype,b) / type name(atype a,btype b) / { / long __res; / __asm__ volatile ( "int $0x80" / : "=a" (__res) / : "" (__NR_##name), "b" ((long)(a)), "c" ((long)(b))); / if (__res >= 0) / return (type) __res; / errno = -__res; / return -1; / } // 有3 個參數(shù)的系統(tǒng)調(diào)用宏函數(shù)。type name(atype a, btype b, ctype c) // %0 - eax(__res),%1 - eax(__NR_name),%2 - ebx(a),%3 - ecx(b),%4 - edx(c)。 #define _syscall3(type,name,atype,a,btype,b,ctype,c) / type name(atype a,btype b,ctype c) / { / long __res; / __asm__ volatile ( "int $0x80" / : "=a" (__res) / : "" (__NR_##name), "b" ((long)(a)), "c" ((long)(b)), "d" ((long)(c))); / if (__res>=0) / return (type) __res; / errno=-__res; / return -1; / }

與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖

總結(jié)

以上是生活随笔為你收集整理的Linux0.11内核--系统中断处理程序int 0x80实现原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。