本書主要面向應用型大學計算機類專業(yè)學生,從程序員的視角出發(fā),圍繞可執(zhí)行文件的生成、加載和執(zhí)行,重點介紹如何利用計算機系統(tǒng)相關知識來編寫更有效的程序。全書將每個環(huán)節(jié)涉及的硬件和軟件的基本概念關聯(lián)起來,幫助學生建立完整的層次框架,從而加強系統(tǒng)觀。本書共分8章,涵蓋計算機系統(tǒng)基礎、高級語言程序、數(shù)據(jù)的機器級表示、數(shù)據(jù)的基本運算、指令集體系結(jié)構、程序的機器級表示、程序的鏈接、程序的加載和執(zhí)行等內(nèi)容。本書內(nèi)容詳盡、概念清楚、實例豐富,適合作為高等學校計算機專業(yè)計算機系統(tǒng)相關課程的教材,也適合相關專業(yè)的研究生和技術人員閱讀參考。
本書主要面向應用型大學計算機類專業(yè)學生,從程序員的視角出發(fā),圍繞可執(zhí)行文件的生成、加載和執(zhí)行,重點介紹如何利用計算機系統(tǒng)相關知識來編寫更有效的程序。
前 言
隨著計算機信息技術的飛速發(fā)展,早期多人一機的主機終端模式發(fā)展為PC(個人計算機)時代的一人一機模式,又發(fā)展為如今的人機物互聯(lián)的智能化大數(shù)據(jù)并行計算模式,F(xiàn)如今各行各業(yè)都離不開計算機信息技術,計算機信息產(chǎn)業(yè)對我國現(xiàn)代化戰(zhàn)略目標的實現(xiàn)發(fā)揮著極其重要的支撐作用。這對計算機專業(yè)人才培養(yǎng)提出了更高的要求,原先傳統(tǒng)的計算機專業(yè)教學課程體系和教學內(nèi)容已經(jīng)遠遠不能反映現(xiàn)代社會對計算機專業(yè)人才的培養(yǎng)要求,特別是傳統(tǒng)課程體系按計算機系統(tǒng)抽象層劃分課程,不同課程內(nèi)容之間相互割裂,軟件和硬件分離,導致學生無法形成計算機系統(tǒng)的整體概念,缺乏系統(tǒng)思維。為此,過去十多年來,高等學校計算機類專業(yè)教學指導委員會在全國開展了計算機類專業(yè)系統(tǒng)能力培養(yǎng)教學改革,重新規(guī)劃教學課程體系,調(diào)整教學理念和教學內(nèi)容,加強學生系統(tǒng)能力培養(yǎng),使學生能夠深刻理解計算機系統(tǒng)整體概念,更好地掌握軟/硬件協(xié)同設計和并行程序設計技術,從而更多地培養(yǎng)出滿足業(yè)界需求的各類計算機專業(yè)人才。
雖然不同類型高校的計算機類專業(yè)人才培養(yǎng)目標有所區(qū)別,例如,對于應用型大學計算機專業(yè)學生來說,畢業(yè)后絕大部分將從事計算機系統(tǒng)應用開發(fā)工作而不會直接從事計算機硬件和系統(tǒng)軟件的設計開發(fā)工作,但是,不管培養(yǎng)計算機系統(tǒng)哪個層面的技術人才,計算機專業(yè)教育都要重視學生系統(tǒng)觀的培養(yǎng)。本書的主要目的就是為加強計算機專業(yè)學生的系統(tǒng)觀而提供一本關于計算機系統(tǒng)導論課程教學的教材,該課程主要面向應用型大學的計算機類專業(yè)課程體系而設置。
本書的寫作思路和內(nèi)容組織
本書從程序員視角出發(fā),重點介紹應用程序員應該如何利用計算機系統(tǒng)相關知識來編寫更有效的程序。本書以高級語言程序的開發(fā)和運行過程為主線,將該過程中每個環(huán)節(jié)涉及的硬件和軟件的基本概念關聯(lián)起來,試圖使讀者建立完整的計算機系統(tǒng)層次結(jié)構框架,了解計算機系統(tǒng)全貌和相關知識體系,初步理解計算機系統(tǒng)中每個抽象層及其相互轉(zhuǎn)換關系,建立高級語言程序、ISA(指令集體系結(jié)構)、OS(操作系統(tǒng))、編譯器、鏈接器之間的相互關聯(lián),對指令在硬件上的執(zhí)行過程和指令的底層硬件執(zhí)行機制有一定的認識和理解,從而增強程序調(diào)試、性能優(yōu)化、移植和健壯性保證等方面的能力,并為后續(xù)相關課程的學習打下堅實基礎。
本書從高級語言程序中的變量/常量及其運算、控制結(jié)構語句和函數(shù)調(diào)用出發(fā),將C語言程序與后續(xù)各章節(jié)的內(nèi)容建立關聯(lián)并進行導引。本書的具體內(nèi)容包括數(shù)據(jù)在機器中的表示、數(shù)據(jù)在機器中的基本運算、指令集體系結(jié)構的基本內(nèi)容、程序中各類控制語句和函數(shù)調(diào)用對應的機器級代碼結(jié)構、復雜數(shù)據(jù)類型的分配和訪問、緩沖區(qū)溢出及其攻擊和防范、可執(zhí)行目標代碼的鏈接和加載、可執(zhí)行文件中指令序列的基本執(zhí)行過程等。
不管構建一個計算機系統(tǒng)的各類硬件和軟件差別有多大,計算機系統(tǒng)的構建原理以及在計算機系統(tǒng)上程序的轉(zhuǎn)換和執(zhí)行機理都是相通的,因而,本書僅介紹一種特定計算機系統(tǒng)平臺下的相關內(nèi)容。
本書共分8章:第1章是計算機系統(tǒng)概述;第2章是高級語言程序;第3章和第4章分別介紹高級語言程序中數(shù)據(jù)的機器級表示及其在機器中的各類基本運算方法;第5章主要介紹IA-32/x86-64指令系統(tǒng);第6章介紹C語言程序中的函數(shù)調(diào)用和各類語句所對應的底層機器級表示,展示高級語言程序與機器級語言程序的對應轉(zhuǎn)換關系;第7章主要介紹如何將不同的程序模塊鏈接起來構成可執(zhí)行目標文件,展示程序的鏈接環(huán)節(jié);第8章簡要介紹程序的加載和執(zhí)行,包括進程的存儲器映射和進程的上下文切換,以及用于執(zhí)行程序的CPU的基本功能和基本組成。
讀者所需的背景知識
本書假定讀者有一定的C語言程序設計基礎,已經(jīng)掌握了C語言的語法和各類控制語句、數(shù)據(jù)類型及其運算、各類表達式、函數(shù)調(diào)用和C語言的標準庫函數(shù)等相關知識。
此外,本書介紹了計算機中的基本運算電路和程序中指令的執(zhí)行過程,理解這些內(nèi)容需要掌握布爾代數(shù)、邏輯表達式和基本邏輯門電路等基礎知識,因而本書假定讀者具有數(shù)字邏輯電路課程的基礎。如果讀者不具備這些背景知識也沒有關系,本書4.1節(jié)對布爾代數(shù)和數(shù)字邏輯基礎進行了簡要介紹,在此基礎上可進一步學習和理解基本運算電路與指令執(zhí)行過程等內(nèi)容。
本書所用平臺為IA-32/x86-64 Linux GCC C語言。書中大多數(shù)C語言程序?qū)臋C器級表示都是基于IA-32/x86-64 Linux平臺用GCC編譯器生成的。本書會在介紹程序的機器級表示之前,先簡要介紹IA-32/x86-64指令集體系結(jié)構,包括其機器語言和匯編語言,因而,讀者不需要具有任何機器語言和匯編語言的背景知識。
對于gcc工具軟件和GDB調(diào)試軟件的使用方法,本書附錄中做了簡要介紹,許多使用上的細節(jié)問題請讀者自行在網(wǎng)上搜索答案。
本書在課程體系中的位置
傳統(tǒng)計算機專業(yè)課程體系設置多按計算機系統(tǒng)層次結(jié)構進行橫向切分,自下而上分解成數(shù)字邏輯電路、計算機組成原理、匯編程序設計、操作系統(tǒng)、編譯原理、程序設計等課程,而且,每門課程都僅局限在本抽象層,相互之間幾乎沒有關聯(lián),因而學生對整個計算機系統(tǒng)的認識過程就像盲人摸象一樣,很難形成對完整計算機系統(tǒng)的全面認識。
本書在內(nèi)容上注重計算機系統(tǒng)各抽象層的縱向關聯(lián),將高級語言程序、匯編語言程序、機器代碼及其執(zhí)行串聯(lián)起來,為學生進一步學習后續(xù)相關課程打下堅實的基礎,適合在完成程序設計基礎課程后進行學習。本書內(nèi)容貫穿計算機系統(tǒng)的各個抽象層,是關于計算機系統(tǒng)的最基礎的內(nèi)容,因而使用本書作為教材開設的課程適用于所有計算機相關專業(yè)。使用本書作為教材開設的課程名稱可以是計算機系統(tǒng)導論 計算機系統(tǒng)基礎等,該課程作為高級語言程序設計課程的解疑答惑課程,在程序設計課程、講解程序編譯轉(zhuǎn)換及程序運行和系統(tǒng)管理機制等系統(tǒng)類課程之間起著承上啟下的作用,因此該課程可以是后續(xù)所有系統(tǒng)類課程的前導課程。
如何閱讀本書
本書試圖將計算機系統(tǒng)各抽象層涉及的重要概念通過程序的開發(fā)和加載、執(zhí)行為主線串接起來,因而本書涉及的所有問題和內(nèi)容都是從程序出發(fā)的,這些內(nèi)容涉及程序中數(shù)據(jù)的表示及運算,或者涉及程序?qū)臋C器級表示,或者涉及多個程序模塊的鏈接,或者涉及程序的加載及執(zhí)行,或者涉及程序執(zhí)行過程中的異常中斷事件等。從讀者熟悉的程序開發(fā)和加載、執(zhí)行出發(fā)來介紹計算機系統(tǒng)基本概念,可以使讀者將新學的概念與已有的知識建立關聯(lián),不斷拓展和深化知識體系。特別是,因為所有內(nèi)容都從程序出發(fā),所以所有內(nèi)容都可以通過具體程序進行驗證,讀者可以在邊學邊做中將所學知識轉(zhuǎn)化為實踐能力。
本書雖然涉及內(nèi)容較廣,但所有內(nèi)容之間具有非常緊密的關聯(lián),因而,建議讀者在閱讀本書時采用整體性學習方法:通過對第1章的學習先建立一個粗略的計算機系統(tǒng)整體框架;然后通過第2章高級語言程序的相關內(nèi)容,一邊回顧前導課程所學內(nèi)容,一邊將高級語言程序中的相關內(nèi)容與后續(xù)各章內(nèi)容建立關聯(lián);再不斷地通過對后續(xù)章節(jié)的學習,將新的內(nèi)容與前面所學內(nèi)容貫穿起來,以逐步細化計算機系統(tǒng)框架內(nèi)容,最終形成比較完整的、相互密切關聯(lián)的計算機系統(tǒng)整體概念。
本書提供了大量的例題和課后習題,這些題目大多是具體的程序示例,通過對這些示例的分析或驗證性實踐,讀者可以對基本概念有更加深刻的理解。因此,讀者在閱讀本書時,若遇到一些難以理解的概念,可以先不用仔細琢磨,而是通過具體的程序示例來對照基本概念和相關手冊中的具體規(guī)定進行理解。
本書提供的小貼士對理解書中的基本概念很有用,由于篇幅有限,這些補充資料不可能占用很大篇幅,大多是簡要內(nèi)容。如果讀者希望了解更多細節(jié),可以自行到網(wǎng)上查找。
本書雖然涉及高級語言程序設計、數(shù)字邏輯電路、匯編語言程序、計算機組成與系統(tǒng)結(jié)構、操作系統(tǒng)、編譯和鏈接等內(nèi)容,但是,本書主要講解它們之間的關聯(lián),而不提供其細節(jié),如果讀者想要了解更詳細的關于數(shù)字系統(tǒng)設計、操作系統(tǒng)、編譯技術、計算機體系結(jié)構等方面的內(nèi)容,還是要閱讀相關的專業(yè)書籍。不過,若讀者學完本書后再去閱讀專業(yè)書籍,則會輕松很多。
致謝
衷心感謝在本書的編寫過程中給予我熱情鼓勵和中肯建議的各位專家、同事和學生,正是因為有他們的鞭策、鼓勵和協(xié)助,本書的編寫才能順利完成。
在本書的編寫過程中,得到了國防科技大學王志英教授、北京航空航天大學馬殿富教授、西北工業(yè)大學周興社教授、武漢大學何炎祥教授、北京大學陳向群教授等各位專家的悉心指導和熱情鼓勵,浙江大學城市學院楊起帆教授對本書提出了許多寶貴的修改意見,西安郵電大學陳莉君教授、山東大學楊興強教授和中國石油大學(華東)張瓊聲副教授從書稿的篇章結(jié)構到內(nèi)容各方面都提出了許多寶貴的意見,中國海洋大學蔣永國副教授對本書的編寫修改提出了很好的建議,中國石油大學(華東)范志東同學提供了第7章中某可執(zhí)行文件程序頭表中的部分信息,在此表示衷心的感謝。
本書以我在南京大學講授的計算機組成與系統(tǒng)結(jié)構和 計算機系統(tǒng)基礎兩門課程的部分講稿內(nèi)容為基礎,感謝南京大學各位同人和各屆學生對講稿內(nèi)容與教學過程所提出的寶貴反饋和改進意見,這使本書的內(nèi)容得以不斷改進和完善。本書第二作者余子濠博士對書中大部分程序進行了驗證,并對書中相關內(nèi)容與對應手冊中的規(guī)定進行了詳細的核對和審查,對一些關鍵內(nèi)容提出了有益的修改意見。
結(jié)束語
本書廣泛參考了國內(nèi)外相關的經(jīng)典教材和教案,在內(nèi)容上力求做到取材先進并反映技術發(fā)展現(xiàn)狀;在內(nèi)容的組織和描述上力求概念準確、語言通俗易懂、實例深入淺出,并盡量利用圖示和實例來解釋和說明問題。但是,由于計算機系統(tǒng)相關技術仍在不斷發(fā)展,新的思想、概念、技術和方法不斷涌現(xiàn),加之作者水平有限,在編寫中難免存在不當或遺漏之處,懇請廣大讀者對本書的不足之處給予指正,以便在后續(xù)的版本中予以改進。
袁春風 于南京
2023年3月
目 錄
前言
第1章 計算機系統(tǒng)概述 1
1.1 計算機基本工作原理 1
1.1.1 馮·諾依曼結(jié)構基本思想 1
1.1.2 馮·諾依曼模型機基本結(jié)構 2
1.1.3 程序和指令的執(zhí)行過程 4
1.2 程序的開發(fā)與運行 7
1.2.1 程序設計語言和翻譯程序 7
1.2.2 從源程序到可執(zhí)行文件 9
1.2.3 可執(zhí)行文件的啟動和執(zhí)行 11
1.3 計算機系統(tǒng)的層次結(jié)構 12
1.3.1 計算機系統(tǒng)抽象層的轉(zhuǎn)換 12
1.3.2 計算機系統(tǒng)核心層之間的關聯(lián) 14
1.3.3 計算機系統(tǒng)的不同用戶 17
1.4 本書的主要內(nèi)容和組織結(jié)構 19
1.5 小結(jié) 21
習題 22
第2章 高級語言程序 23
2.1 C語言概述 23
2.2 變量和常量及其類型 24
2.2.1 C程序中的變量及其類型 24
2.2.2 C程序中的常量及其類型 25
2.3 表達式及運算符 26
2.3.1 C語言表達式中的運算符 26
2.3.2 C語言程序中的運算 27
2.4 控制結(jié)構和函數(shù)調(diào)用 29
2.4.1 C語言中的控制結(jié)構 29
2.4.2 C語言中的函數(shù)調(diào)用 30
2.4.3 變量的作用域及其存儲分配 32
2.4.4 C標準I/O庫函數(shù) 35
2.5 小結(jié) 37
習題 37
第3章 數(shù)據(jù)的機器級表示 39
3.1 二進制編碼和進位計數(shù)制 39
3.1.1 信息的二進制編碼 39
3.1.2 進位計數(shù)制 40
3.1.3 進位計數(shù)制之間數(shù)據(jù)的轉(zhuǎn)換 41
3.2 整數(shù)的表示 44
3.2.1 定點數(shù)的編碼表示 44
3.2.2 無符號整數(shù)和帶符號整數(shù)的表示 49
3.2.3 C語言中的整數(shù)及其相互轉(zhuǎn)換 49
3.3 浮點數(shù)的表示 52
3.3.1 浮點數(shù)的表示范圍 52
3.3.2 浮點數(shù)的規(guī)格化 53
3.3.3 IEEE 754浮點數(shù)標準 53
3.3.4 C語言中的浮點數(shù)類型 57
3.4 非數(shù)值數(shù)據(jù)的編碼表示 59
3.4.1 位串或邏輯值 59
3.4.2 西文字符 59
3.4.3 漢字字符 60
3.5 數(shù)據(jù)的寬度和存儲 62
3.5.1 數(shù)據(jù)的寬度和長度單位 62
3.5.2 數(shù)據(jù)的存儲和排列順序 64
3.5.3 數(shù)據(jù)擴展和數(shù)據(jù)截斷操作 69
3.6 小結(jié) 70
習題 70
第4章 數(shù)據(jù)的基本運算 74
4.1 布爾代數(shù)和邏輯運算 74
4.1.1 布爾代數(shù) 74
4.1.2 邏輯電路基礎 76
4.2 基本運算電路 77
4.2.1 多路選擇器 77
4.2.2 全加器和加法器 77
4.2.3 帶標志信息加法器 78
4.2.4 算術邏輯部件 79
4.3 整數(shù)加減運算 80
4.3.1 補碼加減運算器 80
4.3.2 無符號整數(shù)加減運算 83
4.3.3 帶符號整數(shù)加減運算 84
4.3.4 對整數(shù)加減運算結(jié)果的解釋 85
4.4 整數(shù)的乘運算 86
4.4.1 無符號數(shù)乘法運算 87
4.4.2 原碼乘法運算 88
4.4.3 補碼乘法運算 89
4.4.4 兩種整數(shù)乘的關系 90
4.5 整數(shù)的除運算 92
4.5.1 無符號數(shù)除法運算 93
4.5.2 原碼除法運算 94
4.5.3 補碼除法運算 96
4.6 整數(shù)常量的乘除運算 97
4.7 浮點數(shù)運算 98
4.7.1 浮點數(shù)加減運算 99
4.7.2 浮點數(shù)乘除運算 104
4.7.3 浮點運算異常和精度 105
4.8 小結(jié) 107
習題 108
第5章 指令集體系結(jié)構 113
5.1 程序轉(zhuǎn)換概述 113
5.1.1 機器指令與匯編指令 113
5.1.2 指令集體系結(jié)構概述 115
5.1.3 生成機器代碼的過程 116
5.2 IA-32指令系統(tǒng)概述 122
5.2.1 數(shù)據(jù)類型及格式 123
5.2.2 寄存器組織 124
5.2.3 操作數(shù)的尋址方式 128
5.2.4 機器指令格式 132
5.3 IA-32常用指令類型 133
5.3.1 傳送指令 133
5.3.2 定點算術運算指令 137
5.3.3 按位運算指令 140
5.3.4 程序執(zhí)行流控制指令 142
5.3.5 x87浮點處理指令 147
5.3.6 MMX/SSE指令集 150
5.4 兼容IA-32的64位系統(tǒng) 152
5.4.1 x86-64的發(fā)展簡史 152
5.4.2 x86-64的基本特點 153
5.4.3 x86-64的基本指令 154
5.5 小結(jié) 157
習題 157
第6章 程序的機器級表示 160
6.1 過程調(diào)用的機器級表示 160
6.1.1 IA-32中過程的調(diào)用約定 160
6.1.2 變量的作用域和生存期 164
6.1.3 按值傳遞參數(shù)和按地址傳遞
參數(shù) 166
6.1.4 遞歸過程調(diào)用 171
6.1.5 非靜態(tài)局部變量的存儲分配 173
6.1.6 x86-64的過程調(diào)用 176
6.2 流程控制語句的機器級表示 181
6.2.1 選擇語句的機器級表示 182
6.2.2 循環(huán)結(jié)構的機器級表示 186
6.3 復雜數(shù)據(jù)類型的分配和訪問 189
6.3.1 數(shù)組的分配和訪問 189
6.3.2 結(jié)構體數(shù)據(jù)的分配和訪問 193
6.3.3 聯(lián)合體數(shù)據(jù)的分配和訪問 196
6.3.4 數(shù)據(jù)的對齊 198
6.4 越界訪問和緩沖區(qū)溢出 201
6.4.1 緩沖區(qū)溢出 201
6.4.2 緩沖區(qū)溢出攻擊 203
6.4.3 緩沖區(qū)溢出攻擊的防范 206
6.5 小結(jié) 209
習題 210
第7章 程序的鏈接 223
7.1 編譯、匯編和靜態(tài)鏈接 223
7.1.1 預處理、編譯和匯編 223
7.1.2 可執(zhí)行目標文件的生成 225
7.2 目標文件格式 227
7.2.1 ELF目標文件格式 227
7.2.2 可重定位目標文件格式 228
7.2.3 可執(zhí)行目標文件格式 232
7.2.4 可執(zhí)行文件的存儲器映射 234
7.3 符號表和符號解析 236
7.3.1 符號和符號表 236
7.3.2 符號解析 239
7.3.3 與靜態(tài)庫的鏈接 243
7.4 重定位 246
7.4.1 重定位信息 246
7.4.2 重定位過程 247
7.5 動態(tài)鏈接 251
7.5.1 動態(tài)鏈接的特性 251
7.5.2 程序加載時的動態(tài)鏈接 252
7.5.3 程序運行時的動態(tài)鏈接 253
7.5.4 位置無關代碼 255
7.6 小結(jié) 260
習題 260
第8章 程序的加載和執(zhí)行 266
8.1 進程與可執(zhí)行文件的加載 266
8.1.1 程序和進程的概念 266
8.1.2 Linux系統(tǒng)的虛擬地址空間 267
8.1.3 進程的存儲器映射 270
8.1.4 程序的加載過程 271
8.2 進程的控制 274
8.2.1 進程的邏輯控制流 275
8.2.2 進程的上下文切換 276
8.3 程序執(zhí)行與CPU基本組成 278
8.3.1 程序及指令的執(zhí)行過程 278
8.3.2 打斷程序正常執(zhí)行的事件 280
8.3.3 CPU的基本功能和組成 281
8.4 小結(jié) 283
習題 284
附錄A gcc的常用命令行選項 287
附錄B GDB的常用命令 288
參考文獻 291