分析system_call中斷處理過程

上周的試驗(yàn)中,我選擇的系統(tǒng)調(diào)用號(hào)是34號(hào), 處理函數(shù)為sys_dup.
匯編方式的調(diào)用如下:

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    int new_fildes=0;
    char *szTemp="test_dup\n";

    asm volatile(
        "mov $1,%%ebx\n\t"  //傳遞參數(shù)
        "mov $41,%%eax\n\t"  //設(shè)置系統(tǒng)調(diào)用號(hào)
        "int $0x80\n\t" //進(jìn)行軟中斷觸發(fā)
        "mov %%eax,%0\n\t" //保存返回值
        :"=m"(new_fildes)
        );
    printf("new fildes: %d\n",new_fildes);
    write(new_fildes,szTemp,strlen(szTemp));

    return 0;
}

修改 MenuOS中的 test.c, 加入自己的命令. 大致如下:

int Time(int argc, char *argv[])
{
    time_t tt;
    struct tm *t;
    tt = time(NULL);
    t = localtime(&tt);
    printf("time:%d:%d:%d:%d:%d:%d\n",t->tm_year+1900, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
    return 0;
}

int TimeAsm(int argc, char *argv[])
{
    time_t tt;
    struct tm *t;
    asm volatile(
        "mov $0,%%ebx\n\t"
        "mov $0xd,%%eax\n\t" 
        "int $0x80\n\t" 
        "mov %%eax,%0\n\t"  
        : "=m" (tt) 
    );
    t = localtime(&tt);
    printf("time:%d:%d:%d:%d:%d:%d\n",t->tm_year+1900, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
    return 0;
}
int Dup(int argc, char *argv[]){
    int new_fildes=dup(1);
    char *szTemp="test_dup\n";
    printf("new fildes: %d\n",new_fildes);
    write(new_fildes,szTemp,strlen(szTemp));
    return 0;

}
int DupAsm(int argc, char *argv[]){
        int new_fildes=0;
    char *szTemp="test_dup\n";

    asm volatile(
        "mov $1,%%ebx\n\t"
        "mov $41,%%eax\n\t"
        "int $0x80\n\t"
        "mov %%eax,%0\n\t"
        :"=m"(new_fildes)
        );
    printf("new fildes: %d\n",new_fildes);
    write(new_fildes,szTemp,strlen(szTemp));

    return 0;

}


int main()
{
    PrintMenuOS();
    SetPrompt("MenuOS>>");
    MenuConfig("version","MenuOS V1.0(Based on Linux 3.18.6)",NULL);
    MenuConfig("quit","Quit from MenuOS",Quit);
    MenuConfig("time","Show System Time",Time);
    MenuConfig("time-asm","Show System Time(asm)",TimeAsm);


    MenuConfig("dup","dup the stdout fildes",Dup);
    MenuConfig("dup-asm","dup the stdout fildes",DupAsm);

    ExecuteMenu();
}

修改后的 Menu OS 運(yùn)行效果如下圖所示:

運(yùn)行效果

跟蹤 sys_dup的執(zhí)行過程

我們?cè)趩?dòng)內(nèi)核的時(shí)候,暫時(shí)‘凍住’CPU。

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S

啟動(dòng)另一個(gè)終端,輸入如下命令,建立調(diào)試關(guān)系.

gdb
file linux-3.18.6/vmlinux    加載調(diào)試用的符號(hào)表
target remote:1234
c
b sys_dup

如下圖,停止在sys_dup處.

停在 sys_dup

執(zhí)行完 sys_dup后進(jìn)入 schedule()進(jìn)行進(jìn)程調(diào)度:

進(jìn)程調(diào)度
/linux-3.18.6/arch/x86/kernel/entry_32.S

系統(tǒng)調(diào)用代碼入口如下:

489    # system call handler stub
490ENTRY(system_call)
491    RING0_INT_FRAME            # can't unwind into user space anyway
492    ASM_CLAC
493    pushl_cfi %eax            # save orig_eax
494    SAVE_ALL
495    GET_THREAD_INFO(%ebp)
496                    # system call tracing in operation / emulation
497    testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
498    jnz syscall_trace_entry
499    cmpl $(NR_syscalls), %eax
500    jae syscall_badsys
501syscall_call:
502    call *sys_call_table(,%eax,4)
503syscall_after_call:
504    movl %eax,PT_EAX(%esp)        # store the return value
505syscall_exit:

系統(tǒng)調(diào)用是0x80號(hào)軟中斷而引發(fā)的調(diào)用,0x80號(hào)中斷的處理程序是system_call,也就是上面所列的代碼。當(dāng)檢測(cè)到系統(tǒng)調(diào)用發(fā)生時(shí)(int 0x80中斷),第一步先保存現(xiàn)場(chǎng),通過一個(gè)宏指令SAVE_ALL實(shí)現(xiàn)的,這個(gè)指令是把寄存器的狀態(tài)通過壓棧的方式保存起來。

然后會(huì)調(diào)用sys_call_table,通過eax寄存器的值查找系統(tǒng)調(diào)用表,找到幾號(hào)系統(tǒng)調(diào)用,然后調(diào)用相應(yīng)的系統(tǒng)調(diào)用。

當(dāng)系統(tǒng)調(diào)用完成時(shí),內(nèi)核會(huì)檢測(cè)一些情況,比如進(jìn)程的切換或者信號(hào)發(fā)生什么的。如果發(fā)生了這些情況,內(nèi)核會(huì)轉(zhuǎn)向syscall_exit_work中執(zhí)行.
系統(tǒng)調(diào)用處理的流程圖如下:

system_call (1).png

總結(jié)

本次實(shí)驗(yàn)使用GDB跟蹤了系統(tǒng)調(diào)用執(zhí)行的整個(gè)過程,同時(shí)又從源代碼級(jí)別比較深入的了解到完成系統(tǒng)調(diào)用內(nèi)核所做的工作。系統(tǒng)調(diào)用可以為用戶空間提供訪問硬件資源的統(tǒng)一接口,以至于應(yīng)用程序不必去關(guān)注具體的硬件訪問操作。系統(tǒng)調(diào)用可以對(duì)系統(tǒng)進(jìn)行保護(hù),保證系統(tǒng)的穩(wěn)定和安全。系統(tǒng)調(diào)用的存在規(guī)定了用戶進(jìn)程進(jìn)入內(nèi)核的具體方式,用戶是不能從任意位置進(jìn)入內(nèi)核空間的,這保證了系統(tǒng)的穩(wěn)定性。

Linux中是以0x80號(hào)軟中斷引發(fā)的系統(tǒng)調(diào)用的,即0x80號(hào)中斷的處理程序就是位于kernel/entry_32.S中system_call函數(shù)。這個(gè)函數(shù)使用匯編實(shí)現(xiàn)的,它首先是保存現(xiàn)場(chǎng),然后通過eax查找對(duì)應(yīng)哪一個(gè)系統(tǒng)調(diào)用,然后查找sys_call_table調(diào)用對(duì)應(yīng)的系統(tǒng)調(diào)用。等完成調(diào)用之后檢查是否有信號(hào)發(fā)生或者需要進(jìn)程調(diào)度,如果有就進(jìn)入相應(yīng)的處理程序,并進(jìn)行進(jìn)程調(diào)度,如果沒有就恢復(fù)現(xiàn)場(chǎng)完成了整個(gè)系統(tǒng)調(diào)用,

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 網(wǎng)易云課堂《Linux內(nèi)核分析》作業(yè) 實(shí)驗(yàn)?zāi)康模?使用gdb跟蹤分析一個(gè)系統(tǒng)調(diào)用中斷處理過程,分析系統(tǒng)調(diào)用從sys...
    aapu閱讀 1,075評(píng)論 0 3
  • 初始化的時(shí)候會(huì)將0x80和system_call綁定起來system_call偽代碼 進(jìn)程調(diào)度的時(shí)機(jī)對(duì)于分析很關(guān)鍵...
    xiaoxii閱讀 1,268評(píng)論 0 1
  • 亦如昨天和明天一樣,今天依舊是普普通通,27歲的生日不張揚(yáng)不矯情,安安靜靜,平平安安。對(duì)于熱鬧,中心的感覺已經(jīng)不那...
    Eep_9153閱讀 748評(píng)論 0 0
  • 整齊、清潔、舒適的美容院,是我們的服務(wù)讓顧客滿意的第一步,有滿意的服務(wù)才會(huì)有良好的銷售,也才會(huì)有令人滿意的經(jīng)營(yíng)績(jī)效...
    周明達(dá)老師閱讀 2,674評(píng)論 0 4

友情鏈接更多精彩內(nèi)容