日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

開發(fā)者應(yīng)知道的編譯原理和語言基礎(chǔ)知識(shí)

 我愛你文摘 2019-02-19

作者:ZhengYaWei

鏈接:https://www.jianshu.com/p/0913993a4c3f

一、以 Hello World開篇

Hello World對(duì)程序員而言肯定是如雷貫耳。但是簡單的事物背后往往包含這個(gè)復(fù)雜的機(jī)制,如果深入思考Hello world就會(huì)發(fā)現(xiàn)很多問題。C語言中的Hello World往往是這樣寫的:

#include int main(){ printf('Hello World'); return 0;}

但是你是否想過以下問題:

1、程序?yàn)槭裁匆痪幾g之后才能運(yùn)行?

2、編譯器在把C語言程序轉(zhuǎn)換成可以執(zhí)行的機(jī)器碼的過程中做了什么?

3、最后編譯出來的可執(zhí)行文件里面是什么?除了機(jī)器碼還有什么?如何存放的?

4、#include 的包含意味著什么?又是如何實(shí)現(xiàn)的?

5、什么是編譯器,它以什么為分界線分為前端和后端?編譯器和解釋器有什么區(qū)別,為什么會(huì)有解釋型語言一說?

6、以及由此延伸出的一些相關(guān)問題:Swift 是靜態(tài)語言,為什么還有運(yùn)行時(shí)庫?OC中的Runtime和運(yùn)行時(shí)庫是什么關(guān)系?

7、什么是ABI ?ABI穩(wěn)定對(duì)一門語言的發(fā)展有何影響 ?為什么 Swift 打包的 App 會(huì)平白無故的多出幾Mb ?

8、........

等等,還有很多問題,這些問題實(shí)際上和編譯都脫離不了干系。讀完本篇文章,你的這些疑惑都能得到解答。除此之外,你還將掌握一些主流語言的基本知識(shí)。另外,繼該篇文章之后,筆者打算后期再寫一篇文章動(dòng)手試試LLVM。歡迎關(guān)注。。。。。。

二、編譯總過程預(yù)覽

相信讀者對(duì)編譯的整個(gè)流程組成部分應(yīng)該相對(duì)比較熟悉。整個(gè)流程包括預(yù)處理(Prepressing)、編譯(Compilation)、匯編(Assembly)和鏈接(Linking)。

開發(fā)者應(yīng)知道的編譯原理和語言基礎(chǔ)知識(shí)

GCC編譯hello world程序過程分解

預(yù)編譯

首先是源代碼文件hello.c和相關(guān)頭文件,如 stdio.h 被編譯器 cpp預(yù)編譯到一個(gè) .i 文件。預(yù)編譯過程主要是處理那些源代碼文件中以 # 開始的預(yù)編譯指令。比如#include 、#include 等。經(jīng)預(yù)編譯后的 .i 文件不包含任何宏定義,因?yàn)樗械暮暌呀?jīng)被展開,并且包含的文件已經(jīng)被插入到 .i 文件中。

編譯

編譯過程就是把預(yù)處理的文件經(jīng)過一系列的詞法分析、語法分析、語義分析、生成中間代碼、生成目標(biāo)代碼 優(yōu)化后生產(chǎn)相應(yīng)的匯編文件代碼。

編譯器以中間代碼為界限,又可以分前端和后端。比如 clang 就是一個(gè)前端工具,而 LLVM 則負(fù)責(zé)后端處理。另一個(gè)知名工具 GCC(GNU Compile Collection)則是一個(gè)套裝,包攬了前后端的所有任務(wù)。

前端主要負(fù)責(zé)預(yù)處理、詞法分析、語法分析,最終生成語言無關(guān)的中間代碼。后端主要負(fù)責(zé)目標(biāo)代碼的生成和優(yōu)化。后面我會(huì)重點(diǎn)介紹編譯的整個(gè)過程的每一步。這里暫時(shí)簡單提一下。

匯編

匯編器將匯編代碼轉(zhuǎn)變成機(jī)器可以執(zhí)行的指令,每一個(gè)匯編語句幾乎都對(duì)應(yīng)一條機(jī)器指令。所以匯編起的過程相對(duì)于編譯器而言是比較簡單的。因?yàn)闆]有復(fù)雜的語法,也沒有予以,所以就不需要做指令優(yōu)化,只是根據(jù)匯編指令和機(jī)器指令的對(duì)照便一一翻譯就可以了。到這一步,經(jīng)過預(yù)編譯、編譯和匯編就可直接輸出目標(biāo)文件。

