alloc 底层调用流程图
alloc 为什么会调用 objc_alloc ?
查看源码可以看到alloc的调用顺序,oc-->_objc_rootAlloc(self)
但是当我们断点调试的时候,查看汇编可以看到优先调用的是objc_alloc,这是怎么回事呢?
思路:sel->imp 那么一定是alloc 对应的imp在某个地方被修改了,我们在源文件中搜索objc_alloc
打开查看代码
再找到调用fixupMessageRef的地方
- fixup是修复的意思,那说明在这之前已经被动过了
- ? --> dyld --> readimage 到底是什么在dyld之前是alloc最终调用objc_alloc? 答案是clang 我们先下载llvm的源码 github.com/apple/llvm-…
在llvm中查找对alloc的修改
搜索objc_alloc
shouldUseRuntimeFunctionsForAlloc 在搜索shouldUseRuntimeFunctionsForAlloc
static Optional<llvm::Value *>
tryGenerateSpecializedMessageSend(CodeGenFunction &CGF, QualType ResultType,
llvm::Value *Receiver,
const CallArgList& Args, Selector Sel,
const ObjCMethodDecl *method,
bool isClassMessage) {
auto &CGM = CGF.CGM;
if (!CGM.getCodeGenOpts().ObjCConvertMessagesToRuntimeCalls)
return None;
auto &Runtime = CGM.getLangOpts().ObjCRuntime;
switch (Sel.getMethodFamily()) {
case OMF_alloc:
if (isClassMessage &&
Runtime.shouldUseRuntimeFunctionsForAlloc() &&
ResultType->isObjCObjectPointerType()) {
// [Foo alloc] -> objc_alloc(Foo) or
// [self alloc] -> objc_alloc(self)
if (Sel.isUnarySelector() && Sel.getNameForSlot(0) == "alloc")// 这里这里
return CGF.EmitObjCAlloc(Receiver, CGF.ConvertType(ResultType));
// [Foo allocWithZone:nil] -> objc_allocWithZone(Foo) or
// [self allocWithZone:nil] -> objc_allocWithZone(self)
if (Sel.isKeywordSelector() && Sel.getNumArgs() == 1 &&
Args.size() == 1 && Args.front().getType()->isPointerType() &&
Sel.getNameForSlot(0) == "allocWithZone") {
const llvm::Value* arg = Args.front().getKnownRValue().getScalarVal();
if (isa<llvm::ConstantPointerNull>(arg))
return CGF.EmitObjCAllocWithZone(Receiver,
CGF.ConvertType(ResultType));
return None;
}
}
break;
/// Allocate the given objc object.
/// call i8* \@objc_alloc(i8* %value)
llvm::Value *CodeGenFunction::EmitObjCAlloc(llvm::Value *value,
llvm::Type *resultType) {
return emitObjCValueOperation(*this, value, resultType,
CGM.getObjCEntrypoints().objc_alloc,
"objc_alloc");
}
明显在这里替换成了alloc 调用替换成了objc_alloc
流程整理
CodeGen::RValue CGObjCRuntime::GeneratePossiblySpecializedMessageSend(
CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType,
Selector Sel, llvm::Value *Receiver, const CallArgList &Args,
const ObjCInterfaceDecl *OID, const ObjCMethodDecl *Method,
bool isClassMessage) {
if (Optional<llvm::Value *> SpecializedResult =
tryGenerateSpecializedMessageSend(CGF, ResultType, Receiver, Args,
Sel, Method, isClassMessage)) {
return RValue::get(SpecializedResult.getValue());
}
return GenerateMessageSend(CGF, Return, ResultType, Sel, Receiver, Args, OID,
Method);
}
graph TD
GeneratePossiblySpecializedMessageSend --> tryGenerateSpecializedMessageSend
GeneratePossiblySpecializedMessageSend --> GenerateMessageSend
- alloc llvm
- alloc-->objc_alloc-标记receiver
- objc_alloc-->objc_msgSend
- alloc-->_objc_rootAlloc(self) 这也是为什么callAlloc走两次的原因
内存打印小技巧 x/nuf
n 表示要显示的内存单元的个数
u 表示一个地址单元的长度
- b 表示单字节
- h 表示双字节
- w 表示4字节
- g 表示八字节
- f 表示显示方式 f表示显示方式,可取如下值
- x 按十六进制格式显示变量
- d 按十进制格式显示变量
- u 按十进制格式显示无符号整形
- o 按八进制格式显示变量
- t 按二进制格式显示变量
- a 按十六进制格式显示变量
- i 指令地址格式
- c 按字符格式显示变量
- f 按浮点格式显示变量