Objective-C';是否在运行时执行s@try-@catch实现?

Objective-C';是否在运行时执行s@try-@catch实现?,objective-c,exception-handling,try-catch,objective-c-runtime,Objective C,Exception Handling,Try Catch,Objective C Runtime,在Objective-C的低级运行时标题(/usr/include/objc)中,有一个objc exceptions.h文件。ObjC编译器似乎就是这样实现@try/@catch 我试图手动调用这些函数(用于ObjC运行时和实现的实验),以捕获“未识别的选择器发送到类”异常 因此,基本上,我要寻找的只是一个如何使用低级运行时函数进行@try/@catch的示例。提前谢谢 那么您想知道运行时如何处理异常 做好失望的准备。 因为它没有。ObjC没有异常处理ABI,只有您已经找到的SPI。毫无疑问,

在Objective-C的低级运行时标题(
/usr/include/objc
)中,有一个
objc exceptions.h
文件。ObjC编译器似乎就是这样实现
@try
/
@catch

我试图手动调用这些函数(用于ObjC运行时和实现的实验),以捕获“未识别的选择器发送到类”异常


因此,基本上,我要寻找的只是一个如何使用低级运行时函数进行
@try
/
@catch
的示例。提前谢谢

那么您想知道运行时如何处理异常

做好失望的准备。

因为它没有。ObjC没有异常处理ABI,只有您已经找到的SPI。毫无疑问,您还发现Objective-C异常ABI实际上与。为此,让我们从一些代码开始

#include <Foundation/Foundation.h>

int main(int argc, char **argv) {
    @try {
        @throw [NSException exceptionWithName:@"ExceptionalCircumstances" reason:@"Drunk on power" userInfo:nil];
    } @catch(...) {
        NSLog(@"Catch");
    } @finally {
        NSLog(@"Finally");
    }
}
如果使用ObjC++编译,则不会发生任何更改。(好吧,这并不完全正确。最后一个
\u objc\u terminate
变成了一个跳转到clang的个人
\u clang\u call\u terminate
例程)。无论如何,这段代码可以分为3个重要部分。第一个是从
\u main
LBB0\u 2
的开头,或者是发生try块的地方。因为我们公然抛出一个异常并在
try
块中捕获它,所以编译器已经继续并删除了
LBB0_2
周围的分支,并直接移动到catch处理程序。此时,Objective-C,或者更准确地说是CoreFoundation,已经为我们设置了一个异常对象,并且libC++已经开始在必要的展开阶段搜索异常处理程序

第二个重要的代码块是从
LBB0_2
LBB0_11
的末尾,我们的
catch
最后的
代码块都存在。因为一切都很好,所以下面的所有代码都已经死了(希望在发行版中被剥离),但让我们想象一下它不是

第三部分是从下面的
LBB0_8
开始的,如果我们做了一些愚蠢的事情,比如说,试图不捕获异常,编译器会从
LBB0_2
中的NSLog发出一个跳转。在调用
objc_begin_catch
后,该处理程序会稍微翻转一点,这会导致我们绕过
ret
并转到
objc_exception_rethrow()
,该处理程序会告诉放松处理程序我们丢了球,并继续在其他地方搜索处理程序。当然,我们是main,因此没有其他处理程序,并且在离开时调用
std::terminate


所有这些都表明如果你想用手写的方式写出这些东西,你会很不开心。所有的<代码>、yxCxa**、/Cux>和ObjsSPI函数都以不可依赖的方式抛出异常对象,并且(相当悲观地)处理程序在A中发出,以确保C++的ABI契约得以满足,因为如果不是规范命令<代码> STD::终止< /Calp>被调用。如果你想扮演一个积极的监听角色,你可以使用自己的函数和Objective-C拥有
objc\u setUncaughtExceptionHandler
objc\u setExceptionMatcher
objc\u setExceptionPreprocessor
,考虑到obj-C++,你也想自己进行堆栈展开吗?尤金,我不确定我是否遵循。。。我在寻找一个类似于我在这里找到的未捕获异常的例子:,但我猜更像是
begin\u try
end\u try
之类的东西。try/catch块的汇编确实显示了对objc\u begin\u catch和objc\u end\u catch的调用。你有没有试着看一下它们是如何被调用的?
_main:                                  ## @main
    push    rbp
    mov rbp, rsp
    push    r14
    push    rbx

    mov rdi, qword ptr [rip + L_OBJC_CLASSLIST_REFERENCES_$_]
    mov rsi, qword ptr [rip + L_OBJC_SELECTOR_REFERENCES_]

    lea rdx, qword ptr [rip + L__unnamed_cfstring_]
    lea rcx, qword ptr [rip + L__unnamed_cfstring_2]
    xor r8d, r8d
    call    qword ptr [rip + _objc_msgSend@GOTPCREL]

    mov rdi, rax
    call    _objc_exception_throw
LBB0_2:
    mov rdi, rax
    call    _objc_begin_catch

    lea rdi, qword ptr [rip + L__unnamed_cfstring_4]
    xor eax, eax
    call    _NSLog

    call    _objc_end_catch

    xor ebx, ebx
LBB0_8:
    lea rdi, qword ptr [rip + L__unnamed_cfstring_6]
    xor eax, eax
    call    _NSLog

    test    bl, bl
    jne LBB0_10
LBB0_11:
    xor eax, eax
    pop rbx
    pop r14
    pop rbp
    ret
LBB0_5:
    mov rbx, rax
    call    _objc_end_catch
    jmp LBB0_7
LBB0_6:
    mov rbx, rax
LBB0_7:
    mov rdi, rbx
    call    _objc_begin_catch
    mov bl, 1
    jmp LBB0_8
LBB0_12:
    mov r14, rax
    test    bl, bl
    je  LBB0_14
    jmp LBB0_13
LBB0_10:
    call    _objc_exception_rethrow
    jmp LBB0_11
LBB0_16:                                ## %.thread
    mov r14, rax
LBB0_13:
    call    _objc_end_catch
LBB0_14:
    mov rdi, r14
    call    __Unwind_Resume
LBB0_15:
    call    _objc_terminate