鏈接

在一個(gè)目標(biāo)文件中,不可能所有變量和函數(shù)都定義在同一個(gè)文件內(nèi)部。不同文件之間要做相應(yīng)的鏈接處理。

三、編譯器做了些什么

最直白的來說,編譯器就是將高級(jí)語言翻譯成機(jī)器語言的一個(gè)工具。先來看一下編譯器的整個(gè)流程。從該流程圖我們可以看到編譯器被分為前端和后端,在前端和后端之間的過度是中間代碼。其中編譯器前端包含詞法分析、語法分析、語義分析、中間代碼生成(嚴(yán)格意義來說在此四個(gè)步驟之前還有預(yù)編譯操作);編譯器后端主要是代碼優(yōu)化、目標(biāo)代碼生成以及目標(biāo)代碼優(yōu)化,編譯器的大致自責(zé)就是如此。編譯器在整個(gè)編譯過程中輸入源是源代碼,輸出的是中間代碼。

開發(fā)者應(yīng)知道的編譯原理和語言基礎(chǔ)知識(shí)

3.1 詞法分析

首先是源代碼程序被輸入到掃描器,掃描器的任務(wù)很簡單,它只是簡單的進(jìn)行詞法分析。運(yùn)用有限狀態(tài)機(jī)的算法可以很輕松的將源代碼的字符序列分割成一系列的記號(hào)。記號(hào)一般分為如下幾類:關(guān)鍵字、標(biāo)識(shí)符、字面量(數(shù)字和字符串等)以及特殊符號(hào)(如+,= .....)。

lex程序可以實(shí)現(xiàn)詞法分析,它會(huì)按照用戶之前掃描害的詞法規(guī)則將輸入的字符串分割成一個(gè)個(gè)記號(hào)。因?yàn)檫@樣一個(gè)程序的存在,編譯器開發(fā)者就無需為每一個(gè)編譯器開發(fā)一個(gè)獨(dú)立的詞法掃描器,而是根據(jù)需要改變詞法規(guī)則就可以了。

3.2 語法分析

這一步驟語法分析器將由掃描器產(chǎn)生的記號(hào)進(jìn)行語法分析,從而產(chǎn)生語法樹。簡單的講,由語法分析器生成的語法樹就是以表達(dá)式為節(jié)點(diǎn)的樹。

int fun(int a, int b) { int c = 0; c = a + b; return c;}

以如上代碼為例,它的語法樹形式如下:

開發(fā)者應(yīng)知道的編譯原理和語言基礎(chǔ)知識(shí)

語法樹將字符串格式的源代碼轉(zhuǎn)化為樹狀的數(shù)據(jù)結(jié)構(gòu),更容易被計(jì)算機(jī)理解和處理。如前面詞法分析的 lex 一樣,語法分析同樣有現(xiàn)成的工具,其中有一個(gè)叫做Yet Another Compiler Compiler 簡稱 yacc 的工具。它可以根據(jù)用戶給定的語法規(guī)則對(duì)輸入的記號(hào)序列進(jìn)行解析,從而構(gòu)建出一棵語法樹。針對(duì)不同的語言,一般編譯器開發(fā)者只需要改變語法規(guī)則,根本不需要為每個(gè)編譯器重新寫一個(gè)語法分析器,所以它又被稱為編譯器的編譯器。3.3 語義分析

語義分析有語義分析器完成。語義分析之前的語法分析僅僅只是完成了對(duì)表達(dá)式成眠的語法層面分析,但是它并不能確定這個(gè)語句是否真正有意義。如OC中兩個(gè) Person 對(duì)象實(shí)例直接做加減乘除運(yùn)算,實(shí)際上是沒有意義的,但是在語法分析上確實(shí)合情合理。這里要說明一下編譯器分析的語義都是靜態(tài)語義,靜態(tài)語義是指在編譯器件可以確定的語義,與之對(duì)應(yīng)的動(dòng)態(tài)語義只能在運(yùn)行期間才能被確定。

