從linux0 11看乙個程序的誕生

2021-09-26 23:22:17 字數 3117 閱讀 6516

系統有乙個gdt表。該錶儲存了系統和所有程序的tss和ldt描述符資訊。tss就是我們平時說的程序上下文。每個程序有乙個ldt陣列,裡面儲存了**段和資料段的描述符資訊。

首先,從乙個程序的誕生說起。我們知道,通過fork可以建立乙個程序。下面我們來看一下fork的過程都做了什麼事情。先通過find_empty_process獲取乙個可用的程序id和pcb。pid是程序id。pcb是管理程序的結構體。

int

find_empty_process

(void

)

接著呼叫copy_process複製父程序的資訊。

/*

* ok, this is the main fork-routine. it copies the system process

* information (task[nr]) and sets up the necessary registers. it

* also copies the data segment in it's entirety.

*/int

copy_process

(int nr,

long ebp,

long edi,

long esi,

long gs,

long none,

long ebx,

long ecx,

long edx,

long fs,

long es,

long ds,

long eip,

long cs,

long eflags,

long esp,

long ss)

// 父子程序都有同樣的檔案描述符,file結構體加一

for(i=

0; i

(f=p->filp[i]

) f->f_count++

;// inode節點加一

if(current->pwd)

current->pwd->i_count++;if

(current->root)

current->root->i_count++;if

(current->executable)

current->executable->i_count++;/*

掛載tss和ldt位址到gdt,nr << 1即乘以2,這裡算出的是第nr個程序距離第乙個tss描述符位址的偏移,

單位是8個位元組,即選擇描述符大小,_ldt是偏移的大小,單位是1,這裡是8

*/set_tss_desc

(gdt+

(nr<<1)

+first_tss_entry,

&(p->tss));

set_ldt_desc

(gdt+

(nr<<1)

+first_ldt_entry,

&(p->ldt));

p->state = task_running;

/* do this last, just in case */

return last_pid;

}int

copy_mem

(int nr,

struct task_struct * p)

return0;

}

下面具體分析一下幾個地方。

1 _ldt的巨集展開如下:

/*

* entry into gdt where to find first tss. 0-nul, 1-cs, 2-ds, 3-syscall

* 4-tss0, 5-ldt0, 6-tss1 etc ...

*/#define first_tss_entry 4

#define first_ldt_entry (first_tss_entry+1)

// 第乙個tss選擇子的偏移是4<<3,4乘以8,等於32,即從gdt的偏移為32開始算,第乙個程序的n是0,tss是32

#define _tss(n) ((((unsigned long) n)<<4)+(first_tss_entry<<3))

// 第乙個ldt選擇子的偏移是5<<3,5乘以8,等於40,即從gdt的偏移為40開始算,第乙個程序的n是0,ldt是40

#define _ldt(n) ((((unsigned long) n)<<4)+(first_ldt_entry<<3))

_ldt是計算出程序ldt在gdt表的索引。

// 設定線性位址到ldt的描述符中

set_base

(p->ldt[1]

,new_code_base)

;set_base

(p->ldt[2]

,new_data_base)

/*

掛載tss和ldt位址到gdt,nr << 1即乘以2,這裡算出的是第nr個程序距離第乙個tss描述符位址的偏移,

單位是8個位元組,即選擇描述符大小,_ldt是偏移的大小,單位是1,這裡是8

*/set_tss_desc

(gdt+

(nr<<1)

+first_tss_entry,

&(p->tss));

set_ldt_desc

(gdt+

(nr<<1)

+first_ldt_entry,

&(p->ldt)

);

設定完後的結構

程序建立的本質就是申請乙個新的pcb,裡面儲存了該程序的相關資訊,假設現在輪到該程序執行。系統會根據tss選擇子到gdt表中找到tss結構體的位址。然後使用tss結構體的內容恢復執行上下文。然後找到tss中的ldt選擇子,把ldt選擇子載入到ldtr暫存器,然後根據ldt選擇子到gdt表中可以找到對應的ldt描述符。根據cs:ip的值。cs暫存器裡存的是**段的選擇子。是0x17。即ldt的第二項,和資料段一樣。從ldt第二項中找出基位址和限長。基位址+ip得到線性位址的值。然後再根據頁目錄和頁表就能得到物理值。

從Linux 0 11核心看Linux訊號處理機制

摘要 訊號處理機制是unix作業系統的一大特點。本文以linux0.11訊號處理相關原始碼為例,針對幾個細節對訊號處理的整個流程進行描述,力求簡單明瞭,參考趙炯博士的 linux核心完全剖析 和潘曉雷的 linux0.11原始碼分析 所謂訊號,是一種軟中斷機制,是實現程序間非同步通訊的手段。訊號的傳...

如何向Linux0 11新增乙個系統呼叫?

我們假設這個呼叫是foo 返回值型別是void。linux0.11實現系統呼叫的基本過程如下 舉例說明 include linux sys.h extern intsys iam sys iam include unistd.h define nr iam 72 intiam const char ...

從另乙個角度看自己

從去年11月15號寫下豪言壯語 每天更新一篇,到現在一篇也沒有更新,確實是吹牛吹大了。當然,我並不是忘記了天天積累的重要性,而是,稍微換了乙個地方踐行了不一樣的東西。我從2016年開始,一直在嘗試著通過踐行來重新認知自己,漸漸我發現,很多道理是相通的,很多踐行也是相通的,沒有呈現出來,不代表什麼都沒...