免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Linux x86_64與i386區(qū)別

1 引子

 

毫無疑問,不管是32位,還是64位處理器,所有進程(執(zhí)行的程序)都必須占用一定數(shù)量的內(nèi)存,它或是用來存放從磁盤載入的程序代碼,或是

存放取自用戶輸入的數(shù)據(jù)等等。不過進程對這些內(nèi)存的管理方式因內(nèi)存用途不一而不盡相同,有些內(nèi)存是事先靜態(tài)分配和統(tǒng)一回收的,而有些卻是按需要動態(tài)分配和回收的。

 

對任何一個普通進程來講,它都會涉及到5種不同的數(shù)據(jù)段。稍有編程知識的朋友都該能想到這幾個數(shù)據(jù)段種包含有“程序代碼段”、“程序數(shù)據(jù)段”、“程序堆棧段”等。不錯,這幾種數(shù)據(jù)段都在其中,但除了以上幾種數(shù)據(jù)段之外,進程還另外包含兩種數(shù)據(jù)段。下面我們來簡單歸納一下進程對應(yīng)的內(nèi)存空間中所包含的5種不同的數(shù)據(jù)區(qū)。

 

代碼段:代碼段是用來存放可執(zhí)行文件的操作指令,也就是說是它是可執(zhí)行程序在內(nèi)存種的鏡像。代碼段需要防止在運行時被非法修改,所以只準許讀取操作,而不允許寫入(修改)操作——它是不可寫的。

 

數(shù)據(jù)段:數(shù)據(jù)段用來存放可執(zhí)行文件中已初始化全局變量,換句話說就是存放程序靜態(tài)分配的變量和全局變量。

 

BSS段:BSS段包含了程序中未初始化全局變量,在內(nèi)存中 bss段全部置零。

 

堆(heap):堆是用于存放進程運行中被動態(tài)分配的內(nèi)存段,它大小并不固定,可動態(tài)擴張或縮減。當進程調(diào)用malloc等函數(shù)分配內(nèi)存時,新分配的內(nèi)存就被動態(tài)添加到堆上(堆被擴張);當利用free等函數(shù)釋放內(nèi)存時,被釋放的內(nèi)存從堆中被剔除(堆被縮減)。

 

棧:棧是用戶存放程序臨時創(chuàng)建的局部變量,也就是說我們函數(shù)括弧“{}”中定義的變量(但不包括static聲明的變量,static意味這在數(shù)據(jù)段中存放變量)。除此以外在函數(shù)被調(diào)用時,其參數(shù)也會被壓入發(fā)起調(diào)用的進程棧中,并且待到調(diào)用結(jié)束后,函數(shù)的返回值也回被存放回棧中。由于棧的先進先出特點,所以棧特別方便用來保存/恢復(fù)調(diào)用現(xiàn)場。從這個意義上將我們可以把堆棧看成一個臨時數(shù)據(jù)寄存、交換的內(nèi)存區(qū)。

 

靜態(tài)分配內(nèi)存就是編譯器在編譯程序的時候根據(jù)源程序來分配內(nèi)存. 動態(tài)分配內(nèi)存就是在程序編譯之后, 運行時調(diào)用運行時刻庫函數(shù)來分配內(nèi)存的. 靜態(tài)分配由于是在程序運行之前,所以速度快, 效率高, 但是局限性大. 動態(tài)分配在程序運行時執(zhí)行, 所以速度慢, 但靈活性高。

 

術(shù)語"BSS"已經(jīng)有些年頭了,它是block started by symbol的縮寫。因為未初始化的變量沒有對應(yīng)的值,所以并不需要存儲在可執(zhí)行對象中。但是因為C標準強制規(guī)定未初始化的全局變量要被賦予特殊的默認值(基本上是0值),所以內(nèi)核要從可執(zhí)行代碼裝入變量(未賦值的)到內(nèi)存中,然后將零頁映射到該片內(nèi)存上,于是這些未初始化變量就被賦予了0值。這樣做避免了在目標文件中進行顯式地初始化,減少空間浪費(來自《Linux內(nèi)核開發(fā)》)

 

我們在x86_64環(huán)境上運行以下經(jīng)典程序:

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

int bss_var;
int data_var0=1;