靜態(tài)語義分析通常包括聲明、類型匹配、類型轉(zhuǎn)換等。如一個(gè)浮點(diǎn)類型賦值給整形變量,其中就隱含了浮點(diǎn)類型轉(zhuǎn)換為整型的語義;動(dòng)態(tài)語義分析是指運(yùn)行期間出現(xiàn)的相關(guān)語義問題。

經(jīng)過語義分析之后,在語法分析生成的語法樹的基礎(chǔ)上進(jìn)一步對(duì)表達(dá)式做一些標(biāo)識(shí)。如:有些某些類型需要做隱式轉(zhuǎn)化,語義分析器會(huì)在之前的語法樹中插入相應(yīng)的轉(zhuǎn)換節(jié)點(diǎn)。

3.4 生成中間代碼

3.4.1 生成中間代碼的意義

理論上來說,中間代碼是可以直接被省略的,因?yàn)槌橄笳Z法樹可以直接轉(zhuǎn)為目標(biāo)代碼(匯編代碼)。然而不同的 CPU 架構(gòu)采用的匯編語法并不一樣,如: Intel 架構(gòu)和 AT&T 架構(gòu)的匯編碼中,源操作數(shù)和目標(biāo)操作數(shù)位置恰好相反參考鏈接。中間代碼可以理解為抽象的代碼,一方面它和語言無關(guān),同時(shí)也和 CPU 無關(guān),它僅僅只是描述了代碼要做的事情,可以將其理解為是全世界通用的語言,任何語言都可以轉(zhuǎn)換為世界語言,而世界語言又能被任何人翻譯理解。要知道,中間代碼的存在使得編譯器被分為前端和后端。其中編譯器前端主要負(fù)責(zé)產(chǎn)生與機(jī)器無關(guān)的中間代碼,編譯器后端主要是將中間代碼轉(zhuǎn)換成目標(biāo)機(jī)器代碼。因?yàn)檫@意味著針對(duì)那些跨平臺(tái)的編譯器而言,可以針對(duì)不同的平臺(tái)使用同一個(gè)前端和針對(duì)不同機(jī)器平臺(tái)的多個(gè)后端。

3.4.2 生成中間代碼的過程

生成中間代碼主要包含以下步驟,以下是用 GCC 編譯器為實(shí)例說明。

  • 1、語法樹轉(zhuǎn)高端 gimple(簡化樹)
  • 該步驟主要是處理寄存器和棧,比如拿c = a + b來說通常顯示執(zhí)行a + b,然后將該結(jié)果保存到寄存器中,最后再將其賦值給c。此外,調(diào)用函數(shù)時(shí)會(huì)進(jìn)入到此函數(shù)自己的棧中,建棧操作需要在gimple中聲明。
  • 2、高端 gimple 轉(zhuǎn)低端 gimple
  • 該步驟主要是把變量定義、語句執(zhí)行和返回語句區(qū)分開來,分別存儲(chǔ),這樣可以很好的計(jì)算一個(gè)函數(shù)所需要的??臻g。同時(shí)在這一步驟中,return語句會(huì)被統(tǒng)一處理轉(zhuǎn)換成goto語句,返回值同意放在最后處理。
if (1 > 0) { return 1;}else { return 0;}//上述代碼將會(huì)被轉(zhuǎn)換成如下形式:if (1 > 0) { goto a;}else { goto b;}a: return 1;b: return 0;
  • 3、低端 gimple 經(jīng)過 cfa 轉(zhuǎn) ssa 再轉(zhuǎn)中間代碼。
  • 該步驟主要是進(jìn)行各種相關(guān)的優(yōu)化。

3.5 目標(biāo)代碼生成與優(yōu)化

經(jīng)過上面生成中間代碼步驟之后,這一步驟屬于編譯器后端。該步驟主要的任務(wù)是生成并優(yōu)化目標(biāo)代碼,目標(biāo)代碼亦稱為匯編代碼(其實(shí)和匯編代碼非常接近)。編譯器后端主要包括目標(biāo)代碼生成器和目標(biāo)代碼優(yōu)化去。

代碼生成器將中間代碼轉(zhuǎn)換成目標(biāo)機(jī)器代碼,此過程依賴目標(biāo)機(jī)器,應(yīng)為不同的機(jī)器有不同的寄存器、整數(shù)數(shù)據(jù)類型和浮點(diǎn)數(shù)據(jù)類型等。

