What does (.eh) mean in nm output?

When I look at the characters in my library, nm mylib.a , I see several duplicate entries that look like this:

 000000000002d130 S __ZN7quadmat11SpAddLeavesC1EPNS_14BlockContainerEPy 00000000000628a8 S __ZN7quadmat11SpAddLeavesC1EPNS_14BlockContainerEPy.eh 

When passing through c++filt :

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

What does this .eh mean and what is this extra character used for?

I see that this is due to exception handling. But why does this use an extra character?

(I notice this with clang)

+6
source share
2 answers

Here is a simple code:

 bool extenrnal_variable; int f(...) { if (extenrnal_variable) throw 0; return 42; } int g() { return f(1, 2, 3); } 

I added extenrnal_variable to prevent the compiler from optimizing all branches. f has ... to prevent inlining.

When compiling with:

 $ clang++ -S -O3 -m32 -o - eh.cpp | c++filt 

it produces the following code for g() (the rest is omitted):

 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 

All of these .cfi_* directives exist to expand the stack if an exception is thrown. All of them were compiled into the FDE block (frame description record) and saved under the name g().eh __Z1gv.eh ( __Z1gv.eh ). These directives determine where the CPU registers are stored on the stack. When an exception is thrown and the stack is unwound, the code in the function should not be executed (with the exception of locale destructors), but the registers that were saved earlier must be restored. These tables store exactly this information.

These tables can be reset using the dwarfdump tool:

 $ dwarfdump --eh-frame --english eh.o | c++filt 

Output:

 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] 

Here you can find out about the format of this block. Here are a few more and several alternative more compact ways of presenting the same information. Basically this block describes which registers and where to pop out of the stack during stack unloading.

To see the original contents of these characters, you can list all the characters with their offsets:

 $ 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 

And then unload the section (__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 

By matching offsets, you can see how each character is encoded.

When there are local variables, they must be destroyed during the expansion of the stack. To do this, usually more code is built into the functions themselves, and several additional large tables are created. You can study this yourself by adding a local variable with a non-trivial destructor in g , compiling and looking at the output of the assembly.

Further reading

+4
source

It denotes icons for an exception handler and is usually associated with the information below:

If you use the export list and create either a shared library or an executable file that will be used with the ld-bundle_loader flag, you need to include the characters for the exception frame information in the export list for the exported C ++ characters. Otherwise, they may be deleted. These characters end in .eh; You can view them with the nm tool.

  • from XcodeUserGuide20
+2
source

Source: https://habr.com/ru/post/955966/


All Articles