(.eh)在nm输出中是什么意思
What does (.eh) mean in nm output?
当我查看库中的符号时,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
是什么意思,这个额外的符号是用来做什么的?
我看到它与异常处理有关。但是为什么它使用一个额外的符号呢?
(我用叮当声注意到了这一点)
下面是一些简单的代码:
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_*
指令都用于在抛出异常的情况下展开堆栈。它们都编译成一个FDE(帧描述条目)块,并以g().eh
(__Z1gv.eh
残缺)的名称保存。这些指令指定 CPU 寄存器在堆栈上的保存位置。当抛出异常并且堆栈被展开时,不应执行函数中的代码(局部变量的析构函数除外),但应恢复之前保存的寄存器。这些表完全存储该信息。
这些表可以通过dwarfdump
工具转储:
$ 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
然后转储(__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
中添加一个带有非平凡析构函数的局部变量,编译和查看程序集输出。
延伸阅读
- 一些
.cfi_*
指令的解释 - LLVM 中的异常处理
它代表异常处理程序,通常与以下信息相关联:
如果使用导出列表并构建共享库或将与 ld 的 -bundle_loader 标志一起使用的可执行文件,则需要在导出的C++符号的导出列表中包括异常帧信息的符号。否则,它们可能会被剥离。这些符号以 .eh 结尾;您可以使用 NM 工具查看它们。
- 来自 XcodeUserGuide20
- 这个语法std::class<>{}(arg1, arg2) 在C++中是什么意思?
- 标准 N3337 5.2.10 第 7 条中的C++"类型"是什么意思?
- "类模板示例<int>;"语句对 C++11 是什么意思?
- 线应该是什么意思
- "CID"在AT+HTTPPARA= "CID" ,1中是什么意思
- 表达式"b=(b-x)&x"是什么意思?
- 这个表达是什么意思?
- 此代码验证公式是什么意思?
- 跟踪日志中的T.11803()是什么意思?
- 这个额外的关键字在这个 c++ 类声明中是什么意思?
- * 和 ** 在 C++ 函数声明中是什么意思?
- _T("xyz")是什么意思?
- #define Dbg(fmt,..) (0) 是什么意思? 警告:表达式无效
- 这行代码到底是什么意思?
- 在命名空间名称之前加上 :: 是什么意思?
- 从字符数组的元素中减去'a'是什么意思
- "friend"关键字在C++中是什么意思?
- 减法中的"0"是什么意思?
- 字符数组前面的加号是什么意思?
- 这里的字符串函数是什么意思