欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

首頁綜合 正文
目錄

柚子快報激活碼778899分享:系統(tǒng)架構(gòu) 程序人生Hello

柚子快報激活碼778899分享:系統(tǒng)架構(gòu) 程序人生Hello

http://yzkb.51969.com/

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

大作業(yè)

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

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

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

班 ??級???2103? ? ? ? ? ? ??

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

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

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

2022年5月

摘 ?要

經(jīng)過一學(xué)期對計算機(jī)系統(tǒng)的課程,對《深入理解計算機(jī)系統(tǒng)》一書的前八章進(jìn)行了系統(tǒng)的學(xué)習(xí),并且通過四次實(shí)驗(yàn)鞏固了學(xué)習(xí)內(nèi)容,提高了實(shí)踐能力。通過本文,將借助對hello程序在Linux下生命周期的分解,回顧課程知識,深化學(xué)習(xí)內(nèi)容,增強(qiáng)知識連貫性,加強(qiáng)實(shí)踐能力。

????????

關(guān)鍵詞:計算機(jī)系統(tǒng);Ubuntu;程序的生命周期;操作系統(tǒng);編譯;鏈接;進(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é)

結(jié)論

第1章 概述

1.1 Hello簡介

根據(jù)Hello的自白,利用計算機(jī)系統(tǒng)的術(shù)語,簡述Hello的P2P,020的整個過程。

1. P2P(From Program to Process)

程序員通過編輯器編寫高級語言程序得到.c文件,經(jīng)過cpp預(yù)處理得到.i文件,經(jīng)過ccl編譯器編譯得到.s匯編語言文件,利用匯編器(as)獲得重定位的.o目標(biāo)文件,最后經(jīng)鏈接器(ld)與庫函數(shù)鏈接得到可執(zhí)行文件hello。Linux>./hello執(zhí)行此文件,shell會調(diào)用fork函數(shù)為其fork產(chǎn)生子進(jìn)程,再調(diào)用execve函數(shù)加載進(jìn)程。于是hello從程序轉(zhuǎn)變?yōu)榱诉M(jìn)程。

2.020(From Zero-0 to Zero-0)

子進(jìn)程調(diào)用execve加載hello,創(chuàng)建新的區(qū)域結(jié)構(gòu)以提供給hello的代碼、數(shù)據(jù)、bss和棧區(qū)域,映射虛擬內(nèi)存,載入物理內(nèi)存,然后進(jìn)入程序入口處開始執(zhí)行,然后進(jìn)入main函數(shù),CPU為hello分配時間片執(zhí)行邏輯控制流。

為讓hello程序能夠調(diào)用硬件進(jìn)行從鍵盤讀入字符,操作系統(tǒng)將I/O設(shè)備都抽象為文件,進(jìn)而實(shí)現(xiàn)向屏幕輸入輸出。hello執(zhí)行完成后操作系統(tǒng)回收hello進(jìn)程,內(nèi)核從系統(tǒng)中刪除hello所有相關(guān)數(shù)據(jù),hello一生結(jié)束。

1.2 環(huán)境與工具

列出你為編寫本論文,折騰Hello的整個過程中,使用的軟硬件環(huán)境,以及開發(fā)與調(diào)試工具。

硬件:

CPU:AMD Ryzen 7 5800H with Radeon Graphics

顯卡:NVIDIA GeForce RTX 3060 Laptop GPU 6 GB

硬件平臺:Intel X86-64

軟件:Linux: Vmware虛擬機(jī); Ubuntu 18.04 LTS 64位/優(yōu)麒麟 64位

開發(fā)與調(diào)試工具:gcc,as,ld,vim,edb,readelf

1.3 中間結(jié)果

列出你為編寫本論文,生成的中間結(jié)果文件的名字,文件的作用等。

文件名 文件功能

hello.c 源程序

hello.i 預(yù)處理之后得到的文本文件

hello.s 編譯得到的匯編文件

hello.o 匯編得到的可重定位目標(biāo)文件

hello 鏈接得到的可執(zhí)行目標(biāo)文件

hello1.elf hello.o經(jīng)readelf輸出的elf文件

hello2.elf hello經(jīng)readelf輸出的elf文件

說明:由于hello(1).c出現(xiàn)bash:未預(yù)期的符號’(’附近有語法錯誤,因此改名為hello.c

1.4 本章小結(jié)

本章對hello程序進(jìn)行了概括,介紹了P2P,020過程,列出了本次作業(yè)的軟硬件環(huán)境及開發(fā)工具以及從hello.c到hello的中間文件。

第2章 預(yù)處理

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

概念:

在程序設(shè)計中,預(yù)處理是在編譯之前調(diào)用預(yù)處理器進(jìn)行的處理。一般指的是在程序源代碼被翻譯為目標(biāo)代碼的過程中,生成二進(jìn)制代碼之前的過程,預(yù)處理器(cpp)會展開以#起始的行,試圖解釋為預(yù)處理指令(preprocessing directive) ,其中ISO C/C++要求支持的包括#if/#ifdef/#ifndef/#else/#elif/#endif(條件編譯)、#define(宏定義)、#include(源文件包含)、#line(行控制)、#error(錯誤指令)、#pragma(和實(shí)現(xiàn)相關(guān)的雜注)以及單獨(dú)的#(空指令) 。預(yù)處理指令一般被用來使源代碼在不同的執(zhí)行環(huán)境中被方便的修改或者編譯。

作用:

1. 預(yù)處理可以擴(kuò)展源代碼,插入所有用#include命令指定的文件。

2. 擴(kuò)展所有用#define聲明指定的宏,又稱宏展開。

3. 根據(jù)#if以及#endif和#ifdef以及#ifndef后面的條件決定需要編譯的代碼

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

圖一.輸入預(yù)處理命令

輸入命令:gcc -E hello.c -o hello.i

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

預(yù)處理得到了3105行的.i文件

圖二.頭文件的宏展開

圖三.hello.i中的源代碼

可以發(fā)現(xiàn),hello.i相較hello.c已經(jīng)擴(kuò)展了三千余行,原來的代碼出現(xiàn)在hello.i的最后,main函數(shù)主體內(nèi)容沒有什么變化,注釋部分刪除。頭文件stdio.h unistd.h stdlib.h展開成為三個頭文件的源碼,且對 stdio 中的define 宏定義遞歸展開,此外,預(yù)編譯程序可識別一些特殊的符號,預(yù)編譯程序?qū)υ谠闯绦蛑谐霈F(xiàn)的這些串將用合適的值進(jìn)行替換。

