文章由来: 重新看objc 编译成C++ 时候block 实现时梳理代码时候发现,C++实现的block 内部没找到直接调用__foo_block_impl_0* 这个函数(foo 是定义和实现block 的函数名称,具体看各自测试代block码在哪个函数里面调用的)。
object 代码
// main.m
#import
void foo() {
int a_int = 0;
NSNumber *a_number = [NSNumber numberWithInt:0];
void(^blockA)(void) = ^(void) {
NSLog(@"a_int = %d", a_int);
NSLog(@"a_number = %@", a_number);
};
a_int = 1;
a_number = @1;
blockA();
return ;
}
int main(int argc, const char * argv[]) {
foo();
return 0;
}
对应的C++ 编译之后的主要代码,其他多余代码已经去掉
struct __foo_block_impl_0 {
struct __block_impl impl;
struct __foo_block_desc_0* Desc;
int a_int;
NSNumber *a_number;
__foo_block_impl_0(void *fp, struct __foo_block_desc_0 *desc, int _a_int, NSNumber *_a_number, int flags=0) : a_int(_a_int), a_number(_a_number) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __foo_block_func_0(struct __foo_block_impl_0 *__cself) {
int a_int = __cself->a_int; // bound by copy
NSNumber *a_number = __cself->a_number; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_hf_ff518dhs4cq81s4jf93ppmg00000gn_T_blockTest_e6692f_mi_0, a_int);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_hf_ff518dhs4cq81s4jf93ppmg00000gn_T_blockTest_e6692f_mi_1, a_number);
}
static void __foo_block_copy_0(struct __foo_block_impl_0*dst, struct __foo_block_impl_0*src) {_Block_object_assign((void*)&dst->a_number, (void*)src->a_number, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static void __foo_block_dispose_0(struct __foo_block_impl_0*src) {_Block_object_dispose((void*)src->a_number, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static struct __foo_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __foo_block_impl_0*, struct __foo_block_impl_0*);
void (*dispose)(struct __foo_block_impl_0*);
} __foo_block_desc_0_DATA = { 0, sizeof(struct __foo_block_impl_0), __foo_block_copy_0, __foo_block_dispose_0};
void foo() {
int a_int = 0;
NSNumber *a_number = ((NSNumber * _Nonnull (*)(id, SEL, int))(void *)objc_msgSend)((id)objc_getClass("NSNumber"), sel_registerName("numberWithInt:"), 0);
void(*blockA)(void) = ((void (*)())&__foo_block_impl_0((void *)__foo_block_func_0, &__foo_block_desc_0_DATA, a_int, a_number, 570425344));
a_int = 1;
a_number = ((NSNumber *(*)(Class, SEL, int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithInt:"), 1);
((void (*)(__block_impl *))((__block_impl *)blockA)->FuncPtr)((__block_impl *)blockA);
return ;
}
int main(int argc, const char * argv[]) {
foo();
return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };
会发现 __foo_block_impl_0 虽然在 __foo_block_desc_0 结构体定义,但是在 __foo_block_impl_0 复制给Desc 时候并没有明显的发现调用__foo_block_impl_0拷贝的痕迹,开始以为在调用block 静态函数__foo_block_func_0 时候给int值变量复制系统会自动调用__foo_block_impl_0之类的,但是后面发现并没有,于是 编译成汇编代码:我们把注意力集中到_foo 函数里面的 ___block_descriptor_44_e8_32s_e5_v8 ,最终调用到 section里面去了,然后在里面执行了___copy_helper_block_e8_32s, 全局搜索下___copy_helper_block_e8_32s 发现 .section __TEXT,__cstring,cstring_literals 属于代码段字符串符号表定义表达式(.quad,具体自行网上搜索)__copy_helper_block_e8_32s 。 其他地方实在无法联系到调用___copy_helper_block_e8_32s进行拷贝。
.section __TEXT,__text,regular,pure_instructions
.build_version macos, 11, 0 sdk_version 12, 0
.globl _foo ## -- Begin function foo
.p2align 4, 0x90
_foo: ## @foo
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
subq $80, %rsp
xorl %edx, %edx
movl $0, -4(%rbp)
movq _OBJC_CLASSLIST_REFERENCES_$_(%rip), %rdi
movq _OBJC_SELECTOR_REFERENCES_(%rip), %rsi
callq *_objc_msgSend@GOTPCREL(%rip)
movq %rax, %rdi
callq _objc_retainAutoreleasedReturnValue
movq %rax, %rsi
leaq "___block_descriptor_44_e8_32s_e5_v8?0l"(%rip), %rax
leaq ___foo_block_invoke(%rip), %rcx
movq __NSConcreteStackBlock@GOTPCREL(%rip), %rdx
movq %rsi, -16(%rbp)
movq %rdx, -72(%rbp)
movl $-1040187392, -64(%rbp) ## imm = 0xC2000000
movl $0, -60(%rbp)
movq %rcx, -56(%rbp)
movq %rax, -48(%rbp)
movl -4(%rbp), %eax
movl %eax, -32(%rbp)
leaq -72(%rbp), %rax
addq $32, %rax
movq %rax, -80(%rbp) ## 8-byte Spill
movq -16(%rbp), %rdi
callq *_objc_retain@GOTPCREL(%rip)
movq %rax, -40(%rbp)
leaq -72(%rbp), %rdi
callq _objc_retainBlock
leaq l__unnamed_nsconstantintegernumber_(%rip), %rsi
movq %rax, -24(%rbp)
movl $1, -4(%rbp)
leaq -16(%rbp), %rdi
callq _objc_storeStrong
movq -24(%rbp), %rax
movq %rax, %rdi
callq *16(%rax)
xorl %eax, %eax
movl %eax, %esi
leaq -24(%rbp), %rdi
callq _objc_storeStrong
movq -80(%rbp), %rdi ## 8-byte Reload
xorl %eax, %eax
movl %eax, %esi
callq _objc_storeStrong
xorl %eax, %eax
movl %eax, %esi
leaq -16(%rbp), %rdi
callq _objc_storeStrong
addq $80, %rsp
popq %rbp
retq
.cfi_endproc
## -- End function
.p2align 4, 0x90 ## -- Begin function __foo_block_invoke
___foo_block_invoke: ## @__foo_block_invoke
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
subq $32, %rsp
movq %rdi, %rax
movq %rax, -24(%rbp) ## 8-byte Spill
leaq L__unnamed_cfstring_(%rip), %rdi
movq %rax, -8(%rbp)
movq %rax, %rcx
movq %rcx, -16(%rbp)
movl 40(%rax), %esi
movb $0, %al
callq _NSLog
movq -24(%rbp), %rax ## 8-byte Reload
leaq L__unnamed_cfstring_.2(%rip), %rdi
movq 32(%rax), %rsi
movb $0, %al
callq _NSLog
addq $32, %rsp
popq %rbp
retq
.cfi_endproc
## -- End function
.private_extern ___copy_helper_block_e8_32s ## -- Begin function __copy_helper_block_e8_32s
.globl ___copy_helper_block_e8_32s
.weak_def_can_be_hidden ___copy_helper_block_e8_32s
.p2align 4, 0x90
___copy_helper_block_e8_32s: ## @__copy_helper_block_e8_32s
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
subq $16, %rsp
movq %rdi, -8(%rbp)
movq %rsi, -16(%rbp)
movq -16(%rbp), %rcx
movq -8(%rbp), %rax
movq %rax, %rdi
addq $32, %rdi
movq 32(%rcx), %rsi
movq $0, 32(%rax)
callq _objc_storeStrong
addq $16, %rsp
popq %rbp
retq
.cfi_endproc
## -- End function
.private_extern ___destroy_helper_block_e8_32s ## -- Begin function __destroy_helper_block_e8_32s
.globl ___destroy_helper_block_e8_32s
.weak_def_can_be_hidden ___destroy_helper_block_e8_32s
.p2align 4, 0x90
___destroy_helper_block_e8_32s: ## @__destroy_helper_block_e8_32s
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
subq $16, %rsp
xorl %eax, %eax
movl %eax, %esi
movq %rdi, -8(%rbp)
movq -8(%rbp), %rdi
addq $32, %rdi
callq _objc_storeStrong
addq $16, %rsp
popq %rbp
retq
.cfi_endproc
## -- End function
.globl _main ## -- Begin function main
.p2align 4, 0x90
_main: ## @main
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
subq $16, %rsp
movl $0, -4(%rbp)
movl %edi, -8(%rbp)
movq %rsi, -16(%rbp)
callq _foo
xorl %eax, %eax
addq $16, %rsp
popq %rbp
retq
.cfi_endproc
## -- End function
.section __DATA,__objc_classrefs,regular,no_dead_strip
.p2align 3 ## @"OBJC_CLASSLIST_REFERENCES_$_"
_OBJC_CLASSLIST_REFERENCES_$_:
.quad _OBJC_CLASS_$_NSNumber
.section __TEXT,__objc_methname,cstring_literals
L_OBJC_METH_VAR_NAME_: ## @OBJC_METH_VAR_NAME_
.asciz "numberWithInt:"
.section __DATA,__objc_selrefs,literal_pointers,no_dead_strip
.p2align 3 ## @OBJC_SELECTOR_REFERENCES_
_OBJC_SELECTOR_REFERENCES_:
.quad L_OBJC_METH_VAR_NAME_
.section __TEXT,__cstring,cstring_literals
L_.str: ## @.str
.asciz "a_int = %d"
.section __DATA,__cfstring
.p2align 3 ## @_unnamed_cfstring_
L__unnamed_cfstring_:
.quad ___CFConstantStringClassReference
.long 1992 ## 0x7c8
.space 4
.quad L_.str
.quad 10 ## 0xa
.section __TEXT,__cstring,cstring_literals
L_.str.1: ## @.str.1
.asciz "a_number = %@"
.section __DATA,__cfstring
.p2align 3 ## @_unnamed_cfstring_.2
L__unnamed_cfstring_.2:
.quad ___CFConstantStringClassReference
.long 1992 ## 0x7c8
.space 4
.quad L_.str.1
.quad 13 ## 0xd
.section __TEXT,__cstring,cstring_literals
L_.str.3: ## @.str.3
.asciz "v8@?0"
.private_extern "___block_descriptor_44_e8_32s_e5_v8?0l" ## @"__block_descriptor_44_e8_32s_e5_v8\01?0l"
.section __DATA,__const
.globl "___block_descriptor_44_e8_32s_e5_v8?0l"
.weak_def_can_be_hidden "___block_descriptor_44_e8_32s_e5_v8?0l"
.p2align 3
"___block_descriptor_44_e8_32s_e5_v8?0l":
.quad 0 ## 0x0
.quad 44 ## 0x2c
.quad ___copy_helper_block_e8_32s
.quad ___destroy_helper_block_e8_32s
.quad L_.str.3
.quad 256 ## 0x100
.section __TEXT,__cstring,cstring_literals
L_.str.4: ## @.str.4
.asciz "i"
.section __DATA,__objc_intobj,regular,no_dead_strip
.p2align 3 ## @_unnamed_nsconstantintegernumber_
l__unnamed_nsconstantintegernumber_:
.quad _OBJC_CLASS_$_NSConstantIntegerNumber
.quad L_.str.4
.quad 1 ## 0x1
.section __DATA,__objc_imageinfo,regular,no_dead_strip
L_OBJC_IMAGE_INFO:
.long 0
.long 64
.subsections_via_symbols
目前大概明白了通过传结构体值时发生了参数拷贝,本人对C++不是很熟悉,不是很了解到底C++内部是如何传调用copy函数,只能通过汇编跳转猜测应该是在block 内部赋值DESC 时候进行拷贝(可以当参考思路不能当正确答案,不敢胡乱猜测 !-_-!)。