日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

哈工大计算机系统大作业——hello P2P

發(fā)布時間:2023/12/20 windows 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 哈工大计算机系统大作业——hello P2P 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

計算機系統(tǒng)

大作業(yè)

題 ????目??程序人生-Hello’s P2P ?

專 ??????業(yè) ?????????計算學(xué)部????????

學(xué)   ??號 ???????

班 ??級?????? ? ?

學(xué) ??????生 ????????????? ??

指 導(dǎo) 教 師????????????劉宏偉??????

計算機科學(xué)與技術(shù)學(xué)院

2021年5月

摘 ?要

Hello World程序幾乎是每個程序員第一次接觸編程學(xué)習(xí)到的內(nèi)容。hello.c程序歷經(jīng)預(yù)處理、編譯、匯編、鏈接四個環(huán)節(jié),最終生成可執(zhí)行文件hello。而后,shell為hello創(chuàng)建子進(jìn)程,可執(zhí)行文件被加載到內(nèi)存中執(zhí)行。在hello執(zhí)行的過程中,硬件和操作系統(tǒng)分工協(xié)同,共同完成程序的執(zhí)行。

本文通過對hello程序執(zhí)行的各個環(huán)節(jié)的探究,展示了計算機系統(tǒng)的各個組成部分是如何分工合作,共同完成hello的P2P過程。

關(guān)鍵詞:計算機系統(tǒng);P2P;預(yù)處理;編譯;進(jìn)程????????????????????????????

目 ?錄

第1章 概述

1.1 Hello簡介

1.2 環(huán)境與工具

1.3 中間結(jié)果

1.4 本章小結(jié)

第2章 預(yù)處理

2.1 預(yù)處理的概念與作用

2.2在Ubuntu下預(yù)處理的命令

2.3 Hello的預(yù)處理結(jié)果解析

2.4 本章小結(jié)

第3章 編譯

3.1 編譯的概念與作用

3.2 在Ubuntu下編譯的命令

3.3 Hello的編譯結(jié)果解析

3.4 本章小結(jié)

第4章 匯編

4.1 匯編的概念與作用

4.2 在Ubuntu下匯編的命令

4.3 可重定位目標(biāo)elf格式

4.4 Hello.o的結(jié)果解析

4.5 本章小結(jié)

第5章 鏈接

5.1 鏈接的概念與作用

5.2 在Ubuntu下鏈接的命令

5.3 可執(zhí)行目標(biāo)文件hello的格式

5.4 hello的虛擬地址空間

5.5 鏈接的重定位過程分析

5.6 hello的執(zhí)行流程

5.7 Hello的動態(tài)鏈接分析

5.8 本章小結(jié)

第6章 hello進(jìn)程管理

6.1 進(jìn)程的概念與作用

6.2 簡述殼Shell-bash的作用與處理流程

6.3 Hello的fork進(jìn)程創(chuàng)建過程

6.4 Hello的execve過程

6.5 Hello的進(jìn)程執(zhí)行

6.6 hello的異常與信號處理

6.7本章小結(jié)

第7章 hello的存儲管理

7.1 hello的存儲器地址空間

7.2 Intel邏輯地址到線性地址的變換-段式管理

7.3 Hello的線性地址到物理地址的變換-頁式管理

7.4 TLB與四級頁表支持下的VA到PA的變換

7.5 三級Cache支持下的物理內(nèi)存訪問

7.6 hello進(jìn)程fork時的內(nèi)存映射

7.7 hello進(jìn)程execve時的內(nèi)存映射

7.8 缺頁故障與缺頁中斷處理

7.9動態(tài)存儲分配管理

7.10本章小結(jié)

第8章 hello的IO管理

8.1 Linux的IO設(shè)備管理方法

8.2 簡述Unix IO接口及其函數(shù)

8.3 printf的實現(xiàn)分析

8.4 getchar的實現(xiàn)分析

8.5本章小結(jié)

結(jié)論

附件

參考文獻(xiàn)


第1章 概述

1.1 Hello簡介

在Unix系統(tǒng)中,GCC驅(qū)動程序讀取源文件hello.c,經(jīng)過預(yù)處理,編譯,匯編和鏈接四個階段,最終生成一個可執(zhí)行目標(biāo)文件hello,并保存在磁盤上。

為了執(zhí)行hello,操作系統(tǒng)為hello分配了虛擬內(nèi)存,shell為hello創(chuàng)建了一個新的子進(jìn)程,并在這個進(jìn)程中調(diào)用execve函數(shù),加載器將hello從磁盤中加載到內(nèi)存,并將PC值設(shè)置為程序的入口。

然后,CPU從內(nèi)存中讀取指令并執(zhí)行,操作系統(tǒng)調(diào)度程序進(jìn)行上下文切換。四級頁表和三級cache分工協(xié)作,共同完成地址的翻譯和數(shù)據(jù)的讀取。

程序執(zhí)行完畢后,由父進(jìn)程shell將子進(jìn)程回收,hello的生命周期結(jié)束了。

1.2 環(huán)境與工具

1.2.1 硬件環(huán)境

X64 CPU;2GHz;2G RAM;256GHD Disk 以上

Windows10 64位以上;VirtualBox 11以上;Ubuntu 16.04 LTS 64位

1.2.2 軟件環(huán)境

Visual Studio 2010 64位以上;CodeBlocks 64位;vi/vim/gedit+gcc

1.2.3 開發(fā)工具

Ubuntu,gcc,edb

1.3 中間結(jié)果

中間文件

作用

hello.i

經(jīng)過預(yù)處理的源程序,用于編譯器的翻譯

hello.s

匯編程序,用于匯編

hello.o

可重定位目標(biāo)文件,用于鏈接

hello

可執(zhí)行目標(biāo)文件,可以加載到內(nèi)存中執(zhí)行

elf.txt

hello.o對應(yīng)的elf文本文件

dump1.txt

hello.o 的反匯編文本文件

elf2.txt