2.4 本章小結(jié)

本章主要介紹了預(yù)處理(包括頭文件的展開、宏替換、去掉注釋、條件編譯)的概念和功能,同時在Ubuntu上輸入命令進(jìn)行預(yù)處理并作結(jié)果解析。

第3章 編譯

3.1 編譯的概念與作用

概念:

編譯過程是整個程序構(gòu)建的核心部分,編譯成功,會將源代碼由文本形式轉(zhuǎn)換成機(jī)器語言匯編程序。編譯過程就是把預(yù)處理完的文件進(jìn)行一系列詞法分析、語法分析、語義分析以及優(yōu)化后生成相應(yīng)的匯編代碼文件,將文本文件 hello.i 翻譯成匯編程序hello.s。

作用:

把源程序(高級語言)翻譯成匯編語言或機(jī)器語言。其包括以下幾個步驟:

1、詞法分析:詞法分析是使用一種叫做lex的程序?qū)崿F(xiàn)詞法掃描,它會按照用戶之前描述好的詞法規(guī)則將輸入的字符串分割成一個個記號。產(chǎn)生的記號一般分為:關(guān)鍵字、標(biāo)識符、字面量(包含數(shù)字、字符串等)和特殊符號(運(yùn)算符、等號等),然后他們放到對應(yīng)的表中。方法分為兩種:自上而下分析法和自下而上分析法。

2、語法分析:語法分析器根據(jù)用戶給定的語法規(guī)則,將詞法分析產(chǎn)生的記號序列進(jìn)行解析,然后將它們構(gòu)成一棵語法樹,即在詞法分析的基礎(chǔ)上將單詞序列組合成各類語法短語,如“程序”,“語句”,“表達(dá)式”等等。對于不同的語言,只是其語法規(guī)則不一樣。

3、語義分析:即靜態(tài)語法檢查,對結(jié)構(gòu)上正確的源程序進(jìn)行上下文有關(guān)性質(zhì)的審查,進(jìn)行類型審查。語義分析是審查源程序有無語義錯誤,為代碼生成階段收集類型信息。

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

5、目標(biāo)代碼生成與優(yōu)化:代碼生成器將中間代碼轉(zhuǎn)成機(jī)器代碼,這個過程是依賴于目標(biāo)機(jī)器的,因?yàn)椴煌臋C(jī)器有著不同的字長、寄存器、數(shù)據(jù)類型等。最后目標(biāo)代碼優(yōu)化器對目標(biāo)代碼進(jìn)行優(yōu)化,比如選擇合適的尋址方式、使用唯一來代替乘除法、刪除出多余的指令等,即對程序進(jìn)行多種等價變換,使得從變換后的程序出發(fā),能生成更有效的目標(biāo)代碼 ?

3.2 在Ubuntu下編譯的命令

圖四.輸入編譯命令

輸入命令:gcc -S hello.i?-o hello.s

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

3.3.1匯編指令介紹

圖五.匯編指令

.file:聲明源文件

.text:代碼節(jié)

.section:

.rodata:只讀代碼段

.align:數(shù)據(jù)或者指令的地址對齊方式

.string:聲明一個字符串(.LC0,.LC1)

.global:聲明全局變量(main)

.type:聲明一個符號是數(shù)據(jù)類型還是函數(shù)類型

3.3.2數(shù)據(jù)

1.常量

圖六.常量4

圖七.常量4的直接引用

常量4被儲存在寄存器%rbq中,也就是在.text中,作為指令的一部分

.字符串

圖八.字符串

字符串作為printf函數(shù)的參數(shù),保存在只讀數(shù)據(jù)段中。

變量

全局變量:儲存在.data或.bss節(jié)中。初始化的全局變量儲存在.data節(jié),它的初始化不需要匯編語句,而是直接完成的。

局部變量:在main函數(shù)中定義了一個局部變量i。

圖九.局部變量i的賦值

編譯器編譯時將局部變量i放在堆棧中,如圖九所示,本程序中局部變量i存放在棧-4(%rbp)中。

3.3.3賦值

如上圖九,編譯器通過mov語句將局部變量i賦值為0。

3.3.4算術(shù)操作

圖十.實(shí)現(xiàn)i++

在每次循環(huán)執(zhí)行內(nèi)容結(jié)束后,利用addl算術(shù)操作對i進(jìn)行+1。

3.3.5關(guān)系跳轉(zhuǎn)與控制轉(zhuǎn)移

圖十一.源程序

圖十二.if判斷語句的實(shí)現(xiàn)

圖十三.for語句的實(shí)現(xiàn)

匯編語言中首先設(shè)置條件碼,然后根據(jù)條件碼來進(jìn)行控制轉(zhuǎn)移。

在圖十一,在13行和17行分別出現(xiàn)了if(argc!=4)和for(i=0;i<8;i++)兩處關(guān)系操作,前者通過圖十二中的cmpl指令設(shè)置的條件碼來判斷是否需要跳轉(zhuǎn)到分支中,后者通過圖十三中的cmpl指令設(shè)置的條件碼(即如果小于等于8就跳轉(zhuǎn))來判斷是否跳轉(zhuǎn)到指定地址。

3.3.6數(shù)組/指針/結(jié)構(gòu)體

主函數(shù)main的參數(shù)中有指針數(shù)組char *argv[],數(shù)組的每個元素都是一個指向字符類型的指針。

