From Brad.Cox to Chris.Lattner.
嘗試?yán)靡恍I(yè)余時(shí)間研究下 Swift栽烂,寫(xiě)一些由 OC 到 Swift 的變化啊掏。
背景
當(dāng)我使用 ClassDump 對(duì)一個(gè)項(xiàng)目操作的時(shí)候,輸出了一些看不懂的東西蟀拷。(后來(lái)知道了這是一個(gè) OC Swift 混編的工程)
#import <UIKit/UIViewController.h>
@interface _TtC11MandrakeKit11LoadingView : UIViewController {
}
- (id)initWithCoder:(id)arg1;
- (id)initWithNibName:(id)arg1 bundle:(id)arg2;
- (void)viewDidLoad;
@end
通過(guò) Reveal 分析 UI制市,我大概知道這個(gè)類(lèi)是 MandrakeKit.LoadingView
,通過(guò)查看 MachO 發(fā)現(xiàn) __TEXT
段中有 __swift5_typeref
暖庄,其中的數(shù)據(jù)跟這些很類(lèi)似聊替,所以這些就是Swift輸出的類(lèi)名。
Swift 這樣進(jìn)行轉(zhuǎn)換的原因是為了防止不同的庫(kù)不會(huì)出現(xiàn)命名沖突培廓。
OC & C
OC 的符號(hào)表中沒(méi)有這些復(fù)雜的符號(hào)重整惹悄,OC 使用 Selector + Type Encoding,并且OC 無(wú)重載肩钠。
C 語(yǔ)言有輕微的 Name Mangling泣港,即會(huì)將 void main(){return 0;}
符號(hào)化為:_main
暂殖,增加一個(gè)下劃線(xiàn)。
OC 舉一個(gè)栗子:Point類(lèi)下的 + (id) initWithX: (int) number andY: (int) number;
方法
+ (id) initWithX: (int) number andY: (int) number;
- (id) value;
_c_Point_initWithX_andY_
_i_Point_value
C++
對(duì)于如下方法当纱,C++的NameMangling會(huì)翻譯成下面這樣:
int foo(int a) { return a * 2; }
int foo(double a) { return a * 2.0; }
int main() { return foo(1) + foo(1.0); }
0000000100000f30 T __Z3food
0000000100000f10 T __Z3fooi
0000000100000000 T __mh_execute_header
0000000100000f60 T _main
C++編譯器遵循一套嚴(yán)格的 mangles 規(guī)則呛每,參考這個(gè)鏈接Itanium C++ ABI documentation
以 int foo(double a)
為例,重整后的符號(hào)為 __Z3fooi
大致意思如下:
_ _Z 3 foo d
- : 代表C風(fēng)格的符號(hào)
_Z : 這個(gè)前綴標(biāo)記這個(gè)符號(hào)是一個(gè)mangled(重整)的全局C++名字
3 : 字符長(zhǎng)度坡氯,foo 這個(gè)名字晨横,有3個(gè)字符
foo :
d : 代表`double`,如果是 `int` 的話(huà)就是`i`
Swift
Swift 的重整規(guī)則基于 C++箫柳,也有些不同手形,包含更多的信息和概念。
栗子:
xcrun swiftc -emit-library -o test -
public class myClass{
public func calculate(x: Int) -> Int {
return 0;
}
}
nm -g test
0000000000002bb0 T _$s4test7myClassC9calculate1xS2i_tF
_$s4test7myClassC9calculate1xS2i_tF
_ // 通用起始
$s // '$s' global // Swift 穩(wěn)定mangling版本
4test // 字符長(zhǎng)度滞时,模塊名
7myClass // 方法歸屬的類(lèi)名
C // 從屬關(guān)系叁幢,myClass 是 test 模塊中的 Class
9calculate // 字符 calculate
1x // 參數(shù)類(lèi)型
S2i // 堆棧中放入兩個(gè) Swift.Int
_
tF // 從屬關(guān)系,calculate 是 test.myClass 的 Function ???
這里解釋一下S2i坪稽,這個(gè)是從后往前取的曼玩,參數(shù)往里放是棧結(jié)構(gòu),先進(jìn)后出窒百,第一個(gè)進(jìn)棧的是參數(shù) `x:Int` 第二個(gè)是返回的參數(shù) Int黍判,所以S2i兩個(gè)`Swift.Int`。
如果入?yún)⑹?`x:String`篙梢,反參是 Int顷帖,那就變成是 `SSSi` 了。
/* 此段過(guò)期渤滞,是以前的老版本
_TFC4test7MyClass9calculatefS0_FT1xSi_Si
_T // Swift通用起始標(biāo)記
F // Non-curried function
C // Function of a class. (method)
4test // 字符長(zhǎng)度贬墩,模塊名
7MyClass // 方法歸屬的類(lèi)名
9calculate // 函數(shù)名
f // 非柯里化函數(shù)(Uncurried Function)
S0 // 指定 類(lèi)實(shí)例 為類(lèi)型堆棧的第一個(gè)參數(shù)
_FT // 參數(shù)開(kāi)始
1x // 第一個(gè)參數(shù)參數(shù)名
Si // Swift 內(nèi)置類(lèi)型 Swift.Int
_Si // 返回類(lèi)型,同上 Swift.Int
*/
// 結(jié)果:
test.MyClass.calculate(test.MyClass) -> (x: Swift.Int) -> Swift.Int
栗子2:
didi ~ xcrun swiftc -emit-library -o test -
public func ?? (lhs: Int, rhs: Int) -> Int {
return 0;
}
didi ~ nm -g test
0000000000002d60 T _$s4test004GrIh3lhs3rhsS2i_SitF
_ // 通用起始
$s // '$s' global // Swift 穩(wěn)定mangling版本
4test // 符號(hào) 4是長(zhǎng)度
004GrIh // 00 特殊字符 GrIh 就是 emoji U+1F49B
3lhs // 參數(shù) 3是字符串長(zhǎng)度
3rhs // 參數(shù) 3是字符串長(zhǎng)度
S2i // 解釋參數(shù)的類(lèi)型妄呕,兩個(gè)Swift.Int
_ // end??? 待填坑
Si // Swift.Int
tF // 從屬關(guān)系陶舞,?? 是 test 的 Function ???
//結(jié)果:
test.??(Swift.Int, Swift.Int) -> Swift.Int
以上
對(duì)大多數(shù)人來(lái)說(shuō),不是很多绪励。從算法的意義上講肿孵,讀取變形的名稱(chēng)是相當(dāng)簡(jiǎn)單的,但是對(duì)于人眼來(lái)說(shuō)則是不必要的困難疏魏。
這就是為什么存在拆解工具的原因停做。
補(bǔ)充
關(guān)于curried & uncurried function:
上面案例中的方法d是一個(gè)uncurried function
大莫,因?yàn)閰?shù)是一個(gè)一個(gè)傳遞進(jìn)去的蛉腌,并不是當(dāng)做一個(gè)多元元組傳遞進(jìn)去的。(可能理解有誤。眉抬。)
這個(gè)概念是跟函數(shù)式編程相關(guān)的贯吓,暫未深入了解,挖個(gè)坑蜀变,稍后填坑。
ref:stackOverFlow:How is this exactly a curried function?