目標(biāo)代碼優(yōu)化器主要是對(duì)目標(biāo)代碼進(jìn)行優(yōu)化,如:選擇合適的尋址方式、使用位移代替乘法運(yùn)算、刪除多余的指令等。

3.6 編譯過程小結(jié)

編譯器的結(jié)構(gòu)實(shí)際上是異常復(fù)雜的,主要在于三個(gè)因素。

  • 1、高級(jí)編程語言本身就異常復(fù)雜。
  • 就拿C++來說,至今沒有一個(gè)編譯器能夠比較完整的支持C++標(biāo)準(zhǔn)語言所規(guī)定的所有語言特性。
  • 2、計(jì)算機(jī)的 CPU 也同樣異常復(fù)雜。
  • 3、要求編譯器要支持多種硬件平臺(tái),即要求編譯器能生成與多種 CPU 匹配的代碼。

四、匯編

匯編過程中輸入源是匯編代碼,輸出是二進(jìn)制機(jī)器碼(后綴為 .o 的目標(biāo)文件)。輸出的二進(jìn)制機(jī)器碼可以直接被 CPU 識(shí)別并執(zhí)行。匯編過程相對(duì)于編譯器過程而言相對(duì)簡單些,因?yàn)闆]有復(fù)雜的語法、沒有語義、不需要做指令優(yōu)化,根據(jù)匯編指令和機(jī)器指令的對(duì)照表一一翻譯即可。

由于匯編更接近機(jī)器語言,能夠直接對(duì)硬件進(jìn)行操作,生成的程序與其他的語言相比具有更高的運(yùn)行速度,占用更小的內(nèi)存,因此在一些對(duì)于時(shí)效性要求很高的程序、許多大型程序的核心模塊以及工業(yè)控制方面大量應(yīng)用。

五、鏈接

5.1 鏈接的簡單介紹

大型軟件往往有成千上萬的模塊,模塊之前相互依賴但又獨(dú)立。一個(gè)程序被分割成多個(gè)模塊之后,這些模塊又是通過何種形式組合成一個(gè)完整的程序?模塊之間如何組合的問題實(shí)際上就是模塊之間的通信問題。

鏈接過程主要包括了:

  • 地址和空間的分配(Address and Storage Alloction)
  • 符號(hào)決議(Symbol Resolution)Ps:'決議'更傾向于靜態(tài)鏈接,而'綁定'更傾向于動(dòng)態(tài)鏈接。
  • 重定位(Relocation)
開發(fā)者應(yīng)知道的編譯原理和語言基礎(chǔ)知識(shí)

鏈接的過程

讓我們來看看什么是重定位。假設(shè)有個(gè)全局變量叫做 var ,它在目標(biāo)文件A里面。我們在目標(biāo)文件B里面要訪問這個(gè)全局變量。由于在編譯目標(biāo)文件B的時(shí)候,編譯器并不知道變量var的目標(biāo)地址,所以編譯器在沒法確定的情況下,將目標(biāo)地址設(shè)置為0,等待鏈接器在目標(biāo)文件A和B連接起來的時(shí)候?qū)⑵湫拚?。這個(gè)地址修正的過程被叫做重定位,每個(gè)被修正的地方叫一個(gè)重定位入口。

鏈接器就是靠著重定位表來知道哪些地方需要被重定位的。每個(gè)可能存在重定位的段都會(huì)有對(duì)應(yīng)的重定位表。在鏈接階段,鏈接器會(huì)根據(jù)重定位表中,需要重定位的內(nèi)容,去別的目標(biāo)文件中找到地址并進(jìn)行重定位。