hello對應(yīng)的elf文本文件

dump2.txt

hello 的反匯編文本文件

1.4 本章小結(jié)

本章介紹了hello的P2P流程,給出了開發(fā)中用到的工具,同時介紹了中間文件的名稱和作用。


第2章 預(yù)處理

2.1?預(yù)處理的概念與作用

2.1.1 預(yù)處理的概念

在hello程序中,預(yù)處理器(cpp)根據(jù)以字符#開頭的命令,修改原始的C程序。比如 hello . c中第1行的?#include<stdio. h> 命令告訴預(yù)處理器讀取系統(tǒng)頭文件stdio . h 的內(nèi)容,并把它直接插入程序文本中。結(jié)果就得到了另一個 C 程序。預(yù)處理后的程序通常是以.i作為文件擴(kuò)展名。

2.2.2 預(yù)處理的作用

預(yù)處理器(cpp)將頭文件的內(nèi)容插入到程序文本中,方便編譯器進(jìn)行下一步的編譯。

2.2在Ubuntu下預(yù)處理的命令

Linux系統(tǒng)中對hello.c進(jìn)行預(yù)處理的命令是gcc -E hello.c -o hello.i,執(zhí)行過程如下圖所示:

????

圖2-1:linux下預(yù)處理命令執(zhí)行過程

2.3 Hello的預(yù)處理結(jié)果解析

???????????????

圖2-2:hello.i文件部分截圖

對比hello.c和hello.i的文件大小,可以看到,文件從1kb增長到了64kb。在hello.i中,源代碼被放到了文件的最后,文件前面插入了系統(tǒng)頭文件stdio.h unistd.h和stdlib.h的源代碼,說明頭文件的內(nèi)容被展開并插入到程序中。

2.4 本章小結(jié)

本章介紹了預(yù)處理的概念和作用,并對預(yù)處理生成的hello.i文件進(jìn)行初步分析。


第3章 編譯

3.1 編譯的概念與作用

3.1.1 編譯的概念

編譯是指編譯器將文本文件hello.i翻譯成文本文件hello.s,即將預(yù)處理后的文件轉(zhuǎn)換成匯編語言程序

3.3.2 編譯的作用

編譯將高級語言指令翻譯為統(tǒng)一的低級機器語言指令,便于機器處理。在生成匯編語言的過程中,同時對代碼進(jìn)行優(yōu)化,發(fā)現(xiàn)和報告錯誤。

3.2 在Ubuntu下編譯的命令

Linux下編譯的命令為gcc -s hello.i -o hello.s

???????

圖3-1:編譯過程展示

3.3 Hello的編譯結(jié)果解析

下面將分類討論編譯器如何處理各種數(shù)據(jù)類型和操作:

3.3.1 對數(shù)據(jù)的處理

編譯器將局部變量保存在寄存器或棧中,并用棧指針+偏移量的形式進(jìn)行所以進(jìn)行索引。hello.c程序有兩個局部變量,分別是參數(shù)個數(shù)argc和循環(huán)索引i,分別保存在相對棧指針%rsp偏移量為20和4的內(nèi)存空間中。

在程序中,指針就是一個地址值,同樣保存在?;蛘呒拇嫫髦?。

??????????????

????????????????

圖3-2 對數(shù)據(jù)的處理

同時,編譯器將常量表示為立即數(shù)的形式,無全局變量和靜態(tài)變量

3.3.2 對賦值運算的處理

一種常見的賦值操作是使用mov指令,如圖3-2所示

?????????????????

圖3-2 hello.s中的mov指令

3.3.3 對類型轉(zhuǎn)換的處理

源代碼中有顯式類型轉(zhuǎn)換atoi函數(shù)將字符串轉(zhuǎn)換為常量,通過調(diào)用函數(shù)實現(xiàn)

???????????????

圖3-3 atoi函數(shù)調(diào)用

3.3.4 對算術(shù)操作的處理

使用算術(shù)操作指令進(jìn)行算數(shù)操作

????????????????

圖3-4 add指令

3.3.5 對關(guān)系操作和控制轉(zhuǎn)移的處理

編譯器通常使用cmp指令和條件跳轉(zhuǎn)共同完成控制轉(zhuǎn)移,例如原程序中的for(i=0;i<8;i++)語句被轉(zhuǎn)換為下面的指令

??????????????

圖3-5 cmp指令+條件跳轉(zhuǎn)

3.3.6 對函數(shù)的處理

編譯器使用call指令調(diào)用函數(shù),call后接函數(shù)名稱。

函數(shù)調(diào)用參數(shù)傳遞規(guī)則:X86-64中,過程調(diào)用傳遞參數(shù)規(guī)則為第1~6個參數(shù)依次儲存在%rdi、%rsi、%rdx、%rcx、%r8、%r9寄存器中,剩下的參數(shù)通過棧傳遞。

?????????????

圖3-6 函數(shù)調(diào)用

3.4 本章小結(jié)

本章介紹了編譯的概念和作用,并分析了hello.s文件,可以看到,源文件中的不同代碼段被翻譯為了不同的匯編指令。


第4章 匯編

4.1 匯編的概念與作用

4.1.1 匯編的概念

驅(qū)動程序運行匯編器as,將匯編語言文件hello.s翻譯成可重定位目標(biāo)文件hello.o的過程

4.1.2 匯編的作用

將文本文件翻譯為機器可讀懂的二進(jìn)制文件,以便于執(zhí)行鏈接

4.2 在Ubuntu下匯編的命令

Linux下的匯編指令:as hello.s -o hello.o

????????????

圖4-1 匯編過程展示

4.3 可重定位目標(biāo)elf格式

下面分析hello.o的ELF格式,并用readelf等列出其各節(jié)的基本信息。

readelf指令:readelf -a hello.o > ./elf.txt

4.3.1 ELF頭

