標(biāo)識(shí)符
LLVM的標(biāo)識(shí)符有兩類:全局標(biāo)識(shí)符和局部標(biāo)識(shí)符。全局標(biāo)識(shí)符以符號(hào)@開頭,局部標(biāo)識(shí)符由符號(hào)%開頭。此外,標(biāo)識(shí)符還有三種格式:
- 命名的值由前綴(@或者%)加字符串表示,比如%foo等。識(shí)別變量的正則表達(dá)式為[%@][-a-zA-Z$._][-a-zA-Z$._0-9]*。
- 未命名的值由簽注加無(wú)符號(hào)數(shù)字表示,比如%2等。
- 常量
標(biāo)識(shí)符由前綴開頭有兩個(gè)方面的原因:一是編譯器不用擔(dān)心其與保留字沖突;二是編譯器可以方便的給未命名的值設(shè)置臨時(shí)變量而不需要考慮符號(hào)表沖突。
LLVM的其他特點(diǎn):
- 注釋以;開始,持續(xù)被該行的結(jié)束
- 當(dāng)計(jì)算結(jié)果沒(méi)有分配給指定值時(shí),就會(huì)創(chuàng)建未命名的臨時(shí)變量。
- 未命名的臨時(shí)文件是按順序編號(hào)的,從0開始。
模塊
LLVM程序有模塊組成,每個(gè)輸入程序都對(duì)應(yīng)一個(gè)模塊。模塊包括函數(shù)、全局變量和符號(hào)表。多個(gè)模塊可以被LLVM 鏈接器(linker)組合在一起。
鏈接類型
全局的值(全局變量和函數(shù))都由指向某個(gè)特定位置的指針表示,并且有一個(gè)鏈接類型:
private。private類型的全局變量只能被當(dāng)前模塊內(nèi)的對(duì)象直接訪問(wèn)。而且,當(dāng)將代碼鏈接到一個(gè)包含private類型值的模塊的時(shí)候,這個(gè)private值可能被重命名以避免沖突。由于這個(gè)值是模塊私有的,所以所有的引用都可以直接更新。private的值不會(huì)出現(xiàn)在目標(biāo)代碼的符號(hào)表中。
internal。與private類似,不過(guò)它的值會(huì)作為局部變量出現(xiàn)在目標(biāo)文件中。類似C語(yǔ)言中static的概念。
available_externally。該類型的變量不會(huì)被輸出到對(duì)應(yīng)模塊的目標(biāo)文件中。對(duì)于鏈接者來(lái)說(shuō),該類型相當(dāng)于一個(gè)外部聲明。這種類型只允許在定義時(shí)使用,而不能在聲明時(shí)使用。
linkonce。鏈接時(shí),這種類型的變量會(huì)和其他同名變量merge。該類型的變量如果沒(méi)被使用則可以被丟棄。這種類型的函數(shù)不允許優(yōu)化器將其內(nèi)聯(lián)到調(diào)用者的函數(shù)體中,這個(gè)它有可能被重寫。如果想允許內(nèi)聯(lián)或者其他優(yōu)化,請(qǐng)使用“l(fā)inkonce_odr”類型
weak。與linkonce類似,但即使不被使用,也不能丟棄。類似C語(yǔ)言中的“weak”類型的變量(多個(gè)變量擁有相同的名字不會(huì)造成沖突,只要其中一個(gè)是weak類型的。鏈接時(shí),weak類型的定義被忽略而使用正常的定義,如果沒(méi)有正常的定義,則使用weak的定義)。
common。與weak類似,用于C語(yǔ)言中的臨時(shí)定義,比如全局作用域中的“int x;”。函數(shù)和別名沒(méi)有common類型
appending。只用于數(shù)組類型的指針。兩個(gè)這種類型的變量鏈接時(shí),對(duì)應(yīng)的全局?jǐn)?shù)組被連接在一起。
extern_weak。這種類型在鏈接之前是weak的,如果不被鏈接,這個(gè)變量是null而不是undefined reference。
linkonce_odr, weak_odr。ODR(one definition rule),只有等效的變量才能被merge。這個(gè)鏈接類型就表示只能跟等效的變量合并。
external。如果沒(méi)有指定上面的任意類型,那么就是external的。
函數(shù)聲明只能使用external或者extern_weak。
調(diào)用約定
LLVM支持的調(diào)用約定如下:
- "ccc",C調(diào)用約定。如果沒(méi)有指定其他類型,那么就默認(rèn)是這種類型。這個(gè)類型支持可變參數(shù)的函數(shù)調(diào)用并且允許聲明的原型和函數(shù)聲明的實(shí)現(xiàn)之間有一些不匹配。
- "fastcc",快速調(diào)用約定。使生成的目標(biāo)代碼盡可能快,可以使用任意tricks。不支持可變參數(shù),并且原型和實(shí)現(xiàn)要嚴(yán)格匹配。
- "coldcc",冷調(diào)用。假定這種調(diào)用不經(jīng)常發(fā)生。不支持可變參數(shù),并且原型和實(shí)現(xiàn)要嚴(yán)格匹配。
- “cc 10”,GHC調(diào)用。 Glasgow Haskell Compiler 專用。支持尾調(diào)用優(yōu)化,但是要求caller和callee都是它。
- “cc 11”,HiPE調(diào)用約定。
- "webkit_jscc", webkit的js調(diào)用約定。
- “anyregcc” ,代碼補(bǔ)丁的動(dòng)態(tài)調(diào)用。
- “preserve_mostcc”,PreserveMost調(diào)用約定。目前是實(shí)驗(yàn)性的,未來(lái)會(huì)被objectiveC使用。
- “preserve_allcc”。也是實(shí)驗(yàn)性的。
- “cxx_fast_tlscc”。Clang生成訪問(wèn)函數(shù)去訪問(wèn)C++風(fēng)格的TLS。訪問(wèn)函數(shù)包括入口塊、出口塊和初始化塊,入口和出口塊可以訪問(wèn)一些TLS IR變量。這個(gè)調(diào)用約定就是通過(guò)保留盡可能多的寄存器變量來(lái)降低這種訪問(wèn)的開銷。
- “swiftcc”,Swift語(yǔ)言的調(diào)用約定。
- “cc <n>”,從64開始。
可見性
所有的全局變量和函數(shù)都有一種可見性樣式:
- “default”,默認(rèn)樣式。對(duì)于使用ELF(Executable and Linking Format)格式的目標(biāo)文件,這種可見性樣式意味著聲明對(duì)其他模塊可見;在共享庫(kù)中,意味著聲明的實(shí)體可以被重寫;在Darwin,聲明對(duì)其他模塊可見。
- “hidden”,具有這種可見性樣式的聲明引用相同的對(duì)象,如果它們?cè)谙嗤墓蚕韺?duì)象中的話。通常,具有這種可見性樣式的符號(hào)不會(huì)出現(xiàn)在動(dòng)態(tài)符號(hào)表中,所有其他模塊不能直接引用它。
- “pretected”,對(duì)于ELF,這種樣式表明符號(hào)會(huì)放置在動(dòng)態(tài)符號(hào)表中,但是在定義這個(gè)符號(hào)的模塊中的引用會(huì)綁定到局部變量,也就是說(shuō)這個(gè)符號(hào)不能被其他模塊重寫。
用于internal或者private鏈接類型的符號(hào)必須是default類型的。
以前一直使用rose,最近要轉(zhuǎn)到LLVM了。本文是官方LLVM IR文檔的翻譯,本人能力有限,如有錯(cuò)漏,歡迎批評(píng)指正。