5.2靜態(tài)鏈接的缺點(diǎn)

  • 靜態(tài)鏈接這種方法的確很簡單,原理上很容易理解,實(shí)踐上很難實(shí)現(xiàn),但是靜態(tài)鏈接對(duì)于計(jì)算機(jī)內(nèi)存和磁盤的空間浪費(fèi)非常嚴(yán)重。特別是多進(jìn)程操作系統(tǒng)的情況下,靜態(tài)鏈接極大的浪費(fèi)了內(nèi)存和空間。想象一下每個(gè)程序內(nèi)部除了都保留著print()函數(shù)、scanf()函數(shù)、strlen()等這樣的公用函數(shù)庫,還有數(shù)量相當(dāng)可觀的其他庫以及它們所需要的輔助數(shù)據(jù)結(jié)構(gòu)。
  • 空間浪費(fèi)是靜態(tài)鏈接的一個(gè)問題,另一個(gè)問題是靜態(tài)鏈接對(duì)程序的更新、部署和發(fā)布也會(huì)帶來很多麻煩。比如Program1所使用的Lib.o是由一個(gè)第三方廠商提供的,當(dāng)該廠商更新了Lib.o的時(shí)候(比如修復(fù)了lib.o里面包含的一個(gè)bug),那么Program1的廠商就需要拿到最新版的Lib.o,然后將其與Program1.o鏈接后將新的Program1整個(gè)發(fā)布給用戶。這樣做的缺點(diǎn)很明顯,即一旦程序中有任何模塊更新,整個(gè)程序就要重新鏈接、發(fā)布給用戶。

基于上述兩個(gè)問題,就引出了一個(gè)名詞,動(dòng)態(tài)鏈接。

5.3 動(dòng)態(tài)鏈接

要解決上述兩個(gè)問題,就是不對(duì)哪些組成程序的目標(biāo)文件進(jìn)行鏈接,等到程序要運(yùn)行時(shí)才進(jìn)行鏈接。也就是說,把鏈接這個(gè)過程推遲到了運(yùn)行時(shí)再進(jìn)行,這就是動(dòng)態(tài)鏈接(Dynamic Linking)的基本思想。所謂的動(dòng)態(tài)鏈接表示重定位發(fā)生在運(yùn)行時(shí)而非編譯后。

雖然動(dòng)態(tài)鏈接可以解決上述的兩個(gè)問題,但是在性能上要略微比靜態(tài)鏈接差一些。筆者之前也寫過一篇Swift性能分析的文章,其中也涉及到一些關(guān)于OC和Swift語言動(dòng)態(tài)鏈接相關(guān)的點(diǎn)。

六、編譯器和解釋器

6.1 解釋型語言

開發(fā)者應(yīng)知道的編譯原理和語言基礎(chǔ)知識(shí)

編譯器和解釋器

解釋器是一條一條的解釋執(zhí)行源語言,不需要編譯直接由解釋器執(zhí)行,對(duì)應(yīng)的語言稱為解釋型語言也稱作腳本語言。比如 Php,Ruby,JavaScript、Python 等就是典型的解釋性語言。

源代碼 ---> 解釋器 ---> 執(zhí)行

解釋型語言同編譯型語言相比,編譯器是把源代碼整個(gè)編譯成目標(biāo)代碼,執(zhí)行時(shí)不在需要再去編譯器,直接在支持目標(biāo)代碼的平臺(tái)上運(yùn)行,所以執(zhí)行效率比解釋執(zhí)行快很多。比如C語言代碼被編譯成二進(jìn)制代碼(exe程序),在windows平臺(tái)上執(zhí)行。

6.2 解釋型語言和編譯型語言的共同點(diǎn)

兩者的共同點(diǎn)很簡單,一句話總結(jié):都需要轉(zhuǎn)換成二進(jìn)制才能執(zhí)行。