ELF頭以一個16字節(jié)的序列開始,這個序列描述了生成該文件的系統(tǒng)的字的大小和字節(jié)順序。ELF頭剩下的部分包含幫助鏈接器語法分析和解釋目標(biāo)文件的信息。其中包括ELF頭的大小、目標(biāo)文件的類型、機器類型、節(jié)頭部表的文件偏移,以及節(jié)頭部表中條目的大小和數(shù)量。

??????

圖4-2 hello.o的ELF頭

4.3.2 節(jié)頭部表

節(jié)頭部表描述不同節(jié)的位置和大小信息,其中目標(biāo)文件的每個節(jié)都有一個固定大小的條目。如圖所示,hello.o共有14個條目,代表了14個不同的節(jié)。

???????????????

圖4-3 hello.o的節(jié)頭部表

4.3.3 符號表

.symtab節(jié)中包含的符號表,符號表存放在程序中定義和引用的全局變量的信息。如圖4-4所示,在符號表中可以看到函數(shù)定義或引用的sleep,getchar等符號

???????????

圖4-4 hello.o的符號表

4.3.4 .rela.text節(jié)

?.rela.text包含代碼的重定位條目。offset?是需要被修改的引用的節(jié)偏移。symbol?標(biāo)識被修改引用應(yīng)該指向的符號;?type告知鏈接器如何修改新的引用。addend?是一個有符號常數(shù),一些類型的重定位要使用它對被修改引用的值做偏移調(diào)整。

圖4-4 hello.o的.rela.text節(jié)

4.4 Hello.o的結(jié)果解析

使用objdump -d -r hello.o指令,得到hello.o的反匯編??

????????

圖4-5 hello.o反匯編過程

將hello.o的反匯編與hello.s進(jìn)行對照分析,可以看出其明顯差異如下:

4.4.1 操作數(shù)的差異

匯編語言使用10進(jìn)制操作數(shù),而機器語言使用十六進(jìn)制操作數(shù)

4.4.1 分支轉(zhuǎn)移的差異

hello.s使用代碼的標(biāo)號進(jìn)行直接跳轉(zhuǎn),如圖4-6所示,控制直接跳轉(zhuǎn)到.L2處

????????????????

圖4-6 hello.s的跳轉(zhuǎn)指令

而hello.o的反匯編中使用相對地址進(jìn)行跳轉(zhuǎn),如圖所示

????????????????

圖4-7 hello.o的反匯編中的跳轉(zhuǎn)

4.4.3?函數(shù)調(diào)用的差異

hello.s中使用call+函數(shù)名的方式調(diào)用函數(shù),如圖4-8所示

???????????????????

圖4-8 hello.s的函數(shù)調(diào)用

而hello.o的反匯編中使用call+函數(shù)地址調(diào)用函數(shù)(由于此時尚未進(jìn)行重定位,所以對函數(shù)的調(diào)用采用了重定位條目的形式)

??????????????

圖4-8 hello.o的反匯編中的跳轉(zhuǎn)

4.5 本章小結(jié)

本章介紹了將文本文件進(jìn)行匯編生成可執(zhí)行目標(biāo)文件的過程。同時對生成的ELF文件進(jìn)行了分析,可以看到,ELF文件由ELF頭,節(jié)頭部表以及夾在二者之間的若干節(jié)構(gòu)成。此外還將匯編后的文件與匯編前的文件進(jìn)行對比,并觀察到二者在分支轉(zhuǎn)移和函數(shù)調(diào)用等方面差異顯著。


??????????????????第5章 鏈接

5.1 鏈接的概念與作用

5.1.1 鏈接的概念

鏈接是將各種代碼和數(shù)據(jù)片段收集并組合成為一個單一文件的過程,這個文件可以被加載到內(nèi)存執(zhí)行。

5.1.2 鏈接的作用

鏈接將獨立的可重定位目標(biāo)模塊組織成統(tǒng)一的可執(zhí)行目標(biāo)文件。在軟件開發(fā)中扮演重要的角色,它使得分離編譯成為可能。我們不用將一個大型的應(yīng)用程序組織稱為一個巨大的源文件,而是可以把它們分解成更好管理的模塊。

5.2 在Ubuntu下鏈接的命令

5.2.1 Linux下的鏈接命令

ld -o hello -dynamic-linker /lib64/ld-linux-x86-64.so.2

/usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o hello.o

/usr/lib/x86_64-linux-gnu/libc.so /usr/lib/x86_64-linux-gnu/crtn.o

5.2.2 鏈接過程

如下圖所示:

圖5-1 鏈接過程展示

5.3 可執(zhí)行目標(biāo)文件hello的格式

5.3.1 ELF頭

?????????

圖5-2 hello文件的ELF頭

5.3.2 節(jié)頭部表

從節(jié)頭部表可以得到每個節(jié)的位置和大小信息,比如.text節(jié)的開始位置是0x4010f0,大小為145個字節(jié),如圖5-3所示

????????

圖5-3 hello文件節(jié)頭部表

5.3.3 程序頭部表

程序頭部表描述了可執(zhí)行文件到內(nèi)存的映射關(guān)系,如圖5-4所示

?????????

圖5-4 hello文件程序頭部表

5.4 hello的虛擬地址空間

5.4.1 虛擬地址空間概述

圖5-5展示了一個x86-64 Linux進(jìn)程的虛擬地址空間的組織結(jié)構(gòu)。地址空間底部是保留給用戶程序的,包括通常的代碼、數(shù)據(jù)、堆和棧段。代碼段總是從地址0x400000開始。地址空間頂部保留給內(nèi)核(操作系統(tǒng)常駐內(nèi)存的部分)。地址空的這個部分包含內(nèi)核在代表進(jìn)程執(zhí)行指令時(比如當(dāng)應(yīng)用程序執(zhí)行系統(tǒng)調(diào)用時)使用的碼、數(shù)據(jù)和棧。

????????????????????

圖5-5 一個標(biāo)準(zhǔn)linux進(jìn)程的虛擬內(nèi)存結(jié)構(gòu)