圖十四.main函數(shù)定義

圖十五.argc和argv的存儲位置

argc存儲在%edi中,argv存儲在%esi中

圖十六.對argv數(shù)組成員取值

用movq指令獲取argv[1]和argv[2]的地址

3.3.7函數(shù)操作

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

main函數(shù):

參數(shù)傳遞:傳入?yún)?shù)argc和argv[],分別用寄存器%rdi和%rsi存儲。

局部變量:創(chuàng)建了一個int類型的局部變量i。

函數(shù)調(diào)用:被系統(tǒng)啟動函數(shù)調(diào)用。

函數(shù)返回:設(shè)置%eax為0并且返回,對應(yīng)return 0 。

圖十七.printf函數(shù)調(diào)用

printf函數(shù):

參數(shù)傳遞:call puts時只傳入了字符串參數(shù)首地址;for循環(huán)中call printf時傳入了 argv[1]和argc[2]的地址。

函數(shù)調(diào)用:if判斷滿足條件后調(diào)用,與for循環(huán)中被調(diào)用。

exit函數(shù):

參數(shù)傳遞:傳入的參數(shù)為1,再執(zhí)行退出命令。

函數(shù)調(diào)用:if判斷條件滿足后被調(diào)用。

sleep函數(shù):

參數(shù)傳遞:傳入?yún)?shù)atoi(argv[3])。

函數(shù)調(diào)用:for循環(huán)下被調(diào)用,call sleep。

getchar函數(shù):

函數(shù)調(diào)用:在main中被調(diào)用,call getchar。

3.4 本章小結(jié)

本章內(nèi)容圍繞編譯展開,介紹了編譯的概念以及作用,說明了ubuntu下的編譯命令,對hello.i程序進(jìn)行編譯獲得了hello.s程序,并對hello.s程序進(jìn)行了解析,分析了其數(shù)據(jù)、操作、函數(shù)調(diào)用等,加深了對匯編語言的理解。

第4章 匯編

4.1 匯編的概念與作用

概念:

匯編器(as)將.s 匯編程序翻譯成等價的二進(jìn)制機(jī)器語言指令,匯編輸入的是匯編語言,輸出的是機(jī)器語言。此機(jī)器語言是可重定位目標(biāo)程序。

作用:

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

4.2 在Ubuntu下匯編的命令

圖十八.輸入?yún)R編命令

輸入命令:gcc -C?hello.s -o hello.o

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

1.ELF Header

圖十九.ELF Header

ELF頭:以 16B 的序列 Magic 開始,Magic 描述了生成該文件的系統(tǒng)的字的大小和字節(jié)順序,余下部分指明了類別,數(shù)據(jù),版本,OS/ABI,ABI,ELF頭的大小、目標(biāo)文件的類型、機(jī)器類型、字節(jié)頭部表的文件偏移,以及節(jié)頭部表中條目的大小和數(shù)量等信息。

Section Headers

圖二十.1.Section Headers

圖二十.2.Section Headers

節(jié)頭表:節(jié)頭表包括節(jié)名稱,節(jié)的類型,節(jié)的屬性(讀寫權(quán)限),節(jié)在ELF文件中所占的長度以及節(jié)的對齊方式和偏移量。

符號表.symtab

圖二十一..symtab

符號表.symtab:存放在程序中定義和引用的函數(shù)和全局變量的信息,但它不包含局部變量的條目。

重定位節(jié)

圖二十二.重定位節(jié)

重定位節(jié):,包含.text 節(jié)和.eh_frame中需要進(jìn)行重定位的信息,當(dāng)鏈接器把這個目標(biāo)文件和其他文件組合時,需要修改這些位置。

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

objdump -d -r hello.o ?分析hello.o的反匯編,并請與第3章的 hello.s進(jìn)行對照分析。

圖二十三.hello.o反匯編

hello.o的反匯編相較于hello.s多了機(jī)器代碼。機(jī)器指令由操作碼和操作數(shù)構(gòu)成,每一條匯編語言操作碼都可以用機(jī)器二進(jìn)制數(shù)據(jù)來表示,進(jìn)而可以將所有的匯編語言(操作碼和操作數(shù))和二進(jìn)制機(jī)器語言建立一一映射的關(guān)系。

分支轉(zhuǎn)移:hello.s文件中分支轉(zhuǎn)移使用段名稱進(jìn)行跳轉(zhuǎn),hello.o文件中通過地址進(jìn)行直接跳轉(zhuǎn)。

函數(shù)調(diào)用:因?yàn)?hello.c 中調(diào)用的函數(shù)都是共享庫中的函數(shù),最終都需要通過動態(tài)鏈接器才能確定函數(shù)的運(yùn)行時執(zhí)行地址,在匯編成為機(jī)器語言的時候,對于這些不確定地址的函數(shù)調(diào)用,將其 call 指令后的相對地址設(shè)置為全 0,然后在.rela.text 節(jié)中為其添加重定位條目,等待靜態(tài)鏈接的進(jìn)一步確定。所以在.s 文件中,函數(shù)調(diào)用之后直接跟著函數(shù)名稱,而在反匯編程序中,call 的目標(biāo)地址是當(dāng)前下一條指令。

(3)全局變量:hello.s文件中,全局變量通過語句“段地址+%rip”完成,在于hello.o的反匯編后生成的代碼中是通過“0+%rip”實(shí)現(xiàn),因?yàn)?rodata節(jié)中的數(shù)據(jù)是在運(yùn)行時確定的,也需要重定位,現(xiàn)在填0占位,并為其在.rela.text節(jié)中添加重定位條目。

4.5 本章小結(jié)

本章圍繞匯編展開,闡述了匯編的概念以及作用,指出了在ubuntu下的匯編指令,利用指令查看了hello.o的可重定位目標(biāo)文件的格式,體分析elf格式的可重定位目標(biāo)文件的各個部分(如ELF Header等等)。最后使用反匯編查看了hello.o經(jīng)過反匯編后生成的代碼并與hello.s進(jìn)行了對比分析,更加深入地理解了匯編。

