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è)類是 MandrakeKit.LoadingView,通過(guò)查看 MachO 發(fā)現(xiàn) __TEXT 段中有 __swift5_typeref,其中的數(shù)據(jù)跟這些很類似,所以這些就是Swift輸出的類名。
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è)下劃線。
OC 舉一個(gè)栗子:Point類下的 + (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` 的話就是`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 // 方法歸屬的類名
C // 從屬關(guān)系,myClass 是 test 模塊中的 Class
9calculate // 字符 calculate
1x // 參數(shù)類型
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 // 方法歸屬的類名
9calculate // 函數(shù)名
f // 非柯里化函數(shù)(Uncurried Function)
S0 // 指定 類實(shí)例 為類型堆棧的第一個(gè)參數(shù)
_FT // 參數(shù)開(kāi)始
1x // 第一個(gè)參數(shù)參數(shù)名
Si // Swift 內(nèi)置類型 Swift.Int
_Si // 返回類型,同上 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ù)的類型,兩個(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ō),不是很多。從算法的意義上講,讀取變形的名稱是相當(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?