(追記)引用元ブログの追加。肝心なものを忘れてた。。
Swiftのランタイムをリバースエンジニアリングした人のブログ。いくつか興味深い調査結果を紹介している。
気になったところを抜き出してみる。
Objects, Classes,...
Swift objects are actually Objective-C objects.
Swift classes have no Objective-C methods.
SwiftObject is a root Objective-C class, similar to NSObject. It has no superclass,...
classes for Swift objects have no methods. Instead, they have been replaced with C++-like functions, mangling and all. This is likely why Swift has been said to be much faster than Objective-C; there is no more need for objc_msgSend to find and call method implementations.
Swiftのメソッドは、Objective-Cのメソッドの代わりに C++ライクな関数で実装されていて、これが速い理由の一つのようだ。C++のような vtableをクラスが持っているとのこと。
Name Mangling
Swiftは関数のメタ情報を保持する。これを Name Mangling と呼ぶらしい。
例えば
class Shape{ func numberOfSides() -> Int { return 5 } }というクラスがあった場合、The mangled nameは
_TFC9swifttest5Shape17simpleDescriptionfS0_FT_Si.となる。それぞれの文字が意味を持っている。Objective-Cのタイプエンコードっぽいが、クラス名とメソッド名も一緒にまとめられている。
Function Hooking
脱獄系ツールのMobileSubstrateを使っての解析。
class Shape { var numberOfSides: Int; init(){ numberOfSides = 5; } }関数フックを使ってメンバ変数 numberOfSidesの値を4に変えてみる。
先ほどの Name Mangling を応用してメンバ変数のget/setをフックしている。
まず getter
int (*numberOfSides)(id self); MSHook(int, numberOfSides, id self){ return 4; } %ctor{ numberOfSides = (int (*)(id self)) dlsym(RTLD_DEFAULT, "_TFC9swifttest5Shapeg13numberOfSidesSi"); MSHookFunction(numberOfSides, MSHake(numberOfSides)); }これは成功。
次に setter
void (*setNumberOfSides)(int newNumber, id self); MSHook(void, setNumberOfSides, int newNumber, id self){ _setNumberOfSides(4, self); } %ctor { setNumberOfSides = (void (*)(int newNumber, id self)) dlsym(RTLD_DEFAULT, "_TFC9swifttest5Shapes13numberOfSidesSi"); MSHookFunction(setNumberOfSides, MSHake(setNumberOfSides)); }これは失敗。コンストラクタにおけるメンバ変数設定はインラインで行われる(setterを呼ばない)ため。
そこでsetterを経由せず直接設定
void (*setNumberOfSides)(int newNumber, id self); MSHook(void, setNumberOfSides, int newNumber, id self){ MSHookIvarこれは成功。(self, "numberOfSides") = 4; } %ctor { setNumberOfSides = (void (*)(int newNumber, id self)) dlsym(RTLD_DEFAULT, "_TFC9swifttest5Shapes13numberOfSidesSi"); MSHookFunction(setNumberOfSides, MSHake(setNumberOfSides)); }
参考:dlsym
dlsym() が特別な handle RTLD_DEFAULT を使用して呼び出された場合は、オブジェクトが ロードされる際に未定義のシンボルを解決するために 使用されるアルゴリズムに従ってシンボルを探索します。 探索されるオブジェクトは次のように書かれた順番になります。.....