5.4.1 棧

使用edb查看hello程序,可以看到虛擬空間的棧向下增長,棧指針位于地址00007ffdbdec6030

???????????????????????????

圖5-5 edb中展示的棧結(jié)構(gòu)

5.4.2 數(shù)據(jù)和代碼段

?????????

圖5-5 edb中展示的數(shù)據(jù)和代碼段

數(shù)據(jù)和代碼段從地址0x400000開始。查看可執(zhí)行文件的節(jié)頭部表可知,程序的入口點.init節(jié)開始于地址0x401000處,這與上圖顯示的初始地址相吻合。????????????????

5.5 鏈接的重定位過程分析

5.5.1 hello和hello.o的差異

新增節(jié):hello相比于hello.o,新增了init,plt等節(jié),atoi,sleep等函數(shù)的反匯編代碼也包含在節(jié)中,如圖5-6所示

?????

圖5-6 hello中新增的節(jié)

地址:hello中使用虛擬內(nèi)存地址,如圖5-7所示

???????????????

圖5-7 hello中的虛擬地址

符號引用 :在hello.o函數(shù)中,由于沒有進(jìn)行重定位,所以使用諸如“R_X86_64_PC32 .rodata+0x22”的重定位條目顯示在引用的后面一行上;而在hello中,重定位條目被替換為真實的虛擬內(nèi)存尋址。

???????????

圖5-8 hello中call指令后接虛擬地址

5.5.2 對hello.o的重定位過程分析

鏈接器使用一種叫做重定位算法的方法來解析hello.o中的引用。在hello.o文件中,匯編器為每個引用產(chǎn)生一個重定位條目,顯示在引用的后面一行上。這些重定位條目告訴鏈接器對該符號的引用要使用哪種具體算法。

???????????

圖5-9 重定位算法展示

5.6 hello的執(zhí)行流程

5.6.1 程序執(zhí)行的全過程

使用edb執(zhí)行hello,程序初始位置位于0x7f632c643100。

1. 從加載到進(jìn)入main函數(shù)的過程

開始時,經(jīng)過一系列執(zhí)行,程序首先跳轉(zhuǎn)到子程序hello!_start,該子程序位于地址0x4010f0處。隨后通過callq *0x2ed2(%rip) 指令跳轉(zhuǎn)到位于地址0x7f38faffefc0的“Libc-2.31.so!_libc_start_main”子程序,在子程序中,通過call *%rax指令跳轉(zhuǎn)到main函數(shù),地址為0x401125。

2. 從main函數(shù)到程序執(zhí)行完畢

進(jìn)入main函數(shù),程序按照源代碼順序依次執(zhí)行,在執(zhí)行的過程中分別調(diào)用不同的子程序,子程序名稱和地址見下表

5.6.2 各子程序展示

子程序名稱

地址

Hello!start

0x4010f0

libc-2.31.so!_libc_start_main

0x7f38faffefc0

Hello!main

0x401125

<puts@plt>

0x401090

<printf@plt>

0x4010a0

<getchar@plt>

0x4010b0

<atoi@plt>

Ox4010c0

<exit@plt>

0x4010d0

<sleep@plt>

0x4010e0

5.7 Hello的動態(tài)鏈接分析

下面展示了動態(tài)鏈接前后的變化:

首先在elf文件中找到:

???????????????

動態(tài)鏈接前:

動態(tài)鏈接后:

5.8 本章小結(jié)

本章介紹了鏈接的概念和作用,同時分析了hello程序的虛擬地址空間、重定位過程、執(zhí)行流程、動態(tài)鏈接過程。


6hello進(jìn)程管理

6.1 進(jìn)程的概念與作用

6.1.1進(jìn)程的概念

進(jìn)程的經(jīng)典定義就是一個執(zhí)行中程序的實例,是操作系統(tǒng)對一個正在運行程序的抽象。

6.1.2 進(jìn)程的作用

操作系統(tǒng)通過進(jìn)程提供一種假象,就好像系統(tǒng)上只有這個程序在運行。程序看上去是獨占地使用處理器、主存和 I / O 設(shè)備。處理器看上去就像在不間斷地一條接一條地執(zhí)行程序中的指令,即該程序的代碼和數(shù)據(jù)是系統(tǒng)內(nèi)存中唯一的對象。

6.2 簡述殼Shell-bash的作用與處理流程

6.2.1 shell的作用

Shell是一個交互性的應(yīng)用級程序,代表用戶運行其他程序

6.2.2 處理流程

shell讀取用戶輸入的命令行,解析該命令行并代表用戶運行程序,包括使用fork函數(shù)創(chuàng)建一個新的進(jìn)程,并在新的進(jìn)程上下文中運行程序。

6.3 Hello的fork進(jìn)程創(chuàng)建過程

在命令行輸入“./hello 7203610410 xukun 1”后,shell解析命令行,并發(fā)現(xiàn)該命令行的第一個單詞不是shell的內(nèi)置命令(在這里是./hello),那么shell就會假設(shè)這是一個可執(zhí)行文件的名字,然后加載并運行這個文件。Shell會根據(jù)輸入的命令行的剩余部分構(gòu)造參數(shù)列表,并構(gòu)造最終會傳遞給execve的argv向量。

shell使用fork創(chuàng)建一個新的子進(jìn)程,子進(jìn)程得到與父進(jìn)程用戶級虛擬地址空間相同的(但是獨立的)副本,包括代碼和數(shù)據(jù)段、堆、共享庫以及用戶棧。子進(jìn)程還獲得與父進(jìn)程任何打開文件描述符相同的副本,這就意味著當(dāng)父進(jìn)程調(diào)用 fork時,子進(jìn)程可以讀寫父進(jìn)程中打開的任何文件。父進(jìn)程和新創(chuàng)建的子進(jìn)程之間最大的區(qū)別在于它們有不同的PID。

6.4 Hello的execve過程

