GCC C++ 异常处理实现

2024-01-19

我想知道GCC是如何实现C++程序的异常处理的。我在网上找不到一篇易于理解且不言自明的文章(尽管针对 Visual C++ 有很多这样的文章)。我所知道的是GCC的实现称为DWARF异常处理。

我编写了一个小型 C++ 程序,并使用以下命令将其转换为汇编语言:

g++ main.cpp -S -masm=intel -fno-dwarf2-cfi-asm

The main.cpp and main.s文件在这里给出。谁能解释一下 main.s 文件的内容,特别是这些部分.gcc_except_table and .eh_frame逐行? (我的操作系统是Ubuntu 13.04 32位。)谢谢!

主要.cpp:

void f()
{
    throw 1;
}

int main()
{
    int j;
    try {
        f();
    } catch (int i) {
        j = i;
    }   
    return 0;
}

main.s:

.file "main.cpp"
.intel_syntax noprefix
.text
.globl  _Z1fv
.type   _Z1fv, @function
_Z1fv:
.LFB0:
    push    ebp
.LCFI0:
    mov ebp, esp
.LCFI1:
    sub esp, 24
    mov DWORD PTR [esp], 4
    call    __cxa_allocate_exception
    mov DWORD PTR [eax], 1
    mov DWORD PTR [esp+8], 0
    mov DWORD PTR [esp+4], OFFSET FLAT:_ZTIi
    mov DWORD PTR [esp], eax
    call    __cxa_throw
.LFE0:
    .size   _Z1fv, .-_Z1fv
    .globl  main
    .type   main, @function
main:
.LFB1:
    push    ebp
.LCFI2:
    mov ebp, esp
.LCFI3:
    and esp, -16
    sub esp, 32
.LEHB0:
    call    _Z1fv
.LEHE0:
.L7:
    mov eax, 0
    jmp .L9
.L8:
    cmp edx, 1
    je  .L6
    mov DWORD PTR [esp], eax
.LEHB1:
    call    _Unwind_Resume
.LEHE1:
.L6:
    mov DWORD PTR [esp], eax
    call    __cxa_begin_catch
    mov eax, DWORD PTR [eax]
    mov DWORD PTR [esp+24], eax
    mov eax, DWORD PTR [esp+24]
    mov DWORD PTR [esp+28], eax
    call    __cxa_end_catch
    jmp .L7
.L9:
    leave
.LCFI4:
    ret
.LFE1:
    .globl  __gxx_personality_v0
    .section    .gcc_except_table,"a",@progbits
    .align 4
.LLSDA1:
    .byte   0xff
    .byte   0
    .uleb128 .LLSDATT1-.LLSDATTD1
.LLSDATTD1:
    .byte   0x1
    .uleb128 .LLSDACSE1-.LLSDACSB1
.LLSDACSB1:
    .uleb128 .LEHB0-.LFB1
    .uleb128 .LEHE0-.LEHB0
    .uleb128 .L8-.LFB1
    .uleb128 0x1
    .uleb128 .LEHB1-.LFB1
    .uleb128 .LEHE1-.LEHB1
    .uleb128 0
    .uleb128 0
.LLSDACSE1:
    .byte   0x1
    .byte   0
    .align 4
    .long   _ZTIi
.LLSDATT1:
    .text
    .size   main, .-main
    .section    .eh_frame,"a",@progbits
.Lframe1:
    .long   .LECIE1-.LSCIE1
.LSCIE1:
    .long   0
    .byte   0x1
    .string "zPL"
    .uleb128 0x1
    .sleb128 -4
    .byte   0x8
    .uleb128 0x6
    .byte   0
    .long   __gxx_personality_v0
    .byte   0
    .byte   0xc
    .uleb128 0x4
    .uleb128 0x4
    .byte   0x88
    .uleb128 0x1
    .align 4
.LECIE1:
.LSFDE1:
    .long   .LEFDE1-.LASFDE1
.LASFDE1:
    .long   .LASFDE1-.Lframe1
    .long   .LFB0
    .long   .LFE0-.LFB0
    .uleb128 0x4
    .long   0
    .byte   0x4
    .long   .LCFI0-.LFB0
    .byte   0xe
    .uleb128 0x8
    .byte   0x85
    .uleb128 0x2
    .byte   0x4
    .long   .LCFI1-.LCFI0
    .byte   0xd
    .uleb128 0x5
    .align 4
.LEFDE1:
.LSFDE3:
    .long   .LEFDE3-.LASFDE3