6.3 解釋型語言和編譯型語言的不同點(diǎn)

  • 1、運(yùn)行的時(shí)候是否需要編譯器
  • 編譯型語言運(yùn)行的是最終的二進(jìn)制代碼了,所以不再需要編譯器;但是解釋型語言邊解釋、邊運(yùn)行,所以運(yùn)行時(shí)候還有部分代碼沒有解釋好舉個(gè)例子:在瀏覽器里,要看 html 效果,要通過帶有內(nèi)置編譯工具的軟件去查看(如:瀏覽器或者模擬瀏覽器的工具)。
  • 2、執(zhí)行速度
  • 毫無疑問邊翻譯邊執(zhí)行的解釋型語言的速度會(huì)比編譯型語言運(yùn)行速度要慢。但是CPU的運(yùn)行速度如果很快,你可能看不出來,偶爾會(huì)看到“有點(diǎn)卡”的效果。
  • 3、可移植性對(duì)比
  • 編譯型語言運(yùn)行二進(jìn)制內(nèi)容,一旦 CPU 指令改變,之前的二進(jìn)制文件可能運(yùn)行不了了。即在其他硬件平臺(tái)上運(yùn)行,可能出錯(cuò),如果想在其他平臺(tái)運(yùn)行就需要編譯出新的二進(jìn)制文件,所以編譯型語言可移植性差;解釋型語言在需要的時(shí)候才開始編譯、運(yùn)行,所以具有可移植性,在很多平臺(tái)都能運(yùn)行起來。
  • 4、升級(jí)上對(duì)比
  • 編譯型語言的二進(jìn)制文件如果要升級(jí),需要重新下載一個(gè)新的二進(jìn)制文件了。如QQ的升級(jí),就是要重新下載、安裝、覆蓋;
  • 而解釋型的語言,只要重新寫好源代碼即可。如網(wǎng)站平臺(tái)升級(jí),用戶只要重新刷新即可。
  • 5、 應(yīng)用領(lǐng)域
  • 編譯型語言應(yīng)用領(lǐng)域通常是安裝軟件,如:桌面或手機(jī)上安裝軟件;
  • 解釋型的語言的應(yīng)用領(lǐng)域通常是互聯(lián)網(wǎng),網(wǎng)站等,刷新就可以看到最新效果。

七、額外擴(kuò)充(運(yùn)行時(shí)、ABI )

7.1 關(guān)于運(yùn)行時(shí)

7.1.1 Runtime

如果你是一個(gè) iOS 開發(fā)者,想必都聽過并用過 runtime。但其實(shí) runtime 并非是 Objective-C 的專利,絕大多數(shù)語言都有這個(gè)概念。所以說 runtime 讓 Objective-C 具有動(dòng)態(tài)性這句話是錯(cuò)誤的。如果要認(rèn)清楚這一點(diǎn),感覺有必要先認(rèn)清楚運(yùn)行時(shí)庫,要知道 runtime 就是運(yùn)行時(shí)庫的一部分。

7.1.2 運(yùn)行時(shí)庫概念

以 C 語言為例說明運(yùn)行時(shí)庫的概念。在 C 語言中 glibc 這個(gè)動(dòng)態(tài)鏈接庫通常會(huì)被很多操作依賴,包括字符串處理(strlen、strcpy)、信號(hào)處理、socket、線程、IO、動(dòng)態(tài)內(nèi)存分配等等。由于每個(gè)程序都依賴于運(yùn)行時(shí)庫,這些庫一般都是動(dòng)態(tài)鏈接的。這樣一來,運(yùn)行時(shí)庫可以存儲(chǔ)在操作系統(tǒng)中,很多程序共享一個(gè)動(dòng)態(tài)庫,這樣就可以節(jié)省內(nèi)存占用空間和應(yīng)用程序大小。

7.1.3 Swift運(yùn)行時(shí)庫

參照上述 C 語言的運(yùn)行石庫,就很容易理解 Swift運(yùn)行時(shí)庫的概念了。一方面,swift 是絕對(duì)的靜態(tài)語言,另一方面,swift 毫無疑問的帶有自己的運(yùn)行時(shí)庫。按照常理來說類似字符串、數(shù)組、print 函數(shù)都應(yīng)該是運(yùn)行時(shí)庫中的一部分。然而,Swift 依然沒有穩(wěn)定自己的 ABI ,導(dǎo)致每個(gè)程序都必須自帶運(yùn)行時(shí)庫,這也就是為什么目前 swift 開發(fā)的 app 普遍會(huì)增加幾 Mb 包大小的原因。

7.2 ABI 簡單概念

7.2.1 什么是ABI?

ABI 是 Application Binary Interface的縮寫,它是一個(gè)規(guī)范。簡單的說它就是編譯后的 API (API 描述了在應(yīng)用程序級(jí)別,模塊之間的調(diào)用約定)。 通過這個(gè)規(guī)范,所有被獨(dú)立編譯的二進(jìn)制實(shí)體才能被鏈接在一起并執(zhí)行。這些二進(jìn)制實(shí)體必須在一些很低層的細(xì)節(jié)上達(dá)成一致,例如:如何調(diào)用函數(shù),如何在內(nèi)存中表示數(shù)據(jù),甚至是如何存儲(chǔ)以及訪問數(shù)據(jù)。要重點(diǎn)知道,ABI 是平臺(tái)相關(guān)的,因?yàn)樗P(guān)注的這些底層細(xì)節(jié)會(huì)受到不同的硬件架構(gòu)以及操作系統(tǒng)的的影響。

