(.eh)在nm输出中的含义是什么?

时间:2013-10-15 08:26:50

标签: c++ nm symbol-table

当我查看我的库中的符号nm mylib.a时,我看到一些重复的条目如下所示:

000000000002d130 S __ZN7quadmat11SpAddLeavesC1EPNS_14BlockContainerEPy
00000000000628a8 S __ZN7quadmat11SpAddLeavesC1EPNS_14BlockContainerEPy.eh

通过c++filt传送:

000000000002d130 S quadmat::SpAddLeaves::SpAddLeaves(quadmat::BlockContainer*, unsigned long long*)
00000000000628a8 S quadmat::SpAddLeaves::SpAddLeaves(quadmat::BlockContainer*, unsigned long long*) (.eh)

.eh是什么意思,这个额外符号用于什么?

我发现它与异常处理有关。但为什么会使用额外的符号?

(我用clang注意到这一点)

2 个答案:

答案 0 :(得分:4)

这是一些简单的代码:

bool extenrnal_variable;

int f(...)
{
    if (extenrnal_variable)
        throw 0;

    return 42;
}

int g()
{
    return f(1, 2, 3);
}

我添加了extenrnal_variable以防止编译器优化所有分支。 f ...$ clang++ -S -O3 -m32 -o - eh.cpp | c++filt 来阻止内联。

编译时使用:

g()

它为g(): ## @_Z1gv .cfi_startproc ## BB#0: pushl %ebp Ltmp9: .cfi_def_cfa_offset 8 Ltmp10: .cfi_offset %ebp, -8 movl %esp, %ebp Ltmp11: .cfi_def_cfa_register %ebp subl $24, %esp movl $3, 8(%esp) movl $2, 4(%esp) movl $1, (%esp) calll f(...) movl $42, %eax addl $24, %esp popl %ebp ret .cfi_endproc 发出以下代码(其余部分被省略):

.cfi_*

在抛出异常的情况下,所有这些g().eh指令都用于堆栈展开。它们全部编译成FDE(帧描述条目)块并保存在__Z1gv.ehdwarfdump损坏的)名称下。这些指令指定堆栈中CPU寄存器的保存位置。当抛出异常并且堆栈被解除时,不应该执行函数中的代码(本地的析构函数除外),但是应该恢复先前保存的寄存器。这些表准确存储了这些信息。

可以通过$ dwarfdump --eh-frame --english eh.o | c++filt 工具转储这些表格:

0x00000018: FDE
        length: 0x00000018
   CIE_pointer: 0x00000000
    start_addr: 0x00000000 f(...)
    range_size: 0x0000004d (end_addr = 0x0000004d)
  Instructions: 0x00000000: CFA=esp+4     eip=[esp]
                0x00000001: CFA=esp+8     ebp=[esp]  eip=[esp+4]
                0x00000003: CFA=ebp+8     ebp=[ebp]  eip=[ebp+4]
                0x00000007: CFA=ebp+8     ebp=[ebp]  esi=[ebp-4]  eip=[ebp+4]

0x00000034: FDE
        length: 0x00000018
   CIE_pointer: 0x00000000
    start_addr: 0x00000050 g()
    range_size: 0x0000002c (end_addr = 0x0000007c)
  Instructions: 0x00000050: CFA=esp+4     eip=[esp]
                0x00000051: CFA=esp+8     ebp=[esp]  eip=[esp+4]
                0x00000053: CFA=ebp+8     ebp=[ebp]  eip=[ebp+4]

输出:

$ nm -n eh.o

00000000 T __Z1fz
         U __ZTIi
         U ___cxa_allocate_exception
         U ___cxa_throw
00000050 T __Z1gv
000000a8 s EH_frame0
000000c0 S __Z1fz.eh
000000dc S __Z1gv.eh
000000f8 S _extenrnal_variable

Here你可以找到关于这个块的格式。 Here更多一些代表相同信息的替代更紧凑的方式。基本上,这个块描述了堆栈展开期间堆栈中的哪些寄存器以及从哪里开始。

要查看这些符号的原始内容,您可以列出所有符号及其偏移量:

(__TEXT,__eh_frame)

然后转储$ otool -s __TEXT __eh_frame eh.o eh.o: Contents of (__TEXT,__eh_frame) section 000000a8 14 00 00 00 00 00 00 00 01 7a 52 00 01 7c 08 01 000000b8 10 0c 05 04 88 01 00 00 18 00 00 00 1c 00 00 00 000000c8 38 ff ff ff 4d 00 00 00 00 41 0e 08 84 02 42 0d 000000d8 04 44 86 03 18 00 00 00 38 00 00 00 6c ff ff ff 000000e8 2c 00 00 00 00 41 0e 08 84 02 42 0d 04 00 00 00 部分:

g

通过匹配偏移量,您可以看到每个符号的编码方式。

当存在局部变量时,在堆栈展开期间必须销毁它们。为此,通常会在函数本身中嵌入更多代码,并创建一些更大的表。你可以通过在{{1}}中添加一个带有非平凡析构函数的局部变量来自己探索,编译并查看汇编输出。

进一步阅读

答案 1 :(得分:2)

它代表异常处理程序的代表,通常与以下信息相关联:

如果您正在使用导出列表并构建共享库或将与ld的-bundle_loader标志一起使用的可执行文件,则需要在导出的C ++符号的导出列表中包含异常帧信息的符号。否则,他们可能会被剥夺。这些符号以.eh结尾;您可以使用nm工具查看它们。

  • 来自XcodeUserGuide20