int main(int argc,char **argv)
{
        printf("below are addresses of types of process's mem/n");

        printf("Text location:/n");
        printf("/tAddress of main(Code Segment):%p/n",main);

        printf("____________________________/n");

        int stack_var0=2;

        printf("Stack Location:/n");
        printf("/tInitial end of stack:%p/n",&stack_var0);

        int stack_var1=3;

        printf("/tnew end of stack:%p/n",&stack_var1);

        printf("____________________________/n");

        printf("Data Location:/n");
        printf("/tAddress of data_var(Data Segment):%p/n",&data_var0);

        static int data_var1=4;

        printf("/tNew end of data_var(Data Segment):%p/n",&data_var1);

        printf("____________________________/n");

        printf("BSS Location:/n");
        printf("/tAddress of bss_var:%p/n",&bss_var);

        printf("____________________________/n");

        char *b = sbrk((ptrdiff_t)0);

        printf("Heap Location:/n");
        printf("/tInitial end of heap:%p/n",b);
        brk(b+4);
        b=sbrk((ptrdiff_t)0);

        printf("/tNew end of heap:%p/n",b);

        return 0;

}

 

運行結(jié)果:
[root@kollera updilogs]# ./memory
below are addresses of types of process's mem
Text location:
        Address of main(Code Segment):0x400568
____________________________
Stack Location:
        Initial end of stack:0x7fff0e0dc544
        new end of stack:0x7fff0e0dc540
____________________________
Data Location:
        Address of data_var(Data Segment):0x600bfc
        New end of data_var(Data Segment):0x600c00
____________________________
BSS Location:
        Address of bss_var:0x600c14
____________________________
Heap Location:
        Initial end of heap:0xb059000
        New end of heap:0xb059004

 

2 x86_64體系新變化

 

AMD x86_64的出現(xiàn),給全新的64位的x86帶來了很多結(jié)構(gòu)上的變化:   

 

1)64位整型數(shù)   

 

在x86-64中,所有通用寄存器(GPRs)都從32位擴充到了64位,名字也發(fā)生了變化。8個通用寄存器(eax, ebx, ecx, edx,

ebp, esp, esi, edi)在新的結(jié)構(gòu)中被命名為rax, rbx, rcx, rdx, rbp, rsp, rsi, rdi,它們都是64位的。呵呵,想當年,從16位擴充到32位時,同樣也有一次名字的變化。所有算術(shù)邏輯操作、寄存器到內(nèi)存的數(shù)據(jù)傳輸現(xiàn)在都能以64位的整形類型進行操作。堆棧的壓棧和彈出操作都以8字節(jié)的單位進行,而且指針類型也擁有了64位。

 

2)新增寄存器   

 

在新的架構(gòu)中,另外新增了8個通用寄存器:64位的r8, r9, r10, r11, r12, r13, r14, r15。這樣就有利與編譯器將函數(shù)參數(shù)、返回值等放在這些新增的GPR里面進行傳遞,從而提高了程序的運行速度。同時,128位的MMX寄存器也從原來的8個增加到了16個。

 

3)增大的邏輯地址空間   

 

目前在新的架構(gòu)中,應(yīng)用程序可以擁有的邏輯地址空間從4GB增加到了256TB(2^48),而且這一邏輯地址空間在未來可能增加到16EB

(2^64,1EB=1024PB,1PB=1024TB,1TB=1024GB)。

 

4)增大的物理地址空間   

 

目前的x86-64架構(gòu),可以支持的物理內(nèi)存擴展到了1TB(2^40),當然,在未來該數(shù)字可以擴展到4PB(2^52)。相比于經(jīng)過PAE技術(shù)擴展的i386的64GB物理內(nèi)存,新的架構(gòu)帶來了不小的飛躍。

 

5)無縫使用SSE指令   

 

新的架構(gòu)借鑒和吸收了Intel的SSE、SSE2的核心指令,并在2005年加入了SSE3。在這一新的架構(gòu)下,可以不再需要x87浮點協(xié)處理器來完成浮點運算了。

 

6)NX位   

 

跟PAE技術(shù)一樣,新的x86-64架構(gòu)也在頁表項中增加了NX位,來幫助CPU判斷該頁包含的內(nèi)容是否是可以執(zhí)行的,從而避免借助“buffer overrun”導致的病毒攻擊。

 

7)去除舊的機制   

 

在新架構(gòu)的“長模式(long mode)”下,很多在IA32中被提出,但確不經(jīng)常被操作系統(tǒng)用到的一些機制不再被支持。這些機制包括段式地址變化機制(FS和GS仍然被保留),任務(wù)轉(zhuǎn)移門(TSS)機制,以及虛擬86模式。當然,出于向下兼容的考慮,x86-64在“傳統(tǒng)模式”(Legacy mode)下,仍然對這些機制進行了保留。

 