第5章 鏈接

5.1 鏈接的概念與作用

概念:

將各種機(jī)器代碼和數(shù)據(jù)的片段進(jìn)行收集并組合成一個單一的鏈接后的文件的過程, 這個單一文件的鏈接可被應(yīng)用程序加載(或者復(fù)制)到一個內(nèi)存并加載和執(zhí)行。

作用:

鏈接使得分離編譯成為可能。我們可以將一個大型應(yīng)用程序分解為更小更好管理的模塊,可以獨(dú)立地修改和編譯這些模塊,提升了進(jìn)行大型文件編寫的效率,節(jié)省了大量的工作空間。鏈接可以執(zhí)行于編譯時,也就是源代碼被翻譯成機(jī)器代碼時;也可以執(zhí)行于加載時,即程序被加載器加載到內(nèi)存并執(zhí)行時;甚至執(zhí)行于運(yùn)行時,也就是由應(yīng)用程序來執(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.3 可執(zhí)行目標(biāo)文件hello的格式

ELF Header:

圖二十五.ELF Header

其與.o文件的差別僅僅是類型(可執(zhí)行文件)與節(jié)數(shù)(25)不同

Section Headers:

圖二十六.Section Headers

各節(jié)的基本信息均在節(jié)頭表(描述目標(biāo)文件的節(jié))中進(jìn)行了聲明。節(jié)頭表(包括名稱,大小,類型,全體大小,地址,旗標(biāo),偏移量,對齊等信息)。

符號表.dynsym和.symtab

圖二十七.符號表.dynsym和.symtab

重定位節(jié):.rela.dyn和.rela.plt

圖二十八.重定位節(jié):.rela.dyn和.rela.plt

5.4 hello的虛擬地址空間

使用edb加載hello,查看本進(jìn)程的虛擬地址空間各段信息,并與5.3對照分析說明。

1. 在data dump中查看加載到虛擬地址情況:

圖二十九.data dump

各節(jié)位置和名稱:地址和名稱與5.3相對應(yīng)

圖三十.各節(jié)位置和名稱

利用節(jié)頭表可以去到各個節(jié),比如下圖為.rodata節(jié):

圖三十一..rodata節(jié)

5.5 鏈接的重定位過程分析

objdump -d -r hello 分析hello與hello.o的不同,說明鏈接的過程。

結(jié)合hello.o的重定位項(xiàng)目,分析hello中對其怎么重定位的。

圖三十二.Hello的部分反匯編代碼

1、對比可以發(fā)現(xiàn)hello反匯編的代碼有確定的虛擬空間絕對地址并在后面標(biāo)出執(zhí)行函數(shù)的地址和函數(shù)名,也就是說已經(jīng)完成了重定位,而hello.o反匯編代碼中代碼的虛擬地址均為0,未完成重定位的過程,0只是起到了占位的作用。由此,hello.o文件中有重定位條目而hello文件中沒有。

2、hello相較于hello.o增加了新的節(jié)(.init和.plt)和函數(shù)(如exit、printf等庫函數(shù))。

hello重定位過程:

1、鏈接器將所有相同類型的節(jié)合并成同一類型的新的聚合節(jié)。然后將運(yùn)行時內(nèi)存地址賦給新的聚合節(jié),賦給輸入模塊定義的每個節(jié),以及賦給輸入模塊定義的每個符號。這時,程序中的每條指令和全局變量都有唯一的運(yùn)行時內(nèi)存地址。

2、鏈接器利用可重定位目標(biāo)模塊中稱為重定位條目的數(shù)據(jù)結(jié)構(gòu),修改節(jié)代碼和數(shù)據(jù)節(jié)中對每個符號的引用,使得它們指向正確的運(yùn)行時地址。

3、重定位條目:匯編器遇到對最終位置未知的目標(biāo)引用時,就會生成一個重定位條目,告訴鏈接器如何修改這個引用。代碼的重定位條目放在.rel.text中,已初始化數(shù)據(jù)的重定位條目放在.rel.data中。

5.6 hello的執(zhí)行流程

使用edb執(zhí)行hello,說明從加載hello到_start,到call main,以及程序終止的所有過程。請列出其調(diào)用與跳轉(zhuǎn)的各個子程序名或程序地址。

ld-2.27.so!_start@0x7f99:35f0e090

ld-2.27.so!_dl_start_user@0x7f99:35f0e098

hello!_start@0x400550

hello!_main@0x400582

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

分析hello程序的動態(tài)鏈接項(xiàng)目,通過edb調(diào)試,分析在dl_init前后,這些項(xiàng)目的內(nèi)容變化。要截圖標(biāo)識說明。

動態(tài)鏈接的基本思想是把程序按照模塊拆分成各個相對獨(dú)立部分,在程序運(yùn)行時才將它們鏈接在一起形成一個完整的程序,而不是像靜態(tài)鏈接一樣把所有程序模塊都鏈接成一個單獨(dú)的可執(zhí)行文件。雖然動態(tài)鏈接把鏈接過程推遲到了程序運(yùn)行時,但是在形成可執(zhí)行文件時,還是需要用到動態(tài)鏈接庫。

在調(diào)用共享庫函數(shù)時,編譯器沒有辦法預(yù)測這個函數(shù)的運(yùn)行時地址,因?yàn)槎x它的共享模塊在運(yùn)行時可以加載到任意位置。正常的方法是為該引用生成一條重定位記錄,然后動態(tài)鏈接器在程序加載的時候再解析它。GNU編譯系統(tǒng)使用延遲綁定(lazybinding),將過程地址的綁定推遲到第一次調(diào)用該過程時,以此防止運(yùn)行時修改調(diào)用模塊的代碼段。

動態(tài)鏈接器使用過程鏈接表PLT+全局偏移量表GOT實(shí)現(xiàn)函數(shù)的動態(tài)鏈接,GOT中存放函數(shù)目標(biāo)地址,PLT使用GOT中地址跳轉(zhuǎn)到目標(biāo)函數(shù)。