在新創(chuàng)建的子進(jìn)程中,shell調(diào)用execve函數(shù)加載并運行可執(zhí)行目標(biāo)文件hello,且?guī)?shù)列表argv和環(huán)境變量列表envp。參數(shù)列表在shell解析的過程中創(chuàng)建, argv變量指向一個以null結(jié)尾的指針數(shù)組,其中每個指針都指向一個參數(shù)字符串。按照慣例,argv [0]是可執(zhí)行目標(biāo)文件的名字。環(huán)境變量的列表是由一個類似的數(shù)據(jù)結(jié)構(gòu)表示的,envp變量指向一個以null結(jié)尾的指針數(shù)組,其中每個指針指向一個環(huán)境變量字符串,每個串都是形如name = value的名字-值對。

execve函數(shù)代碼如下:

??????????

圖6-1 execve函數(shù)代碼

6.5 Hello的進(jìn)程執(zhí)行

6.5.1 基本概念

上下文:內(nèi)核為每個進(jìn)程維持一個上下文,上下文就是內(nèi)核重新啟動一個被搶占的進(jìn)程所需的狀態(tài)。

調(diào)度:在進(jìn)程執(zhí)行的某些時刻,內(nèi)核可以決定搶占當(dāng)前進(jìn)程,并重新開始一個先前被搶占了的進(jìn)程,這種決策就叫做調(diào)度,是由內(nèi)核中稱為調(diào)度器的代碼處理的。

上下文切換:在內(nèi)核調(diào)度了一個新的進(jìn)程運行后,它就搶占當(dāng)前進(jìn)程,并使用一種稱為上下文切換的機制來將控制轉(zhuǎn)移到新的進(jìn)程。

時間片:一個進(jìn)程執(zhí)行它的控制流的一部分的每一時間段叫做時間片

6.5.2 hello的進(jìn)程執(zhí)行

本例中有兩個并發(fā)的進(jìn)程: shell進(jìn)程和 hello 進(jìn)程。最開始,shell進(jìn)程在運行,即等待命令行上的輸入。當(dāng)我們讓它運行hello程序時,shell通過系統(tǒng)調(diào)用,來執(zhí)行我們的請求,系統(tǒng)調(diào)用會將控制權(quán)傳遞給操作系統(tǒng)。操作系統(tǒng)保存shell進(jìn)程的上下文,創(chuàng)建一個新的hello進(jìn)程及其上下文,然后將控制權(quán)傳給新的hello進(jìn)程。在hello進(jìn)程的執(zhí)行過程中,在某些時刻,hello程序調(diào)用sleep函數(shù)顯式請求進(jìn)程休眠,此時內(nèi)核執(zhí)行上下文切換,從用戶模式轉(zhuǎn)換到內(nèi)核模式,搶占hello進(jìn)程。隨后,在其他進(jìn)程執(zhí)行一段時間后,內(nèi)核做出決定將控制返回給hello進(jìn)程繼續(xù)執(zhí)行。如此反復(fù)直到hello進(jìn)程終止后,操作系統(tǒng)恢復(fù)shell進(jìn)程的上下文,并將控制權(quán)傳給它,shell進(jìn)程會繼續(xù)等待下一個命令行輸入。

6.6 hello的異常與信號處理

hello執(zhí)行過程中會出現(xiàn)異步中斷異常和系統(tǒng)調(diào)用,中斷即來自外部I/O設(shè)備的信號打斷進(jìn)程。同時會產(chǎn)生諸如SIGINT,SIGQUIT,SIGTSTP等信號。

6.6.1 執(zhí)行過程中鍵入Ctrl-z

當(dāng)在鍵盤中敲入Ctrl-z時,內(nèi)核會向前臺進(jìn)程組的每個進(jìn)程發(fā)送SIGTSTP信號,hello進(jìn)程捕獲信號并停止,如下圖所示。

????????

圖6-2 執(zhí)行過程中鍵入Ctrl-z

6.6.2 停止后輸入ps/jobs/pstree等命令

ps/jobs/pstree等命令是shell的內(nèi)置命令,shell執(zhí)行并實現(xiàn)相應(yīng)指令的功能。

????????

圖6-3 停止后輸入jobs命令,列出所有的jobs

???????????

圖6-4 停止后輸入pstree命令

??????????????????

圖6-5 停止后輸入ps命令

6.6.3 停止后輸入fg命令

fg指令是shell的內(nèi)置命令,當(dāng)在鍵盤中敲入fg時,內(nèi)核會向前臺進(jìn)程組的每個進(jìn)程發(fā)送SIGCONT信號,此時被停止的hello進(jìn)程被喚醒并繼續(xù)運行

???????????????????

圖6-5 停止后輸入fg命令

6.6.4 停止后輸入kill命令

kill是shell的內(nèi)置命令,當(dāng)在鍵盤中敲入kill時,會顯示地從從進(jìn)程向目標(biāo)進(jìn)程發(fā)送指定的信號,如圖所示,是向hello所在進(jìn)程發(fā)送SIGKILL信號殺死該進(jìn)程。

??????????????

圖6-6 停止后輸入kill命令

6.6.5 執(zhí)行過程中鍵入Ctrl-c

當(dāng)在鍵盤中敲入Ctrl-c時,內(nèi)核會向前臺進(jìn)程組的每個進(jìn)程發(fā)送SIGINT信號,hello進(jìn)程捕獲信號并終止,等待回收。

????????

圖6-7 執(zhí)行過程中鍵入Ctrl-c

6.6.5 執(zhí)行過程中不停亂按和鍵入回車

亂按的字符會保存在緩沖區(qū)內(nèi),等待getchar()函數(shù)讀取

??????????

圖6-8 執(zhí)行過程中不停亂按

?????????????

圖6-8 執(zhí)行過程中鍵入回車

6.7本章小結(jié)

本章從進(jìn)程和上下文的角度分析了hello的執(zhí)行過程,以及在執(zhí)行過程中程序?qū)Ξ惓5奶幚砹鞒獭?/p>


