2012年2月9日 星期四

從原始碼到可執行檔

編譯原始碼,最原始的指令就是gcc helloworld.c -o helloworld,其實中間跳過了很多的過程,這中間的過程隱藏了許多過去前人所累積的技術能量,其實過程大致上如下,並不是一下子就從source code變成binary code




  • Preprocessing過程先把大部分的#include之類的編譯指令拿掉,直接將一些function code變成一個text file,比方說printf()這個function會被加入一個暫時的文字檔案(.i)中,把註解拿掉,因為他對編譯程式沒有意義,註解是給人看得,不是給機器看的,種種目的就是為了純化資料到電腦必須要處理的
  • Compilation:將source跟著就是轉成組合語言,這是平台相關性的code,如果是arm CPU,就轉成arm的組合語言指令,如果是x86就轉成x86,這時候已經進入平台相關的議題了
  • Assembly: 將組合語言轉為object code,object跟作業系統的平台很有相關,比方說ELF(Unix/Linux)或者PE(M$)
  • Linking: 則是將一些object code做relocation等等動作,還有引入library


先掠過preprocessing的部分(它基本上只比copy/paste複雜一些,是大量的取代動作),單單是從source code產生.s就需要很大的技術,底下可以看到流程


線上的字體,可以看成一種軟體元件,並不一定會在檔案系統上留下檔案,在System Software的書籍上有比較詳細的介紹。先用Scanner將source code切成一堆單位/token,這些東西表示該程式語言內接受的元件,比方說有++i,被分解成++跟i,接著建構Syntax Tree,透過事先定義的grammar,將statement建構出來,有時會牽涉到類似先乘除後加減的概念,跟著將語意辨識出來,就是賦予型態等等意涵,在原始碼上i就是i,除非你找到int i的宣告,不然他並不會在code上面有意義,但是電腦是很死板,必須有人把每個i標註上他的型態,如整數或者物件等等意涵。接著再把該tree轉成一些p-code,對應到了組合語言,中間當然會有一些最佳化的議題,在此略過不談

在討論linking這動作之前,先理解object code,object code其實很豐富,可以用file指令來觀察檔案屬性
可以看到都是ELF (Executable Linkable Format)格式,object稱為是一個relocatable的,bash是一個可執行檔,so則是share object


沒有留言:

張貼留言