PLT:PLT是一個數(shù)組,其中每個條目是16字節(jié)代碼。PLT[0]是一個特殊條目,它跳轉(zhuǎn)到動態(tài)鏈接器中。每個被可執(zhí)行程序調(diào)用的庫函數(shù)都有它自己的PLT條目。每個條目都負(fù)責(zé)調(diào)用一個具體的函數(shù)。

GOT:GOT是一個數(shù)組,其中每個條目是8字節(jié)地址。和PLT聯(lián)合使用時,GOT[O]和GOT[1]包含動態(tài)鏈接器在解析函數(shù)地址時會使用的信息。GOT[2]是動態(tài)鏈接器在1d-linux.so模塊中的入口點(diǎn)。其余的每個條目對應(yīng)于一個被調(diào)用的函數(shù),其地址需要在運(yùn)行時被解析。每個條目都有一個相匹配的PLT條目。

如果一個目標(biāo)模塊調(diào)用定義在共享庫中的任何函數(shù),那么就有自己的GOT和PLT。前者是數(shù)據(jù)段的一部分,后者為代碼段的一部分。PLT是一個數(shù)組,其中每個條目是16字節(jié)代碼。每個庫函數(shù)都有自己的PLT條目,PLT[0]是一個特殊的條目,跳轉(zhuǎn)到動態(tài)鏈接器中。從PLT[2]開始的條目調(diào)用用戶代碼調(diào)用的函數(shù)。GOT同樣是一個數(shù)組,每個條目是8字節(jié)的地址,和PLT聯(lián)合使用時,GOT[2]是動態(tài)鏈接在ld-linux.so模塊的入口點(diǎn),其余條目對應(yīng)于被調(diào)用的函數(shù),在運(yùn)行時被解析。每個條目都有匹配的PLT條目。當(dāng)某個動態(tài)鏈接函數(shù)第一次被調(diào)用時先進(jìn)入對應(yīng)的PLT條目例如PLT[2],然后PLT指令跳轉(zhuǎn)到對應(yīng)的GOT條目中例如GOT[4],其內(nèi)容是PLT[2]的下一條指令。然后將函數(shù)的ID壓入棧中后跳轉(zhuǎn)到PLT[0]。PLT[0]通過GOT[1]將動態(tài)鏈接庫的一個參數(shù)壓入棧中,再通過GOT[2]間接跳轉(zhuǎn)進(jìn)動態(tài)鏈接器中。動態(tài)鏈接器使用兩個棧條目來確定函數(shù)的運(yùn)行時位置,用這個地址重寫GOT[4],然后再次調(diào)用函數(shù)。經(jīng)過上述操作,再次調(diào)用時PLT[2]會直接跳轉(zhuǎn)通過GOT[4]跳轉(zhuǎn)到函數(shù)而不是PLT[2]的下一條地址。

圖三十三..GOT起始地址

由圖三十三知GOT起始表位置為0x601000

圖三十四.edb執(zhí)行init之前的地址

在調(diào)用dl_init之前0x601008后的16個字節(jié)均為0,對于每一條PIC函數(shù)調(diào)用,調(diào)用的目標(biāo)地址都實(shí)際指向PLT 中的代碼邏輯,GOT存放的是PLT中函數(shù)調(diào)用指令的下一條指令地址。

圖三十五.edb執(zhí)行init之后的地址

在之后的函數(shù)調(diào)用時,首先跳轉(zhuǎn)到PLT執(zhí)行.plt中邏輯,第一次訪問跳轉(zhuǎn)時,GOT 地址為下一條指令,將函數(shù)序號壓棧,然后跳轉(zhuǎn)到PLT[0],在 PLT[0]中將重 定位表地址壓棧,然后訪問動態(tài)鏈接器,在動態(tài)鏈接器中使用函數(shù)序號和重定位 表確定函數(shù)運(yùn)行時地址,重寫 GOT,再將控制傳遞給目標(biāo)函數(shù)。之后如果對同樣函數(shù)調(diào)用,第一次訪問跳轉(zhuǎn)直接跳轉(zhuǎn)到目標(biāo)函數(shù)。

5.8 本章小結(jié)

本章圍繞鏈接展開,闡述了鏈接的概念以及作用,詳細(xì)闡述了hello.o是怎么鏈接成為一個可執(zhí)行目標(biāo)文件的過程,并對hello的ELF格式各個部分進(jìn)行了分析,還使用edb加載hello,查看本了進(jìn)程的虛擬地址空間各段信息,并通過反匯編hello文件,將其與hello.o反匯編文件進(jìn)行了對比,詳細(xì)了解了重定位過程;此外,還遍歷了整個hello的執(zhí)行過程,在最后對hello進(jìn)行了動態(tài)鏈接分析。極大加深了對鏈接的理解。

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

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

概念:

狹義定義:進(jìn)程就是一個執(zhí)行中程序的實(shí)例。系統(tǒng)中每個程序都運(yùn)行在某個進(jìn)程的上下文中。上下文是由程序正確運(yùn)行所需的狀態(tài)所組成的。這個狀態(tài)包括存放在內(nèi)存中的程序的代碼和數(shù)據(jù),它的棧、通用目的寄存器的內(nèi)容、程序計數(shù)器、環(huán)境變量以及打開文件描述符的集合。

廣義定義:進(jìn)程是一個具有一定獨(dú)立功能的程序關(guān)于某個數(shù)據(jù)集合的一次運(yùn)行活動。它是操作系統(tǒng)動態(tài)執(zhí)行的基本單元,在傳統(tǒng)的操作系統(tǒng)中,進(jìn)程既是基本的分配單元,也是基本的執(zhí)行單元。