3 x86_64段式管理

 

x86的兩種工作模式:實地址模式和虛地址模式(保護模式)。Linux主要工作在保護模式下。

 

在保護模式下,64位x86體系架構(gòu)的虛地址空間可達2^48Byte,即256TB,這可比只能到達區(qū)區(qū)4GB的32位x86體系大多了。邏輯地址到線性地址的轉(zhuǎn)換由x86分段機制管理。段寄存器CS、DS、ES、SS、FS或GS各標識一個段。這些段寄存器作為段選擇器,用來選擇該段的描述符。

 

Linux中關(guān)于段描述符的宏定義集中在文件/arch/x86/include/asm/Segment.h中,我們先貼出部分代碼:

 

32位的:

 

#define GDT_ENTRY_KERNEL_BASE 12                             /* 0x0000000c c=>1100*/
#define GDT_ENTRY_KERNEL_CS (GDT_ENTRY_KERNEL_BASE + 0)      /* 0x0000000c c=>1100*/
#define GDT_ENTRY_KERNEL_DS (GDT_ENTRY_KERNEL_BASE + 1)      /* 0x0000000d c=>1101*/

 

64位的:

 

#define GDT_ENTRY_KERNEL32_CS 1         /* 0x00000001 */
#define GDT_ENTRY_KERNEL_CS 2           /* 0x00000002 */
#define GDT_ENTRY_KERNEL_DS 3           /* 0x00000003 */

#define __KERNEL32_CS   (GDT_ENTRY_KERNEL32_CS * 8)          /* 0x00000100 */

#define GDT_ENTRY_DEFAULT_USER32_CS 4   /* 0x00000004 */
#define GDT_ENTRY_DEFAULT_USER_DS 5     /* 0x00000005 */
#define GDT_ENTRY_DEFAULT_USER_CS 6     /* 0x00000006 */

#define __USER32_CS   (GDT_ENTRY_DEFAULT_USER32_CS * 8 + 3)  /* 0x00000403 */
#define __USER32_DS __USER_DS

 

不管32位還是64位的:(我們只關(guān)心64位)

 

#define __KERNEL_CS (GDT_ENTRY_KERNEL_CS * 8)            /* 0x00000200 */
#define __KERNEL_DS (GDT_ENTRY_KERNEL_DS * 8)            /* 0x00000300 */
#define __USER_DS     (GDT_ENTRY_DEFAULT_USER_DS* 8 + 3)     /* 0x00000503 */
#define __USER_CS     (GDT_ENTRY_DEFAULT_USER_CS* 8 + 3)     /* 0x00000603 */

 

看見沒有,我們熟悉的__USER_CS,__USER_DS,__KERNEL_CS,和__KERNEL_DS,就是傳說中的段選擇子。

 

我們看到,內(nèi)核代碼段的描述子存放在以0x200為基地址的內(nèi)存單元中,占8個字節(jié)。同樣,內(nèi)核數(shù)據(jù)段、用戶代碼段、用戶數(shù)據(jù)段分別存放在

以0x300、0x500、0x600為基地址的內(nèi)存單元中。我們注意到,__USER_DS和__USER_CS的最低三位為3,也就是011,這正說明

其CPL位為11,代表用戶模式,TI為0,代表GDT。

 

對于x86_64來說,虛擬地址由16位選擇子和64位偏移量組成,段寄存器僅僅存放選擇子。CPU的分段單元(SU)執(zhí)行以下操作:
[1] 先檢查選擇子的TI字段,以決定描述子對應(yīng)的描述子保存在哪一個描述符表中。TI字段指明描述子是在GDT中(在這種情況下,分段單元從gdtr寄存器中得到GDT的線性基地址)還是在激活的LDT中(在這種情況下,分段單元從ldtr寄存器中得到LDT的線性基地址)。
[2] 從選擇子的13位index字段計算描述子的地址,index字段的值乘以8(一個描述子的大小,其實就是屏蔽掉末尾那三位指示特權(quán)級的CPL和指示TI的字段),這個結(jié)果與gdtr或ldtr寄存器中的內(nèi)容相加。
[3] 將對應(yīng)的段描述子從內(nèi)存拷貝到CPU的影子Cache中,這樣,只有在選擇子改變的情況下才會修改影子Cache中的內(nèi)容。
[4] 把虛擬地址的偏移量與隱Cache中描述子Base字段的值相加就得到了線性地址。

 