7hello的存儲管理

7.1 hello的存儲器地址空間?

7.1.1 邏輯地址

邏輯地址是用戶編程時使用的地址,分為段地址和偏移地址兩部分。在hello程序中,指的是hello.o中的地址。

7.1.2 線性地址

線性地址(Linear Address)是邏輯地址到物理地址變換之間的中間層。程序代碼會產(chǎn)生邏輯地址,或者說是段中的偏移地址,加上相應(yīng)段的基地址就生成了一個線性地址。

7.1.3 物理地址

物理地址是指出現(xiàn)在CPU外部地址總線上的尋址物理內(nèi)存的地址信號,是地址變換的最終結(jié)果地址,這里指的是hello保存在主存上的實際地址。

7.1.4 虛擬地址

虛擬地址指的是程序在虛擬內(nèi)存空間的地址,這里就是hello的虛擬地址。

7.2 Intel邏輯地址到線性地址的變換-段式管理

linux是通過分段機制,將邏輯地址轉(zhuǎn)化為線性地址。通過數(shù)據(jù)段寄存器ds,可以找到此進(jìn)程數(shù)據(jù)段所在的段描述符,再通過段描述符找到相應(yīng)的線性地址。

段描述符是描述段的屬性的數(shù)據(jù)結(jié)構(gòu),長度一般為8字節(jié)。

給定一個完整的邏輯地址段選擇符+段內(nèi)偏移地址,看段選擇符的T1=0還是1,知道當(dāng)前要轉(zhuǎn)換是GDT中的段,還是LDT中的段,再根據(jù)相應(yīng)寄存器,得到其地址和大小。拿出段選擇符中前13位,可以在這個數(shù)組中,查找到對應(yīng)的段描述符,就得到了其基地址。從邏輯地址到線性地址的全部流程如下圖所示:

?????????

圖7-1 從邏輯地址到線性地址的全部流程

7.3 Hello的線性地址到物理地址的變換-頁式管理

線性地址怎么對應(yīng)到物理地址是通過分頁機制來完成的,具體的說,就是通過頁表查找來對應(yīng)物理地址。

分頁的基本原理是把線性地址分成固定長度的單元,稱為頁(page)。頁內(nèi)部連續(xù)的線性地址映射到連續(xù)的物理地址中。X86每頁為4KB。為了能轉(zhuǎn)換成物理地址,我們需要給CPU提供當(dāng)前任務(wù)的線性地址轉(zhuǎn)物理地址的查找表,即頁表(page table),頁表存放在內(nèi)存中。

在保護(hù)模式下,控制寄存器CR0的最高位PG位控制著分頁管理機制是否生效,如果PG=1,分頁機制生效,需通過頁表查找才能把線性地址轉(zhuǎn)換物理地址。如果PG=0,則分頁機制無效,線性地址就直接作為物理地址。

為了實現(xiàn)每個任務(wù)的平坦的虛擬內(nèi)存和相互隔離,每個任務(wù)都有自己的頁目錄表和頁表。

7.4 TLB與四級頁表支持下的VA到PA的變換

core i7支持48位虛擬地址空間和52位物理地址空間,采用四級頁表層次結(jié)構(gòu)。如圖所示,展示了VA到PA的變換。CPU首先生成一個虛擬地址,并將其拆分為36位的VPN部分和12位的VPO部分。

首先查找TLB,MMU從虛擬地址中抽取VPN部分,并將其解讀為標(biāo)記(TLBT)和索引(TLBL)兩部分,用于對TLB進(jìn)行組選擇和行匹配。然后檢查TLB,若命中,則直接將緩存的PPN返回,與VPO連接起來,這就形成了物理地址,完成了VA到PA的變換。

若TLB不命中,那么MMU必須從頁表中的PTE取出PPN。此時,36位VPN被劃分成四個9位的片,每個片被用作到一個頁表的偏移量。比如前9位就被用作到一級頁表的偏移量,以此類推。前3層頁表中,每個頁表的PTE都指向下一個頁表的基址。第四層頁表中,每個PTE包含某個物理頁面的PPN。分層順序查找頁表,將得到的PPN與VPO連接起來,形成物理地址,完成了VA到PA的變換。

??????
圖7-2 TLB與四級頁表支持下的VA到PA的變換

7.5 三級Cache支持下的物理內(nèi)存訪問

當(dāng)MMU生成物理地址后,將獲得的物理地址拆分為CT(標(biāo)記位)CI(組索引),CO(塊偏移)。

組索引位是一個到組的索引。第一個組是組0,第二個組是組1,依此類推。組索引位被解釋為一個無符號整數(shù)、它告訴我們這個字必須存儲在哪個組中。一旦我們知道了這個字必須放在哪個組中,A中的個標(biāo)記位就告訴我們這個組中的哪一行包含這個字(如果有的話)。當(dāng)且僅當(dāng)設(shè)置了有效位并且該行的標(biāo)記位與地址 A 中的様記位相匹配時,組中的這一行才包含這個字。一旦我們在由組索引標(biāo)識的組中定位了由標(biāo)號所標(biāo)識的行,那么塊偏移位給出了在B個字節(jié)的數(shù)據(jù)塊中的字偏移。

整個流程分為三步:組選擇,行匹配,字抽取。

?????????????????

圖7-3 Intel core i7 高速緩存層次結(jié)構(gòu)

???????????????????

圖7-4 三級Cache支持下的物理內(nèi)存訪問

7.6 hello進(jìn)程fork時的內(nèi)存映射

7.6.1 私有對象的內(nèi)存映射

私有對象使用一種叫做寫時復(fù)制的巧妙技術(shù)被映射到虛擬內(nèi)存中。對于每個映射私有對象的進(jìn)程,相應(yīng)私有區(qū)域的頁表條目都被標(biāo)記位只讀,并且區(qū)域結(jié)構(gòu)被標(biāo)記位私有的寫時復(fù)制。