進(jìn)程的概念主要有兩點(diǎn):第一,進(jìn)程是一個實(shí)體。每一個進(jìn)程都有它自己的地址空間,一般情況下,包括文本區(qū)域(text region)、數(shù)據(jù)區(qū)域(data region)和堆棧(stack region)。文本區(qū)域存儲處理器執(zhí)行的代碼;數(shù)據(jù)區(qū)域存儲變量和進(jìn)程執(zhí)行期間使用的動態(tài)分配的內(nèi)存;堆棧區(qū)域存儲著活動過程調(diào)用的指令和本地變量。第二,進(jìn)程是一個“執(zhí)行中的程序”。程序是一個沒有生命的實(shí)體,只有處理器賦予程序生命時(操作系統(tǒng)執(zhí)行之),它才能成為一個活動的實(shí)體,我們稱其為進(jìn)程。

進(jìn)程是操作系統(tǒng)中最基本、重要的概念。是多道程序系統(tǒng)出現(xiàn)后,為了刻畫系統(tǒng)內(nèi)部出現(xiàn)的動態(tài)情況,描述系統(tǒng)內(nèi)部各道程序的活動規(guī)律引進(jìn)的一個概念,所有多道程序設(shè)計操作系統(tǒng)都建立在進(jìn)程的基礎(chǔ)上。

作用:

進(jìn)程為應(yīng)用程序提供兩個抽象,一是獨(dú)立的邏輯控制流,一個是私有的地址空間。提高CPU的執(zhí)行效率,減少因?yàn)槌绦虻却龓淼腃PU空轉(zhuǎn)以及其它計算機(jī)軟硬件資源浪費(fèi)。在現(xiàn)代計算機(jī)中,進(jìn)程為用戶提供了以下假象:我們的程序好像是系統(tǒng)中當(dāng)前運(yùn)行的唯一程序一樣,我們的程序好像是獨(dú)占的使用處理器和內(nèi)存,處理器好像是無間斷的執(zhí)行 我們程序中的指令,我們程序中的代碼和數(shù)據(jù)好像是系統(tǒng)內(nèi)存中唯一的對象。

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

作用:Shell是用戶與操作系統(tǒng)之間完成交互式操作的一個接口程序,它為用戶提供簡化了的操作,它代表用戶運(yùn)行其他程序,解釋命令,連接用戶和操作系統(tǒng)以及內(nèi)核。

處理流程:

1、讀取用戶由鍵盤輸入的命令行。

2、分析命令,以命令名作為文件名,并將其它參數(shù)改造為系統(tǒng)調(diào)用execve( )內(nèi)部處理所要求的形式。

3、檢查第一個(首個、第0個)命令行參數(shù)是否是一個內(nèi)置的shell命令,是則立即執(zhí)行,如果不是,則用fork創(chuàng)建子進(jìn)程。

4、終端進(jìn)程本身調(diào)用waitpid()來等待子進(jìn)程完成(如果是后臺命令,則不等待)。當(dāng)子進(jìn)程運(yùn)行時調(diào)用execve(),子進(jìn)程根據(jù)文件名到目錄中查找有關(guān)文件,調(diào)入內(nèi)存,執(zhí)行這個程序。

5、如果命令末尾有&,則終端進(jìn)程不用執(zhí)行系統(tǒng)調(diào)用waitpid(),立即發(fā)提示符,讓用戶輸入下一條命令;否則終端進(jìn)程會一直等待,當(dāng)子進(jìn)程完成工作后,向父進(jìn)程報告,此時中斷進(jìn)程醒來,作必要的判別工作后,終端發(fā)出命令提示符,重復(fù)上述處理過程。

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

終端程序通過調(diào)用fork()函數(shù)創(chuàng)建一個子進(jìn)程,子進(jìn)程得到與父進(jìn)程完全相同但是獨(dú)立的一個副本,包括代碼段、段、數(shù)據(jù)段、共享庫以及用戶棧。子進(jìn)程還獲得與父進(jìn)程任何打開文件描述符相同的副本,父進(jìn)程和子進(jìn)程最大的不同時他們的PID是不同的。父進(jìn)程與子進(jìn)程是并發(fā)運(yùn)行的獨(dú)立進(jìn)程,內(nèi)核能夠以任意方式交替執(zhí)行它們的 邏輯控制流的指令。在子進(jìn)程執(zhí)行期間,父進(jìn)程默認(rèn)選項(xiàng)是顯示等待子進(jìn)程的完成。fork函數(shù)只會被調(diào)用一次,但會返回兩次,在父進(jìn)程中,fork返回子進(jìn)程的PID,在子進(jìn)程中,fork返回0。

6.4 Hello的execve過程

Execve函數(shù)加載并運(yùn)行可執(zhí)行目標(biāo)文件hello,且包含相對應(yīng)的一個帶參數(shù)的列表argv和環(huán)境變量的列表exenvp,,只有當(dāng)出現(xiàn)錯誤時,例如找不到hello文件時,execve才會返回-1到調(diào)用程序,execve調(diào)用成功則不會產(chǎn)生返回。

1. 為子進(jìn)程調(diào)用函數(shù)fork之后,子進(jìn)程調(diào)用execve函數(shù)(傳入命令行參數(shù))在當(dāng)前進(jìn)程的上下文中加載并運(yùn)行一個新程序hello。

2. 為執(zhí)行hello程序加載器、刪除子進(jìn)程現(xiàn)有的虛擬內(nèi)存段,execve 調(diào)用駐留在內(nèi)存中的、被稱為啟動加載器的操作系統(tǒng)代碼,并創(chuàng)建一組新的代碼、數(shù)據(jù)、堆和棧段。

3. 新的棧和堆段被初始化為零,通過將虛擬地址空間中的頁映射到可執(zhí)行文件的頁大小的片,新的代碼和數(shù)據(jù)段被初始化為可執(zhí)行文件中的內(nèi)容。最后加載器設(shè)置PC指向_start 地址,_start 最終調(diào)用 hello中的 main 函數(shù)。

