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

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

内容简介:要从我们已经为我们的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函数里使用它。


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

查看所有标签

猜你喜欢:

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

算法概论

算法概论

Sanjoy Dasgupta、Christos Papadimitriou、Umesh Vazirani / 王沛、唐扬斌、刘齐军 / 清华大学出版社 / 2008-7 / 39.99元

《国外经典教材·算法概论》涵盖了绝大多数算法设计中的常用技术。在表达每一种技术时,阐述它的应用背景,强调每个算法运转背后的简洁数学思想,注意运用与其他技术类比的方法来说明它的特征,并提供了大量相应实际问题的例子。《国外经典教材·算法概论》同时也注重了对每一种算法的复杂性分析。全书共10章,从基本的数字算法人手,先后介绍了分治、图的遍历、贪心算法、动态规划、线性规划等技术,对NP完全问题进行厂基本而......一起来看看 《算法概论》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具