美文网首页
block 捕获外部变量,内部调用copy 函数的时机

block 捕获外部变量,内部调用copy 函数的时机

作者: 三三哥 | 来源:发表于2021-11-15 14:05 被阅读0次

    文章由来:  重新看objc 编译成C++ 时候block 实现时梳理代码时候发现,C++实现的block 内部没找到直接调用__foo_block_impl_0* 这个函数(foo 是定义和实现block 的函数名称,具体看各自测试代block码在哪个函数里面调用的)。

    object 代码

    // main.m

    #import <Foundation/Foundation.h>

    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 时候进行拷贝(可以当参考思路不能当正确答案,不敢胡乱猜测 !-_-!)。

    相关文章

      网友评论

          本文标题:block 捕获外部变量,内部调用copy 函数的时机

          本文链接:https://www.haomeiwen.com/subject/vokqtrtx.html