程式的執行步驟(程式在電腦裡如何運行)

Sharon Peng
Dec 13, 2021

--

首先,如果有一直在關注我發文的夥伴們,可能會發現我文章的內容十分凌亂,內容包括:C程式語言、演算法、資料結構、機器學習、有時居然還有t程式解題??這是因為筆者自己在學習的過程中,有很多東西都摸不清楚,或是很希望當初可以看到類似的文章,來幫助我釐清觀念。因此想把曾經苦思很久的觀念或想法都重新整理一遍,幫助到未來有需要的人。

還請各位原諒一下這些凌亂的文章~~

話不多說,直接開始今天的主題吧!

前情提要:想當初在學習程式語言的時候,隱隱約約有聽到老師說C語言是怎麼進行的,會從.c 檔,轉成.s 檔,最後又變成.a 檔等等。當聽到的當下,覺得非常新奇,很想要一探究竟,但起出找資料的功力不夠高明(關鍵字下得不好),實在還是無法理解網頁的內容。因此今天就要帶大家認識,

平常在使用的程式是怎麼被機器理解、執行

Outline:

1. C 語言是如何被編譯(Compiler)

2. 什麼是組譯器(Assembler)、連結器(Linker)、載入器(Loader)及其功用

3. 整個程式在電腦裡的執行過程

1. C 語言是如何被編譯(Compiler)

首先,請看下面這張圖,之後會對圖有更詳細的說明。

目標:

Input:C program

Output:可執行檔案

從這張圖來說,最難理解的莫過是Assembler → Object File → Linker的部分。讓我來解釋一下:

  1. 從C語言變成組合語言的過程,請參考下圖。有寫過組合語言的應該知道,組與有很多東西,需要事前先宣告,後面才能使用。
下面組合語言程式出自:https://ithelp.ithome.com.tw/articles/10201469

2. 有了組合語言程式後,我們發現他雖然比C語言複雜,但如果有對組合語言有基本的認知的話,我們人類還是看得懂,主要因為還是大部分由英文字母所組成。所以Assembler的任務,就是要將這些還是由英文字母所組成的語言,轉換成只有機器(電腦)才能理解的「機器語言(Machine Language)」,而電腦能理解的語言當然只有0和1。而經由Assembler所產生的檔案,我們稱為Object File。(可以回上面對照一下圖片有很多01產生的圖片)

相信一定還有人有疑問說,為什麼圖上有好幾個 Object File?

Ans:因為在原本的程式中,我們有呼叫到外部的函式(printf),而在 Linker的階段會把程式所需要的函式、檔案都彙整再一起。因此在前面的步驟要事先產生出多個 Object File,以便後面(Linker)做整合。

補充說明:在C語言中,我們可以看到最上方有#include<stdio.h> 吧。因為我們在程式內有用到一個printf() 的函式,而在程式碼中,我們也沒有寫過關於怎麼把字串顯示到螢幕上的程式,所以可想而知printf() 這個程式一定存在於某個地方。在程式編譯的過程中,會把printf() 函式呼叫到程式後,再執行。

所以在Assembler這個階段,他會去判斷程式中,使用到哪些外部的函式,或是呼叫到哪些額外的 function等。並把程式執行中,所有會用到的 function都列出來。方便之後連結器(Linker)把他們全部連接再一起。

3. 最後連結器(Linker)的工作,則是會把Assembler所產生的object file全部都「連結」再一起後,形成一個「可執行檔(execute)」。

2. 什麼是組譯器(Assembler)、連結器(Linker)、載入器(Loader)

前面大概都已經把各自的任務交代清楚,這邊要對他們做更詳細的說明。

組譯器(Assembler)

組譯器的任務在於「將組合語言轉換成機器語言(由0, 1所組成的語言)」。

Input:組合語言程式

Output:Object File

其中轉換的東西包括以下幾點:

  1. Header:描述程式的內容、大小、位址等資訊
  2. Text Segment:機器語言(machine language code)
  3. Static data segment:資料在程式中的生命週期。
  4. Relocation information:程式載入到記憶體,表示指定和資料之間的相對位址。
  5. Symbol table:儲存未定義的標籤,例如:external reference
  6. Debug information:簡明的闡述程式碼如何被compile,好讓debugger可以連結到原始的C source file。
computer organizations and design

這邊有些我是直接參考白算盤去翻譯,請大家參考參考即可。不了解的話也沒關係,這不會影響我們對他整個的了解~~

連結器(Linker)

Input:Object File

Output:Execute File(.exe)

主要有三個功能:

  1. Allocation:向OS要一個起始位址
  2. Loading:將object code中的Text records載入到Memory
  3. 決定內部與外部位址參考(Reference)

注意!!這邊為了方便大家理解,上面所呈現的畫面是「一般我們看得懂的程式碼」,但實際上這些程式是Object File(由很多的0, 1所組成的程式碼)

載入器(Loader)

載入器顧名思義,就是把程式變成「可執行檔(.exe)」後,放到電腦裡運行。載入器主要可以分為6個步驟:

  1. 讀取可執行檔(.exe)的header來決定程式碼(text)、資料區(data segments)
  2. 建立出一個足夠容納程式碼以及資料(data)的記憶體空間(memory space)
  3. 複製可執行黨的指令以及資料到memory
  4. 複製主程式的參數到stack中
  5. 初始化暫存器、並將堆疊指標(stack pointer)在第一個可用空間
  6. 跳到start-up routine並且複製參數到argument registers,而且呼叫將要被執行的主程式。主程式結束返回後,呼叫exit來結束程式的執行。

3. 整個程式的執行架構

最後只是1, 2兩個步驟的大彙整。

如果內容有任何錯誤,懇請各位夥伴不吝指教~~

希望這篇能幫助大家更加了解程式在電腦裡面的運作,今天就到這邊結束了,那我們就下次再見囉~~

--

--