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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

程序人生-Hello’s P2P

發(fā)布時(shí)間:2023/12/10 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 程序人生-Hello’s P2P 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

計(jì)算機(jī)系統(tǒng)

大作業(yè)

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

專?????? 業(yè) ??計(jì)算機(jī)科學(xué)與技術(shù)??????

學(xué)  ?? 號(hào) ??2021113044????????????

班  ?? 級(jí) ??2103101???????????????

學(xué)?????? 生 ??方健??????????????   

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

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

2022年5月

摘? 要

本文深入的研究了hello的一生,深入研究它是如何從一個(gè)源程序hello.c轉(zhuǎn)化為一個(gè)可執(zhí)行文件的,并在shell里面的運(yùn)行步驟,詳細(xì)的分析了每一個(gè)過程的具體內(nèi)容,如編譯、匯編、鏈接、重定位等等。

關(guān)鍵詞:匯編、重定位、ELF、鏈接???????????????????????????

(摘要0分,缺失-1分,根據(jù)內(nèi)容精彩稱都酌情加分0-1分

目? 錄

第1章 概述............................................................................................................. - 4 -

1.1 Hello簡(jiǎn)介...................................................................................................... - 4 -

1.2 環(huán)境與工具..................................................................................................... - 4 -

1.3 中間結(jié)果......................................................................................................... - 4 -

1.4 本章小結(jié)......................................................................................................... - 4 -

第2章 預(yù)處理......................................................................................................... - 5 -

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

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

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

2.4 本章小結(jié)......................................................................................................... - 5 -

第3章 編譯............................................................................................................. - 6 -

3.1 編譯的概念與作用......................................................................................... - 6 -

3.2 在Ubuntu下編譯的命令............................................................................. - 6 -

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

3.4 本章小結(jié)......................................................................................................... - 6 -

第4章 匯編............................................................................................................. - 7 -

4.1 匯編的概念與作用......................................................................................... - 7 -

4.2 在Ubuntu下匯編的命令............................................................................. - 7 -

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

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

4.5 本章小結(jié)......................................................................................................... - 7 -

第5章 鏈接............................................................................................................. - 8 -

5.1 鏈接的概念與作用......................................................................................... - 8 -

5.2 在Ubuntu下鏈接的命令............................................................................. - 8 -

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

5.4 hello的虛擬地址空間.................................................................................. - 8 -

5.5 鏈接的重定位過程分析................................................................................. - 8 -

5.6 hello的執(zhí)行流程.......................................................................................... - 8 -

5.7 Hello的動(dòng)態(tài)鏈接分析.................................................................................. - 8 -

5.8 本章小結(jié)......................................................................................................... - 9 -

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

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

6.2 簡(jiǎn)述殼Shell-bash的作用與處理流程..................................................... - 10 -

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

6.4 Hello的execve過程................................................................................. - 10 -

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

6.6 hello的異常與信號(hào)處理............................................................................ - 10 -

6.7本章小結(jié)....................................................................................................... - 10 -

第7章 hello的存儲(chǔ)管理................................................................................ - 11 -

7.1 hello的存儲(chǔ)器地址空間............................................................................ - 11 -

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

7.3 Hello的線性地址到物理地址的變換-頁(yè)式管理....................................... - 11 -

7.4 TLB與四級(jí)頁(yè)表支持下的VA到PA的變換............................................. - 11 -

7.5 三級(jí)Cache支持下的物理內(nèi)存訪問.......................................................... - 11 -

7.6 hello進(jìn)程fork時(shí)的內(nèi)存映射.................................................................. - 11 -

7.7 hello進(jìn)程execve時(shí)的內(nèi)存映射.............................................................. - 11 -

7.8 缺頁(yè)故障與缺頁(yè)中斷處理........................................................................... - 11 -

7.9動(dòng)態(tài)存儲(chǔ)分配管理....................................................................................... - 11 -

7.10本章小結(jié)..................................................................................................... - 12 -

第8章 hello的IO管理................................................................................. - 13 -

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

8.2 簡(jiǎn)述Unix IO接口及其函數(shù)....................................................................... - 13 -

8.3 printf的實(shí)現(xiàn)分析........................................................................................ - 13 -

8.4 getchar的實(shí)現(xiàn)分析.................................................................................... - 13 -

8.5本章小結(jié)....................................................................................................... - 13 -

結(jié)論......................................................................................................................... - 14 -

附件......................................................................................................................... - 15 -

參考文獻(xiàn)................................................................................................................. - 16 -

第1章 概述

1.1 Hello簡(jiǎn)介

P2P: From Program to Process

最開始我們將代碼一個(gè)個(gè)寫入hello.c中,它是hello程序的生命的起點(diǎn),然后調(diào)用預(yù)處理器cpp將hello.c預(yù)處理為hello.i,接下來編譯器ccl會(huì)將hello.i翻譯為hello.s,然后通過匯編器將hello.s翻譯為機(jī)器指令保存在hello.o中,最后調(diào)用鏈接器形成可執(zhí)行文件hello,在shell中輸入命令./hello,操作系統(tǒng)就會(huì)通過fork為其生成子進(jìn)程,然后通過execve將其加載,不斷進(jìn)行訪存、內(nèi)存申請(qǐng)等操作。最后,在程序結(jié)束返回后,由父進(jìn)程或祖先進(jìn)程進(jìn)行回收,程序結(jié)束。這樣就實(shí)現(xiàn)了完整的P2P過程。

020: From Zero-0 to Zero-0

指一個(gè)程序從無到擁有自己的內(nèi)存,地址和時(shí)間周期等,然后直到該程序執(zhí)行結(jié)束后,父進(jìn)程負(fù)責(zé)將其回收的全部過程。shell在子進(jìn)程中使用execve執(zhí)行這個(gè)程序時(shí),系統(tǒng)將會(huì)把這個(gè)程序加載到內(nèi)存,等待進(jìn)程結(jié)束時(shí),它的父進(jìn)程將會(huì)回收hello,而系統(tǒng)內(nèi)核將會(huì)對(duì)內(nèi)存進(jìn)行清理,這個(gè)過程就叫做020。

1.2 環(huán)境與工具

1.2.1 硬件環(huán)境:

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

1.2.2 軟件環(huán)境:

Windows11 64位以上; Vmware 16;Ubuntu 20.04 ;LTS 64位/優(yōu)麒麟 64位

1.2.3 開發(fā)工具:

Visual Studio 2021 64位;CodeBlocks 64位;vi/vim/gedit/gcc;edb

1.3 中間結(jié)果

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖1-3:中間過程文件

hello.c:源程序

hello.i:經(jīng)過預(yù)處理過后的文件;

hello.s:經(jīng)過編譯生成的匯編文件;

hello.o:匯編生成的可重定位的文件;

hello:通過鏈接產(chǎn)生的可執(zhí)行目標(biāo)文件二進(jìn)制文件;

elf.txt: 可重定位目標(biāo)文件hello.o導(dǎo)出的ELF文件;

hello_elf.txt:可執(zhí)行文件hello導(dǎo)出的ELF文件;

objdump_hello.s:可重定位目標(biāo)文件hello.o反匯編生成的文件

hello_objdump.s:可執(zhí)行文件hello反匯編生成的文件

1.4 本章小結(jié)

本章簡(jiǎn)單介紹hello程序的一生,介紹了P2P和020過程,然后又介紹我所使用的硬件環(huán)境、軟件環(huán)境和開發(fā)調(diào)試工具,最后則簡(jiǎn)述了過程中間生成的中間文件的名字和作用。

(第1章0.5分)

第2章 預(yù)處理

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

預(yù)處理概念:

預(yù)處理指的是預(yù)處理器cpp根據(jù)以字符#開頭的命令,來修改原始的C程序,最后生成.i文本文件的過程

預(yù)處理作用:

1.將源文件中用#include 形式聲明的文件復(fù)制到新的程序中;

2..用實(shí)際值替換用#define 定義的字符串;

3.根據(jù)#if后面的條件決定需要編譯的代碼;

4.預(yù)編譯程序可以識(shí)別一些特殊符號(hào),預(yù)編譯程序?qū)τ谠谠闯绦蛑谐霈F(xiàn)的這些特殊符號(hào)串會(huì)用合適值進(jìn)行替換。