為了更好的理解什么是ABI,如下舉個(gè)詳細(xì)的列子說明。

比如模塊 A 有兩個(gè)整數(shù) a 和 b,它們的內(nèi)存布局如下:

開發(fā)者應(yīng)知道的編譯原理和語言基礎(chǔ)知識(shí)

其他模塊調(diào)用 A 模塊的 b 變量,可以通過初始地址加偏移量的方式獲取b變量。如果后來模塊 A 新增了一個(gè)整數(shù) c (該過程可以看做是手機(jī)系統(tǒng)更新(伴隨著運(yùn)行時(shí)庫更新)),它的內(nèi)存布局可能又會(huì)變成如下這種形式。如果還是通過初始地址加偏移量的方式獲取變量,那么此時(shí)獲取的是 a 變量,而不再是之前的 b 變量。如果把模塊 A 看做是 Swift 運(yùn)行時(shí)庫,假設(shè)現(xiàn)在該運(yùn)行時(shí)庫已經(jīng)內(nèi)置于操作系統(tǒng)中并與手機(jī)上不同的應(yīng)用程序動(dòng)態(tài)鏈接在一些。如果每次更新系統(tǒng),就會(huì)出現(xiàn)某些 App 崩潰的情況。如何定義好 A 模塊獲取變量的規(guī)則,其中的規(guī)則就是所謂的 ABI 。

開發(fā)者應(yīng)知道的編譯原理和語言基礎(chǔ)知識(shí)

7.2.2 什么是ABI穩(wěn)定?

ABI 穩(wěn)定就是將 ABI 鎖定在某種形式下,使之后的相關(guān)編譯器可以遵守這種二進(jìn)制實(shí)體,這種二進(jìn)制實(shí)體可以是庫也可以是程序。一旦穩(wěn)定了 ABI ,基本便是它會(huì)伴隨著這個(gè)平臺(tái)一生一世,甚至是走到滅忙。

對(duì) ABI 做出的每一個(gè)決定都會(huì)對(duì)一門編程語言產(chǎn)生長遠(yuǎn)的影響,甚至可能會(huì)約束一門語言后期的發(fā)展和進(jìn)化。如:Swift 語言一直尚未申明ABI的穩(wěn)定,但只要申明了某個(gè)平臺(tái)的 ABI 已經(jīng)穩(wěn)定,那么任何有缺陷的設(shè)計(jì)將永遠(yuǎn)伴隨著這個(gè)平臺(tái)。

7.2.3 ABI穩(wěn)定了會(huì)怎樣?

ABI 穩(wěn)定之后,OS 發(fā)行商就可以把 Swift 標(biāo)準(zhǔn)庫和運(yùn)行時(shí)作為操作系統(tǒng)的一部分嵌入,由于這些標(biāo)準(zhǔn)庫和運(yùn)行時(shí)可以支持用更老或更新版本 Swift 構(gòu)建的應(yīng)用程序,這樣,開發(fā)者就無需在分發(fā)應(yīng)用的同時(shí),還要帶上一份自己構(gòu)建應(yīng)用時(shí)使用的標(biāo)準(zhǔn)庫和運(yùn)行時(shí)拷貝。這使得工具和操作系統(tǒng)可以更好的進(jìn)行集成。 然而目前 Swift 還是一門年輕的語言,ABI 尚未穩(wěn)定,暫時(shí)還未和 iOS 系統(tǒng)硬件綁定,所以在開發(fā)移動(dòng)端應(yīng)用的時(shí)候會(huì)發(fā)現(xiàn) app 普遍會(huì)增加幾 Mb 包大小。

八、總結(jié)

簡單的做個(gè)小結(jié),本文顯示總的介紹的整個(gè)編譯過程,之后針對(duì)編輯中的每個(gè)步驟做了進(jìn)一步的說明。最后相繼介紹了編譯型和解釋型語言的區(qū)別、runtime、運(yùn)行時(shí)庫、什么是 ABI 以及 ABI 穩(wěn)定的意義。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多