.LASFDE3:
    .long   .LASFDE3-.Lframe1
    .long   .LFB1
    .long   .LFE1-.LFB1
    .uleb128 0x4
    .long   .LLSDA1
    .byte   0x4
    .long   .LCFI2-.LFB1
    .byte   0xe
    .uleb128 0x8
    .byte   0x85
    .uleb128 0x2
    .byte   0x4
    .long   .LCFI3-.LCFI2
    .byte   0xd
    .uleb128 0x5
    .byte   0x4
    .long   .LCFI4-.LCFI3
    .byte   0xc5
    .byte   0xc
    .uleb128 0x4
    .uleb128 0x4
    .align 4
.LEFDE3:
    .ident  "GCC: (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3"
    .section    .note.GNU-stack,"",@progbits

Itanium ABI(gcc、clang 和其他一些都遵循)指定异常处理应遵循零成本策略 http://www.cs.ucla.edu/classes/spring08/cs259/llvm-2.2/docs/ExceptionHandling.html.

零成本策略的想法是将所有异常处理推送到不保留在主程序执行路径上的副表中(因此不会破坏指令缓存)。这些表按程序点进行索引。

此外,DWARF 信息(实际上是调试信息)用于展开堆栈。此功能通常作为库提供,例如利本温德 http://www.nongnu.org/libunwind/docs.html例如,源代码充满了汇编(因此非常特定于平台)。

优点:

  • 0成本进入try/catch阻塞(就像没有一样快)
  • 0成本拥有throw函数中的语句(只要不采取)

坏处:

  • 出现异常时速度较慢(比正常情况慢 10 倍)if策略),因为边表通常不在缓存中,然后需要运行昂贵的计算才能知道哪些catch子句实际匹配(基于 RTTI)

