| 內核技術(shù) | Linux | 1685 次查看 |
|---|---|---|
| - 一、內存數據表示: 我們在教材或閱讀中,經(jīng)常需要直觀(guān)的用圖示來(lái)展示數據在內存中的分布,那么數據是如何在內存中組織的呢?不同的機器有不同的表示法,我們以最常見(jiàn)的Intel X86系列計算機為例來(lái)說(shuō)明這個(gè)問(wèn)題。 ![]() 如上圖示內存示意圖:內存低址在上。內存高址在下,內存單位為16bit。對于基于intel i386架構的計算機,系統采用小端字節序來(lái)存放數據,所謂小端字節序是指低序字節低地址,高序字節高地址(內存地址增大方向),大端字節序反之,給定系統所用的字節序稱(chēng)為主機字節序;CPU也以小端字節序形式讀取數據,如上圖所示,如果變量num是16位的short短整類(lèi)型,則CPU從內存中讀出的num=0x1234;如果num是32位的int類(lèi)型,則CPU從內存中讀出的是num=0x56781234,其中num地址是0x12345678,即&num=0x12345678 二、linux內核獲取進(jìn)程任務(wù)結構的指針 明白了系統內存數據表示,我們現在來(lái)看看linux內核是如何獲取當前進(jìn)程的任務(wù)結構指針的,以下代碼均參照linux內核2.4.0的源碼。 在include\asm-i386\ current.h中 #ifndef _I386_CURRENT_H #define _I386_CURRENT_H struct task_struct; static inline struct task_struct * get_current(void) { struct task_struct *current; __asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL)); return current; } #define current get_current() #endif /* !(_I386_CURRENT_H) */ 每個(gè)進(jìn)程都有一個(gè)task_struct任務(wù)結構,和一片用于系統空間堆棧的存儲空間,他們在物理內存空間中也是聯(lián)系在一起的,當給進(jìn)程申請task_struct任務(wù)結構空間時(shí),系統將連同系統的堆??臻g一起分配,如下圖為某個(gè)進(jìn)程切換時(shí)刻的內存圖: ![]() 下面針對代碼實(shí)現來(lái)分析一下系統如何通過(guò)一系列操作獲取進(jìn)程在內核中的任務(wù)結構指針的: 由于linux內核分配進(jìn)程任務(wù)結構空間時(shí),是以8KB(2個(gè)頁(yè)面空間,即2^1*4KB,linux對物理內存空間和虛擬內存空間管理時(shí),均規定其頁(yè)面單位的尺寸為4KB)為單位來(lái)分配的,所以?xún)却鎽玫刂肥?span>8KB(2^13)的整數倍,即指針地址的低13位全為0,所以根據小端字節序,分配內存返回地址應該是指向struct task_struct結構,如圖中的0xc2342000地址所指,至于為何采用代碼中的做法而不是直接將此指針保存在全局變量中以供應用,內核是從其自身的效率方面來(lái)考慮的,我們在此只針對代碼解釋?zhuān)?br> 根據上圖,此刻內存esp內容必定在0xc2342000和0xc2344000之間的一個(gè)數值,我們假設取0xc2343ffe(即堆棧壓棧EIP、返回地址、內部數據等相關(guān)數據了,地址值要減??;只要符合0xc2342xxx 、0xc2343xxx的地址指針都是正確的),來(lái)通過(guò)代碼運算看是否current的指針是0xc2342000。 __asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL)); 語(yǔ)句的意思是將ESP的內容與8191UL的反碼按位進(jìn)行與操作,之后再把結果賦值給current,其中8191UL=8192-1=2^13-1,計算過(guò)程如下: 8192UL=2^13 0000 0000 0000 0000 0010 0000 0000 0000 8191UL 0000 0000 0000 0000 0001 1111 1111 1111 ~8191UL(反碼) 1111 1111 1111 1111 1110 0000 0000 0000 0xc2343ffe 1100 0010 0011 0100 0011 1111 1111 1110 andl結果: 1100 0010 0011 0100 0010 0000 0000 0000 || (對照著(zhù)看) 0x c 2 3 4 2 0 0 0 所以按位與操作之后的結果位0xc2342000,正好是struct task_struct結構的地址指針.通過(guò)觀(guān)察可知,只要符合0xc2342xxx 、0xc2343xxx的地址指針經(jīng)過(guò)相同的計算,都可以得到內核進(jìn)程任務(wù)結構的指針。 另外,在進(jìn)入中斷或系統調用時(shí)所引用的宏操作(include\asm-i386\ hw_irq.h): #define GET_CURRENT \ "movl %esp, %ebx\n\t" \ "andl $-8192, %ebx\n\t" 其原理與上述描述也是一致的。 | ||
聯(lián)系客服