4. 除了一些頭部信息,在加載過程中沒有任何從磁盤到內(nèi)存的數(shù)據(jù)復(fù)制。直到 CPU 引用一個被映射的虛擬頁時才會進(jìn)行復(fù)制,這時,操作系統(tǒng)利用它的頁面調(diào)度機(jī)制自動將頁面從磁盤傳送到內(nèi)存。

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

結(jié)合進(jìn)程上下文信息、進(jìn)程時間片,闡述進(jìn)程調(diào)度的過程,用戶態(tài)與核心態(tài)轉(zhuǎn)換等等。

Linux 系統(tǒng)中的每個程序都運(yùn)行在一個進(jìn)程上下文中,有自己的虛擬地址空間。當(dāng)shell 運(yùn)行一個程序時,父進(jìn)程生成一個子進(jìn)程,它是父進(jìn)程的一個復(fù)制。子進(jìn)程通過execve 函數(shù)系統(tǒng)調(diào)用啟動加載器。加載器刪除子進(jìn)程現(xiàn)有的虛擬內(nèi)存段,并創(chuàng)建一組新的代碼、數(shù)據(jù)、堆和棧段。新的棧和堆段被初始化為零。通過將虛擬地址空間中的頁映射到可執(zhí)行文件的頁大小的片(chunk), 新的代碼和數(shù)據(jù)段袚初始化為可執(zhí)行文件的內(nèi)容。最后,加載器跳轉(zhuǎn)到_start地址,它最終會調(diào)用應(yīng)用程序的main 函數(shù)。進(jìn)程的執(zhí)行并不一定是完整、連續(xù)地執(zhí)行完成,每一個進(jìn)程在執(zhí)行時都會有其對應(yīng)的時間片。

進(jìn)程提供給應(yīng)用程序的抽象:

(1) 一個獨(dú)立的邏輯控制流,它提供一個假象,好像我們的進(jìn)程獨(dú)占的使用處理器。

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

邏輯控制流:一系列程序計數(shù)器 PC 的值的序列叫做邏輯控制流,在同一個處理器核心中,每個進(jìn)程執(zhí)行它的流的一部分后被搶占(暫時掛起),然后輪到其他進(jìn)程,進(jìn)程輪流使用處理器。并發(fā)流:一個邏輯流的執(zhí)行在時間上與另一個流重疊,稱為并發(fā)流,這兩個流被稱為并發(fā)地運(yùn)行。多個流并發(fā)地執(zhí)行的一般現(xiàn)象被稱為并發(fā)。時間片:一個進(jìn)程執(zhí)行它的控制流的一部分的每一時間段叫做時間片。上下文信息:上下文就是內(nèi)核重新啟動一個被搶占的進(jìn)程所需要的狀態(tài)。它由通用寄存器、浮點(diǎn)寄存器、程序計數(shù)器、用戶棧、狀態(tài)寄存器、內(nèi)核棧和各種內(nèi)核數(shù)據(jù)結(jié)構(gòu)等對象的值構(gòu)成。私有地址空間:進(jìn)程為每個流都提供一種假象,好像它是獨(dú)占的使用系統(tǒng)地址空間。一般而言,和這個空間中某個地址相關(guān)聯(lián)的那個內(nèi)存字節(jié)是不能被其他進(jìn)程讀或者寫的,在這個意義上,這個地址空間是私有的。用戶模式和內(nèi)核模式:處理器通常使用一個寄存器描述了進(jìn)程當(dāng)前享有的特權(quán),對兩種模式區(qū)分。設(shè)置模式位時,進(jìn)程處于內(nèi)核模式,該進(jìn)程可以訪問系統(tǒng)中的任何內(nèi)存位置,可以執(zhí)行指令集中的任何命令;當(dāng)沒有設(shè)置模式位時,進(jìn)程就處于用戶模式中,用戶模式的進(jìn)程不允許執(zhí)行特權(quán)指令,也不允許直接引用地址空間中內(nèi)核區(qū)內(nèi)的代碼和數(shù)據(jù)。上下文切換:當(dāng)內(nèi)核選擇一個新的進(jìn)程運(yùn)行時,則內(nèi)核調(diào)度了這個進(jìn)程。在內(nèi)核調(diào)度了一個新的進(jìn)程運(yùn)行后,它就搶占當(dāng)前進(jìn)程,并使用一種稱為上下文切換的機(jī)制來將控制轉(zhuǎn)移到新的進(jìn)程:

保存以前進(jìn)程的上下文;恢復(fù)新恢復(fù)進(jìn)程被保存的上下文;將控制傳遞給這 個新恢復(fù)的進(jìn)程 ,來完成上下文切換。

下面來看hello的進(jìn)程執(zhí)行。最初hello運(yùn)行在用戶模式下,輸出edb --run ./hello 2021112655?gzb?3,然后hello調(diào)用sleep函數(shù)之后進(jìn)程陷入內(nèi)核模式,內(nèi)核處理休眠請求主動釋放當(dāng)前進(jìn)程,并將hello進(jìn)程從運(yùn)行隊(duì)列中移出加入等待隊(duì)列,定時器開始計時,內(nèi)核進(jìn)行上下文切換將當(dāng)前進(jìn)程的控制權(quán)交給其他進(jìn)程,當(dāng)定時器發(fā)送一個中斷信號,此時進(jìn)入內(nèi)核狀態(tài)執(zhí)行中斷處理,將hello進(jìn)程從等待隊(duì)列中移出重新加入到運(yùn)行隊(duì)列,hello進(jìn)程繼續(xù)進(jìn)行自己的控制邏輯流。

圖三十六.調(diào)用edb及程序執(zhí)行結(jié)果

圖三十七.sleep進(jìn)程上下文切換

6.6 hello的異常與信號處理

?hello執(zhí)行過程中會出現(xiàn)哪幾類異常,會產(chǎn)生哪些信號,又怎么處理的。

?程序運(yùn)行過程中可以按鍵盤,如不停亂按,包括回車,Ctrl-Z,Ctrl-C等,Ctrl-z后可以運(yùn)行ps ?jobs ?pstree ?fg ?kill 等命令,請分別給出各命令及運(yùn)行結(jié)截屏,說明異常與信號的處理。