5.預(yù)處理還可以幫助程序員節(jié)省工作量,提高程序可讀性,便于維護(hù)。

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

命令:cpp hello > hello.i

??????????? 圖2-2:Ubuntu下預(yù)處理命令展示

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

? ? ? ?? ????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖2-3:hello.i內(nèi)容展示

解析:可以看見程序被拓展成了3060行,原始hello.c程序出現(xiàn)在3046行之后。在這之前是頭文件stdio.h、unistd.h以及stdlib.h依次展開。預(yù)處理器將它們?nèi)慷颊归_直接插入程序文本中,所以最后的.i文件特別的長(zhǎng)

2.4 本章小結(jié)

本章介紹了預(yù)處理的概念和作用,以及預(yù)處理的方法,然后展示了.i文件的部分內(nèi)容,分析了里面內(nèi)容的由來。

(第2章0.5分)

第3章 編譯

3.1 編譯的概念與作用

編譯的概念:

編譯程序是通過詞法分析和語法分析,在確認(rèn)所有的指令都符合語法規(guī)則后,將其翻譯成等價(jià)的中間代碼或匯編代碼來表示。編譯器cc1將預(yù)處理過的文本文件hello.i 翻譯轉(zhuǎn)換成匯編文本文件hello.s。

編譯的作用:

1.語法分析:編譯程序的語法分析器以單詞符號(hào)作為輸入,分析單詞符號(hào)串是否形成了符合語法規(guī)則的語法單位,方法有自上而下分析法和自下而上分析法兩種;

2.中間代碼:源程序的一種內(nèi)部表示,或稱之為中間語言。中間代碼的作用是使編譯程序的結(jié)構(gòu)在邏輯上更為簡(jiǎn)單明確,特別是使目標(biāo)代碼的優(yōu)化比較容易實(shí)現(xiàn);

3.代碼優(yōu)化:指對(duì)程序進(jìn)行多種等價(jià)變換,使得從變換后的程序出發(fā)時(shí)能生成更有效的目標(biāo)代碼;

4.目標(biāo)代碼:生成目標(biāo)代碼是編譯的最后階段。目標(biāo)代碼生成器把語法分析或優(yōu)化后生成的中間代碼轉(zhuǎn)換成目標(biāo)代碼。此處目標(biāo)代碼指匯編語言代碼,即不同種類的語言提供相同的形式,其指令與處理器的指令集類似,更貼近底層,便于匯編器將其轉(zhuǎn)換為可執(zhí)行機(jī)器語言代碼供機(jī)器執(zhí)行。

3.2 在Ubuntu下編譯的命令

命令:gcc -S hello.i -o hello.s

????????????????? 圖3-2:Ubuntu下編譯的命令展示

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

3.3.1結(jié)果展示:

????????????????????????????? 圖3-3-1:hello.s內(nèi)容展示

3.3.2偽指令

打開我們的hello.s文件我們可以發(fā)現(xiàn)匯編代碼有一部分是以.作為開頭,這些以‘.’開頭的行都是指導(dǎo)匯編器和鏈接器工作的偽指令,通常我們可以忽略這些行,下面給出這些偽指令的含義:如下表

偽指令

含義

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?.file

聲明源文件

.text

聲明代碼節(jié)

?? .section

文件代碼段

? .rodata

只讀文件

?.align

數(shù)據(jù)指令地址對(duì)齊方式

?.string

聲明字符串

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .globl

聲明全局變量

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?.type

聲明變量類型

?????????????????? 表3-3-2:偽指令的類型、含義

3.3.3數(shù)據(jù)

(1)字符串常量

??????????????? 圖3-3-3-1:hello.s匯編代碼關(guān)于字符串常量的部分

解析:.LC0和.LC1作為兩個(gè)字符串變量被聲明對(duì)于原程序printf里面的字符串“用法: Hello 學(xué)號(hào) 姓名 秒數(shù)!”和“Hello %s %s”。而在.LC0中出現(xiàn)的\347\224等是因?yàn)橹形淖址麤]有對(duì)應(yīng)的ASCII碼值無法直接顯式顯示,所以這樣的字符方式顯示。而且這兩個(gè)字符串都在.rodata下面,所以是只讀數(shù)據(jù)。

(2)全局變量

? ? ? ? ? ? ?圖3-3-3-2:hello.s匯編代碼關(guān)于全局變量main的部分

解析:這里.globl聲明了main是一個(gè)全局變量,.type main,@function看出main是一個(gè)函數(shù)類型

(3)變量

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

??????? 圖3-3-3-3:hello.s匯編代碼關(guān)于函數(shù)參數(shù)argc、argv的部分?

解析:可以看出來%edi保存的main函數(shù)的第一個(gè)參數(shù)int argc,%rsi保存的是main函數(shù)的第二個(gè)參數(shù)char *argv[],然后在棧中-20(%rbp)的位置保存變量argc占4個(gè)字節(jié),在-32(%rbp)的位置保存變量argv[],占八個(gè)字節(jié),接下來程序就可以通過-20(%rbp)和-32(%rbp)直接找到函數(shù)的參數(shù)內(nèi)容。

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

???????? 圖3-3-3-3-1:hello.s匯編代碼關(guān)于局部變量i的部分

解析:可以看出-4(%rbp)保存的是變量i的值,初始為0,每次循環(huán)加一,循環(huán)的條件是i<=8。

3.3.4賦值

????????

圖3-3-3-4:hello.s匯編代碼關(guān)于變量i賦值操作的部分

解析:通過使用mov指令,將立即數(shù)0直接賦值給變量i。

3.3.5算術(shù)操作

????????

圖3-3-5-1:hello.s匯編代碼關(guān)于棧指針%rsp算術(shù)操作的部分

解析:通過sub將棧指針%rsp減去立即數(shù)32,代表?xiàng)I暾?qǐng)32個(gè)字節(jié)的空間。

????????

圖3-3-5-2:hello.s匯編代碼關(guān)于棧指針%rsp算術(shù)操作的部分

解析:通過add可以將-4(%rbp)里面的值加是立即數(shù)1,即i=i+1。

3.3.6關(guān)系操作/控制轉(zhuǎn)移

????????

?????????????圖3-3-6-1 hello.s匯編代碼關(guān)于控制轉(zhuǎn)移if else的部分

解析:在-20(%rbp)保存的是第一個(gè)參數(shù)argc,通過cmpl操作將argc與4做比較,je指令可以根據(jù)上一步比較結(jié)果設(shè)置的條件碼狀態(tài)實(shí)現(xiàn)跳轉(zhuǎn)(關(guān)系操作!),若argc不等于4,則跳過25行的命令,從26行開始執(zhí)行if里面的內(nèi)容;若argc等于4,則跳轉(zhuǎn)到.L2處去執(zhí)行else部分的內(nèi)容,從而實(shí)現(xiàn)if else的控制轉(zhuǎn)移。

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

? ????????

圖3-3-6-2 hello.s匯編代碼關(guān)于控制轉(zhuǎn)移for循環(huán)的部分

解析:首先在.L2里面初始化i=0,然后通過jmp無條件跳轉(zhuǎn)到.L3,在.L3里面進(jìn)行for循環(huán)里面的條件判斷,通過cmpi8比較,然后通過jle實(shí)現(xiàn)條件跳轉(zhuǎn)(關(guān)系控制<=),若i<=8,則跳轉(zhuǎn)到.L4里面進(jìn)行for循環(huán)里面的操作,在.L4里面有一個(gè)add的操作,使得每次循環(huán)i++;若最后i>8了,則在.L3中不會(huì)跳轉(zhuǎn)到.L4,結(jié)束循環(huán),從而實(shí)現(xiàn)了一個(gè)完整的for循環(huán)的操作。

3.3.7數(shù)組/指針/結(jié)構(gòu)操作

????????

圖3-3-7:hello.s匯編代碼關(guān)于數(shù)組/指針操作argv的部分

解析:在之前談過,在-32%rbp)保存著一個(gè)數(shù)組指針argv,它指向一個(gè)字符串?dāng)?shù)組,其中argv[0]保存著命令行第一個(gè)參數(shù),一般是可執(zhí)行文件的名字這里是./helloargv[1],argv[2]則保存著我們輸入的倆個(gè)字符串,這里是我們的學(xué)號(hào)和姓名,char *8個(gè)字節(jié),將-32%rbp)加16就是argc[2]-32%rbp)加8就是argv[1],從而實(shí)現(xiàn)利用指針對(duì)數(shù)組argv[]的調(diào)用。

3.3.8函數(shù)操作

????????

圖3-3-8-1:hello.s中關(guān)于函數(shù)printf的調(diào)用部分

解析:printf是庫(kù)里面的一個(gè)函數(shù),在最后鏈接的時(shí)候內(nèi)容會(huì)復(fù)制進(jìn)去,參數(shù)傳遞:call puts時(shí)只輸入字符串參數(shù)首地址,for循環(huán)中call printf時(shí)輸入argv[1]和argc[2]的地址,函數(shù)調(diào)用:if判斷滿足條件后在for循環(huán)中被調(diào)用,調(diào)用之后會(huì)在屏幕是輸出我們想要的結(jié)果

????????

3-3-8-2hello.s關(guān)于函數(shù)exit的調(diào)用

解析:參數(shù)傳遞:輸入?yún)?shù)為1后再執(zhí)行退出命令,exit1)表示正常退出,exit0)表示非正常退出;函數(shù)調(diào)用:if判斷條件滿足后被調(diào)用;在調(diào)用之后程序就會(huì)結(jié)束進(jìn)程。

????????

圖3-3-8-3:hello.s關(guān)于函數(shù)sleep的調(diào)用

解析:參數(shù)傳遞:輸入?yún)?shù)atoi(argv[3]),函數(shù)調(diào)用:在for循環(huán)中被調(diào)用,call sleep;調(diào)用之后程序延遲。其中其中函數(shù)atoi()是把字符串轉(zhuǎn)換成整型數(shù)的一個(gè)函數(shù)。

????????

圖3-3-8-4:hello.s關(guān)于函數(shù)getchar的調(diào)用

解析:函數(shù)調(diào)用:在main中被調(diào)用,沒有參數(shù)傳遞,getchar()

????????

圖3-3-8-5:hello.s中關(guān)于main函數(shù)的調(diào)用。

解析:main是主函數(shù),有倆參數(shù)argc和argv先前已經(jīng)介紹過,在函數(shù)里面最后會(huì)return 0,來結(jié)束main函數(shù)。

3.4 本章小結(jié)

本章首先介紹了編譯的概念與作業(yè),然后介紹了在Ubuntu下編譯的命令,展示了hello.s的內(nèi)容,最后根據(jù)hello.s文件,詳細(xì)介紹了中編譯器是怎么處理C語言的各個(gè)數(shù)據(jù)類型以及各類操作的。

(第32分)

第4章 匯編

4.1 匯編的概念與作用

匯編的概念:

驅(qū)動(dòng)程序運(yùn)行匯編器as將匯編語言(hello.s)翻譯成機(jī)器語言(hello.o)的過程稱為匯編,同時(shí)這個(gè)機(jī)器語言文件是可重定位目標(biāo)文件。匯編器接受.s文件作為輸入,以.o可重定位目標(biāo)文件作為輸出。可重定位目標(biāo)文件包含二進(jìn)制代碼和數(shù)據(jù),在編譯時(shí)與其他可重定位目標(biāo)文件能夠合并起來,創(chuàng)建成一個(gè)可執(zhí)行目標(biāo)文件,從而被加載到內(nèi)存中執(zhí)行。

匯編的作用:

匯編是將高級(jí)語言轉(zhuǎn)化為機(jī)器可以直接識(shí)別并且執(zhí)行的代碼文件的過程,匯編器將.s文件匯編程序翻譯成機(jī)器語言指令,并將這些指令打包成為可重定位目標(biāo)程序的格式,最后將結(jié)果保留在.o目標(biāo)文件中,.o文件是一個(gè)包含程序指令編碼的二進(jìn)制文件。

4.2 在Ubuntu下匯編的命令

??? 命令:gcc -c hello.s -o hello.o

????????

????????????? 圖4-2:Ubuntu下匯編命令展示

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

4.3.1導(dǎo)出ELF文件

由于hello.o文件不能直接打開,因此我們需要輸入readelf -a hello.o > ./elf.txt將其轉(zhuǎn)換成elf文件后查看,如下圖:

???????????????????????????? 圖4-3-1:Ubuntu下導(dǎo)出elf文件展示

????

??????????????????? 圖4-3-1-1:elf文件展示

4.3.2 ELF

? ? ? ? ? ? ? ? ????????????????????? 圖4-3-2:ELF頭信息

解析:可以看見ELF以16個(gè)字節(jié)開頭,其中前4個(gè)字節(jié)稱為ELF的魔數(shù),分別與ASCll中的DEF控制符、字符E、字符L、字符F對(duì)應(yīng),這4個(gè)字節(jié)是用來確認(rèn)文件類型的。接下來一個(gè)字節(jié)是用來表示ELF文件類型的,0x1表示32位,0x2表示64位。第六個(gè)字節(jié)用來表示字節(jié)序,0x1表示小段,0x2表示大端。第7個(gè)字節(jié)表示ELF的版本號(hào),一般為1。剩下的字節(jié)在ELF標(biāo)準(zhǔn)中沒有定義用0填充。16個(gè)字節(jié)下面也給出了文件的類別,字節(jié)序,ELF文件類型,版本號(hào),在第11行還給出了這個(gè)ELF的起始地址,在15行還給出了ELF頭的長(zhǎng)度為64個(gè)字節(jié),13行給出了節(jié)頭部表的起始位置是1240,19行說明了節(jié)頭部表里面有14個(gè)表項(xiàng),18行說明了每一個(gè)表項(xiàng)的大小是64個(gè)字節(jié)。

4.3.3節(jié)頭部表:

???????? ? ? ? ? ? ? ? ??? ? ? ? ? ? ? ? ? ? ? 圖4-3-3:節(jié)頭部表信息

解析:上面分析過里面會(huì)有13個(gè)表項(xiàng)即13個(gè)節(jié),頭節(jié)目表描述了.o文件中出現(xiàn)的各個(gè)節(jié)的類型、位置、所占空間大小等必要有效信息。如上圖所示,其屬性分別有名稱、類型、地址(此時(shí)暫時(shí)未被分配均為0)、偏移量(節(jié)相對(duì)于文件開始的偏移)、節(jié)大小、全體(Entry)大小、旗標(biāo)(節(jié)屬性)、鏈接(與其他節(jié)的)、信息(附加節(jié))、對(duì)齊(2Align次方)。以第一個(gè)表項(xiàng)為例,它的名稱是.test,位置在0x40,大小是146個(gè)字節(jié)(0x92)。

4.3.4重定位節(jié)

? ????????????????? 4-3-4重定位節(jié)信

解析:當(dāng)匯編器生成一個(gè)目標(biāo)模塊時(shí),它并不知道數(shù)據(jù)和代碼最終將放在內(nèi)存中的什么位置。它也不知道這個(gè)模塊引用的任何外部定義的函數(shù)或者全局變量的位置。所以,無論何時(shí)匯編器遇到最終未知的目標(biāo)引用,它就會(huì)生成一個(gè)重定位條目,告訴鏈接器在將目標(biāo)文件合并到可執(zhí)行文件時(shí)如何修改新的引用。在重定位節(jié)中包含了在代碼中使用的一些外部變量等信息,在鏈接的時(shí)候需要根據(jù)重定位節(jié)的信息對(duì)這些變量符號(hào)進(jìn)行修改。本程序需要重定位的信息有:.rodata中的模式串,putsexitprintfslepsecssleepgetchar這些符號(hào)需要與相應(yīng)的地址進(jìn)行重定位這些符號(hào)的相關(guān)信息偏移量如上圖。

4.3.5符號(hào)表

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ??4-3-5:符號(hào)表信息

解析:在符號(hào)表中存放了所有引用的函數(shù)和全局變量的信息。Num為某個(gè)符號(hào)的編號(hào),value表示符號(hào)在對(duì)應(yīng)節(jié)中的偏移量,size是所占字節(jié)數(shù),type是符號(hào)的類型,Bind表示這個(gè)符號(hào)是本地的還是全局的,VisC語言中并未使用可以忽略,Ndxsection的索引值, Name是符號(hào)的名稱。這里我們發(fā)現(xiàn)main這個(gè)符號(hào)為例,它的Ndx1,說明它的定義在./test節(jié)中(之前節(jié)頭部表可以看節(jié)的索引值),BindGLOBAL說明是一個(gè)全局變量,TypeFUNC說明main是一個(gè)函數(shù),size146,說明它在./test節(jié)中占146個(gè)字節(jié),value0,說明它偏移量為0,就在./test最上面

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

4.4.1生成反匯編文件

命令為:objdump -d -r hello.o > objdump_hello.s

???????? ? ? ? ? ? ????????????????? 圖4-4-1-0:Ubuntu下生成反匯編文件展示

????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖4-4-1-1:hello反匯編生成的objdump_hello.s

4.4.2對(duì)比與分析:

(1)操作數(shù)變化

hello.s中的操作數(shù)一般是十進(jìn)制表示的,而objdump_hello.s中的操作數(shù)一般是十六進(jìn)制表示的,如下圖:

????????

??圖4-4-2-1:hello.s中立即數(shù)操作數(shù)展示

????????

???????? 圖4-4-2-2:objdump_hello.s中立即數(shù)操作數(shù)展示

(2)跳轉(zhuǎn)指令變化

hello.s中地址使用段名稱如 je .L2,而objdump_hello.s中則使用相對(duì)偏移地址,如je? 2f <main+0x2f>,如下圖:

? ????????

??? 圖4-4-2-3:hello.s中跳轉(zhuǎn)指令展示

????????

??? 圖4-4-2-4:objdump_hello.s中跳轉(zhuǎn)指令展示

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

在hello.s中,call的后面緊跟著函數(shù)名,而在objdump_hello.s中,call的后面緊跟著下一條指令的地址。這是因?yàn)樵摮绦蛘{(diào)用的函數(shù)是共享庫(kù)中的函數(shù),最終需要通過動(dòng)態(tài)鏈接器才能確定函數(shù)的運(yùn)行時(shí)執(zhí)行地址。對(duì)于這一類函數(shù)調(diào)用,call指令中的相對(duì)偏移量暫時(shí)編碼為全0,然后在.rela.text節(jié)添加重定位條目,等待鏈接時(shí)的進(jìn)一步確定。如下圖所示:

????????? ? ? ? ? ? ? ? ?圖4-4-2-5:objdump_hello.s函數(shù)調(diào)用展示

???????? ? ? ? ? ? ? ? ?圖4-4-2-6:hello.s函數(shù)調(diào)用展示

(4)數(shù)據(jù)訪問變化

在hello.s 文件中,使用段名稱+%rip訪問 rodata(printf 中的字符串),而在反匯編得到的hello.asm中,使用 0+%rip進(jìn)行訪問。其原因與函數(shù)調(diào)用類似,rodata 中數(shù)據(jù)地址在運(yùn)行時(shí)才能確定,故訪問時(shí)也需要重定位。在匯編成為機(jī)器語言時(shí),將操作數(shù)設(shè)置為全 0 并添加相應(yīng)的重定位條目,如下圖所示:

???????? ? ? ? ?? ? ? ? ? ? ? ? 圖4-4-2-7:hello.s中數(shù)據(jù)訪問的變化

??????????????????????? 圖4-4-2-8:objdump_hello.s中數(shù)據(jù)訪問的變化

4.4.3機(jī)器語言與匯編語言:

發(fā)現(xiàn)hello.o的反匯編文件objdump_hello.s與hello.s匯編代碼基本是一致的,但是在這反匯編文件的字里行間中,也混雜著一些我們相對(duì)陌生的面孔,也就是機(jī)器代碼。這些機(jī)器代碼是二進(jìn)制機(jī)器指令的集合,每一條機(jī)器代碼都對(duì)應(yīng)一條機(jī)器指令,到這才是機(jī)器真正能識(shí)別的語言。每一條匯編語言都可以用機(jī)器二進(jìn)制數(shù)據(jù)來表示,匯編語言中的操作碼和操作數(shù)以一種相當(dāng)于映射的方式和機(jī)器語言進(jìn)行對(duì)應(yīng),從而讓機(jī)器能夠真正理解代碼的含義并且執(zhí)行相應(yīng)的功能。總之匯編語言能與機(jī)器碼建立一一對(duì)應(yīng)的關(guān)系。

4.5 本章小結(jié)

本章首先介紹了匯編的概念和作用,然后給出了在Ubuntu下啟動(dòng)匯編的指令,以及如何導(dǎo)出ELF文件。然后詳細(xì)的分析了ELF文件里面的內(nèi)容,對(duì)ELF頭、頭部表、重定向節(jié)、符號(hào)表的內(nèi)容做了詳細(xì)的解釋,然后利用objdump反匯編hello.o將反匯編文件objdump_hello.s與原匯編文件hello.s做比較,分析了倆者的異同點(diǎn),最后分析了機(jī)器語言與匯編語言的關(guān)系。

(第41分)

第5章 鏈接

5.1 鏈接的概念與作用

鏈接的概念:

鏈接是指將多種不同重定位目標(biāo)文件或靜態(tài)/動(dòng)態(tài)庫(kù)的代碼和數(shù)據(jù)部分收集整合起來,修改符號(hào)引用,組合并且輸出成一個(gè)單一可執(zhí)行目標(biāo)文件的過程。?

鏈接的作用:

鏈接能夠節(jié)省源程序空間,同時(shí)對(duì)于未編入的常用函數(shù)文件能夠進(jìn)行合并從而生成能夠正常工作的可執(zhí)行目標(biāo)文件。除此之外鏈接也可以表述為使得一個(gè)復(fù)雜程序被分解成諸多簡(jiǎn)明模塊來進(jìn)行編寫,并且最終被合并為一個(gè)可執(zhí)行程序。這些作用使得分離編譯成為了一種可能。

5.2 在Ubuntu下鏈接的命令

命令: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:Ubuntu下匯編命令展示

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

5.3.1導(dǎo)出hello的ELF文件

命令: readelf -a hello > ./hello_elf.txt

???????? ? ? ? ? ? ? ?????????????? 圖5-3-1:導(dǎo)出hello的ELF文件

5.3.2 ELF頭

????????

??????????????? 圖5-3-2:hello的ELF頭內(nèi)容

解析:與之前分析hello.o的過程類似,不過注意到第8行的類型變?yōu)榱薊XEC即可執(zhí)行文件,同時(shí)發(fā)現(xiàn)ELF頭的地址變了,變?yōu)榱?x4010f0,這是因?yàn)樗鼈冃枰囟ㄎ坏阶罱K運(yùn)行時(shí)的內(nèi)存地址,section也變多了變?yōu)榱?7個(gè),還多了一個(gè)program headers程序頭部表。

5.3.3節(jié)頭

?????????????????????????? 圖5-3:節(jié)頭內(nèi)容展示

解析:節(jié)頭的內(nèi)容分析和之前一樣,唯一的區(qū)別一個(gè)就是節(jié)的數(shù)量多了,由原來的14個(gè)變成了現(xiàn)在的27個(gè),多出來的節(jié)如下:

節(jié)

主要作用

.interp:

包含了動(dòng)態(tài)鏈接器在文件系統(tǒng)中的路徑;

.note???? .ABI-tag:

ELF規(guī)范中記錄的注釋部分,包含一些版本信息;

.gnu???? .hash:

符號(hào)的哈希表,用于加速查找符號(hào);

.dynamic??? .dynsym??? .dynstr:

與動(dòng)態(tài)鏈接符號(hào)相關(guān);

.gnu.version?? .gnu.version_r:

與版本有關(guān)的信息;

.init_array?? .fini_array:

存放函數(shù)指針,其中的函數(shù)分別在main函數(shù)

之前之后調(diào)用,用于初始化和收尾;

.init??? .fini:

存放上述初始化和收尾的代碼

.eh_frame_hdr

與異常處理相關(guān)。

?????????????????? 表5-3-3-1:多出的節(jié)主要功能展示

5.3.4程序頭

??????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖5-3-4程序頭展示

解析:?elf可執(zhí)行文件易加載到內(nèi)存,可執(zhí)行文件連續(xù)的片被映射到連續(xù)的內(nèi)存段,程序頭部表描述了這一映射關(guān)系。程序頭部表包括各程序頭的偏移量、內(nèi)存地址、對(duì)其要求、目標(biāo)文件與內(nèi)存中的段大小及運(yùn)行時(shí)訪問權(quán)限等信息。

5.3.5段節(jié)

???????????????????????????? 圖5-3-5:段節(jié)展示

解析:如圖所示的節(jié)段映射,說明了在鏈接過程中,將多個(gè)代碼段與數(shù)據(jù)段分別合并成一個(gè)單獨(dú)的代碼段和數(shù)據(jù)段,并根據(jù)段的大小以及偏移量重新設(shè)置各個(gè)符號(hào)的地址。

5.3.6重定位節(jié)

????????????????????????? 圖5-3-6:重定位節(jié)展示

解析:分析過程與之前類似,由于對(duì)于可執(zhí)行目標(biāo)文件來說,仍然會(huì)存在重定位信息,因?yàn)橛行┬枰獎(jiǎng)討B(tài)鏈接的塊還沒有被鏈接,重定位節(jié)中就給出了這些符號(hào)的相關(guān)信息。

5.3.7符號(hào)表

?? ? ? ? ? ? ? ? ??? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖5-3-7:符號(hào)表內(nèi)容

解析:對(duì)于可執(zhí)行目標(biāo)文件來說,包含兩個(gè)符號(hào)表,一個(gè)符號(hào)表的名稱為.dynsym, 從名稱和符號(hào)表中的內(nèi)容來看應(yīng)該是還沒有動(dòng)態(tài)鏈接的一些未知符號(hào)。另一張符 號(hào)表就是熟知的.symtab,里面保存了程序中定義和引用的函數(shù)以及全局變量等的 信息,其余分析與之前類似。

5.3.8版本信息

??????????????????????????????? 圖5-3-8:關(guān)于版本信息的節(jié)

解析:這部分不重要,只是介紹版本信息而已。

5.4 hello的虛擬地址空間

???????? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? ? ? ? ? ? ? ? ? ? ? 圖5-4-1:Date Dump窗口

解析:打開edb,加載程序后,打開edb的Date Dump窗口,查看本進(jìn)程的虛擬地址空間各段信息,并與5.3對(duì)照分析說明。通過查看edb可以發(fā)現(xiàn)虛擬地址開始于0x400000,如上圖所示。

??????? ? ? ? ? ? ? ? ? ???????????????????????? 圖5-4-2:Date Dump窗口

解析:根據(jù)查看的信息我們發(fā)現(xiàn)虛擬地址結(jié)束于0x400ff0

然后根據(jù)節(jié)頭目表,我們可以通過edb查看各個(gè)節(jié)的信息,比如.text節(jié),虛擬地址起始于0x4010f0,大小為0x145,如下圖所示:

???????? ? ? ? ? ? ??????????????????? 圖5-4-3:Data Dump尋找./test節(jié)部分

同理我們還可以同樣找到其他節(jié)在虛擬地址空間例的信息

5.5 鏈接的重定位過程分析

5.5.1生成hello的反匯編文件

命令:objdump -d -r hello > hello_objdump.s ??如圖:

??????????????????????????? 圖5-5-1:生成hello的反匯編文件

5.5.2 hello與hello.o反匯編文件的差異:

(1)代碼增多

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

??圖5-5-2-1:hello.o反匯編內(nèi)容 ???????????圖5-5-2-2:hello反匯編內(nèi)容

解析:可以看出來hello反匯編多了很多代碼,接下來我會(huì)慢慢介紹為什么會(huì)多出這些代碼

(2)增加了外部的共享庫(kù)函數(shù)

???????????????????? 圖5-5-2-3:hello反匯編代碼關(guān)于共享庫(kù)的部分

解析:在鏈接之后,鏈接器會(huì)把共享庫(kù)里面被hello.o里面調(diào)用的函數(shù)復(fù)制進(jìn)去,所以代碼增加了不少

(3)函數(shù)調(diào)用地址不同

???????????????????? 圖5-5-2-4:hello.o反匯編文件函數(shù)調(diào)用部分

????????? ? ? ? ? ? ?圖5-5-2-5:hello反匯編文件函數(shù)調(diào)用部分

分析:hello中沒有hello.o中的重定位條目,并且跳轉(zhuǎn)和函數(shù)調(diào)用的地址在hello中都變成了虛擬內(nèi)存空間地址。對(duì)于hello.o的反匯編代碼,函數(shù)只有在鏈接之后才能確定運(yùn)行執(zhí)行的地址,所以在.rela.text節(jié)中為其添加了重定位條目。所以在hello.o文件中,函數(shù)的調(diào)用時(shí)直接用當(dāng)前的下一個(gè)地址占位,而在hello文件中是跳轉(zhuǎn)到一個(gè)【函數(shù)名@plt】的函數(shù)的地址處。

(4).text段的內(nèi)容增多了

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

? 圖5-5-2-6:hello.o反匯編./test部分 ???????圖5-5-2-7:hello反匯編./test部分

分析:發(fā)現(xiàn)左方的.text段只有main函數(shù),右方的.text段不僅包含.main,更包含main函數(shù)的很多入口函數(shù),如_start之類,所以./test變長(zhǎng)了很多。

5.5.3 鏈接的過程:

通過分析hello和hello.o的不同之處,得到鏈接的主要過程就是鏈接就是鏈接器ld將各個(gè)目標(biāo)文件(即各種.o文件)整合組裝在一起時(shí)其各個(gè)目標(biāo)文件中的各個(gè)庫(kù)函數(shù)段會(huì)按照一定的規(guī)則累積在一起,需要進(jìn)行符號(hào)解析、重定位及計(jì)算符號(hào)引用地址三個(gè)步驟。

5.5.4重定位:

重定位將合并輸入模塊。并為每個(gè)符號(hào)分配運(yùn)行地址。重定位由兩個(gè)步驟組成:重定位節(jié)與符號(hào)定義、重定位節(jié)中的符號(hào)引用。

1.定位節(jié)與符號(hào)定義,鏈接器將相同類型的節(jié)合并為同一類型的新的聚合節(jié),此后鏈接器將運(yùn)行時(shí)內(nèi)存地址賦值新的聚合節(jié)、輸入模塊定義的每個(gè)節(jié),還有輸入模塊定義的每個(gè)符號(hào)。

2.重定位節(jié)中的符號(hào)引用,鏈接器修改代碼節(jié)與數(shù)據(jù)節(jié)中對(duì)每個(gè)符號(hào)的引用,使他們指向正確的運(yùn)行地址,這一步依賴hello.o中的重定位條目。

5.6 hello的執(zhí)行流程

??????????????????????? 圖5-6:Ubuntu下edb執(zhí)行

通過edb的調(diào)試記錄下每列函數(shù)調(diào)用call命令進(jìn)入的函數(shù)如下所示:

這其中的子函數(shù)名和地址(后6位)如下所示:

<_init>????? 401000

<.plt>?????? 401020

<puts@plt>? 401090

<printf@plt> 4010a0

<getchar@plt>4010b0

<atoi@plt>? 4010c0

<exit@plt>? 4010d0

<sleep@plt> 4010e0

<_start>???? 4010f0

<_dl_relocate_static_pie> 401120

<main>?????????????? 401125

<__libc_csu_init>?????? 4011c0

<__libc_csu_fini>?????? 401230

<_fini>??????????????? 401238

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

???????? ?? ? ? ? ? ? ? ? ?圖5-7-1:hello的節(jié)頭部表

分析:elf文件中我們可以找到got pit開頭地址為0x404000,edb中找到它

????????????????????????? 圖5-7-2:dl_init之前窗口

dl_init之后

???????? ? ? ? ? ? ? ? ? ? 圖5-7-3:dl_init之后窗口

分析:找到的地址已經(jīng)由0變成了相應(yīng)的偏移量

5.8 本章小結(jié)

在本章中先介紹了鏈接的概念和作用,還介紹了然后在Ubuntu下利用ld命令實(shí)現(xiàn)鏈接,然后導(dǎo)出helloELF文件,分析該ELF文件里面的具體內(nèi)容,并與hello.oELF做對(duì)比,分析異同,然后分析了hello的虛擬地址空間、重定位過程、執(zhí)行流程、以及動(dòng)態(tài)鏈接過程。

(第51分)

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

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

進(jìn)程的概念:

經(jīng)典定義是一個(gè)執(zhí)行中程序的實(shí)例,提供給我們一種錯(cuò)覺:我們的程序好像是系統(tǒng)中當(dāng)前運(yùn)行的唯一程序,我們的程序獨(dú)占使用處理器和內(nèi)存,處理器好像是無間斷的執(zhí)行我們程序中的指令,我們程序的代碼和數(shù)據(jù)好像是系統(tǒng)中內(nèi)存唯一的對(duì)象。

進(jìn)程的作用:

進(jìn)程提供給了應(yīng)用程序兩個(gè)關(guān)鍵抽象

一個(gè)獨(dú)立的邏輯控制流,它提供一個(gè)假象,好像我們的程序獨(dú)占地使用處理器。

一個(gè)私有的地址空間,它提供一個(gè)假象,好像我們的程序獨(dú)占地使用內(nèi)存系統(tǒng)。

6.2 簡(jiǎn)述殼Shell-bash的作用與處理流程

作用:Shell執(zhí)行一系列的讀取解析步驟,然后終止。讀取步驟讀取來自用戶的一個(gè)命令行。解析步驟將命令行解析,并運(yùn)行程序。

處理流程:

(1)終端進(jìn)程讀取用戶由鍵盤輸入的命令行。

(2)分析命令行字符串,獲取命令行參數(shù),并構(gòu)造傳遞給execve的argv向量

(3)檢查第一個(gè)(首個(gè)、第0個(gè))命令行參數(shù)是否是一個(gè)內(nèi)置的shell命令

(4)如果不是內(nèi)部命令,調(diào)用fork( )創(chuàng)建新進(jìn)程/子進(jìn)程

(5)在子進(jìn)程中,用步驟2獲取的參數(shù),調(diào)用execve( )執(zhí)行指定程序。

(6)如果用戶沒要求后臺(tái)運(yùn)行(命令末尾沒有&號(hào))否則shell使用waitpid(或wait等待作業(yè)終止后返回。

(7)如果用戶要求后臺(tái)運(yùn)行(如果命令末尾有&號(hào)),則shell返回;

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

根據(jù) shell 的處理流程,可以推斷,輸入命令執(zhí)行 hello 后,父進(jìn)程如果判斷不是內(nèi)部指令,即會(huì)通過fork函數(shù)創(chuàng)建子進(jìn)程。子進(jìn)程與父進(jìn)程近似,并得到一份與父進(jìn)程用戶級(jí)虛擬空間相同且獨(dú)立的副本——包括數(shù)據(jù)段、代碼、共享庫(kù)、堆和用戶棧。父進(jìn)程打開的文件,子進(jìn)程也可讀寫。二者之間最大的不同或許在于 PID 的不同。Fork函數(shù)只會(huì)被調(diào)用一次,但會(huì)返回兩次,在父進(jìn)程中,fork返回子進(jìn)程的 PID,在子進(jìn)程中,fork返回0。

6.4 Hello的execve過程

當(dāng)Hello的進(jìn)程被創(chuàng)建之后,他會(huì)調(diào)用execve函數(shù)加載并調(diào)用程序。exevce函數(shù)在被調(diào)用時(shí)會(huì)在當(dāng)前進(jìn)程的上下文中加載并運(yùn)行一個(gè)新程序。它被調(diào)用一次從不返回,執(zhí)行過程如下:

1.刪除已存在的用戶區(qū)域

2.映射私有區(qū):為 hello 的代碼、數(shù)據(jù)、.bss 和棧區(qū)域創(chuàng)建新的區(qū)域結(jié)構(gòu),所有這些區(qū)域都是私有的、寫時(shí)才復(fù)制的

3.映射共享區(qū):比如 hello 程序與共享庫(kù) libc.so 鏈接

4.設(shè)置 PC:exceve() 做的最后一件事就是設(shè)置當(dāng)前進(jìn)程的上下文中的程序計(jì)數(shù)器,使之指向代碼區(qū)域的入口點(diǎn)

5.execve() 在調(diào)用成功的情況下不會(huì)返回,只有當(dāng)出現(xiàn)錯(cuò)誤時(shí),例如找不到需要執(zhí)行的程序時(shí),execve() 才會(huì)返回到調(diào)用程序

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

6.5.1邏輯控制流:

一系列程序計(jì)數(shù)器PC的值的序列叫做邏輯控制流,這些值唯一地對(duì)應(yīng)于包含在程序的可執(zhí)行目標(biāo)文件中的指令,或是包含在運(yùn)行時(shí)動(dòng)態(tài)鏈接到程序的共享對(duì)象中的指令。各個(gè)進(jìn)程將輪流使用處理器,在同一個(gè)處理器核心中,每個(gè)進(jìn)程執(zhí)行它的流的一部分后被暫時(shí)掛起,然后執(zhí)行其他進(jìn)程。

6.5.2用戶模式與內(nèi)核模式:

處理器通過某個(gè)控制寄存器中的一個(gè)模式位來提供限制一個(gè)應(yīng)用可以執(zhí)行的指令以及它可以訪問的地址空間范圍的功能。該寄存器描述了當(dāng)前進(jìn)程運(yùn)行的權(quán)限。當(dāng)設(shè)置了模式位時(shí),進(jìn)程就運(yùn)行在內(nèi)核模式中。沒有設(shè)置模式位時(shí),進(jìn)程就運(yùn)行在用戶模式中。一個(gè)運(yùn)行在內(nèi)核模式的進(jìn)程可以執(zhí)行指令集中的任何指令,并且可以訪問系統(tǒng)中的任何內(nèi)存;而用戶模式的進(jìn)程不允許和執(zhí)行特權(quán)指令、也不允許用戶模式中的進(jìn)程直接引用地址空間中內(nèi)核區(qū)內(nèi)的代碼和數(shù)據(jù)。

6.5.3上下文切換:

內(nèi)核為每個(gè)進(jìn)程維持一個(gè)上下文。上下文就是內(nèi)核重新啟動(dòng)的一個(gè)進(jìn)程所需的狀態(tài)。這個(gè)狀態(tài)包括通用目的寄存器、浮點(diǎn)寄存器、程序計(jì)數(shù)器、用戶棧、狀態(tài)寄存器、內(nèi)核棧和各種內(nèi)核數(shù)據(jù)結(jié)構(gòu)。

6.5.4進(jìn)程時(shí)間片:

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

6.5.5調(diào)度的過程:

在進(jìn)程執(zhí)行的某些時(shí)刻,內(nèi)核可以決定搶占當(dāng)前進(jìn)程,并且可以重新開始一個(gè)先前被搶占了的進(jìn)程,這種決策便稱為調(diào)度。調(diào)度是由內(nèi)核中的調(diào)度器代碼處理的。當(dāng)內(nèi)核選擇一個(gè)新進(jìn)程運(yùn)行時(shí),即內(nèi)核調(diào)度了這個(gè)進(jìn)程。在內(nèi)核調(diào)度一個(gè)新的進(jìn)程運(yùn)行之后,它就可以稱之為搶占了當(dāng)前進(jìn)程,并使用上下文切換機(jī)制來將控制轉(zhuǎn)移到新的進(jìn)程。例如執(zhí)行sleep()函數(shù),sleep()函數(shù)請(qǐng)求調(diào)用休眠進(jìn)程,sleep()將內(nèi)核搶占,進(jìn)入倒計(jì)時(shí),當(dāng)?shù)褂?jì)時(shí)結(jié)束后,hello程序重新?lián)屨純?nèi)核,繼續(xù)執(zhí)行。

6.5.6? 用戶模式與核心模式的相互轉(zhuǎn)換:

為了能讓處理器安全運(yùn)行,從而不至于損壞操作系統(tǒng),必須提前已知應(yīng)用程序可執(zhí)行指令所能訪問的地址空間范圍。因此就存在用戶模式與核心模式的劃分:核心模式可以戲稱為“創(chuàng)世模式”,因?yàn)樗鼡碛凶罡咴L問權(quán)限,此時(shí)處理器有以一個(gè)寄存器當(dāng)做模式位來描述當(dāng)前進(jìn)程的特權(quán)。進(jìn)程只有故障、中斷或陷入系統(tǒng)調(diào)用時(shí)才會(huì)得到內(nèi)核訪問權(quán)限,其他情況下始終處于用戶權(quán)限之中,從而保證了系統(tǒng)的安全性。

6.6 hello的異常與信號(hào)處理

6.6.1異常的種類:

類別

原因

異步/同步

返回行為

中斷

來自I/O設(shè)備的信號(hào)

異步

總是返回到下一條指令

陷阱

有意的異常

同步

總是返回到下一條指令