7.6.2 hello進(jìn)程fork時的內(nèi)存映射

當(dāng)shell調(diào)用fork函數(shù)為hello創(chuàng)建新的進(jìn)程時,內(nèi)核為新進(jìn)程創(chuàng)建各種數(shù)據(jù)結(jié)構(gòu),并分配給它一個唯一的PID。為了給這個新進(jìn)程創(chuàng)建虛擬內(nèi)存,它創(chuàng)建了當(dāng)前進(jìn)程的 mm_struct、區(qū)域結(jié)構(gòu)和頁表的原樣副本。它將兩個進(jìn)程中的每個頁面都標(biāo)記為只讀,并將兩個進(jìn)程中的每個區(qū)域結(jié)構(gòu)都標(biāo)記為私有的寫時復(fù)制。

當(dāng)fork在新進(jìn)程中返回時,新進(jìn)程現(xiàn)在的虛擬內(nèi)存剛好和調(diào)用fork時存在的虛擬內(nèi)存相同。當(dāng)這兩個進(jìn)程中的任一個后來進(jìn)行寫操作時,寫時復(fù)制機制就會創(chuàng)建新頁面,因此,也就為每個進(jìn)程保持了私有地址空間的抽象概念。

7.7 hello進(jìn)程execve時的內(nèi)存映射

當(dāng)在新的進(jìn)程中調(diào)用execve函數(shù)時,在當(dāng)前進(jìn)程中加載并運行包含在可執(zhí)行目標(biāo)文件hello中的程序,用hello程序有效地替代了當(dāng)前程序。加載并運行hello需要以下幾個步驟:

1. 刪除已存在的用戶區(qū)域。刪除當(dāng)前進(jìn)程虛擬地址的用戶部分中的已存在的區(qū)域結(jié)構(gòu)。

2. 映射私有區(qū)域。為新程序的代碼、數(shù)據(jù)、 bss和棧區(qū)域創(chuàng)建新的區(qū)域結(jié)構(gòu)。所有這些新的區(qū)域都是私有的、寫時復(fù)制的。代碼和數(shù)據(jù)區(qū)域被映射為hello文件中的.text和.data 區(qū)。bss區(qū)域是請求二進(jìn)制零的,映射到匿名文件,其大小包含在hello中。棧和堆區(qū)域也是請求二進(jìn)制零的,初始長度為零。下圖概括了私有區(qū)域的不同映射。

3. 映射共享區(qū)域。hello程序與共享對象鏈接,比如標(biāo)準(zhǔn)C庫1ibc. So,那么這些對象都是動態(tài)鏈接到這個程序的,然后再映射到用戶虛擬地址空間中的共享區(qū)域內(nèi)。

4. 設(shè)置程序計數(shù)器(PC)。 execve做的最后一件事情就是設(shè)置當(dāng)前進(jìn)程上下文中的程序計數(shù)器,使之指向代碼區(qū)域的入口點。下一次調(diào)度這個進(jìn)程時,它將從這個入口點開始執(zhí)行。 Linux將根據(jù)需要換入代碼和數(shù)據(jù)頁面。

7.8 缺頁故障與缺頁中斷處理

7.8.1 缺頁故障

在虛擬內(nèi)存的習(xí)慣說法中,DRAM緩存不命中稱為缺頁。

7.8.2 缺頁中斷處理

處理缺頁要求硬件和操作系統(tǒng)內(nèi)核協(xié)作完成。當(dāng)發(fā)生缺頁故障時,MMU觸發(fā)了一次異常,傳遞CPU中的控制到操作系統(tǒng)中的缺頁異常處理程序,處理程序隨后執(zhí)行下面的步驟:

1. 判斷虛擬地址A是否合法。

處理程序首先判斷A是否在某個區(qū)域結(jié)構(gòu)定義的區(qū)域內(nèi)。為了回答這個問題,缺頁處理程序搜索區(qū)域結(jié)構(gòu)的鏈表,把A和每個區(qū)域結(jié)構(gòu)中的vm_start和vm_end 做比較。如果這個指令是不合法的,那么缺頁處理程序就觸發(fā)一個段錯誤,從而終止這個進(jìn)程。這個情況在下圖中標(biāo)識為“1”。

因為一個進(jìn)程可以創(chuàng)建任意數(shù)量的新虛擬內(nèi)存區(qū)域,所以順序搜索區(qū)域結(jié)構(gòu)的鏈表花銷可能會很大。因此在實際中,Linux使用某些我們沒有顯示出來的字段, Linux在鏈表中構(gòu)建了一棵樹,并在這棵樹上進(jìn)行査找。

2. 判斷試圖進(jìn)行的內(nèi)存訪問是否合法

處理程序需要判斷進(jìn)程是否有讀、寫或者執(zhí)行這個區(qū)域內(nèi)頁面的權(quán)限。例如,這個缺頁可能是由一條試圖對這個代碼段里的只讀頁面進(jìn)行寫操作的存儲指令造成的。如果試圖進(jìn)行的訪問是不合法的,那么缺頁處理程序會觸發(fā)一個保護(hù)異常,從而終止這個進(jìn)程。這種情況在圖9-28中標(biāo)識為2。

3. 最終處理

此刻,內(nèi)核知道了這個缺頁是由于對合法的虛擬地址進(jìn)行合法的操作造成的。它是這樣來處理這個缺頁的:選擇一個犧牲頁面,如果這個犧牲頁面被修改過,那么就將它交換出去,換入新的頁面并更新頁表。當(dāng)缺頁處理程序返回時,CPU 重新啟動引起缺頁的指令,這條指令將再次發(fā)送A到MMU。這次,MMU就能正常地翻譯A,而不會再產(chǎn)生缺頁中斷了。

7.9動態(tài)存儲分配管理

7.9.1 動態(tài)內(nèi)存管理的基本方法和策略

使用動態(tài)內(nèi)存分配器是一種常見的動態(tài)內(nèi)存管理方法。分配器按照釋放方式不同分為顯式分配器和隱式分配器。

