67

Test is on 32 bit x86 Linux with gcc 4.6.3

When using gcc to compile a C program and using readelf to check the section info, I can see the .eh_frame section and .eh_frame_hdr sections inside.

For example, here is the section info of binary program Perlbench.

readelf -S perlbench

There are 28 section headers, starting at offset 0x102e48:

Section Headers:
[Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
[ 0]                   NULL            00000000 000000 000000 00      0   0  0
[ 1] .interp           PROGBITS        08048154 000154 000013 00   A  0   0  1
[ 2] .note.ABI-tag     NOTE            08048168 000168 000020 00   A  0   0  4
[ 3] .note.gnu.build-i NOTE            08048188 000188 000024 00   A  0   0  4
[ 4] .gnu.hash         GNU_HASH        080481ac 0001ac 000044 04   A  5   0  4
[ 5] .dynsym           DYNSYM          080481f0 0001f0 0007b0 10   A  6   1  4
[ 6] .dynstr           STRTAB          080489a0 0009a0 0003d6 00   A  0   0  1
[ 7] .gnu.version      VERSYM          08048d76 000d76 0000f6 02   A  5   0  2
[ 8] .gnu.version_r    VERNEED         08048e6c 000e6c 0000a0 00   A  6   2  4
[ 9] .rel.dyn          REL             08048f0c 000f0c 000028 08   A  5   0  4
[10] .rel.plt          REL             08048f34 000f34 000388 08   A  5  12  4
[11] .init             PROGBITS        080492bc 0012bc 00002e 00  AX  0   0  4
[12] .plt              PROGBITS        080492f0 0012f0 000720 04  AX  0   0 16
[13] .text             PROGBITS        08049a10 001a10 0cf86c 00  AX  0   0 16
[14] .fini             PROGBITS        0811927c 0d127c 00001a 00  AX  0   0  4
[15] .rodata           PROGBITS        081192a0 0d12a0 017960 00   A  0   0 32
[16] .eh_frame_hdr     PROGBITS        08130c00 0e8c00 003604 00   A  0   0  4
[17] .eh_frame         PROGBITS        08134204 0ec204 01377c 00   A  0   0  4
[18] .ctors            PROGBITS        08148f0c 0fff0c 000008 00  WA  0   0  4
[19] .dtors            PROGBITS        08148f14 0fff14 000008 00  WA  0   0  4
[20] .jcr              PROGBITS        08148f1c 0fff1c 000004 00  WA  0   0  4
[21] .dynamic          DYNAMIC         08148f20 0fff20 0000d0 08  WA  6   0  4
[22] .got              PROGBITS        08148ff0 0ffff0 000004 04  WA  0   0  4
[23] .got.plt          PROGBITS        08148ff4 0ffff4 0001d0 04  WA  0   0  4
[24] .data             PROGBITS        081491e0 1001e0 002b50 00  WA  0   0 32
[25] .bss              NOBITS          0814bd40 102d30 002b60 00  WA  0   0 32
[26] .comment          PROGBITS        00000000 102d30 00002a 01  MS  0   0  1
[27] .shstrtab         STRTAB          00000000 102d5a 0000ec 00      0   0  1

In my understanding, these two sections are used for handling exceptions, it produce tables that describe how to unwind the stack.

But it is for C++ program, they use eh_frame and gcc_exception_table sections to manage exceptions, then why does compiler put the eh_frame and eh_frame_hdr sections inside ELF compiled from C program?

lllllllllllll
  • 8,519
  • 9
  • 45
  • 80
  • 8
    x86-64 ABI mandates `.eh frames` everywhere exact. This was added to allow unwinding of stack everywhere as this is needed system wide in some occasions, like in profiling tools. GCC thus on x86_64 defaults to EH frame generation and attempts to make it everywhere exact, while on most of other ABIs it defaults to EH frame generation only when EH frame is needed and it is precise only at the points of program that might trigger EH and thus unwinding. – askmish Oct 10 '14 at 14:13
  • I suspect `gcc` also uses them to implement `__attribute__((cleanup(..)))`. – gsg Oct 10 '14 at 14:57
  • possible duplicate of [What's the use of the .eh\_frame section in C programs?](http://stackoverflow.com/questions/21351099/whats-the-use-of-the-eh-frame-section-in-c-programs) – Ciro Santilli OurBigBook.com Jun 25 '15 at 14:00
  • "reference in that question?" I don't understand what you mean. Do you mean the comments? Why are the questions different? I may be wrong. Closing the other way around is another possibility: this is slightly better posed, so but the other is older, tough choice. About username, leave discussion for meta or twitter. Cheers. – Ciro Santilli OurBigBook.com Jun 25 '15 at 15:57

1 Answers1

83

First of all, the original reason for this was largely political - the people who added DWARF-based unwinding (.eh_frame) wanted it to be a feature that's always there so it could be used for implementing all kinds of stuff other than just C++ exceptions, including:

  • backtrace()
  • __attribute__((__cleanup__(f)))
  • __builtin_return_address(n), for n>0
  • pthread_cleanup_push, implemented in terms of __attribute__((__cleanup__(f)))
  • ...

However if you don't need any of these things, .eh_frame is something like a 15-30% increase to .text size with no benefit. You can disable generation of .eh_frame with -fno-asynchronous-unwind-tables for individual translation units, and this mostly eliminates the size cost, although you still have a few left over coming from crtbegin.o, etc. You cannot strip them with the strip command later; since .eh_frame is a section that lives in the loaded part of the program (this is the whole point), stripping it modifies the binary in ways that break it at runtime. See https://sourceware.org/bugzilla/show_bug.cgi?id=14037 for an example of how things can break.

Note that DWARF tables are also used for debugging, but for this purpose they do not need to be in the loadable part of the program. Using -fno-asynchronous-unwind-tables will not break debugging, because as long as -g is also passed to the compiler, the tables still get generated; they just get stored in a separate, non-loadable, strippable section of the binary, .debug_frame.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • 2
    A small correction: `crtbegin.o` contains no CFI, at least on RedHat and Ubuntu. The leftovers would most likely come from the CFI for `__libc_csu_init` and `__libc_csu_fini`. Those are not in `crtbegin.o` but rather in the non-shared part of GLIBC `libc_nonshared.a` – Hristo Iliev Oct 10 '14 at 15:37
  • @HristoIliev: I've experienced getting `.eh_frame` in the output when not using glibc, so there must be some coming from somewhere else too. I thought it was `crtbegin.o` but I may be wrong. – R.. GitHub STOP HELPING ICE Oct 10 '14 at 18:33
  • What do you mean by ``You *cannot* strip them with the `strip` command?'' I think it can be stripped without risk (and the executable will become smaller) if none of the features above are used in the executable. Am I right? – pts Nov 10 '14 at 17:32
  • @pts: No. The strip command does not support stripping loadable sections. Attempting to do so produces a corrupt binary. See the bug I linked to in the answer. – R.. GitHub STOP HELPING ICE Nov 11 '14 at 03:22
  • Unfortunately if you compile with -ffunction-sections then link with -gc-sections, then it appears that eh_frame section is full of relocations for functions that are being dropped from the binary and the link fails. If anybody knows much about this stuff, please take a look at my question: http://stackoverflow.com/questions/28356552/how-do-i-link-objects-discarding-unused-functions-without-breaking-eh-frame# – codeshot Feb 14 '15 at 16:31
  • 2
    Hi, I am wondering if the usage of `eh_frame` is a GCC specified feature? I tried to use `clang` and `gcc` to compile a piece of C code. The `eh_frame` section generated by GCC is around `0x5cfc` while it is only `a4` for `clang`. – lllllllllllll Jun 03 '15 at 19:28
  • 1
    Worth mentioning that exception unwinding can need to traverse the stack frames of C functions. E.g. if a C library take a function pointer to a callback function, or anything like that, it can end up calling a C++ function again. BTW, `-fno-omit-frame-pointer` can shrink the eh_frame size significantly, and gcc devs have considered trying to have gcc use rbp as a frame pointer in functions where it won't be a slowdown. – Peter Cordes Sep 13 '16 at 23:54
  • 2
    @PeterCordes: That's UB, and even if it weren't it would be breaking the contract of the C library almost certainly - most C library code using callbacks assumes the callbacks return rather than `longjmp`, and propagating an exception out would be equivalent to `longjmp`. If C++ code using exceptions is called as a callback from C, the callback needs to catch all exceptions and translate them into error returns to the C caller. – R.. GitHub STOP HELPING ICE Sep 14 '16 at 01:50
  • 1
    hrm, ok that makes sense. I had thought that was why even C code always ended up with eh_frame data, and why it wasn't removed by strip. But if it's not for C++ exceptions propagating through C, then your "largely political" assessment makes sense. However, even if it's part of the text segment and is mapped, that doesn't mean it's actually loaded from disk. Wouldn't it mostly just waste space on disk (and network bandwidth for distribution and backups, and CPU time checksumming), without having much effect on the run-time of a cold executable? It can't be in the same page as the data seg. – Peter Cordes Sep 14 '16 at 03:05
  • 4
    @PeterCordes: Well "C++ exceptions *should* be able to propagate through C even though it's undefined behavior" **is** a political position (and IMO an indefensible one for the reasons I described above -- even if it were defined it could only be used for very pure C functions with no need to cleanup on errors). – R.. GitHub STOP HELPING ICE Sep 14 '16 at 14:31
  • 1
    @PeterCordes: Re: text segment and actual vs virtual memory usage, you're right that, on systems with an mmu, just because the text is mapped does not mean it has to be loaded. In that case all that's wasted is storage (which can still be annoying in that your Docker image is 30% larger to upload, but it's less bad). However on systems without mmu the entire mapped text has to be in-ram. And even on 32-bit systems with mmu, virtual address space is a fairly precious resource; filling it up with junk you don't need means `malloc` will fail sooner. – R.. GitHub STOP HELPING ICE Sep 14 '16 at 14:35
  • Hi Rich, maybe you want to answer this :-) https://stackoverflow.com/questions/60817268/how-to-prevent-relocation-truncated-to-fit-r-aarch64-prel32-against-text-w :-) – Ciro Santilli OurBigBook.com Mar 23 '20 at 20:09