例如,為了對內(nèi)核代碼段尋址,內(nèi)核只需要把__KERNEL_CS宏產(chǎn)生的選擇子的值裝進cs段寄存器即可。注意,與段相關(guān)的線性地址還是從

0開始,達到264 -1的尋址限長。這就意味著在用戶態(tài)或內(nèi)核態(tài)下的所有進程任然使用相同的虛擬地址,這就是傳說中的“基本平坦模式”。
按照這個模式,虛擬地址跟線性地址數(shù)字一樣,唯一的不同就是CS和DS裝的內(nèi)容不同,可能是KERNEL級別的選擇子,也可能是USER級別
的選擇子。

 

4 x86_64分頁管理

 

雖然邏輯地址擴展到了64位,但是,現(xiàn)有的設(shè)計并沒有完全用到這64位的空間(2^64=16EB),因為使用到如此大的空間,勢必造成很大的

系統(tǒng)開銷。AMD64在設(shè)計的時候就決定在x86_64的第一階段,只用這64位中的低48位來做頁式地址轉(zhuǎn)換,高16位(48-64位)將填充第47位相同的內(nèi)容(這種方式類似于符號擴展)。如果邏輯地址不符合此規(guī)定,系統(tǒng)將產(chǎn)生異常。符合此規(guī)定的地址稱為canonical form,地址的范圍分為兩段:0 到 00007FFF-FFFFFFFF,以及FFFF8 000-0000 0000到FFFFFFFF-FFFFFFFF,總共為256TB。這種虛擬地址的分層結(jié)構(gòu),也為操作系統(tǒng)的設(shè)計帶來了一定便利:可以取地址的上半段保留做為操作系統(tǒng)的邏輯地址空間,而低地址部分做為裝載應(yīng)用程序的空間,而canonical form不允許的地址空間則做為操作系統(tǒng)的標志、以及特權(quán)級的標識等。當然,這樣的設(shè)計在未來地址進一步擴展的時候?qū)⒊蔀橐粋€新的問題。

 

采用64位地址空間的x86-86被稱為是運行在“長模式”(long mode)下,該模式可以看成是對PAE模式的一個擴充。長模式允許使用三個不同的物理頁面大?。?KB、2MB和1GB。在使用64位中的48位用來存放地址時,與PAE模式下的三級頁面映射機制不同的是,長模式下線性地址到物理地址的映射需要經(jīng)過四級地址映射。在這四級地址映射機制中,原來PAE模式下僅擁有4個表項的頁目錄指針表被擴展到512個表項。同時,在最末一級加入一級新的頁面映射結(jié)構(gòu),該結(jié)構(gòu)被稱為第四級頁表(Page-Map Level 4 Table,PML4),它跟PAE模式下的頁目錄及頁表(在長模式中,成為了頁目錄)一樣,擁有512個表項。如果地址進一步擴充,如把64位尋址全部用上,該頁表就能夠擴充到33,554,432個表項,或者干脆再加一層地址映射(PML5),當然,按照目前只用了48位的情況下,用到512個表項的PML4就已經(jīng)夠用了。   

 

可以想象,用到48位的x86-64虛擬地址的分配機制為:   
- 0-11(12)位:頁內(nèi)偏移;   
- 12-20(9)位:由PML4來映射;   
- 21-29(9)位:高一級頁目錄來映射(如果PS=1,則該頁表項指向一個2MB的頁);   
- 30-38(9)位:再高一級的頁目錄來映射(如果PS=2,則該頁表項指向一個1GB的頁);   
- 39-47(9)位:頁目錄指針表來映射。   

 

x86-64的長模式下,對16位以及32位代碼進行了兼容,即使CPU上跑的是64位的操作系統(tǒng),歷史遺留的16位以及32位代碼將都能夠在該操作系統(tǒng)上運行。由于x86-64兼容IA32的指令,所以,這些代碼在這種情況下運行,基本上沒有性能損耗。   

 

在傳統(tǒng)模式(Legacy mode)下,x86-64的CPU的工作模式跟傳統(tǒng)的IA32沒有什么兩樣。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Linux內(nèi)存管理圖解
linux 內(nèi)存分頁機制
保護模式簡介
Linux系統(tǒng)中段機制的實現(xiàn)
保護模式Protected Mode 簡寫為 pmode
LINUX程序的虛擬內(nèi)存映射機制
更多類似文章 >>
生活服務(wù)
分享 收藏 導長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服