对于所有主要编译器来说,它是 32 位和 64 位平台上非常流行的策略实现......除了 MSVC 32 位(如果我没记错的话)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GCC C++ 异常处理实现 的相关文章

  • Cocoa 常量名称中的“k”代表什么[重复]

    这个问题在这里已经有答案了 可能的重复 Apple 的 API 中的 k 前缀表示什么 https stackoverflow com questions 675816 what does the k prefix indicate in
  • 具有自动返回类型推导的 Friend 函数模板无法访问私有成员

    抱歉这个问题的标题太复杂了 我试图描述我为这个问题构建的最小 SSCCE 我有以下代码 include
  • 如何防止函数中的隐式转换?

    我正在编写一个实用程序类 其中包含 IsEquals 和 IsGreaterThanEquals 等接受 double 类型参数的方法 当我将浮点值发送到方法时 它们会隐式转换为双精度值并进行比较 我不希望这种事发生 当我发送 float
  • Motif 库的水平绘制的 RowColumn 类 (C)?

    我正在使用 Motif Library 来完成我的工作 如果有人不熟悉这个库 您可以在这里找到文件列表https packages ubuntu com xenial amd64 libmotif dev filelist https pa
  • 减少最大值并保存其索引

    int v 10 2 9 1 3 5 7 1 2 0 0 int maximo 0 int b 0 int i pragma omp parallel for shared v private i reduction max maximo
  • 具有 Nhibernate 设计问题的领域模型

    我正在尝试进入 DDD with C 世界 我使用NHibernate作为我的ORM工具 因此尝试开发一个PI Persistence Ignorance 模型 但是 在我的一些实体 表示为 POCOS 中 我的属性设置器中有业务规则 例如
  • gcc 的错误?模板类中友元函数的访问控制问题

    我有一个模板类 并在类中定义了一个友元函数 include
  • 更改 Json 中属性的键

    这些天我正在尝试制作一个 json 编辑器 与树视图一起使用 我确实更改了值函数 我也可以更改一些键 但我无法在对象中设置键 我可以设置值 SetValue ref JObject main JToken token JToken newV
  • 对指针列表进行排序

    我再次发现自己在 C 中的一些非常简单的任务上失败了 有时我希望我能从 Java 中的 OO 中学到所有知识 因为我的问题通常是从像 Java 一样思考开始的 无论如何 我有一个std list
  • llvm clang 编译器上的dynamic_cast失败

    我看到一个奇怪的失败dynamic cast正在返回NULL在 clang 编译器上 但相同的代码可以在 gcc 环境下运行 您能否指出根本原因是什么 之间可能有什么区别dynamic cast关于 llvm 和 gcc 我正在使用两个编译
  • 如何在运行时统一捕捉两个对象?

    这是 3D 模型 我想将另一个像这样的模型连接到顶部的银色连接器 并将另一个模型连接到右侧 所以请帮助我捕捉它 https i stack imgur com qoWwl png我想知道如何在运行时将两个 3D 对象对齐在一起 即 在 玩
  • 从高斯分布中采样随机值的最快方法是什么?

    The Box Muller 变换 http en wikipedia org wiki Box E2 80 93Muller transform 是一种从高斯分布中采样随机值的优雅且性能合理的方法 我正在寻找一种用 C 编写 清晰的更快方
  • boost::bind 会导致开销吗?

    我目前正在从事网络软件方面的工作 它有一个主要类 server这显然代表一个服务器实例 A server实例可以发送请求 并通过回调通知用户响应 代码如下 class server public typedef boost function
  • 作为服务运行时,URLDownloadToFile() 将对象写入缓存中

    我有一个软件 可以将图像下载到工作目录中 然后对其进行处理以创建视频 之后 这些文件将被独立脚本删除 问题是它还将文件写入以下目录 该软件作为系统服务运行 C Windows SysWOW64 config systemprofile Ap
  • 我如何在 WPF 中模仿这种行为?

    我对 WPF 和 C 开发相当陌生 我正在制作这个应用程序 我不知道是否有人熟悉 VOIP App Discord 但他们有一个我非常喜欢的特定行为 并且想尝试使用 WPF 创建类似的风格 当您在 Discord 上添加服务器时 单击一个按
  • SQlite 查询 - 如何检索多列数据?

    我很难在网上找到一个关于使用 xcode 和 cocos2dx 从 SQlite DB 获取多个值的工作示例 这是我的sql查询 char sql query 100 sprintf sql query SELECT FROM SQList
  • .so 文件的 objdump?需要帮助来理解消息

    我正在开发一个与流相关的本机应用程序 我在我的 c 模块中遇到了一些问题 我收到的是来自 Logcat 的一些消息 这是 Logcat 消息 INFO DEBUG 28 Build fingerprint generic sdk gener
  • 找出用户属于哪些组

    我有一个刚刚创建的 Windows 用户帐户 以 XYZ 为例 此 XYZ 属于我在计算机管理 gt 本地用户和组中创建的用户组和自定义组 因此 在属性中我看到该用户属于 2 个组 现在我想获取这些组并显示它们 有什么建议么 我已经这样做了
  • 系统.安全.加密与 PCLCrypto

    我们正在删除系统中的许多共享功能并将其移植到 PCL 库中 我在使用 PCLCrypto 时遇到问题 我正在获取数据库中的一些现有数据 并尝试使用相同的算法对其进行解密 我得到了值 但末尾有 16 个额外字节 这些字节都是垃圾 参见下面的代
  • Interlocked.CompareExchange 可以抛出 NullReferenceException 吗?

    From https msdn microsoft com en us library bb297966 v vs 110 aspx https msdn microsoft com en us library bb297966 v vs

