溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

linux怎么實現(xiàn)程序的執(zhí)行

發(fā)布時間:2021-12-17 09:25:06 來源:億速云 閱讀:112 作者:iii 欄目:大數(shù)據(jù)

本篇內(nèi)容主要講解“l(fā)inux怎么實現(xiàn)程序的執(zhí)行”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“l(fā)inux怎么實現(xiàn)程序的執(zhí)行”吧!

我們先看一下這時候的內(nèi)存布局。

linux怎么實現(xiàn)程序的執(zhí)行    

當cpu通過cs:eip執(zhí)行第一條指令的時候。首先通過cs的值,在ldt中找到代碼段的基地址,然后加上eip,得到線性地址,然后通過線性地址到頁目錄和頁表項里找是否已經(jīng)映射到物理地址了。這時候發(fā)現(xiàn),還沒有對應的物理地址,然后就觸發(fā)缺頁中斷。  
我們看一下缺頁中斷的處理。


// 缺頁處理,進程的內(nèi)容還沒有加載到內(nèi)存,訪問的時候?qū)е氯表摦惓?br/>void do_no_page(unsigned long error_code,unsigned long address)
{
    int nr[4];
    unsigned long tmp;
    unsigned long page;
    int block,i;
    // 取得線性地址對應頁的頁首地址,與0xfffff000即減去頁偏移 
    address &= 0xfffff000;
    // 算出離代碼段首地址的偏移
    tmp = address - current->start_code;
    // tmp大于等于end_data說明是訪問堆或者棧的空間時發(fā)生的缺頁,直接申請一頁
    if (!current->executable || tmp >= current->end_data) {
        get_empty_page(address);
        return;
    }
    // 是否有進程已經(jīng)使用了
    if (share_page(tmp))
        return;
    // 獲取一頁,4kb
    if (!(page = get_free_page()))
        oom();
/* remember that 1 block is used for header */
    /*
     算出要讀的硬盤塊號,但是最多讀四塊。
     tmp/BLOCK_SIZE算出線性地址對應頁的
     頁首地址離代碼塊距離了多少塊,然后讀取頁首
     地址對應的塊號,所以需要加一。比如距離2塊的距離,則
     需要讀取的塊是第三塊
    */
    block = 1 + tmp/BLOCK_SIZE;
    // 查找文件前4塊對應的硬盤號
    for (i=0 ; i<4 ; block++,i++)
        // bmap算出邏輯塊號對應的物理塊號
        nr[i] = bmap(current->executable,block);
    // 從硬盤讀四塊數(shù)據(jù)進來,并且復制到物理頁中
    bread_page(page,current->executable->i_dev,nr);
    /*
     tmp是小于end_data的,因為從tmp開始加載了4kb的數(shù)據(jù),
     所以tmp+4kb(4096)后大于end_data,所以大于的部分需要清0,
     i即超出的字節(jié)數(shù)
    */
    i = tmp + 4096 - current->end_data;
    // page是物理頁首地址,加上4kb,從后往前清0
    tmp = page + 4096;
    while (i-- > 0) {
        tmp--;
        *(char *)tmp = 0;
    }
    // 建立線性地址和物理地址的映射
    if (put_page(page,address))
        return;
    // 失敗則是否剛才申請的物理頁
    free_page(page);
    oom();
}
 

我們發(fā)現(xiàn)缺頁中斷有一句代碼是

// 算出離代碼段首地址的偏移
    tmp = address - current->start_code
 

start_code的值就是cs對應的基地址。即進程號*64MB。address就是剛才我們通過cs:eip算出來的值。兩個相減得到線性地址離代碼段基址的距離,即硬盤中,在代碼section中的偏移。然后算出這個偏移在硬盤中相對代碼section首地址塊偏移。因為代碼塊不是可執(zhí)行文件的第一塊。所以還需要做一個處理。

/* remember that 1 block is used for header */
    /*
     算出要讀的硬盤塊號,但是最多讀四塊。
     tmp/BLOCK_SIZE算出線性地址對應頁的
     頁首地址離代碼塊距離了多少塊,然后讀取頁首
     地址對應的塊號,所以需要加一。比如距離2塊的距離,則
     需要讀取的塊是第三塊
    */
    block = 1 + tmp/BLOCK_SIZE;

就是加上可執(zhí)行文件頭占據(jù)的那一塊,這樣就得出了cs:eip在硬盤中絕對偏移,最后把這塊數(shù)據(jù)讀進來。并且建立線性地址到物理地址的映射。然后重新執(zhí)行cs:eip對應的指令,這時候就能找到對應的指令執(zhí)行了。同理,當我們通過ds訪問數(shù)據(jù)段的時候也是這樣,在指令里,訪問數(shù)據(jù)的時候,用的地址是相對數(shù)據(jù)段的偏移,通過地址的轉(zhuǎn)換,會落到數(shù)據(jù)段對應的線性地址里。然后通過缺頁中斷加載進來。堆和棧缺頁中斷時候直接分配一頁物理內(nèi)存就行。因為他的數(shù)據(jù)不在硬盤里。

到此,相信大家對“l(fā)inux怎么實現(xiàn)程序的執(zhí)行”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關內(nèi)容可以進入相關頻道進行查詢,關注我們,繼續(xù)學習!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI