本文跟隨hello程序從源文件經(jīng)由預(yù)處理岳锁,編譯监嗜,匯編,鏈接成為可執(zhí)行文件环鲤,再到在shell中加載hello程序的進(jìn)程過程,分析hello程序的內(nèi)存管理以及Linux I/O接口實(shí)現(xiàn)的函數(shù)憎兽。
關(guān)鍵詞:預(yù)處理冷离;編譯;匯編纯命;鏈接西剥;進(jìn)程創(chuàng)建;信號與異常處理亿汞;地址訪問瞭空;內(nèi)存映射???????????????????????????
(摘要0分,缺失-1分疗我,根據(jù)內(nèi)容精彩稱都酌情加分0-1分)
?
?
?
?
?
?
?
目? 錄
?
6.2簡述殼Shell-bash的作用與處理流程........................................................ - 10 -
7.2 Intel邏輯地址到線性地址的變換-段式管理............................................... - 11 -
7.3 Hello的線性地址到物理地址的變換-頁式管理.......................................... - 11 -
7.4 TLB與四級頁表支持下的VA到PA的變換................................................ - 11 -
7.5三級Cache支持下的物理內(nèi)存訪問............................................................. - 11 -
7.8缺頁故障與缺頁中斷處理.............................................................................. - 11 -
?
第1章 概述
1.1 Hello簡介
?????? P2P過程:hello.c經(jīng)過預(yù)處理->編譯->匯編->鏈接生成一個(gè)hello的二進(jìn)制可執(zhí)行文件咆畏,然后由shell新建一個(gè)進(jìn)程給他執(zhí)行。
020過程:shell執(zhí)行./hello碍粥,為其映射出虛擬內(nèi)存鳖眼,然后在開始運(yùn)行進(jìn)程的時(shí)候分配并載入物理內(nèi)存黑毅,開始執(zhí)行hello的程序嚼摩,將輸出的東西顯示到屏幕,然后hello進(jìn)程結(jié)束矿瘦,shell回收內(nèi)存空間枕面。
根據(jù)Hello的自白,利用計(jì)算機(jī)系統(tǒng)的術(shù)語缚去,簡述Hello的P2P潮秘,020的整個(gè)過程。
1.2 環(huán)境與工具
硬件環(huán)境X64 CPU易结;2GHz枕荞;2G RAM;256GHD Disk 搞动;
軟件環(huán)境Windows10家庭版 64位以上躏精;VMware Workstation
15 Player;Ubuntu 18.04 LTS 64位
開發(fā)與調(diào)試工具texteditor gdb edb objdump
列出你為編寫本論文鹦肿,折騰Hello的整個(gè)過程中矗烛,使用的軟硬件環(huán)境,以及開發(fā)與調(diào)試工具箩溃。
hello.i 預(yù)處理后的文本文件瞭吃,加載了頭文件
hello.s 編譯后的匯編文件碌嘀,將源代碼翻譯成匯編語言
hello.o 匯編后的可重定位目標(biāo)文件,將匯編語言翻譯成機(jī)器語言指令
hello??? 鏈接產(chǎn)生的可執(zhí)行目標(biāo)文件
列出你為編寫本論文歪架,生成的中間結(jié)果文件的名字股冗,文件的作用等。
(第1章0.5分)
第2章 預(yù)處理
2.1 預(yù)處理的概念與作用
預(yù)處理器(cpp)根據(jù)以字符#開頭的命令和蚪,修改原始的C程序魁瞪,得到一個(gè)以.i為文件擴(kuò)展名的C程序文件。
C語言標(biāo)準(zhǔn)規(guī)定惠呼,預(yù)處理是指前4個(gè)編譯階段(phases of translation)导俘。
(1)三字符組與雙字符組的替換
(2)行拼接(Line
splicing): 把物理源碼行(Physical source line)中的換行符轉(zhuǎn)義字符處理為普通的換行符,從而把源程序處理為邏輯行的順序集合剔蹋。
(3)單詞化(Tokenization): 處理每行的空白旅薄、注釋等,使每行成為token的順序集泣崩。
(4)宏擴(kuò)展與預(yù)處理指令(directive)處理.
[if !vml]
[endif]
gcc –Ehello.c >hello.i
[if !vml]
[endif]
預(yù)處理器讀取系統(tǒng)頭文件stdio.h少梁,unistd.h, stdlib.h的內(nèi)容,并將其直接插入到程序文本中矫付。
[if !vml]
[endif]
[if !vml]
[endif]
[if !vml]
[endif]
預(yù)處理器cpp讀取系統(tǒng)頭文件stdio.h凯沪,將內(nèi)容插入hello.c原來的程序文本中。
(第2章0.5分)
第3章 編譯
編譯器(ccl)將C語言文本文件翻譯成匯編語言文本文件买优,它包含一個(gè)匯編語言程序妨马。
編譯器的作用是將便于人編寫、閱讀杀赢、維護(hù)的高級計(jì)算機(jī)語言所寫作的源代碼程序烘跺,翻譯為計(jì)算機(jī)能解讀、運(yùn)行的低階機(jī)器語言的程序脂崔。
注意:這兒的編譯是指從 .i 到 .s 即預(yù)處理后的文件到生成匯編語言程序
?????? gcc-S hello.i -o hello.s?????
[if !vml]
[endif]
3.3.1 數(shù)據(jù):
全局變量sleepsecs:
[if !vml]
[endif]
Sleepsecs作為一個(gè)已經(jīng)初始化的全局變量以4字節(jié)長度存放在.data節(jié)
修改源代碼滤淳,添加輸出語句
[if !vml]
[endif]
再次編譯
[if !vml]
[endif]
由編譯錯(cuò)誤得,sleepsecs盡管在源程序中被賦值一個(gè)浮點(diǎn)數(shù)砌左,在編譯過程中被隱式類型轉(zhuǎn)換為int類型脖咐。
局部變量i:
[if !vml]
[endif]
Main函數(shù)中第一個(gè)判斷指令cmpl應(yīng)為if語句,則相等時(shí)跳轉(zhuǎn)到.L2為for語句汇歹,那么movl $0, -4(%rbp)對應(yīng)i = 0; , i存放在-4(%rbp)中屁擅。
表達(dá)式:①if(argc!=3)對應(yīng)cmpl $3, -20(%rbp)
????????????? ?②i=0;對應(yīng)movl $0, -4(%rbp)
????????????? ③i<8;對應(yīng)cmpl $7, -4(%rbp)
????????????? ④i++;對應(yīng)addl $1, -4(%rbp)
?
3.3.2 算術(shù)操作
????? i++;對應(yīng)addl???? $1, -4(%rbp)
3.3.3 關(guān)系操作
????? argc!=3對應(yīng)cmpl??? $3, -20(%rbp)???? /????? je??? .L2
i<8 對應(yīng)cmpl?? $7, -4(%rbp)????????????? /????? jle?? .L4
3.3.4???? 數(shù)組操作
????? char *argv[]對應(yīng) subq????? $32, %rsp
????????????????????????????????? 秤朗。煤蹭。。。硝皂。常挚。
????????????????????????????????? movq???? %rsi, -32(%rbp)
3.3.5???? 控制轉(zhuǎn)移
????? if(argc!=3)對應(yīng) cmpl????? $3, -20(%rbp)
????????????????????????????????? je??? .L2
????? for(i=0;i<8;i++)
????? .L2:????????????? //設(shè)置初始值,開始循環(huán)
????? movl????? $0, -4(%rbp)
????? jmp .L3
????? .L3:????????????? //判斷循環(huán)條件是否成立
????? cmpl????? $7, -4(%rbp)
????? jle?? .L4
3.3.6???? 函數(shù)操作
????? main函數(shù):參數(shù)傳遞movl? %edi, -20(%rbp) \????? movq???? %rsi, -32(%rbp)
?????????????????????????? 函數(shù)返回movl?? $0, %eax\???? leave\??? .cfi_def_cfa 7, 8\ ret
????? printf函數(shù):? 參數(shù)傳遞movq %rax, %rsi\? leaq .LC1(%rip), %rdi\????????????????????????????????????????????????????? ?????? ??? ??movl? $0, %eax
?????????????????????????? 函數(shù)調(diào)用call???? printf@PLT
????? puts函數(shù): 參數(shù)傳遞leaq?? .LC0(%rip), %rdi
?????????????????????????? 函數(shù)調(diào)用call???? puts@PLT
????? Exit函數(shù): 參數(shù)調(diào)用movl? $1, %edi
?????????????????????????? 函數(shù)調(diào)用call???? exit@PLT
????? Sleep函數(shù):參數(shù)傳遞movl %eax, %edi
?????????????????????????? 函數(shù)調(diào)用call???? sleep@PLT
????? Getchar函數(shù):函數(shù)調(diào)用 call getchar@PLT
此部分是重點(diǎn)稽物,說明編譯器是怎么處理C語言的各個(gè)數(shù)據(jù)類型以及各類操作的奄毡。應(yīng)分3.3.1~ 3.3.x等按照類型和操作進(jìn)行分析,只要hello.s中出現(xiàn)的屬于大作業(yè)PPT中P4給出的參考C數(shù)據(jù)與操作贝或,都應(yīng)解析吼过。
編譯器(ccl)將預(yù)處理過的源程序文件從高級語言翻譯成匯編語言。
(第3章2分)
第4章 匯編
?????? 匯編概念:把匯編語言翻譯成機(jī)器語言的過程咪奖。
?????? 匯編器(as)將.s文件翻譯成機(jī)器語言指令盗忱,并把這些指令打包成可重定位目標(biāo)程序(relocatable object program)的格式,并將結(jié)果保存在.o格式的目標(biāo)文件中羊赵,為二進(jìn)制文件趟佃。
注意:這兒的匯編是指從 .s 到 .o 即編譯后的文件到生成機(jī)器語言二進(jìn)制程序的過程。
as hello.s-o hello.o
[if !vml]
[endif]
應(yīng)截圖昧捷,展示匯編過程闲昭!
??? [if !vml]
[endif]
[if !vml]
[endif]
?????? 重定位條目
?????? [if !vml]
[endif]
?????? .rela.text記錄了.text的重定位條目,包括節(jié)偏移Offset,偏移類型Type,偏移調(diào)整Addend
?????? .rela.eh_frame是eh_frame節(jié)的重定位條目
??? 分析hello.o的ELF格式靡挥,用readelf等列出其各節(jié)的基本信息序矩,特別是重定位項(xiàng)目分析。
[if !vml]
[endif]
[if !vml]
[endif]
上圖為hello.o反匯編
機(jī)器語言為十六進(jìn)制數(shù)跋破,一般由1-15個(gè)字節(jié)構(gòu)成
機(jī)器語言從左到右依次為地址:指令+操作(對應(yīng)匯編語言)
與hello.s中的不同之處在于hello.o反匯編多了機(jī)器語言簸淀,而且控制轉(zhuǎn)移不單獨(dú)分段。
如
①
cmpl???? $3, -20(%rbp)
je?? .L2
.L2:
????? movl????? $0,-4(%rbp)
????? jmp .L3
變成
? f:????? 837d ec 03????????? ?? cmpl?? $0x3,-0x14(%rbp)
? 13:??? 7416???????????????? je???? 2b
2b:??? c7 45 fc 0000 00 00 movl?? $0x0,-0x4(%rbp)
? 32:??? eb3b???????????????? jmp??? 6f
②
.L3:
????? cmpl????? $7,-4(%rbp)
????? jle?? .L4
????? call getchar@PLT
????? movl????? $0,%eax
????? leave
????? .cfi_def_cfa 7, 8
????? ret
????? .cfi_endproc
變成
6f: 83 7d fc 07????????? ??? cmpl?? $0x7,-0x4(%rbp)
? 73:??? 7ebf??????????????? ? jle??? 34
? 75:??? e800 00 00 00?????? ??? callq? 7a
??????????????????? 76: R_X86_64_PLT32????? getchar-0x4
? 7a:??? b800 00 00 00?????? ??? mov??? $0x0,%eax
? 7f:??? c9??????????????????? leaveq
? 80:??? c3??????????????????? retq??
?????? ③
????? .L4:
????? movq???? -32(%rbp),%rax
????? addq????? $16,%rax
????? movq???? (%rax),%rdx
????? movq???? -32(%rbp),%rax
????? addq????? $8,%rax
????? movq???? (%rax),%rax
????? movq???? %rax,%rsi
????? leaq .LC1(%rip),%rdi
????? movl????? $0,%eax
????? call printf@PLT
????? movl????? sleepsecs(%rip),%eax
????? movl????? %eax,%edi
????? call sleep@PLT
????????????? addl $1, -4(%rbp)
?????? 變成
????? 34:? 488b 45 e0????????? ?? mov??? -0x20(%rbp),%rax
? 38:??? 4883 c0 10????????? ?? add??? $0x10,%rax
? 3c:??? 488b 10???????????? ? mov??? (%rax),%rdx
? 3f:??? 488b 45 e0? ?????????? mov??? -0x20(%rbp),%rax
? 43:??? 4883 c0 08????????? ?? add??? $0x8,%rax
? 47:??? 488b 00???????????? ? mov??? (%rax),%rax
? 4a:??? 4889 c6???????????? ? mov??? %rax,%rsi
? 4d:??? 488d 3d 00 00 00 00????? lea??? 0x0(%rip),%rdi??????? # 54
??????????????????? 50: R_X86_64_PC32 .rodata+0x1b
? ????????? 54:? b8 00 00 0000?????? ??? mov??? $0x0,%eax
????? ?54:???? b8 00 00 00 00?????? ??? mov??? $0x0,%eax
? 59:??? e800 00 00 00?????? ??? callq? 5e
??????????????????? 5a: R_X86_64_PLT32????? printf-0x4
? 5e:??? 8b05 00 00 00 00??? ???? mov??? 0x0(%rip),%eax??????? # 64
??????????????????? 60: R_X86_64_PC32 sleepsecs-0x4
? 64:??? 89c7???????????????? mov??? %eax,%edi
? 66:??? e800 00 00 00?????? ??? callq? 6b
??????????????????? 67: R_X86_64_PLT32????? sleep-0x4
? ?? ???6b:?? 83 45 fc 01????????? ??? addl?? $0x1,-0x4(%rbp)
objdump -d-r hello.o?分析hello.o的反匯編幔烛,并請與第3章的 hello.s進(jìn)行對照分析啃擦。
說明機(jī)器語言的構(gòu)成囊蓝,與匯編語言的映射關(guān)系饿悬。特別是機(jī)器語言中的操作數(shù)與匯編語言不一致,特別是分支轉(zhuǎn)移函數(shù)調(diào)用等聚霜。
匯編器將.s文件從匯編語言翻譯成.o文件的機(jī)器語言并使用elf格式的文件保存狡恬,elf中不同的代碼保存在不同的節(jié)處,.rela開頭的節(jié)保存相應(yīng)后綴的節(jié)的重定位信息蝎宇。
(第4章1分)
第5章 鏈接
?????? 鏈接是將各種代碼和數(shù)據(jù)片段收集并組合成為一個(gè)單一文件的過程弟劲,這個(gè)文件可被加載(復(fù)制)到內(nèi)存中并執(zhí)行。
注意:這兒的鏈接是指從 hello.o 到hello生成過程姥芥。
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
[if !vml]
[endif]
使用ld的鏈接命令兔乞,應(yīng)截圖,展示匯編過程!注意不只連接hello.o文件
5.3 可執(zhí)行目標(biāo)文件hello的格式
?????? [if !vml]
[endif]
?????? [if !vml]
[endif]
[if !vml]
[endif]
Address為各段起始地址庸追,size為大小霍骄。
??? 分析hello的ELF格式,用readelf等列出其各段的基本信息淡溯,包括各段的起始地址读整,大小等信息。
[if !vml]
[endif]
?????? [if !vml]
[endif]
elf文件從0x400000開始咱娶,到0x400ff0結(jié)束米间。
.text節(jié)從0x400500開始
[if !vml]
[endif]
.data節(jié)從0x400640開始
[if !vml]
[endif]
??? 使用edb加載hello,查看本進(jìn)程的虛擬地址空間各段信息膘侮,并與5.3對照分析說明屈糊。??
Hello比hello.o多了下列節(jié):
[if !vml]
[endif]
[if !vml]
[endif]
[if !vml]
[endif]
.interp:保存ld.so的路徑
.note.ABI-tag
.note.gnu.build-i:編譯信息表
.gnu.hash:gnu的擴(kuò)展符號hash表
.dynsym:動(dòng)態(tài)符號表
.dynstr:動(dòng)態(tài)符號表中的符號名稱
.gnu.version:符號版本
.gnu.version_r:符號引用版本
.rela.dyn:動(dòng)態(tài)重定位表
.rela.plt:.plt節(jié)的重定位條目
.init:程序初始化
.plt:動(dòng)態(tài)鏈接表
.fini:程序終止時(shí)需要的執(zhí)行的指令
.eh_frame:程序執(zhí)行錯(cuò)誤時(shí)的指令
.dynamic:存放被ld.so使用的動(dòng)態(tài)鏈接信息
.got:存放程序中變量全局偏移量
.got.plt:存放程序中函數(shù)的全局偏移量
[if !vml]
[endif]
Hello.o中調(diào)用函數(shù)都是使用call+<main+偏移量的做法>,而在hello是直接使用call+<函數(shù)名> 的方法來直接調(diào)用的琼了。
鏈接的過程:
1.符號解析:把目標(biāo)文件中符號的定義和引用聯(lián)系起來;
2.重定位:把符號定義和內(nèi)存地址對應(yīng)起來另玖,然后修改所有對符號的引用。
重定位:
以sleep函數(shù)為例(R_X86_64_PLT32類型)
由4.3?? r.offset = 0x67???? r.addend = -4
由5.3?? ADDR(.text) = 0x400500
由5.5?? ADDR(sleep) = 0x4004f0
則refaddr = ADDR(.text) + offset=0x400567
*refptr = (unsigned) (ADDR(sleep) + r.addend – refaddr)
?????? ??=(unsigned)0x4004f0 – 4 – 0x400567
?????? ? =-0x7b
-0x7b-0x32+PC= -0xad+0x40059d = 0x4004f0=ADDR(sleep)
objdump -d
-r hello 分析hello與hello.o的不同表伦,說明鏈接的過程谦去。
結(jié)合hello.o的重定位項(xiàng)目,分析hello中對其怎么重定位的蹦哼。
ld-2.27.so!_dl_start?????????????????????????????? 0x7f4b236f4093
ld-2.27.so!_dl_init???????????????????????????????? 0x7f4b236f40c5
hello!_start???????????????????????????????????????????
libc-2.27.so!__libc_start_main????????????
-libc-2.27.so!__cxa_atexit??????????????????????????
-libc-2.27.so!__libc_csu_init???????????????
hello!_init?????????????????????????????????????????????
libc-2.27.so!_setjmp????????????????????????????
-libc-2.27.so!_sigsetjmp??????????????????????
--libc-2.27.so!__sigjmp_save??????????????
hello!main?? ?????????????????????????????????????????
hello!puts@plt?????????????????????????????????????? 0x40054e
hello!exit@plt?????????????????????????????????????? 0x400558
*hello!printf@plt????????????????????????????????? 0x40058b
*hello!sleep@plt?????????????????????????????????? 0x400598
*hello!getchar@plt?????????????????????????????? 0x4005a7
ld-2.27.so!_dl_runtime_resolve_xsave
-ld-2.27.so!_dl_fixup???????????????????????????
--ld-2.27.so!_dl_lookup_symbol_x????????????
libc-2.27.so!exit???????????????????????????????????
使用edb執(zhí)行hello鳄哭,說明從加載hello到_start,到call main,以及程序終止的所有過程纲熏。請列出其調(diào)用與跳轉(zhuǎn)的各個(gè)子程序名或程序地址妆丘。
在dl_init調(diào)用之前,對于每一條PIC函數(shù)調(diào)用局劲,調(diào)用的目標(biāo)地址都實(shí)際指向PLT中的代碼邏輯勺拣,GOT存放的是PLT中函數(shù)調(diào)用指令的下一條指令地址。
在dl_init調(diào)用之后鱼填, 0x60ff0,0x601008和0x601010處的三個(gè)8B數(shù)據(jù)分別發(fā)生改變药有,其中GOT[1]指向重定位表(依次為.plt節(jié)需要重定位的函數(shù)的運(yùn)行時(shí)地址)用來確定調(diào)用的函數(shù)地址, GOT[2]指向動(dòng)態(tài)鏈接器ld-linux.so運(yùn)行時(shí)地址苹丸。
[if !vml]
[endif]
分析hello程序的動(dòng)態(tài)鏈接項(xiàng)目愤惰,通過edb調(diào)試,分析在dl_init前后赘理,這些項(xiàng)目的內(nèi)容變化宦言。要截圖標(biāo)識說明。
鏈接器根據(jù)匯編器的符號表以及重定位條目等信息修改可重定位文件并且鏈接庫函數(shù)商模。
(第5章1分)
第6章 hello進(jìn)程管理
?????? 進(jìn)程就是一個(gè)執(zhí)行中程序的實(shí)例奠旺。
?????? 進(jìn)程提供給應(yīng)用程序兩個(gè)關(guān)鍵的抽象:
[if !supportLists]1.????[endif]一個(gè)獨(dú)立的邏輯控制流蜘澜,它提供一個(gè)假象,好像我們的程序獨(dú)占地使用處理器
[if !supportLists]2.????[endif]一個(gè)私有地址空間响疚,它提供一個(gè)假象兼都,好像我們的程序獨(dú)占地使用內(nèi)存系統(tǒng)。
?????? Shell是一個(gè)交互型的應(yīng)用級程序稽寒,它代表用戶運(yùn)行其他程序扮碧。
?????? Shell的處理流程:
[if !supportLists]1.[endif]接收并解析命令行參數(shù)
[if !supportLists]2.[endif]分析命令行參數(shù)是內(nèi)置shell命令還是可執(zhí)行程序文件
[if !supportLists]3.[endif]執(zhí)行內(nèi)置命令或者調(diào)用可執(zhí)行程序文件
[if !supportLists]4.[endif]程序執(zhí)行中監(jiān)視輸入,作出應(yīng)對
6.3 Hello的fork進(jìn)程創(chuàng)建過程
?????? Shell通過fork函數(shù)創(chuàng)建hello子進(jìn)程杏糙,hello進(jìn)程得到與shell用戶級虛擬地址空間相同但獨(dú)立的一份副本慎王,包括代碼和數(shù)據(jù)段、堆宏侍、共享庫以及用戶棧赖淤。Shell進(jìn)程中會(huì)返回hello進(jìn)程的PID,hello進(jìn)程中返回0.
(以下格式自行編排谅河,編輯時(shí)刪除)
?????? Execve函數(shù)加載并運(yùn)行可執(zhí)行目標(biāo)文件hello咱旱,且?guī)?shù)列表argv和環(huán)境變量envp。每一個(gè)進(jìn)程都有一段唯一屬于自己的內(nèi)存地址段绷耍,在execve運(yùn)行時(shí)吐限,開始先是從0x00400000開始程序的執(zhí)行。先是從可執(zhí)行文件中加載的內(nèi)容褂始,然后是運(yùn)行時(shí)的堆棧和共享庫的存儲器映射區(qū)域诸典。
?????? 當(dāng)shell 運(yùn)行hello程序時(shí),shell 進(jìn)程生成hello子進(jìn)程崎苗,它是shell進(jìn)程的一個(gè)復(fù)制狐粱。子進(jìn)程通過execve 系統(tǒng)調(diào)用啟動(dòng)加載器。加載器刪除子進(jìn)程現(xiàn)有的虛擬內(nèi)存段胆数,并創(chuàng)建一組新的代碼肌蜻、數(shù)據(jù)、堆和棧段必尼。新的棧和堆段被初始化為零蒋搜。通過將虛擬地址空間中的頁映射到可執(zhí)行文件的頁大小的片(chunk), 新的代碼和數(shù)據(jù)段袚初始化為可執(zhí)行文件的內(nèi)容。最后胰伍,加載器跳轉(zhuǎn)到_start地址齿诞,它最終會(huì)調(diào)用應(yīng)用程序的main函數(shù)。在內(nèi)核和前端之前切換的動(dòng)作被稱為上下文切換骂租。
[if !vml]
[endif]
在for循環(huán)中,執(zhí)行完printf后由于調(diào)用了sleep函數(shù)斑司,shell從用戶態(tài)切換到核心態(tài)渗饮,接收并執(zhí)行休眠信號后但汞,shell又從核心態(tài)返回用戶態(tài),執(zhí)行下一次循環(huán)的printf語句互站。
結(jié)合進(jìn)程上下文信息私蕾、進(jìn)程時(shí)間片,闡述進(jìn)程調(diào)度的過程胡桃,用戶態(tài)與核心態(tài)轉(zhuǎn)換等等踩叭。
?????? hello執(zhí)行過程中會(huì)出現(xiàn)的異常種類有:
1.中斷:SIGSTP:掛起程序
2.終止:SIGINT:終止程序
[endif][if !mso][endif]
CTRL+Z
[if !mso]
[endif][if !mso & !vml][endif][if !vml]
[endif][if !vml][endif][if !vml][endif][if !vml][endif][if !vml][endif][if !vml][endif][if !mso][endif]
空格
[if !mso]
[endif][if !mso & !vml][endif][if !vml]
[endif][if !vml][endif][if !vml]
[endif]
[if !vml]
[endif]
[if !vml][endif][if !vml][endif][if !vml]
[endif]
CTRL+Z
向進(jìn)程發(fā)送了一個(gè)SIGSTP信號,讓進(jìn)程暫時(shí)掛起翠胰。
之后執(zhí)行ps命令容贝,可看到未被關(guān)閉的hello進(jìn)程
執(zhí)行jobs命令返回CTRL+Z表示暫停命令
執(zhí)行pstree命令看到以樹狀圖形式組織的各個(gè)進(jìn)程
執(zhí)行fg命令,向hello進(jìn)程發(fā)送SIGCONT信號繼續(xù)執(zhí)行
執(zhí)行kill命令之景,發(fā)送SIGKILL信號殺死當(dāng)前的hello進(jìn)程
CTRL+C
[if !vml]
[endif]
向hello進(jìn)程發(fā)送SIGINT信號斤富,結(jié)束進(jìn)程。
hello執(zhí)行過程中會(huì)出現(xiàn)哪幾類異常锻狗,會(huì)產(chǎn)生哪些信號满力,又怎么處理的。
?程序運(yùn)行過程中可以按鍵盤轻纪,如不停亂按油额,包括回車,Ctrl-Z刻帚,Ctrl-C等悔耘,Ctrl-z后可以運(yùn)行ps? jobs?pstree? fg? kill等命令,請分別給出各命令及運(yùn)行結(jié)截屏我擂,說明異常與信號的處理衬以。
?????? Hello在shell中從創(chuàng)建進(jìn)程到進(jìn)程終止的以及信號傳遞的各個(gè)過程分析。
(第6章1分)
第7章 hello的存儲管理
?????? 邏輯地址:又稱相對地址校摩,是程序運(yùn)行由CPU產(chǎn)生的與段相關(guān)的偏移地址部分看峻。是描述一個(gè)程序運(yùn)行段的地址。
線性地址:地址空間是一個(gè)非負(fù)整數(shù)地址的有序集合衙吩,而如果此時(shí)地址空間中的整數(shù)是連續(xù)的互妓,則稱這個(gè)地址空間為線性地址空間。
虛擬地址:是線性地址坤塞。經(jīng)過段機(jī)制轉(zhuǎn)化之后用于描述程序分頁信息的地址冯勉。是對程序運(yùn)行區(qū)塊的一個(gè)抽象映射,即一個(gè)程序應(yīng)該在內(nèi)存的哪些塊上運(yùn)行摹芙。
物理地址: 程序運(yùn)行時(shí)加載到內(nèi)存地址寄存器中的地址灼狰,內(nèi)存單元的真正地址。是在前端總線上傳輸?shù)亩沂俏ㄒ坏母『獭T趆ello程序中交胚,就表示了這個(gè)程序運(yùn)行時(shí)的一條確切的指令在內(nèi)存地址上的具體哪一塊進(jìn)行執(zhí)行份汗。
結(jié)合hello說明邏輯地址、線性地址蝴簇、虛擬地址杯活、物理地址的概念。
邏輯地址段標(biāo)識符段內(nèi)偏移量組成熬词。段標(biāo)識符是一個(gè)16位長的字段組成旁钧,稱為段選擇符,其中前13位是一個(gè)索引號互拾。后面三位包含一些硬件細(xì)節(jié)歪今。
索引號,這里可以直接理解成數(shù)組下標(biāo)摩幔,它對應(yīng)的“數(shù)組”就是段描述符表彤委,段描述符具體描述了一個(gè)段地址,這樣或衡,很多段描述符就組成段描述符表焦影。可以通過段標(biāo)識符的前13位封断,直接在段描述符表中找到一個(gè)具體的段描述符斯辰,這個(gè)描述符就描述了一個(gè)段。
這里面坡疼,我們只用關(guān)心Base字段彬呻,它描述了一個(gè)段的開始位置的線性地址。
Intel設(shè)計(jì)的本意是柄瑰,一些全局的段描述符闸氮,就放在“全局段描述符表(GDT)”中,一些局部的教沾,例如每個(gè)進(jìn)程自己的蒲跨,就放在所謂的“局部段描述符表(LDT)”中。
GDT在內(nèi)存中的地址和大小存放在CPU的gdtr控制寄存器中授翻,而LDT則在ldtr寄存器中或悲。
首先,給定一個(gè)完整的邏輯地址[段選擇符:段內(nèi)偏移地址]堪唐,看段選擇符的T1=0還是1巡语,知道當(dāng)前要轉(zhuǎn)換是GDT中的段,還是LDT中的段淮菠,再根據(jù)相應(yīng)寄存器男公,得到其地址和大小。我們就有了一個(gè)數(shù)組了兜材。拿出段選擇符中前13位理澎,可以在這個(gè)數(shù)組中逞力,查找到對應(yīng)的段描述符曙寡,這樣糠爬,它了Base,即基地址就知道了举庶。把Base
+ offset执隧,就是要轉(zhuǎn)換的線性地址了。
由教材
[if !vml]
[endif]
由教材的i7例子:
36位VPN被劃分成四個(gè)9位的片户侥,每個(gè)片被用作一個(gè)頁表的偏移量镀琉。
[if !vml]
[endif]
將物理地址拆分成CT(標(biāo)記)+CI(索引)+CO(偏移量)瓜客,然后在一級cache內(nèi)部找挪哄,如果未能尋找到標(biāo)記位為有效的字節(jié)(miss)的話就去二級和三級cache中尋找對應(yīng)的字節(jié),找到之后返回結(jié)果檬某。
[if !vml]
[endif]
7.6 hello進(jìn)程fork時(shí)的內(nèi)存映射
?????? 當(dāng)fork函數(shù)被shell調(diào)用時(shí)替梨,內(nèi)核為hello進(jìn)程創(chuàng)建各種數(shù)據(jù)結(jié)構(gòu)钓试,并分配給它一個(gè)唯一的PID。為了給hello進(jìn)程創(chuàng)建虛擬內(nèi)存副瀑,它創(chuàng)建了當(dāng)前進(jìn)程的mm_struct弓熏、區(qū)域結(jié)構(gòu)和頁表的原樣副本。它將兩個(gè)進(jìn)程中的頁面都標(biāo)記為只讀糠睡,并將兩個(gè)進(jìn)程的區(qū)域結(jié)構(gòu)標(biāo)記為私有的寫實(shí)復(fù)制挽鞠。
(以下格式自行編排,編輯時(shí)刪除)
7.7 hello進(jìn)程execve時(shí)的內(nèi)存映射
[if !supportLists]1.[endif]刪除已存在的用戶區(qū)域狈孔。
[if !supportLists]2.[endif]映射私有區(qū)域
[if !supportLists]3.[endif]映射共享區(qū)域
[if !supportLists]4.[endif]設(shè)置程序計(jì)數(shù)器PC信认,使之指向代碼區(qū)域的入口點(diǎn)。
MMU翻譯虛擬地址A時(shí)觸發(fā)缺頁均抽,異常導(dǎo)致控制轉(zhuǎn)移到內(nèi)核的缺頁處理程序嫁赏,處理程序執(zhí)行以下步驟:
[if !supportLists]1.???? [endif]缺頁處理程序搜索區(qū)域結(jié)構(gòu)鏈表,把A與每個(gè)區(qū)域機(jī)構(gòu)中的vm_start和vm_end做比較到忽,判斷虛擬地址是否在某個(gè)區(qū)域結(jié)構(gòu)定義的區(qū)域內(nèi)(合法)橄教。若不合法,則觸發(fā)一個(gè)段錯(cuò)誤喘漏,從而終止進(jìn)程护蝶。即下圖情況①
[if !supportLists]2.???? [endif]判斷進(jìn)行的內(nèi)存訪問是否合法,若不合法翩迈,則觸發(fā)保護(hù)異常終止進(jìn)程持灰。即下圖情況②
[if !supportLists]3.???? [endif]若虛擬地址與內(nèi)存訪問都合法,則選擇一個(gè)犧牲頁负饲,如果該犧牲頁被修改過堤魁,則將它交換出去喂链,換入新的頁面并更新頁表。當(dāng)缺頁處理程序返回時(shí)妥泉,CPU重新啟動(dòng)引起缺頁的指令椭微,該指令再次將A發(fā)送到MMU。
[if !vml]
[endif]
(以下格式自行編排盲链,編輯時(shí)刪除)
Printf會(huì)調(diào)用malloc蝇率,請簡述動(dòng)態(tài)內(nèi)存管理的基本方法與策略。
?????? 本章介紹了hello的地址空間表示刽沾,地址訪問本慕,內(nèi)存映射,缺頁處理的內(nèi)容侧漓。
(以下格式自行編排锅尘,編輯時(shí)刪除)
(第7章 2分)
第8章 hello的IO管理
(以下格式自行編排,編輯時(shí)刪除)
設(shè)備的模型化:文件
文件的類型:
1. 普通文件(regular file):包含任意數(shù)據(jù)的文件布蔗。
2. 目錄(directory):包含一組鏈接的文件藤违,每個(gè)鏈接都將一個(gè)文件名映射到一個(gè)文件(他還有另一個(gè)名字叫做“文件夾”)。
3. 套接字(socket):用來與另一個(gè)進(jìn)程進(jìn)行跨網(wǎng)絡(luò)通信的文件
4. 命名通道(named pipe)
5. 符號鏈接(symbolic link)
6. 字符和塊設(shè)備(character and block device)
設(shè)備管理:unix io接口
[if !supportLists]1.???? [endif]打開文件
[if !supportLists]2.???? [endif]Linux shell創(chuàng)建的每個(gè)進(jìn)程開始都有三個(gè)打開的文件:標(biāo)準(zhǔn)輸入何鸡、標(biāo)準(zhǔn)輸出纺弊、標(biāo)準(zhǔn)錯(cuò)誤
3. 改變當(dāng)前文件位置
4. 讀寫文件
5.?? 關(guān)閉文件
IO接口及其函數(shù)
打開和關(guān)閉文件:
open函數(shù)原型 int open(char * filename, int flags, mode_t mode) 返回值是一個(gè)文件描述符, flags指定打開方式
close函數(shù)原型 int close(int fd) ;成功返回0骡男,失敗-1淆游,關(guān)閉一個(gè)已關(guān)閉的文件描述符會(huì)出錯(cuò)。
讀和寫文件:
read函數(shù)原型 ssize_t read(int fd , void* buf , size_t n) 從描述符為fd的當(dāng)前文件位置復(fù)制最多n個(gè)字節(jié)到內(nèi)存位置buf隔盛。返回值-1表示一個(gè)錯(cuò)誤犹菱,返回值0表示EOF。否則吮炕,返回值表示實(shí)際傳送的字節(jié)數(shù)量腊脱。
write函數(shù)原型 ssize_t write(int fd , const void* buf, size_t n) 返回值是文件寫入字節(jié)數(shù) fd是文件描述符將buf內(nèi)容寫入n個(gè)字節(jié)到文件但這里需要注意默認(rèn)情況是需要在系統(tǒng)隊(duì)列中等待寫入(打開方式不同也會(huì)不同)
修改當(dāng)前文件位置:
lseek函數(shù)
?????? printf函數(shù)的函數(shù)體如下圖
?????? [if !vml]
[endif]
printf需要做的事情是:接受一個(gè)fmt的格式,然后將匹配到的參數(shù)按照fmt格式輸出龙亲。首先arg獲得第二個(gè)不定長參數(shù)陕凹,即輸出的時(shí)候格式化串對應(yīng)的值,其次調(diào)用了兩個(gè)外部函數(shù)鳄炉,一個(gè)是vsprintf杜耙,還有一個(gè)是write。
vsprintf函數(shù)體如下圖:
[if !vml]
[endif]
從上面vsprintf函數(shù)可以看出拂盯,這個(gè)函數(shù)的作用是將所有的參數(shù)內(nèi)容格式化之后存入buf佑女,然后返回格式化數(shù)組的長度。
write函數(shù)是將buf中的i個(gè)元素寫到終端的函數(shù)。
綜上团驱,printf的輸出過程如下:
(1)從vsprintf生成顯示信息摸吠,顯示信息傳送到write系統(tǒng)函數(shù);
(2)write函數(shù)陷阱-系統(tǒng)調(diào)用 int 0x80或syscall.字符顯示驅(qū)動(dòng)子程序嚎花;
(3)從ASCII到字模庫到顯示vram(存儲每一個(gè)點(diǎn)的RGB顏色信息)寸痢。
(4)顯示芯片按照刷新頻率逐行讀取vram,并通過信號線向液晶顯示器傳輸每一個(gè)點(diǎn)(RGB分量)贩幻,這樣轿腺,需要打印的字符串“Hello 1161100122 xian”就顯示在了屏幕上两嘴。
https://www.cnblogs.com/pianist/p/3315801.html
從vsprintf生成顯示信息丛楚,到write系統(tǒng)函數(shù),到陷阱-系統(tǒng)調(diào)用 int 0x80或syscall.
字符顯示驅(qū)動(dòng)子程序:從ASCII到字模庫到顯示vram(存儲每一個(gè)點(diǎn)的RGB顏色信息)憔辫。
顯示芯片按照刷新頻率逐行讀取vram趣些,并通過信號線向液晶顯示器傳輸每一個(gè)點(diǎn)(RGB分量)。
?????? getchar調(diào)用了一個(gè)read函數(shù)贰您,這個(gè)read函數(shù)是將整個(gè)緩沖區(qū)都讀到了buf里面坏平,然后將返回值是緩沖區(qū)的長度。如果buf長度為0锦亦,getchar才會(huì)調(diào)用read函數(shù)舶替,否則是直接將保存的buf中的最前面的元素返回。
異步異常-鍵盤中斷的處理:鍵盤中斷處理子程序杠园。接受按鍵掃描碼轉(zhuǎn)成ascii碼顾瞪,保存到系統(tǒng)的鍵盤緩沖區(qū)。
getchar等調(diào)用read系統(tǒng)函數(shù)抛蚁,通過系統(tǒng)調(diào)用讀取按鍵ascii碼陈醒,直到接受到回車鍵才返回。
?????? 從Linux I/O接口及其函數(shù)到printf和getchar的實(shí)現(xiàn)瞧甩,分析了hello如何從調(diào)用輸出函數(shù)到輸出屏幕的過程钉跷。
(以下格式自行編排,編輯時(shí)刪除)
(第8章1分)
從hello.c開始由預(yù)處理器進(jìn)行預(yù)處理添加頭文件成為hello.i, 然后由編譯器將文本文件hello.i編譯成為匯編文件肚逸,再由匯編器將其翻譯成可重定位目標(biāo)文件hello.o,最后鏈接器將外部文件與hello.o鏈接成為一個(gè)可執(zhí)行目標(biāo)文件hello.
在shell中輸入? ./hello 1161100122 xian運(yùn)行程序
Shell調(diào)用fork函數(shù)創(chuàng)建子進(jìn)程爷辙,調(diào)用execve函數(shù)啟動(dòng)加載器,映射虛擬內(nèi)存朦促,進(jìn)入程序入口后載入物理內(nèi)存膝晾,然后進(jìn)入main函數(shù)
執(zhí)行指令:CPU為其分配時(shí)間片,在一個(gè)時(shí)間片中思灰,hello享有CPU資源玷犹,順序執(zhí)行自己的控制邏輯流。hello在執(zhí)行的過程中可能會(huì)遇到異常和信號以及命令,執(zhí)行異常信號的處理流程歹颓;
內(nèi)存申請和訪問:MMU將程序中使用的虛擬內(nèi)存地址通過頁表映射成物理地址坯屿,printf會(huì)調(diào)用malloc向動(dòng)態(tài)內(nèi)存分配器申請堆中的內(nèi)存;
結(jié)束運(yùn)行:shell父進(jìn)程回收子進(jìn)程巍扛,內(nèi)核刪除為這個(gè)進(jìn)程創(chuàng)建的所有數(shù)據(jù)結(jié)構(gòu)领跛。
你對計(jì)算機(jī)系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)的深切感悟,你的創(chuàng)新理念撤奸,如新的設(shè)計(jì)與實(shí)現(xiàn)方法吠昭。
(結(jié)論0分,缺失 -1分胧瓜,根據(jù)內(nèi)容酌情加分)
hello.i 預(yù)處理后的文本文件矢棚,加載了頭文件
hello.s 編譯后的匯編文件,將源代碼翻譯成匯編語言
hello.o 匯編后的可重定位目標(biāo)文件府喳,將匯編語言翻譯成機(jī)器語言指令
hello?? 鏈接產(chǎn)生的可執(zhí)行目標(biāo)文件
helloelf.txt???? hello.o的ELF格式文件
hellorelf.txt ?????? hello的ELF格式文件
列出所有的中間產(chǎn)物的文件名蒲肋,并予以說明起作用。
(附件0分钝满,缺失 -1分)
為完成本次大作業(yè)你翻閱的書籍與網(wǎng)站等
[1]? 蘭德爾E.布萊恩特.深入理解計(jì)算機(jī)系統(tǒng)[第三版]:美國:機(jī)械工業(yè)出版社兜粘,2016.
[2]? https://zh.wikipedia.org/wiki/C%E9%A2%84%E5%A4%84%E7%90%86%E5%99%A8
[3]? https://zh.wikipedia.org/wiki/%E7%B7%A8%E8%AD%AF%E5%99%A8
[4]? http://www.reibang.com/p/b8ddb4cee7af
[5]? http://www.reibang.com/p/863b279c941e
[6] https://github.com/torvalds/linux/commit/b21ebf2fb4cde1618915a97cc773e287ff49173e
[7]??? https://www.cnblogs.com/pianist/p/3315801.html
(參考文獻(xiàn)0分,缺失 -1分)