llvm对alloc的优化
我们再来动态和静态分析一下alloc的流程,
1:首先使用汇编查看动态流程.
Debug -> Debug Workflow -> Always Show Disassembly
如下图一样打断点, 并运行
可以看出下一个要跑到的方法是objc_alloc
2:command+鼠标静态分析代码
可以看到alloc 要跳到的下一个方法是_objc_rootAlloc 而不是objc_alloc
这又是什么原因呢?
从上面的注释,我猜测是SEL和IMP进行了交换?
首先我们定位到类的加载映射里面找到_read_image方法, 这个方法里面有处理映射方法的代码块
然后在这个长长的方法里面我跟踪到了另一个方法:
fixupMessageRef(message_ref_t *msg)
可以看到这个方法里面将alloc绑定到了objc_alloc上面, 同样这个方法对retain, release, autorelease做了同样的操作. 从上段代码块可以看出, 当alloc出问题时, 会对他做出修复.如果没问题时,就直接执行objc_alloc方法.
苹果对一些方法进行hook处理, alloc是直接对内存进行直接操作的, 所以会对其进行相应的监控, 也就是hook拦截, 当调用alloc的时候, 不直接走alloc的底层流程, 而是先找objc_alloc, 找完objc_alloc之后, 才开始对下层进行标记, 标记完成之后, 才开始找alloc方法.
来到LLVM的源码
在LLVM源码里面搜索objc_alloc, 在CGObjC.cpp中找到了如下代码static Optional<llvm::Value *> tryGenerateSpecializedMessageSend:
进入到llvm::Value *CodeGenFunction::EmitObjCAlloc 方法里
可以看出
alloc和objc_alloc逻辑就这样实现了绑定.
那么谁调用的tryGenerateSpecializedMessageSend 这个方法呢, 在LLVM的源码里面搜索到了GeneratePossiblySpecializedMessageSend这个方法. 可以看出在这个方法里通过消息发送走到了tryGenerateSpecializedMessageSend.
苹果对苹果对
alloc等特殊函数做了hook,先走emitObjCValueOperation, 然后首次会走tryGenerateSpecializedMessageSend分支,第二次就走GenerateMessageSend分支了。
也就是第一次alloc调用了objc_alloc,第二次alloc后就没有调用objc_alloc走了正常的objc_msgSend:alloc-> objc_alloc -> callAlloc -> alloc -> _objc_rootAlloc -> callAlloc。这也就是callAlloc走两次的原因。