在CSDN上看到的文章。轉(zhuǎn)給大家。
find /Applications/Xcode6-Beta.app/Contents/ -name "*swift*"可以找到swift相關(guān)的文件,簡單過濾后,如下的文件比較重要:
/Applications/Xcode6-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift /Applications/Xcode6-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-demangle /Applications/Xcode6-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-ide-test /Applications/Xcode6-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-stdlib-tool /Applications/Xcode6-Beta.app/Contents/SharedFrameworks/LLDB.framework/Versions/A/Resources/repl_swift /Applications/Xcode6-Beta.app/Contents//Developer/Toolchains/XcodeDefault.xctoolchain/usr/share/man/man1/swift.1從找到的文件中我們可以看到包含 man 手冊文件,我們首先看看手冊的內(nèi)容:
swift(1) Swift Documentation swift(1) NAME swift - <strong>the amazingly new programming language</strong> SYNOPSIS swift [-emit-object|-emit-assembly|-emit-library|-i] [-help] -o output-file input-filenames The full list of supported options is available via "swift -help". DESCRIPTION Swift is a new, high performance systems programming language. It has a clean and modern syntax, and offers seamless access to existing C and Objective-C code and frameworks, and is memory safe (by default). Although inspired by Objective-C and many other languages, Swift is not itself a C-derived language. As a complete and independent language, Swift packages core features like flow control, data structures, and functions, with high-level constructs like objects, protocols, closures, and generics. Swift embraces modules, eliminating the need for headers and the code duplication they entail. 2014-05-17 swift(1)從手冊中可以得到的信息也非常有限,但是看到參數(shù):-help,我們看看幫助會輸出什么:
OVERVIEW: Swift compiler USAGE: swift [options] <inputs> MODES: -dump-ast Parse and type-check input file(s) and dump AST(s) -dump-parse Parse input file(s) and dump AST(s) -emit-assembly Emit assembly file(s) (-S) -emit-bc Emit LLVM BC file(s) -emit-executable Emit a linked executable -emit-ir Emit LLVM IR file(s) -emit-library Emit a linked library -emit-object Emit object file(s) (-c) -emit-silgen Emit raw SIL file(s) -emit-sil Emit canonical SIL file(s) -integrated-repl Integrated REPL mode -i Immediate mode -lldb-repl LLDB-enhanced REPL mode -parse Parse input file(s) -print-ast Parse and type-check input file(s) and pretty print AST(s) -repl REPL mode OPTIONS: -application-extension Restrict code to those available for App Extensions -arch <arch> Compile for architecture <arch> -assert-config <value> Specify the assert_configuration replacement. Possible values are Debug, Release, Replacement. -D <value> Specifies one or more build configuration options -emit-dependencies Emit Make-compatible dependencies files -emit-module-path <path> Emit an importable module to <path> -emit-module Emit an importable module -emit-objc-header-path <path> Emit an Objective-C header file to <path> -emit-objc-header Emit an Objective-C header file -framework <value> Specifies a framework which should be linked against -F <value> Add directory to framework search path -g Emit debug info -help Display available options -import-underlying-module Implicitly imports the Objective-C half of a module -I <value> Add directory to the import search path -j <n> Number of commands to execute in parallel -L <value> Add directory to library link search path -l<value> Specifies a library which should be linked against -module-cache-path <value> Specifies the Clang module cache path -module-link-name <value> Library to link against when using this module -module-name <value> Name of the module to build -nostdimport Don't search the standard library import path for modules -output-file-map <path> A file which specifies the location of outputs -o <file> Write output to <file> -parse-as-library Parse the input file(s) as libraries, not scripts -parse-sil Parse the input file as SIL code, not Swift source -save-temps Save intermediate compilation results -sdk <sdk> Compile against <sdk> -serialize-diagnostics Serialize diagnostics in a binary format -target-cpu <value> Generate code for a particular CPU variant -target-feature [+-]<feature-name> Generate code with a particular CPU feature enabled or disabled -target <value> Generate code for the given target -version Print version information and exit -v Show commands to run and use verbose output -Xcc <arg> Pass <arg> to the C/C++/Objective-C compiler -Xfrontend <arg> Pass <arg> to the Swift frontend -Xlinker <value> Specifies an option which should be passed to the linker -Xllvm <arg> Pass <arg> to LLVM.這么多參數(shù)到底怎么用呢?!我們一起來看看 xcode 是怎么使用的。
因此,在iOS8之下的設(shè)備上,程序打包的時候帶上了必要的運行庫。對于iOS8,目前還沒法解開 dyld cache 也就無法知道設(shè)備上是否帶了這些庫,不過應(yīng)該會帶。
接上文,我們建立測試工程的目的是為了看看 xcode 如何使用 swift 編譯工具,xcoce編譯時的相關(guān)參數(shù)如下:
/Applications/Xcode6-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -target armv7-apple-ios5.0 -module-name FuckSwift -O0 -sdk /Applications/Xcode6-Beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.0.sdk -g -module-cache-path /Users/proteas/Library/Developer/Xcode/DerivedData/ModuleCache -I /Users/proteas/Library/Developer/Xcode/DerivedData/FuckSwift-czflmbyelvdrnvaxblvpkcrhfbie/Build/Products/Debug-iphoneos -F /Users/proteas/Library/Developer/Xcode/DerivedData/FuckSwift-czflmbyelvdrnvaxblvpkcrhfbie/Build/Products/Debug-iphoneos -parse-as-library -c -j8 /Users/proteas/Desktop/FuckSwift/FuckSwift/AppDelegate.swift -output-file-map /Users/proteas/Library/Developer/Xcode/DerivedData/FuckSwift-czflmbyelvdrnvaxblvpkcrhfbie/Build/Intermediates/FuckSwift.build/Debug-iphoneos/FuckSwift.build/Objects-normal/armv7/FuckSwift-OutputFileMap.json -serialize-diagnostics -emit-dependencies -emit-module -emit-module-path /Users/proteas/Library/Developer/Xcode/DerivedData/FuckSwift-czflmbyelvdrnvaxblvpkcrhfbie/Build/Intermediates/FuckSwift.build/Debug-iphoneos/FuckSwift.build/Objects-normal/armv7/FuckSwift.swiftmodule -Xcc -iquote -Xcc /Users/proteas/Library/Developer/Xcode/DerivedData/FuckSwift-czflmbyelvdrnvaxblvpkcrhfbie/Build/Intermediates/FuckSwift.build/Debug-iphoneos/FuckSwift.build/FuckSwift-generated-files.hmap -Xcc -I/Users/proteas/Library/Developer/Xcode/DerivedData/FuckSwift-czflmbyelvdrnvaxblvpkcrhfbie/Build/Intermediates/FuckSwift.build/Debug-iphoneos/FuckSwift.build/FuckSwift-own-target-headers.hmap -Xcc -I/Users/proteas/Library/Developer/Xcode/DerivedData/FuckSwift-czflmbyelvdrnvaxblvpkcrhfbie/Build/Intermediates/FuckSwift.build/Debug-iphoneos/FuckSwift.build/FuckSwift-all-target-headers.hmap -Xcc -iquote -Xcc /Users/proteas/Library/Developer/Xcode/DerivedData/FuckSwift-czflmbyelvdrnvaxblvpkcrhfbie/Build/Intermediates/FuckSwift.build/Debug-iphoneos/FuckSwift.build/FuckSwift-project-headers.hmap -Xcc -I/Users/proteas/Library/Developer/Xcode/DerivedData/FuckSwift-czflmbyelvdrnvaxblvpkcrhfbie/Build/Products/Debug-iphoneos/include -Xcc -I/Applications/Xcode6-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -Xcc -I/Users/proteas/Library/Developer/Xcode/DerivedData/FuckSwift-czflmbyelvdrnvaxblvpkcrhfbie/Build/Intermediates/FuckSwift.build/Debug-iphoneos/FuckSwift.build/DerivedSources/armv7 -Xcc -I/Users/proteas/Library/Developer/Xcode/DerivedData/FuckSwift-czflmbyelvdrnvaxblvpkcrhfbie/Build/Intermediates/FuckSwift.build/Debug-iphoneos/FuckSwift.build/DerivedSources -Xcc -DDEBUG=1 -emit-objc-header -emit-objc-header-path /Users/proteas/Library/Developer/Xcode/DerivedData/FuckSwift-czflmbyelvdrnvaxblvpkcrhfbie/Build/Intermediates/FuckSwift.build/Debug-iphoneos/FuckSwift.build/Objects-normal/armv7/FuckSwift-Swift.h
參數(shù)還是太多,繼續(xù)精簡,把去掉絕對路徑:
swift -target armv7-apple-ios5.0 -module-name FuckSwift -O0 -sdk iPhoneOS8.0.sdk -g -module-cache-path ModuleCache -I Debug-iphoneos -F Debug-iphoneos -parse-as-library -c -j8 AppDelegate.swift -output-file-map FuckSwift-OutputFileMap.json -serialize-diagnostics -emit-dependencies -emit-module -emit-module-path FuckSwift.swiftmodule -Xcc -iquote -Xcc FuckSwift-generated-files.hmap -Xcc -IFuckSwift-own-target-headers.hmap -Xcc -IFuckSwift-all-target-headers.hmap -Xcc -iquote -Xcc FuckSwift-project-headers.hmap -Xcc -Iinclude -Xcc -I/usr/include -Xcc -Iarmv7 -Xcc -IDerivedSources -Xcc -DDEBUG=1 <strong>-emit-objc-header -emit-objc-header-path FuckSwift-Swift.h</strong>
這樣就相對清晰了。這里面的參數(shù)大家可以對照上述的幫助查看,這里我們一起看兩點:
1、Xcc <arg>:Pass <arg> to the C/C++/Objective-C compiler,這里我們可以得到:swift代碼很可能最終被轉(zhuǎn)變成C/C++/Objective-C代碼進行靜態(tài)編譯。
2、會生成FuckSwift-Swift.h頭文件,對比下這個文件與swift文件。
@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool { self.window = UIWindow(frame: UIScreen.mainScreen().bounds) self.window!.backgroundColor = UIColor.whiteColor() self.window!.makeKeyAndVisible() return true } func applicationWillResignActive(application: UIApplication) { } func applicationDidEnterBackground(application: UIApplication) { } func applicationWillEnterForeground(application: UIApplication) { } func applicationDidBecomeActive(application: UIApplication) { } func applicationWillTerminate(application: UIApplication) { } }
SWIFT_CLASS("_TtC9FuckSwift11AppDelegate") @interface AppDelegate : UIResponder <UIApplicationDelegate> @property (nonatomic) UIWindow * window; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions; - (void)applicationWillResignActive:(UIApplication *)application; - (void)applicationDidEnterBackground:(UIApplication *)application; - (void)applicationWillEnterForeground:(UIApplication *)application; - (void)applicationDidBecomeActive:(UIApplication *)application; - (void)applicationWillTerminate:(UIApplication *)application; - (instancetype)init OBJC_DESIGNATED_INITIALIZER; @end
可以看到swift程序是被轉(zhuǎn)換了的,但是是不是轉(zhuǎn)換成了Objective-C程序呢?還需要進一步分析。
打開IDA,加載測試程序的MachO:
我們重點看下函數(shù)窗口:
從函數(shù)名上我們可以得到如下結(jié)論:
1、可以看到函數(shù)名被“改編”了。
2、swift代碼并不是被簡單得編譯成了ObjC代碼
3、swift代碼最終被編譯成了純C代碼,相對于ObjC來說省去了運行時查表進行函數(shù)調(diào)用的開銷,執(zhí)行效率應(yīng)該比ObjC要高。
4、從文檔上看swfit相對于ObjC來說是更加動態(tài)的語言,開發(fā)效率也應(yīng)該比ObjC高
5、對于越獄開發(fā)來說,我們只要像Hook C函數(shù)那樣來Hook swift 函數(shù)就可以了,因此MobileSubstrate還是可以工作的。
6、生成的代碼還是要遵循 ARM 的ABI標(biāo)準(zhǔn)
就像C++的名稱改編一樣,改編后的名稱雖然可以手工還原但是太麻煩,最好找到工具來做這一件事。前文,我們在查找swift相關(guān)的文件時看到一個工具:swift-demangle,下面我們就用它來demangle改編后的名稱,看看可以得到什么。
首先,我們切換命令行到xcode6的命令行工具:
sudo xcode-select --switch /Applications/Xcode6-Beta.app/Contents/Developer然后,我們看看swift-demangle的命令行參數(shù):
USAGE: swift-demangle [options] [mangled name...] OPTIONS: -compact - Compact mode (only emit the demangled names) -expand - Expand mode (show node structure of the demangling) -help - Display available options (-help-hidden for more) -no-sugar - No sugar mode (disable common language idioms such as ? and [] from the output) -tree-only - Tree-only mode (do not show the demangled string) -version - Display the version of this program從IDA中復(fù)制一個函數(shù)名,如:
__TToFC9FuckSwift11AppDelegate26applicationDidBecomeActivefS0_FCSo13UIApplicationT_我們執(zhí)行如下命令:
xcrun swift-demangle "__TToFC9FuckSwift11AppDelegate26applicationDidBecomeActivefS0_FCSo13UIApplicationT_"得到輸出:
_TToFC9FuckSwift11AppDelegate26applicationDidBecomeActivefS0_FCSo13UIApplicationT_ ---> @objc FuckSwift.AppDelegate.applicationDidBecomeActive (FuckSwift.AppDelegate)(ObjectiveC.UIApplication) -> ()
可以看到函數(shù)被還原。
到這里我們停下,看看swift對越獄開發(fā)的影響:
1、目前無法使用class-dump得到ObjC的頭文件。
2、MobileSubstrate應(yīng)該還可以正常工作。
3、可以使用demangle工具還原函數(shù)名,后期這部分工作IDA可能會自動支持。
總之,對越獄開發(fā)的流程會稍微有影響,針對應(yīng)用的越獄開發(fā)還可以存在。
下面我們看看命令行工具swift-ide-test的參數(shù):
OVERVIEW: Swift IDE Test USAGE: swift-ide-test [options] [input files...] OPTIONS: -D=<string> - Build configurations -F=<string> - add a directory to the framework search path -I=<string> - add a directory to the import search path -annotate-print - Annotate AST printing -code-completion-diagnostics - Print compiler diagnostics while doing code completion -code-completion-token=<string> - Code completion token name -comments-xml-schema=<string> - Filename of the RelaxNG schema for documentation comments -enable-objc-factory-method-constructors - Implicitly import Objective-C factory methods as initializers -enable-objc-implicit-properties - Implicitly import Objective-C getter/setter pairs as properties -explode-pattern-binding-decls - Separate pattern binding decls into individual var decls -fatal-assembler-warnings - Consider warnings as error -fully-qualified-types - Print fully qualified types -fully-qualified-types-if-ambiguous - Print types fully-qualified if they would be ambiguous otherwise -function-definitions - Print function bodies -help - Display available options (-help-hidden for more) -implicit-objc-with - Make the "with" implicit in initializers -import-objc-header=<string> - header to implicitly import -module-cache-path=<string> - Clang module cache path -module-print-hidden - Print non-exported imported or submodules -module-print-skip-overlay - Skip Swift overlay modules -module-print-submodules - Recursively print submodules -module-to-print=<string> - Name of the module to print -objc-bridge-dictionary - Bridge Dictionary<K, V> to NSDictionary -prefer-type-repr - When printing types, prefer printing TypeReprs -print-after-all - Print IR after each pass -print-before-all - Print IR before each pass Mode: -code-completion - Perform code completion -repl-code-completion - Perform REPL-style code completion -syntax-coloring - Perform syntax coloring -structure - Perform document structure annotation -annotate - Perform semantic annotation -test-input-complete - Check if input source is complete -print-ast-not-typechecked - Print the non-typechecked AST -print-ast-typechecked - Print the typechecked AST -print-module - Print visible declarations in a module -print-types - Print types of all subexpressions and declarations in the AST -print-comments - Print documentation comments attached to decls -print-module-comments - Given a module, print documentation comments attached to decls -print-module-imports - Recursively print all imports visible from a particular module -print-usrs - Print USRs for all decls -parse-rest - Parse a ReST file -print-implicit-attrs - Print implicit attributes -print-regular-comments - Print regular comments from clang module headers -print-stats - Print statistics -sdk=<string> - path to the SDK to build against -skip-private-stdlib-decls - Don't print declarations that start with '_' -skip-unavailable - Don't print unavailable declarations -source-filename=<string> - Name of the source file -split-objc-selectors - Split Objective-C selectors -stats - Enable statistics output from program (available with Asserts) -synthesize-sugar-on-types - Always print Array and Optional with sugar -target=<string> - target triple -terminal - Use terminal color for source annotations -time-passes - Time each pass, printing elapsed time for each on exit -typecheck - Type check the AST -version - Display the version of this program
從參數(shù)上看,這很可能是xcode的內(nèi)部工具,用來做代碼完成與檢查的。這里不具體分析,感興趣的兄弟可以自己試試。
下面我們繼續(xù)回到 swift 工具上,首先看看parse的輸出,執(zhí)行如下命令:
xcrun swift AppDelegate.swift -dump-parse得到如下輸出:
(source_file (import_decl UIKit') (class_decl "AppDelegate" type='<null type>' inherits: <null>, <null> (pattern_binding_decl (pattern_typed (pattern_named 'window') )) (var_decl "window" type='<null type>' storage_kind='stored') (func_decl "application(_:didFinishLaunchingWithOptions:)" type='<null type>' (body_params (pattern_typed implicit (pattern_named implicit 'self')) (pattern_tuple (pattern_typed (pattern_named 'application') (type_ident (component id='UIApplication' bind=none))) (pattern_typed (pattern_named 'launchOptions') ))) (result (type_ident (component id='Bool' bind=none))) (brace_stmt (sequence_expr type='<null>' (unresolved_dot_expr type='<null>' field 'window' (declref_expr type='<null>' decl=AppDelegate.(file).AppDelegate.func decl.self@AppDelegate.swift:17:10 specialized=yes)) (assign_expr (**NULL EXPRESSION**) (**NULL EXPRESSION**)) (call_expr type='<null>' (unresolved_decl_ref_expr type='<null>' name=UIWindow specialized=no) (tuple_expr type='<null>' names=frame (unresolved_dot_expr type='<null>' field 'bounds' (call_expr type='<null>' (unresolved_dot_expr type='<null>' field 'mainScreen' (unresolved_decl_ref_expr type='<null>' name=UIScreen specialized=no)) (tuple_expr type='<null>')))))) (sequence_expr type='<null>' (unresolved_dot_expr type='<null>' field 'backgroundColor' (force_value_expr type='<null>' (unresolved_dot_expr type='<null>' field 'window' (declref_expr type='<null>' decl=AppDelegate.(file).AppDelegate.func decl.self@AppDelegate.swift:17:10 specialized=yes)))) (assign_expr (**NULL EXPRESSION**) (**NULL EXPRESSION**)) (call_expr type='<null>' (unresolved_dot_expr type='<null>' field 'whiteColor' (unresolved_decl_ref_expr type='<null>' name=UIColor specialized=no)) (tuple_expr type='<null>'))) (call_expr type='<null>' (unresolved_dot_expr type='<null>' field 'makeKeyAndVisible' (force_value_expr type='<null>' (unresolved_dot_expr type='<null>' field 'window' (declref_expr type='<null>' decl=AppDelegate.(file).AppDelegate.func decl.self@AppDelegate.swift:17:10 specialized=yes)))) (tuple_expr type='<null>')) (return_stmt (unresolved_decl_ref_expr type='<null>' name=true specialized=no)))) (func_decl "applicationWillResignActive(_:)" type='<null type>' (body_params (pattern_typed implicit (pattern_named implicit 'self')) (pattern_tuple (pattern_typed (pattern_named 'application') (type_ident (component id='UIApplication' bind=none))))) (brace_stmt)) (func_decl "applicationDidEnterBackground(_:)" type='<null type>' (body_params (pattern_typed implicit (pattern_named implicit 'self')) (pattern_tuple (pattern_typed (pattern_named 'application') (type_ident (component id='UIApplication' bind=none))))) (brace_stmt)) (func_decl "applicationWillEnterForeground(_:)" type='<null type>' (body_params (pattern_typed implicit (pattern_named implicit 'self')) (pattern_tuple (pattern_typed (pattern_named 'application') (type_ident (component id='UIApplication' bind=none))))) (brace_stmt)) (func_decl "applicationDidBecomeActive(_:)" type='<null type>' (body_params (pattern_typed implicit (pattern_named implicit 'self')) (pattern_tuple (pattern_typed (pattern_named 'application') (type_ident (component id='UIApplication' bind=none))))) (brace_stmt)) (func_decl "applicationWillTerminate(_:)" type='<null type>' (body_params (pattern_typed implicit (pattern_named implicit 'self')) (pattern_tuple (pattern_typed (pattern_named 'application') (type_ident (component id='UIApplication' bind=none))))) (brace_stmt))))由于不了解編譯器相關(guān)的知識,無法解析上述輸出,但是看起來很像common lisp 的“點對”數(shù)據(jù)結(jié)構(gòu)。
另外,我們會注意到另一個比較重要的命令行參數(shù):-repl,我們一起玩玩,看看這個工具能力怎么樣。
在命令行執(zhí)行如下命令:
xcrun swift -repl可以得到一個腳本解析器的執(zhí)行環(huán)境:
我們參考“The Swift Programming Language”寫一個Hello World,看看效果:
可以使用:Ctrl + D退出解析器。
這里可以得到:
1、swift既可以被編譯執(zhí)行,也可以被解析執(zhí)行,是真正的動態(tài)語言。
2、大家可以用這個工具來學(xué)習(xí)語言特性。
就分析到這里,希望對大家有幫助。