• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-80  評(píng)論-24  文章-0  trackbacks-0
            該文件是系統(tǒng)調(diào)用實(shí)現(xiàn)的主要文件。為了弄清楚系統(tǒng)調(diào)用,首先應(yīng)該拿一個(gè)實(shí)例來(lái)看。
            WinixJ系統(tǒng)僅僅實(shí)現(xiàn)了一個(gè)系統(tǒng)調(diào)用getpid(),但是其他系統(tǒng)調(diào)用的框架應(yīng)是完全相同的,只在函數(shù)實(shí)現(xiàn)細(xì)節(jié)上有所不同,因此我們打算以getpid()作為案例講解。
            先看看getpid()呈現(xiàn)給用戶的調(diào)用接口吧:
            POSIX規(guī)范的getpid()聲明如下:
            pid_t getpid();等同于int getpid();為了簡(jiǎn)單起見(jiàn)我們就實(shí)現(xiàn)為int getpid();
            它的代碼也十分簡(jiǎn)單:

             1 int getpid()
             2 {
             3     int res;
             4     __asm__ __volatile__ (
             5             "movl $0x0, %%eax\n\t"
             6             "movl $0x0, %%ebx\n\t"
             7             "movl $0x0, %%ecx\n\t"
             8             "movl $0x0, %%edx\n\t"
             9             "int $0x30\n"
            10             :"=a" (res)
            11             :);
            12     return res;
            13 }
            14 

            雖然有嵌入?yún)R編,但是也不難理解,看似是將eax、ebx、ecx、edx四個(gè)寄存器均傳值為0,然后調(diào)用軟中斷int 0x30(實(shí)際上應(yīng)該稱之為陷阱,陷阱和中斷還是有細(xì)微區(qū)別的,見(jiàn)此博文),最后將返回的結(jié)果由eax賦值給res變量。很簡(jiǎn)單,不是嗎?
            但是為何eax、ebx、ecx、edx都賦值了呢?調(diào)用int 0x30之后又發(fā)生什么了呢?
            先說(shuō)調(diào)用int 0x30之后會(huì)發(fā)生的事情。我們看下面這段代碼,其實(shí)它在此博文已經(jīng)出現(xiàn)過(guò),就是sys_call函數(shù)的實(shí)現(xiàn):

             1 ; 系統(tǒng)調(diào)用框架,系統(tǒng)調(diào)用采用0x30號(hào)中斷向量,利用int 0x30指令產(chǎn)
             2 ; 生一個(gè)軟中斷,之后便進(jìn)入sys_call函數(shù),該函數(shù)先調(diào)用save_all框
             3 ; 架保存所有寄存器值,然后調(diào)用對(duì)應(yīng)系統(tǒng)調(diào)用號(hào)的入口函數(shù)完成系統(tǒng)調(diào)用
             4 ; 注意?。。。。∠到y(tǒng)調(diào)用默認(rèn)有三個(gè)參數(shù),分別利用ebx、ecx、edx來(lái)
             5 ; 傳遞,其中eax保存系統(tǒng)調(diào)用號(hào)
             6 sys_call:
             7     save_all
             8 
             9     sti
            10 
            11     push ebx
            12     push ecx
            13     push edx
            14     call [sys_call_table + eax * 4]
            15     add esp, 4 * 3
            16 
            17     recover_from_sys_call
            18 
            19     cli
            20 
            21     iretd
            22 

            再看看save_all:

             1 ; 一個(gè)宏,因?yàn)樗械膇rq中斷函數(shù)以及系統(tǒng)調(diào)用都是先保存現(xiàn)場(chǎng)并將數(shù)據(jù)段等堆棧段
             2 ; 切換到內(nèi)核態(tài),因此,該操作所有的irq中斷入口函數(shù)均相同
             3 ; 故寫成宏節(jié)省空間
             4 %macro save_all 0
             5     push eax
             6     push ecx
             7     push edx
             8     push ebx
             9     push ebp
            10     push esi
            11     push edi
            12     push ds
            13     push es
            14     push fs
            15     push gs
            16     mov si, ss
            17     mov ds, si
            18     mov es, si
            19     mov gs, si
            20     mov fs, si
            21 %endmacro
            22 

            有了這一段代碼再說(shuō)int 0x30后都發(fā)生了什么就比較簡(jiǎn)單了,首先和發(fā)生時(shí)鐘中斷等硬件中斷類似,發(fā)生陷阱的時(shí)候CPU同樣先從當(dāng)前進(jìn)程對(duì)應(yīng)的TSS段中找到SS0和ESP0,然后將當(dāng)前進(jìn)程的SS/ESP/EFLAGS/CS/EIP五個(gè)寄存器值壓入SS0:ESP0,然后再去執(zhí)行save_all的代碼,save_all同樣是將所有的常規(guī)寄存器壓入堆棧,這樣一個(gè)過(guò)程之后就完成了從用戶態(tài)到內(nèi)核態(tài)的切換,之后再看sys_call代碼,壓入三個(gè)寄存器作為形參,然后調(diào)用sys_call_table[eax * 4]函數(shù)。到這兒肯定就明白了,原來(lái)getpid()函數(shù)是通過(guò)四個(gè)通用寄存器來(lái)向內(nèi)核態(tài)的系統(tǒng)調(diào)用函數(shù)傳遞參數(shù)的,這樣做是為了快捷。
            還有一點(diǎn)就是install_sys_call_handler和install_sys_call兩個(gè)函數(shù)功能是不同的,說(shuō)白了,WinixJ就只有一個(gè)系統(tǒng)調(diào)用,sys_call,它是所有POSIX規(guī)定的系統(tǒng)調(diào)用的框架,所有系統(tǒng)調(diào)用的實(shí)現(xiàn)都在sys_call_table[]函數(shù)數(shù)組里。這樣,將getpid()作為第0號(hào)系統(tǒng)調(diào)用的意思就是將sys_call_table[0] = sys_call_getpid();然后getpid()函數(shù)在發(fā)生陷阱的時(shí)候會(huì)通過(guò)eax傳入系統(tǒng)調(diào)用號(hào)0,這樣在sys_call中就會(huì)調(diào)用sys_call_table[eax * 4],即sys_call_table[0],即sys_call_getpid();  而install_sys_call_handler函數(shù)的作用是將IDT中0x30這一中斷描述符項(xiàng)設(shè)置成DPL = 3的陷阱門,該陷阱門的入口為sys_call,這樣,當(dāng)用戶程序調(diào)用int 0x30的時(shí)候就會(huì)調(diào)用sys_call;而install_sys_call的作用是將getpid()函數(shù)與第0號(hào)系統(tǒng)調(diào)用對(duì)應(yīng)起來(lái),即完成這一工作:sys_call_table[0] = sys_call_getpid();這樣,當(dāng)通過(guò)eax = 0傳入sys_call中時(shí),sys_call知道需要調(diào)用sys_call_table[]中的第幾個(gè)函數(shù)指針。
            到此基本就明白了,還有最后一個(gè)細(xì)節(jié):為什么在系統(tǒng)調(diào)用完成后返回的時(shí)候不使用所有中斷返回時(shí)都使用的宏recover_all,而使用recover_from_sys_call?我們看看代碼:

             1 ; 一個(gè)宏,恢復(fù)現(xiàn)場(chǎng)
             2 %macro recover_all 0
             3     pop gs
             4     pop fs
             5     pop es
             6     pop ds
             7     pop edi
             8     pop esi
             9     pop ebp
            10     pop ebx
            11     pop edx
            12     pop ecx
            13     pop eax
            14 %endmacro
            15 
            16 ; 注意從系統(tǒng)調(diào)用返回時(shí)不需要從棧中彈出eax的值,因?yàn)閑ax保存著調(diào)用
            17 ; 對(duì)應(yīng)系統(tǒng)調(diào)用之后的返回值
            18 %macro recover_from_sys_call 0
            19     pop gs
            20     pop fs
            21     pop es
            22     pop ds
            23     pop edi
            24     pop esi
            25     pop ebp
            26     pop ebx
            27     pop edx
            28     pop ecx
            29     add esp, 4 * 1
            30 %endmacro

            仔細(xì)研究代碼應(yīng)該已經(jīng)明白了,其實(shí)getpid()是需要返回值的,恰好我們就使用eax作為返回值,這樣,在從堆棧中恢復(fù)現(xiàn)場(chǎng)的時(shí)候就不能將eax的值恢復(fù),因?yàn)閑ax還需要傳遞返回值。
            至此,所有的系統(tǒng)調(diào)用細(xì)節(jié)應(yīng)該明白了,這里只是講述的一種系統(tǒng)調(diào)用的實(shí)現(xiàn),而有些操作系統(tǒng)的系統(tǒng)調(diào)用采用完全不同的風(fēng)格實(shí)現(xiàn)的,它沒(méi)有sys_call_table[]這樣的函數(shù)數(shù)組,而是將每個(gè)系統(tǒng)調(diào)用都設(shè)置成一個(gè)陷阱門,在IDT中都占有一個(gè)描述符項(xiàng),至于優(yōu)劣,其實(shí)沒(méi)有大的差別。WinixJ使用的方法正是Linux的方法。在此向Linus和Linux致敬。
            posted on 2012-02-14 15:41 myjfm 閱讀(524) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 操作系統(tǒng)
            亚洲国产精品热久久| 99久久精品九九亚洲精品| 久久中文字幕精品| 国产成年无码久久久免费| 国产精品99久久久久久人| 国产精品美女久久久| 国产精品久久久久蜜芽| 久久免费视频网站| 久久精品午夜一区二区福利| 国产叼嘿久久精品久久| 久久99国内精品自在现线| 人妻少妇精品久久| 久久er热视频在这里精品| 久久精品卫校国产小美女| 国产精品美女久久久网AV| 精品久久久久久亚洲| 性欧美大战久久久久久久久| 色老头网站久久网| 四虎国产精品成人免费久久| 久久九色综合九色99伊人| 久久午夜无码鲁丝片午夜精品| 久久99精品免费一区二区| 一本一本久久a久久综合精品蜜桃 一本一道久久综合狠狠老 | 99久久99久久精品国产片果冻| 精品国产婷婷久久久| 色99久久久久高潮综合影院| 久久久精品人妻一区二区三区蜜桃| 久久精品中文无码资源站| 国产69精品久久久久9999| 一级女性全黄久久生活片免费| 一本一本久久a久久综合精品蜜桃| 久久电影网一区| 香蕉久久久久久狠狠色| 久久99久久99小草精品免视看| 精品久久久久久久久免费影院| 国产精品九九九久久九九| 伊人久久无码精品中文字幕| 好属妞这里只有精品久久| 丁香色欲久久久久久综合网| 精品免费久久久久国产一区| 亚洲国产精品无码久久一线|