異常就是控制流中的突變,用來響應(yīng)處理器狀態(tài)中的某些變化,它可以分為四類:

1、中斷:中斷是處理來自I/O設(shè)備的信號的結(jié)果,是異步發(fā)生的,總是返回到下一條指令。

2、陷阱:它是有意的異常,是執(zhí)行一條指令的結(jié)果,它是同步發(fā)生的,總是返回到下一條指令。

3、故障:是由錯誤情況引起,它可能能夠被故障處理程序修正。它是同步發(fā)生的,并且可能返回到當(dāng)前指令。

4、終止:是不可恢復(fù)的致命錯誤造成的結(jié)果,通常是一些硬件錯誤。它也是同步的,且不會返回。

信號是更高層的軟件形式的異常,它就是一條小消息,通知進(jìn)程系統(tǒng)中發(fā)生了一個某種類型的事件。它提供了一種機(jī)制,通知用戶進(jìn)程發(fā)生了異常。Linux信號主要有以下幾種:

圖三十八.Linux信號

鍵入ctrl-z:

圖三十九.鍵入ctrl-z

ps查看后臺:

圖四十.ps查看后臺

jobs查看后臺job號:

圖四十一.jobs查看后臺job號

fg調(diào)到前臺:

圖四十二.fg調(diào)到前臺

由上可知:鍵入ctrl-z的默認(rèn)結(jié)果是掛起前臺的作業(yè),hello進(jìn)程并沒有回收,而是運(yùn)行在后臺下。

圖四十三.鍵入crtl-c及后續(xù)驗(yàn)證

由圖四十三可知:在鍵盤上輸入ctrl-c會導(dǎo)致內(nèi)核發(fā)送一個SIGINT信號到前臺進(jìn)程組的每個進(jìn)程,默認(rèn)情況是終止前臺作業(yè)。

kill指令:掛起的進(jìn)程被終止,在ps中無法查到到其PID。

圖四十四.kill命令

6.7本章小結(jié)

本章圍繞hello的進(jìn)程管理展開,簡述了進(jìn)程的概念與作用、shell-bash的作用與處理流程,著重分析了調(diào)用 fork 創(chuàng)建新進(jìn)程,調(diào)用 execve函數(shù)執(zhí)行hello,hello的進(jìn)程執(zhí)行,以及hello的異常與信號處理,加深了對異常與信號處理的理解。

結(jié)論

用計算機(jī)系統(tǒng)的語言,逐條總結(jié)hello所經(jīng)歷的過程。

你對計算機(jī)系統(tǒng)的設(shè)計與實(shí)現(xiàn)的深切感悟,你的創(chuàng)新理念,如新的設(shè)計與實(shí)現(xiàn)方法。

hello的一生經(jīng)歷了被編寫成代碼、預(yù)處理、編譯、匯編、鏈接、運(yùn)行、創(chuàng)建子進(jìn)程、加載、執(zhí)行指令、訪問內(nèi)存、動態(tài)內(nèi)存分配、發(fā)送信號、終止。

hello程序雖然簡單,但其經(jīng)歷的一生豐富而精彩,極大加深了我們對計算機(jī)系統(tǒng)的理解。

預(yù)處理:從hello.c生成.i文件,將hello.c中調(diào)用的外部庫展開合并到.i中

編譯:由hello.i生成hello.s匯編文件

匯編:將hello.s文件翻譯為機(jī)器語言指令,并打包成可重定位目標(biāo)程序hello.o

鏈接:將hello.o可重定位目標(biāo)文件和動態(tài)鏈接庫鏈接成可執(zhí)行目標(biāo)程序hello

運(yùn)行:在shell中輸入命令

創(chuàng)建子進(jìn)程:shell用fork為hello程序創(chuàng)建子進(jìn)程

加載:shell調(diào)用execve函數(shù),將hello程序加載到該子進(jìn)程,映射虛擬內(nèi)存

執(zhí)行指令:CPU為進(jìn)程分配時間片,加載器將計數(shù)器預(yù)置在程序入口點(diǎn),則hello可以順序執(zhí)行自己的邏輯控制流

訪問內(nèi)存:MMU將虛擬內(nèi)存地址映射成物理內(nèi)存地址,CPU通過其來訪問

動態(tài)內(nèi)存分配:根據(jù)需要申請動態(tài)內(nèi)存

信號:shell的信號處理函數(shù)可以接受程序的異常和用戶的請求

終止:執(zhí)行完成后父進(jìn)程回收子進(jìn)程,內(nèi)核刪除為該進(jìn)程創(chuàng)建的數(shù)據(jù)結(jié)構(gòu)

計算機(jī)系統(tǒng)的設(shè)計與實(shí)現(xiàn)非常精妙,應(yīng)用了大量數(shù)學(xué)理論,一些結(jié)構(gòu)設(shè)計也體現(xiàn)了許多哲學(xué)思想,僅僅是簡略的學(xué)習(xí),就已讓我感到無比的驚訝并產(chǎn)生了濃厚的興趣。然而,如此系統(tǒng)一定還有前進(jìn)的空間,未來的計算機(jī)系統(tǒng)會是哪種樣貌,我無比期待。

文件名 文件功能

hello.c 源程序

hello.i 預(yù)處理之后得到的文本文件

hello.s 編譯得到的匯編文件

hello.o 匯編得到的可重定位目標(biāo)文件

hello 鏈接得到的可執(zhí)行目標(biāo)文件

hello1.elf hello.o經(jīng)readelf輸出的elf文件

hello2.elf hello經(jīng)readelf輸出的elf文件

柚子快報激活碼778899分享:系統(tǒng)架構(gòu) 程序人生Hello

http://yzkb.51969.com/

文章鏈接

評論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。

轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/18838842.html

發(fā)布評論

您暫未設(shè)置收款碼

請在主題配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問

文章目錄