當前位置:
首頁 > 最新 > 從hello world初探計算機系統

從hello world初探計算機系統

相信幾乎所有的程序員學習軟體開發的第一個接觸的例子便是hello world,哈哈哈,為啥呢?畢竟這個是最簡單,而且是最容易寫的代碼,那麼今天我們從hello world開始,了解下計算機系統的組成以及程序的執行過程吧。

首先,我們先附上C語言版的hello world代碼,C語言是非常貼近底層硬體的一種編程語言,僅次於彙編語言,操作系統的核心還是C語言和彙編語言結合實現的,用C語言可以更了解計算機系統,好了,廢話不多說,看下代碼,如下:

#include

intmain(intargc,char** argv )

{

printf("hello world
");

return;

}

接著我們使用GCC編譯工具來對代碼進行編譯,那麼我們就有必要先來了解下GCC是個什麼東西?GCC是GNU項目中的其中一個工具,百度百科上說,GCC 原名為 GNU C 語言編譯器(GNU C Compiler),因為它原本只能處理 C語言。GCC 很快地擴展,變得可處理 C++。後來又擴展能夠支持更多編程語言,如Fortran、Pascal、Objective-C、Java、Ada、Go以及各類處理器架構上的彙編語言等,所以改名GNU編譯器套件(GNU Compiler Collection)。 簡單來說,就是能夠將我們寫的代碼編譯,或者說翻譯為機器能夠理解的語言。GCC編譯器具體的的工作流程是如下:

圖1 編譯過程

接下來我們詳細說明下以上四個過程,在預處理階段,使用命令

gcc -E hello.c -o hello.i

預處理器cpp會查找我們代碼中的#字元開頭的代碼,將頭文件或者宏定義的內容展開並插入到源程序hello.c中,得到一個hello.i的源程序;接著進入編譯階段,使用命令

gcc -S hello.i -o hello.s

編譯器ccl將源程序hello.i翻譯成hello.s彙編代碼文件,裡面為具體的彙編代碼,如下,本文使用的是 MinGW GCC 7.1.0編譯所得,不同的編譯器版本編譯後生成的代碼會有些許差異,但過程及功能是相同的,此處我們先不詳細講述彙編代碼,今後再詳細敘述這塊。

.file"hello.c"

.def__main;.scl2;.type32;.endef

.section .rdata,"dr"

.LC0:

.ascii"hello world"

.text

.globlmain

.defmain;.scl2;.type32;.endef

.seh_procmain

main:

pushq%rbp

.seh_pushreg%rbp

movq%rsp, %rbp

.seh_setframe%rbp,

subq$32, %rsp

.seh_stackalloc32

.seh_endprologue

movl%ecx,16(%rbp)

movq%rdx,24(%rbp)

call__main

leaq.LC0(%rip), %rcx

callputs

movl$, %eax

addq$32, %rsp

popq%rbp

ret

.seh_endproc

.ident"GCC: (x86_64-posix-seh-rev2, Built by MinGW-W64 project) 7.1.0"

.defputs;.scl2;.type32;.endef

再接著便是彙編階段,使用命令

gcc -c hello.s -o hello.o

彙編器as將helo.s翻譯成機器語言的指令,並生成一個hello.o的文件,該文件是個可重定位的目標文件,可重定位這次聽起來有點陌生,今後我們將再詳細介紹這塊,此處先略過。另外這個可重定位的目標文件是二進位存儲,我們使用記事本打開時會發現裡面有很多亂碼。最後到了鏈接階段,使用命令

gcc hello.o -o hello

鏈接器ld將hello.o以及printf函數所調用的printf.o鏈接在一起,生成可執行目標文件,在Windows上,可執行目標文件的擴展名為.exe,而Linux上則無擴展名,但許可權屬性為可執行許可權。在Windows上,我們通過cmd命令來執行生成的可執行目標文件,在Linux上可使用shell來執行,此處我們以大家較為熟悉的Windows環境為例介紹下。在cmd窗口上我們輸入hello或者hello.exe,則可以在界面上顯示hello world。那麼這過程究竟發生了什麼事情,接下來,我們詳細介紹下。

為了了解我們運行hello可執行程序的時候發生了什麼,我們需要了解下計算機的硬體組織結構,如下圖所示,

圖2 計算機硬體組織結構

當我們打開cmd窗口時,cmd程序在等待我們輸入命令,當我們輸入hello後,按下回車鍵時,cmd程序知道我們結束了命令的輸入,於是調用了很多指令來載入hello可執行的目標文件,具體為通過系統匯流排訪問IO橋,再通過I/O匯流排和磁碟控制器讀取硬碟中存儲的目標文件,一旦目標文件hello中的代碼和數據被載入到內存中,CPU變開支執行main程序中的機器語言指令,不過,具體在執行main函數之前,CPU會執行一系列操作,此處我們先不詳細說明,今後會詳細描述這期間發生了什麼,我們先理解為從main函數開始執行。接著這些指令將hello world
的字元串從內存中複製到寄存器中,那麼這時候,就涉及到何謂寄存器?這邊解釋下,寄存器是中央處理器(CPU)內的組成部分。寄存器是有限存儲容量的高速存儲部件,它們可用來暫存指令、數據和地址。其中一個特殊的寄存器為PC寄存器,該寄存器存放當前執行的指令地址,寄存器這塊大家可以網上搜索一下,了解有哪些寄存器以及它們的作用是什麼。好了,我們接著往下,將字元串複製到寄存器後,再從寄存器複製到顯示設備,最終顯示到顯示器中,這期間又涉及到CPU的很多寄存器操作,此處略過。

讓我們回到hello world的例子中來,我們執行hello程序的時候,並沒有直接操作顯示器,內存和硬碟,但是這過程是如何發生的呢?沒錯,就是操作系統。操作系統是一種系統軟體,我們可以把它當做是一層軟體,應用程序也就是我們的hello可執行目標文件對硬體的操作都必須通過這層軟體來實現。具體結構如下:

圖3 計算機系統分層結構

操作系統有兩個基本的功能,1、防止硬體被應用程序藍牙;2、提供一種簡單而且統一的方式來控制複雜和不同的底層硬體設備,即系統調用(system call),而實現這兩個功能則採用了一些抽象化的概念,比如虛擬內存、進程和文件,文件是對I/O設備的抽象,即Linux中的一切皆文件思想,虛擬內存則是對內存的抽象,進行則是對虛擬內存、進程和文件的抽象。那麼我們最後在簡單講述下這三個來作為本文的結束語吧。

進程:在一個系統上可以同時運行多個進行,比如同時在運行QQ,網易雲音樂,瀏覽器等,此處的同時運行並非是真正意義上的同時,無論是單核還是多核的系統,一個CPU看上去都像是在並發地執行多個進程(並發運行是指一個進行的指令和另一個進程的指令再交錯執行),這是通過CPU在進行檢不斷切換來實現的,而操作系統實現這種交錯執行的機制叫做上下文切換。

虛擬內存:它為每個進程提供了一個假象,也就是每個進程都單獨佔用內存,每個進程看到的內存都是一致的,也稱作為虛擬地址空間,也就是每個進程的虛擬地址空間的起始都是一樣的,如下圖所示:

圖4 進程的虛擬地址空間

文件:每個I/O設備,包括鍵盤、硬碟、顯示器,甚至是網路都是可以做是文件,我們所有的輸入輸出都是通過系統調用函數讀寫文件來實現的,它嚮應用程序提供了一個統一的方式開看待操作系統中可以含有的所有各種I/O設備。

如果覺得本文還不錯的話,歡迎點贊轉發,以及關注本公眾號,感謝您的支持!

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 IT工程師之道 的精彩文章:

TAG:IT工程師之道 |