[转]Inside Swift
原文地址:http://www.eswick.com/2014/06/inside-swift/
Inside Swift
Swift is Apple’s new programming language, said by many to ‘replace’ Objective-C. This is not the case. I’ve spent some time reverse engineering Swift binaries and the runtime, and I’ve found out quite a bit about it. So far, the verdict is this; Swift is Objective-C without messages.
Objects
Believe it or not, Swift objects are actually Objective-C objects. In a Mach-O binary, the__objc_classlist section contains data for each class in the binary. The structure is like so:
struct objc_class {uint64_t isa;uint64_t superclass;uint64_t cache;uint64_t vtable;uint64_t data;};
(note: all structures are from 64-bit builds)
Note the data entry. It points to a structure listing the methods, ivars, protocols, etc. of the class. Normally, data is 8-byte-aligned. However, for Swift classes, the last bit of data will be 1.
Classes
The actual structure for Swift classes is a bit odd. Swift classes have no Objective-C methods. We’ll get to that later. Variables for Swift classes are stored as ivars. The Swift getter and setter methods actually modify the ivar values. Oddly, ivars for Swift classes have no type encoding. The pointer that is normally supposed to point to the type encoding is NULL. This is presumably due to the fact that the Objective-C runtime is not supposed to deal with Swift variables itself.
Inheritance
Inheritance in Swift is as you would expect. In Swift, a Square that is a subclass of Shape will also be a subclass of Shape in the Objective-C class. However, what if a class in Swift doesn’t have a superclass?
e.g.
class Shape { }
In this case, the Shape class would be a subclass of SwiftObject. SwiftObject is a root Objective-C class, similar to NSObject. It has no superclass, meaning the isa points to itself. Its purpose is to use Swift runtime methods for things like allocation and deallocation, instead of the standard Objective-C runtime. For example, - (void)retain does not call objc_retain, but instead callsswift_retain.
Class Methods
Like I mentioned earlier, 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.
In Objective-C, method implementations are like so:
type method(id self, SEL _cmd, id arg1, id arg2, ...)
Swift methods are very similar, but with a slightly different argument layout. self is passed as the last argument, and there is no selector.
type method(id arg1, id arg2, ..., id self)
vtable
Just like in C++, Swift classes have a vtable which lists the methods in the class. It is located directly after the class data in the binary, and looks something like this:
struct swift_vtable_header {uint32_t vtable_size;uint32_t unknown_000;uint32_t unknown_001;uint32_t unknown_002;void* nominalTypeDescriptor;// vtable pointers}
From what I can tell, the vtable for a Swift class is only used when it is visible during compile time. Otherwise, it finds the mangled symbol.
Name Mangling
Swift keeps metadata about functions (and more) in their respective symbols, which is called name mangling. This metadata includes the function’s name (obviously), attributes, module name, argument types, return type, and more. Take this for example:
classShape{
func numberOfSides()->Int{return5}}
The mangled name for the simpleDescription method is_TFC9swifttest5Shape17simpleDescriptionfS0_FT_Si. Here’s the breakdown:
_T – The prefix for all Swift symbols. Everything will start with this.
F – Function.
C – Function of a class. (method)
9swifttest – The module name, with a prefixed length.
5Shape – The class name the function belongs to, again, with a prefixed length.
17simpleDescription – The function name.
f – The function attribute. In this case it’s ‘f’, which is just a normal function. We’ll get to that in a minute.
S0_FT – I’m not exactly sure what this means, but it appears to mark the start of the arguments and return type.
‘_’ – This underscore separates the argument types from the return type. Since the function takes no arguments, it comes directly after S0_FT.
S – This is the beginning of the return type. The ‘S’ stands for Swift; the return type is a Swift builtin type. The next character determines the type.
i – This is the Swift builtin type. A lowercase ‘I’, which stands for Int.
Function Attributes
|
Character
|
Type
|
|---|---|
| f | Normal Function |
| s | Setter |
| g | Getter |
| d | Destructor |
| D | Deallocator |
| c | Constructor |
| C | Allocator |
Swift Builtins
|
Character
|
Type
|
|---|---|
| a | Array |
| b | Bool |
| c | UnicodeScalar |
| d | Double |
| f | Float |
| i | Int |
| u | UInt |
| Q | ImplicitlyUnwrappedOptional |
| S | String |
There’s a lot more to name mangling than just functions, but I’ve just given a brief overview.
Function Hooking
Enough with semantics, let’s get to the fun part! Let’s say we have a class like so:
classShape{var numberOfSides:Int;
init(){
numberOfSides =5;}}
Let’s say we want to change the numberOfSides to 4. There are multiple ways to do this. We could use MobileSubstrate to hook into the getter method, and change the return value, like so:
int(*numberOfSides)(id self);MSHook(int, numberOfSides, id self){return4;}%ctor{
numberOfSides =(int(*)(id self)) dlsym(RTLD_DEFAULT,"_TFC9swifttest5Shapeg13numberOfSidesSi");MSHookFunction(numberOfSides,MSHake(numberOfSides));}
If we create an instance of Shape and print out the value of numberOfSides, we see 4! That wasn’t so bad, was it? Now, I know what you’re thinking; “aren’t you supposed to return an object instead of a 4 literal?”
Well, in Swift, a lot of the builtin types are literals. An Int, for example, is the same as an int in C (although it could be a long – don’t hold me to that). A little note, the String type is a little bit odd; it’s a little-endian UTF-16 string, so no C literals can be used.
Let’s do the same thing, but this time, we’ll hook the setter instead of the getter.
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));}
Try it again and….it’s still 5. What is happening, you ask? Well, in certain places in Swift, functions are inlined. The class constructor is one of these places. It directly sets the numberOfSides ivar. So, the setter will only be called if the number is set again from the top level code. Call it from there and, what do you know, we get 4.
Finally, let’s change numberOfSides by directly setting the ivar.
void(*setNumberOfSides)(int newNumber, id self);MSHook(void, setNumberOfSides,int newNumber, id self){MSHookIvar<int>(self,"numberOfSides")=4;}%ctor {
setNumberOfSides =(void(*)(int newNumber, id self)) dlsym(RTLD_DEFAULT,"_TFC9swifttest5Shapes13numberOfSidesSi");MSHookFunction(setNumberOfSides,MSHake(setNumberOfSides));}
This works. It’s not recommended, but it works.
That’s all I have to write about for now. There’s quite a few other things that I’m looking at, including witness tables, but I don’t know enough about them to write. A lot of things in this post are subject to change. They’re just what I’ve reverse engineered so far by looking at the runtime and binaries compiled with Swift.
What I’ve found here is very good. It means that MobileSubstrate will not die along with Objective-C, and tweaks can still be made! I wonder what the future has in store for the jailbreaking scene… maybe Logos could be updated to automatically mangle names? Or even a library that deals with common Swift types…
If you find out more about how Swift works, don’t hesitate to let me know!
[转]Inside Swift的更多相关文章
- 窥探Swift编程之别样的HelloWorld
从今天就开始陆陆续续的发布一些有关Swift语言的东西,虽然目前在公司项目开发中Objective-C还是iOS开发的主力军,但是在不久的将来Swift将会成为iOS开发中的新生宠儿.所以在在Xcod ...
- 使用 Swift 在 iOS 10 中集成 Siri —— SiriKit 教程
下载 Xcode 8,配置 iOS 10 和 Swift 3 (可选)通过命令行编译 除 非你想使用命令行编译,使用 Swift 3.0 的工具链并不需要对项目做任何改变.如果你想的话,打开 Xcod ...
- Send Push Notifications to iOS Devices using Xcode 8 and Swift 3, APNs Auth Key
Send Push Notifications to iOS Devices using Xcode 8 and Swift 3 OCT 6, 2016 Push notifications are ...
- Swift 用Delegate和Block实现回调的Demo
一.有关回调 我们知道,执行函数的时候,一般都有return作为返回参数了,那有return了为什么还要回调呢? 回调是为了实现异步的返回,在某些特殊的情况下,比如你执行的函数是一个长时间运行的函数, ...
- Swift 1.0: missing argument label 'xxx' in call
注意,这个问题是在swift1.0时发生的,swift2.0中,好像统一了function 和 method 的定义,具体待正式版发布后研究一下! 今天在使用swift时发现,写的func总是要求写出 ...
- 弱引用?强引用?未持有?额滴神啊-- Swift 引用计数指导
ARC ARC 苹果版本的自动内存管理的编译时间特性.它代表了自动引用计数(Automatic Reference Counting).也就是对于一个对象来说,只有在引用计数为0的情况下内存才会被释放 ...
- swift混编oc碰到的问题
在swift中混编苹果官方的Reachability OC文件. 因为swift工程的target是生成framework而非app,framework中调用oc与app中使用桥接文件还不一样,参考: ...
- swift SDWebImage使用
Web image(网络图像) 该库提供了一个支持来自Web的远程图像的UIImageView类别它提供了: 添加网络图像和缓存管理到Cocoa Touch framework的UIImageView ...
- Swift学习笔记十三
初始化 初始化是一个在类.结构体或枚举的实例对象创建之前,对它进行预处理的过程,包括给那个对象的每一个存储式属性设定初始值,以及进行一些其他的准备操作. 通过定义初始化器(initializer)来实 ...
随机推荐
- 使用C#实现顺序队列
队列(Queue)是插入操作限定在表的尾部而其它操作限定在表的头部进行的线性表.把进行插入操作的表尾称为队尾(Rear),把进行其它操作的头部称为队头(Front).当对列中没有数据元素时称为空对列( ...
- ArcPad 10 的安装和部署
ArcPad它被安装在一个手持装置或业内外的移动终端ArcGIS产品,那ArcPad这是Esri软件产品,哦,不是硬件. 虽然优于ArcGIS Desktop功能复杂的乐趣,是对于野外作业.数据採集等 ...
- Swift # 项目框架
利用Swift--简单的项目界面流程. TabBar+Navigation底部导航控制,界面的切换. GitHub源码分享,地址: URL:https://github.com/SpongeBob-G ...
- HDU 2516 取石子游戏 (博弈论)
取石子游戏 Problem Description 1堆石子有n个,两人轮流取.先取者第1次能够取随意多个,但不能所有取完.以后每次取的石子数不能超过上次取子数的2倍.取完者胜.先取者负输出" ...
- 深入理解PHP中赋值与引用
原文:深入理解PHP中赋值与引用 先看下面的问题: <?php $a = 10;//将常量值赋给变量,会为a分配内存空间 $b = $a;//变量赋值给变量,是不是copy了一份副本,b也分配了 ...
- 【Eclipse提高开发速度-插件篇】Eclipse插件安装慢得几个原因
1.改动"Available Softeware Site" ,降低关联,详细做法 Install New Software >> Available Softewar ...
- 《浪潮之巅》完全系类——IT人士必读经典
浪潮之巅 第一章 帝国的余辉(AT&T) 浪潮之巅第二章 — 蓝色巨人(IBM) 浪潮之巅第三章 — “水果”公司的复兴 (乔布斯和苹果公司) 浪潮之巅第四章 — 计算机工业的生态链 浪潮之巅 ...
- C语言库函数大全及应用实例一
原文:C语言库函数大全及应用实例一 [编程资料]C语言库函数大全及应用实例一 函数名: abort 功 能: 异常终止一个进程 用 法: ...
- typeof小结
- 使用SQL Server Driver for PHP解决PHP连接MSSQL乱码的问题
原文 使用SQL Server Driver for PHP解决PHP连接MSSQL乱码的问题 最近帮客户写了一个.net商城网站的发布接口,大家都知道.net一般都使用MSSQL数据库,但鱼丸不会. ...