[译]C++异常的幕后11:阅读CFI表

栏目: C++ · 发布时间: 5年前

内容简介:要从我们已经为我们的ABI实现的personality函数里正确处理异常,我们需要阅读LSDA(语言特定数据区)来了解哪个调用帧(即哪个函数)可以处理哪个异常,以及了解哪里可以找到着陆垫(catch块))。LSDA是CFI格式的,我们将在本章里学习如何读它。读CFI数据是相当直截了当的,但有一些我们需要首先考虑的陷阱。实际上,两个:

作者: nicolasbrailo

要从我们已经为我们的ABI实现的personality函数里正确处理异常,我们需要阅读LSDA(语言特定数据区)来了解哪个调用帧(即哪个函数)可以处理哪个异常,以及了解哪里可以找到着陆垫(catch块))。LSDA是CFI格式的,我们将在本章里学习如何读它。

读CFI数据是相当直截了当的,但有一些我们需要首先考虑的陷阱。实际上,两个:

  1. 关于.gcc_except_table格式的文档非常少(实际上,我仅找到关于它的几封邮件),因此我们将需要读大量的源代码,并反汇编来理解它。
  2. 虽然格式本身不是特别复杂,它使用一个使得读这个表不那么直截了当的LEB编码。

就我所知,大多数DWARF代价像这样编码,使用 LEB格式 ,对一头雾水的 程序员 看起来不错,在编码任意长的整数时节省代码空间。幸运地,在这里我们可以耍个小花招:大多数时间里,可以uint8_t来读LEB编码的数字,因为我们不准备处理大的异常表或任何类似的东西。

备注:你可以从我的 github repo 下载完整的源代码。

让我们直接从汇编分析CFI数据,然后看我们是否能构建某些在我们的personality函数上读它的东西。我将重命名这些标记,使它们对我们更友好些。LSDA有三部分,试着在下面找出它们:

1

2

3

4

.local_frame_entry:

    .globl  __gxx_personality_v0

    .section    .gcc_except_table,"a",@progbits

    .align 4

这个非常简单:它只是声明我们将使用__gxx_personality_v0作为全局对象,并让链接器知道我们准备为.gcc_except_table节声明内容的头部。继续:

1

2

3

4

5

6

7

8

9

10

11

.local_lsda_1:

    # This declares the encoding type. We don't care.

    .byte   0xff

 

    # This specifies the landing pads start; if zero, the func's ptr is

    # assumed (_Unwind_GetRegionStart)

    .byte   0

 

    # Length of the LSDA area: check that LLSDATT1 and LLSDATTD1 point to the

    # end and the beginning of the LSDA, respectively

    .uleb128 .local_lsda_end - .local_lsda_call_site_table_header

现在这有更多一些信息。这些标签相当模糊,但确实遵循一个模式。LSDA表示语言特定数据区,前面的L表示本地,因此这是本地(对于编译单元,.o文件)语言特定数据区编号1。其他标记遵循类似的模式,但我还没有时间把它们算出来。不过,我们确实不需要。

1

2

3

4

5

6

.local_lsda_call_site_table_header:

    # Encoding of items in the landing pad table. Again, we don't care.

    .byte   0x1.

 

    # The length of the call site table (ie the landing pads)

    .uleb128 .local_lsda_call_site_table_end - .local_lsda_call_site_table

另一个单调的头。继续:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

.local_lsda_call_site_table:

    .uleb128 .LEHB0-.LFB1

    .uleb128 .LEHE0-.LEHB0

    .uleb128 .L8-.LFB1

    .uleb128 0x1

 

    .uleb128 .LEHB1-.LFB1

    .uleb128 .LEHE1-.LEHB1

    .uleb128 0

    .uleb128 0

 

    .uleb128 .LEHB2-.LFB1

    .uleb128 .LEHE2-.LEHB2

    .uleb128 .L9-.LFB1

    .uleb128 0

.local_lsda_call_site_table_end:

这有趣得多,现在我们看到调用表本身。不管怎样,在所有这些项里,我们应该能够找到我们的着陆垫。根据一些网页,每个调用项的格式应该是:

1

2

3

4

5

6

7

8

9

10

11

12

13

struct lsda_call_site_entry {

    // Start of the IP range

    size_t cs_start;

 

    // Length of the IP range

    size_t cs_len;

 

    // Landing pad address

    size_t cs_lp;

 

    // Offset into action table

    size_t cs_action;

};

看起来了我们在正轨上,虽然我们还不知道为什么在我们仅定义了一个着陆垫时,有3个调用项。在任何情形里,我们可以耍点小花招:通过查看汇编,我们可以推断CFI上的所有值将小于128,这意味着在LEB编码中,它们可以作为uchar来读。这使得我们读CFI的代码大为容易,下次我们将看到如何在personality函数里使用它。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

C语言程序设计

C语言程序设计

K. N. King / 吕秀锋、黄倩 / 人民邮电出版社 / 2010-4 / 79.00元

时至今日, C语言仍然是计算机领域的通用语言之一,但今天的 C语言已经和最初的时候大不相同了。本书最主要的一个目的就是通过一种“现代方法”来介绍 C语言,书中强调标准 C,强调软件工程,不再强调“手工优化”。这一版中紧密结合了 C99标准,并与 C89标准进行对照,补充了 C99中的最新特性。本书分为 C语言的基础特性、 C语言的高级特性、 C语言标准库和参考资料 4个部分。每章末尾都有一个“问与......一起来看看 《C语言程序设计》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码