随机推荐

  • 如何为 JavaScript Set 自定义对象相等性

    新ES 6 Harmony 推出新Set https developer mozilla org en US docs Web JavaScript Reference Global Objects Set目的 Set 使用的恒等算法类似于
  • 有用的替代控制结构?

    有时 当我编程时 我发现某些特定的控制结构对我非常有用 但在我的编程语言中不能直接使用 我认为我最常见的愿望是 短暂的一段时间 我不知道实际上该怎么称呼它 foo split while condition bar 这段代码的语义是foo
  • 将初始化数据传递给 Angular 2

    有谁知道如何将初始化数据传递到使用 Angular CLI 构建的 Angular 2 应用程序中 我需要传递当前从预先验证的 NET 后端获得的访问令牌 以便我可以调用 API 我尝试通过本地 Web api 端点执行此操作 但由于 Ob
  • 如何使用 package.json 脚本复制具有特定文件扩展名的文件

    我正在尝试将 npm 作为构建工具 我遇到的一个障碍是我需要将 javascript 文件从一个文件夹复制到另一个文件夹 源文件夹包含打字稿文件 javascript 文件和地图文件 但在目标文件夹中我只对 javascript 文件感兴趣
  • 如何使用反射调用 Scala 对象方法?

    说 我有以下内容 trait SomeTrait def someMethod String object SomeObject extends SomeTrait def someMethod something 我想使用反射调用 som
  • 初始化列表上的 ArgumentOutOfRangeException

    它在 For 循环中间抛出 ArgumentOutOfRangeException 请注意我删除了 for 循环的其余部分 for int i 0 i lt CurrentUser Course ID Count 1 i CurrentUs
  • 当 mongodb 的好处应该是无模式时,为什么 mongoose 使用模式?

    我是 mongodb 的超级新手 我正在使用 mongoose 从 node js 访问 mongodb 并且知道如何让事情正常工作 但我认为我不明白为什么它会这样工作 最重要的是 我不明白为什么 mongoose 有 模式 而 mongo
  • Android Studio Mediastore.Audio.Media.DATA 已弃用,有替代方案吗?

    我正在尝试访问外部存储上的 mp3 文件 并且我正在使用 mediastore 来检索它 然而 android studio 似乎指出通过 mediastore audio media DATA 获取它已被弃用 这是我的代码 val med
  • 在javascript中用多个分隔符分割方程字符串并保留分隔符,然后将字符串重新组合在一起

    我有一个方程 我想使用运算符来拆分 作为分隔符 然后我想改变一项并将方程重新组合起来 例如 一个方程可以是 s 5 3 8 somevariablename 6 我想我可以使用正则表达式来分解方程 re g var elements s s
  • 如何在基于 MFC 对话框的应用程序中使用 CTabCtrl?

    我需要做一些我期望很简单的事情 创建一个有 2 个选项卡的选项卡控件 这意味着我的应用程序有 2 种操作模式 当用户单击 Tab1 时 他会看到一些按钮和文本框 当他单击 Tab2 时 他会看到一些其他输入法 我注意到 MFC 中有一个 C
  • 替换以 # 开头然后是整个单词的占位符

    我需要替换文本中以井号 开头的单词 好吧 我知道如何替换整个单词 preg replace b variable b value text 因为 b 修饰符只接受单词字符 所以包含哈希标记的单词不会被替换 我有这个 html 其中包含 co
  • 获取短日名称

    我想知道如何编写一个方法 该方法将返回一个包含短日名称的字符串 例如 public static string GetShortDayName DayOfWeek day 现在如果我打电话 string monday GetShortDay
  • MySql 重新启动后:#1452 - 无法添加或更新子行:外键约束失败

    MySql 重新启动后 当我尝试更新或插入行时 出现此错误 1452 无法添加或更新子行 外键约束失败 奇怪的是 当我使用 phpMyAdmin 再次删除并添加键约束时 问题就消失了 另外 我只在 MAMP 上遇到这个问题 在 WAMP 上
  • 从 Java 中的 Json 字符串中删除重复项?

    我有一个包含重复值的 Json 字符串 String json Sign In Type Action Sign In Type Action 当我尝试创建 JSONObject 时 它会正确抛出异常 try JSONObject json
  • 如何在 IntelliJ 中保存打开的选项卡组?

    如何在 IntelliJ 中保存一组打开的选项卡 以便我可以在 Git 分支之间切换并为每个分支调出一组工作文件 谢谢 您可以保存上下文 其中包括一组打开的选项卡以及一些其他信息 例如活动的运行配置 使用Tools Tasks Contex
  • 正则表达式如果捕获组匹配字符串

    我需要构建一个简单的脚本来连接罗马尼亚语单词 我见过几个 他们没有正确执行规则 var words arta codru 规则 如果 2 个辅音位于 2 个元音之间 则它们会在音节之间分开 除非它们属于此数组 在这种情况下 两个辅音都会移动
  • 了解 Ubuntu 中不同对象的相同 inode 编号

    为什么 cdrom 的 inode 号与 cdrom 的 inode 号相同 sys devices platform power在Ubuntu中 以下在我的 Ubuntu 中具有相同的 inode 编号 media BACKUP 1 MI
  • WPF - Graphics.CopyFromScreen 返回黑色图像

    以下方法取自 WinForms 应用程序 它只是捕获屏幕 但我需要修改它才能在 WPF 应用程序中工作 当我使用它时 它返回黑色图像 尺寸正确 我没有任何打开的 DirectX 或视频 甚至在我的桌面上也无法工作 public static
  • 如何使用stemCompletion函数(tm包)从字典中完成词干语料库

    我在 R 的 tm 包中遇到问题 我使用的是 0 6 2 版本 以下问题 2个不同的错误 已得到解答here https stackoverflow com questions 24191728 documenttermmatrix err
  • GCC C++ 异常处理实现

    我想知道GCC是如何实现C 程序的异常处理的 我在网上找不到一篇易于理解且不言自明的文章 尽管针对 Visual C 有很多这样的文章 我所知道的是GCC的实现称为DWARF异常处理 我编写了一个小型 C 程序 并使用以下命令将其转换为汇编