動態(tài)內(nèi)存分配器維護(hù)著一個進(jìn)程的虛擬內(nèi)存區(qū)域,稱為堆(heap)。堆是一個請求二進(jìn)制零的區(qū)域,它緊接在未初始化的數(shù)據(jù)區(qū)域后開始,并向上生長(向更高的地址)。對于每個進(jìn)程,內(nèi)核維護(hù)著一個變量brk,它指向堆頂。

分配器將堆視為一組不同大小的塊的集合來維護(hù)。每個塊就是一個連續(xù)的虛擬內(nèi)存片,要么是已分配的,要么是空閑的。已分配的塊顯式地保留為供應(yīng)用程序使用??臻e塊可用來分配??臻e塊保持空閑,直到它顯式地被應(yīng)用所分配。一個已分配的塊保持已分配狀態(tài),直到它被釋放,這種釋放要么是應(yīng)用程序顯式執(zhí)行的,要么是內(nèi)存分配器自身隱式執(zhí)行的。

7.9.2 malloc和free函數(shù)

在hello程序中,printf中使用malloc函數(shù),程序可以通過調(diào)用malloc函數(shù)分配塊。

7.10本章小結(jié)

本章講解了hello的存儲器空間,并給出了?TLB與四級頁表支持下的VA到PA的變換和三級Cache支持下的物理內(nèi)存訪問過程的介紹。


8hello的IO管理

8.1 Linux的IO設(shè)備管理方法

(以下格式自行編排,編輯時刪除)

設(shè)備的模型化:文件

設(shè)備管理:unix io接口

8.2 簡述Unix IO接口及其函數(shù)

(以下格式自行編排,編輯時刪除)

8.3 printf的實現(xiàn)分析

(以下格式自行編排,編輯時刪除)

[轉(zhuǎn)]printf 函數(shù)實現(xiàn)的深入剖析 - Pianistx - 博客園

從vsprintf生成顯示信息,到write系統(tǒng)函數(shù),到陷阱-系統(tǒng)調(diào)用 int 0x80或syscall等.

字符顯示驅(qū)動子程序:從ASCII到字模庫到顯示vram(存儲每一個點的RGB顏色信息)。

顯示芯片按照刷新頻率逐行讀取vram,并通過信號線向液晶顯示器傳輸每一個點(RGB分量)。

8.4 getchar的實現(xiàn)分析

(以下格式自行編排,編輯時刪除)

異步異常-鍵盤中斷的處理:鍵盤中斷處理子程序。接受按鍵掃描碼轉(zhuǎn)成ascii碼,保存到系統(tǒng)的鍵盤緩沖區(qū)。

getchar等調(diào)用read系統(tǒng)函數(shù),通過系統(tǒng)調(diào)用讀取按鍵ascii碼,直到接受到回車鍵才返回。

8.5本章小結(jié)

(以下格式自行編排,編輯時刪除)

(第8章1分)

結(jié)論

逐條總結(jié)hello所經(jīng)歷的過程:

1. ?hello.c經(jīng)過預(yù)處理生成hello.i文件

2. ?hello.i經(jīng)過編譯生成hello.s匯編文件

3. ?hello.s經(jīng)過匯編生成可重定位目標(biāo)文件hello.o

4. ?hello.o經(jīng)過鏈接生成可執(zhí)行目標(biāo)文件hello.out

5. ?shell進(jìn)程調(diào)用fork函數(shù)生成子進(jìn)程

6. ?在子進(jìn)程內(nèi)調(diào)用execve函數(shù)執(zhí)行hello

7. ?CPU執(zhí)行指令,在屏幕上顯示結(jié)果

8. ?操作系統(tǒng)調(diào)度進(jìn)程,進(jìn)行上下文切換

9. ?在TLB、四級頁表和三級cache的合作下完成hello程序與內(nèi)存的交互

在計算機硬件和操作系統(tǒng)分工合作下,完成了hello程序的執(zhí)行,每一步執(zhí)行都顯示出計算機設(shè)計師們的奇思妙想和科學(xué)技術(shù)的飛速發(fā)展。


附件

中間文件

作用

hello.i

經(jīng)過預(yù)處理的源程序,用于編譯器的翻譯

hello.s

匯編程序,用于匯編

hello.o

可重定位目標(biāo)文件,用于鏈接

hello

可執(zhí)行目標(biāo)文件,可以加載到內(nèi)存中執(zhí)行

elf.txt

hello.o對應(yīng)的elf文本文件

dump1.txt

hello.o 的反匯編文本文件

elf2.txt

hello對應(yīng)的elf文本文件

dump2.txt

hello 的反匯編文本文件


參考文獻(xiàn)

為完成本次大作業(yè)你翻閱的書籍與網(wǎng)站等

[1] ?林來興.?空間控制技術(shù)[M].?北京:中國宇航出版社,1992:25-42.

[2] ?辛希孟.?信息技術(shù)與信息服務(wù)國際研討會論文集:A集[C].?北京:中國科學(xué)出版社,1999.

[3] ?趙耀東. 新時代的工業(yè)工程師[M/OL]. 臺北:天下文化出版社,1998?[1998-09-26]. http://www.ie.nthu.edu.tw/info/ie.newie.htm(Big5).

[4] ?諶穎. 空間交會控制理論與方法研究[D]. 哈爾濱:哈爾濱工業(yè)大學(xué),1992:8-13.

[5]??KANAMORI H. Shaking Without Quaking[J]. Science,1998,279(5359):2063-2064.

[6]??CHRISTINE M. Plant Physiology: Plant Biology in the Genome Era[J/OL].?Science,1998,281:331-332[1998-09-23]. http://www.sciencemag.org/cgi/?collection/anatmorp.

(參考文獻(xiàn)0分,缺失 -1分)

總結(jié)

以上是生活随笔為你收集整理的哈工大计算机系统大作业——hello P2P的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。