故障

潛在可恢復(fù)的錯(cuò)誤

同步

可能返回到當(dāng)前指令

終止

不可恢復(fù)的錯(cuò)誤

同步

不會(huì)返回

?????????????????????? 表6-6-1:異常的種類

6.6.2產(chǎn)生信號(hào):

信號(hào)可以被理解為一條小消息,他通知進(jìn)程系統(tǒng)中發(fā)生了一個(gè)某種類型的事件。每種信號(hào)類型都對(duì)應(yīng)于某種系統(tǒng)事件,它提供了一種機(jī)制,通知用戶進(jìn)程發(fā)生了這些異常。發(fā)生異常后,系統(tǒng)會(huì)根據(jù)異常的種類發(fā)出信號(hào),每個(gè)信號(hào)都有對(duì)應(yīng)的序號(hào)。如下圖:

???????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???????????????? 圖6-6-2 Linux信號(hào)

6.2.3執(zhí)行過程中操作實(shí)例:

正常執(zhí)行:

??????????????????????????????? 圖6-2-3-1:正常執(zhí)行

在運(yùn)行過程中按下Ctrl-Z

??????????????????????????????? 圖6-2-3-2:按下Ctrl-Z

按下Ctrl-Z后接其他指令:

??????????????????????? 圖6-2-3-3:按下Ctrl-Z+ps

分析:分析進(jìn)程仍然處于后臺(tái)。

再按下jobs

????????

? ? ? ? ? ? ? 圖6-2-3-4:按下jobs

結(jié)果:進(jìn)程停止。

按下fg

?

? ? ? ? ? ? ? ? ? ? 圖6-2-3-5:按下fg

結(jié)果:使該進(jìn)程轉(zhuǎn)為前臺(tái),繼續(xù)工作

按下kill

????????

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖6-2-3-6:按下kill

結(jié)果:殺死進(jìn)程。

按下pstree

???????? ? ? ? ? ? ? ? ? ???? 圖6-2-3-7:按下pstree

6.2.4異常與信號(hào)處理說明:

當(dāng)按下鍵盤的時(shí)候, 引發(fā)了中斷異常.如圖:

????????

???????????????????????? 圖6-2-4-1中斷異常實(shí)例

而當(dāng)程序在進(jìn)行顯示屏輸出的時(shí)候:

引發(fā)的是陷阱:

????????

???????????????????? 圖6-2-4-1中斷異常實(shí)例

通過陷阱,調(diào)用系統(tǒng)函數(shù).將字符串打印到屏幕上面

信號(hào)處理:

對(duì)于kill -9 12350:直接將SIGKILL發(fā)送到12350進(jìn)程,使其直接終止.

對(duì)于CTRL Z:將SIGINT/SIGSTP由內(nèi)核發(fā)送到12350號(hào)進(jìn)程.SIGINT直接終止12350.而SIGSTP將12350號(hào)進(jìn)程進(jìn)行停止與掛起.

6.7本章小結(jié)

本章介紹了進(jìn)程的相關(guān)概念和作用,了解了shell的處理過程,以及如何利用fork創(chuàng)建子進(jìn)程,介紹了進(jìn)程調(diào)度和內(nèi)核用戶模式切換,好介紹了4種異常和各種信號(hào),最后根據(jù)實(shí)際操作進(jìn)行分析。

(第61分)

第7章 hello的存儲(chǔ)管理

7.1 hello的存儲(chǔ)器地址空間

結(jié)合hello說明邏輯地址、線性地址、虛擬地址、物理地址的概念。

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

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

7.4 TLB與四級(jí)頁(yè)表支持下的VA到PA的變換

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

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

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

7.8 缺頁(yè)故障與缺頁(yè)中斷處理

7.9動(dòng)態(tài)存儲(chǔ)分配管理

Printf會(huì)調(diào)用malloc,請(qǐng)簡(jiǎn)述動(dòng)態(tài)內(nèi)存管理的基本方法與策略。

7.10本章小結(jié)

第8章 hello的IO管理

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

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

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

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

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

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

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

字符顯示驅(qū)動(dòng)子程序:從ASCII到字模庫(kù)到顯示vram(存儲(chǔ)每一個(gè)點(diǎn)的RGB顏色信息)。

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

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

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

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

8.5本章小結(jié)

結(jié)論

Hello程序自被編寫出代碼起,經(jīng)歷了以下幾個(gè)階段:

首先經(jīng)過預(yù)處理解析宏定義、文件包含、條件編譯等,生成hello.i文件,然后編譯器將代碼轉(zhuǎn)化為匯編代碼,生成hello.s文件,然后將匯編語言轉(zhuǎn)換為機(jī)器語言,生成hello.o文件,然后鏈接器進(jìn)行重定位動(dòng)態(tài)解析等一系列操作,最終生成hello的可執(zhí)行文件。然后父進(jìn)程shell-bash進(jìn)程調(diào)用fork函數(shù),為hello創(chuàng)建進(jìn)程,調(diào)用execve函數(shù)在當(dāng)前進(jìn)程的上下文加載并運(yùn)行hello程序,該進(jìn)程映射它的虛擬空間到文件,運(yùn)行的過程當(dāng)中伴隨著虛擬地址到物理地址的轉(zhuǎn)換,調(diào)用的函數(shù)與I/O設(shè)備緊密結(jié)合。運(yùn)行結(jié)束后,子進(jìn)程終止,最終被父進(jìn)程回收。至此,hello程序結(jié)束了自己的一次運(yùn)行。

一學(xué)期的計(jì)算機(jī)系統(tǒng)學(xué)習(xí),雖然很累,不過收獲真的很大,感謝一學(xué)期老師和助教的辛苦付出!

(結(jié)論0分,缺失 -1分,根據(jù)內(nèi)容酌情加分)

附件

列出所有的中間產(chǎn)物的文件名,并予以說明起作用。

hello.c:源程序

hello.i:經(jīng)過預(yù)處理過后的文件;

hello.s:經(jīng)過編譯生成的匯編文件;

hello.o:匯編生成的可重定位的文件;

hello:通過鏈接產(chǎn)生的可執(zhí)行目標(biāo)文件二進(jìn)制文件;

elf.txt: 可重定位目標(biāo)文件hello.o導(dǎo)出的ELF文件;

hello_elf.txt:可執(zhí)行文件hello導(dǎo)出的ELF文件;

objdump_hello.s:可重定位目標(biāo)文件hello.o反匯編生成的文件

hello_objdump.s:可執(zhí)行文件hello反匯編生成的文件

(附件0分,缺失 -1分)

參考文獻(xiàn)

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

[1]?Randal E.Bryant, David O'Hallaron. 深入理解計(jì)算機(jī)系統(tǒng)[M]. 機(jī)械工業(yè)出版社.2019.6

[2] shell解析命令行的過程以及eval命令https://www.cnblogs.com/f-ck-need-u/p/7426371.html

[3]?printf?函數(shù)實(shí)現(xiàn)的深入剖析?https://www.cnblogs.com/pianist/p/3315801.html

[4]老師上課講的PPT

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

總結(jié)

以上是生活随笔為你收集整理的程序人生-Hello’s P2P的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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