-
Notifications
You must be signed in to change notification settings - Fork 14.9k
Description
When compiling a simple program with Clang, the .eh_frame section is placed into a writable segment because of the way __EH_FRAME_LIST__
is defined.
GCC, in contrast, places .eh_frame into a read-only segment.
Although GNU_RELRO later makes the mapping read-only, the initial load maps .eh_frame as writable, which increases virtual memory usage and differs from GCC’s behavior.
gcc main.c -o a.out
readelf -l a.out
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x00000000000001c0 0x00000000000001c0 R 0x8
INTERP 0x0000000000000200 0x0000000000000200 0x0000000000000200
0x000000000000001d 0x000000000000001d R 0x1
[Requesting program interpreter: /lib64/ld-linux-aarch64.so.1]
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x00000000000008a0 0x00000000000008a0 R E 0x10000
LOAD 0x0000000000000db8 0x0000000000010db8 0x0000000000010db8
0x0000000000000280 0x0000000000000288 RW 0x10000
DYNAMIC 0x0000000000000dc8 0x0000000000010dc8 0x0000000000010dc8
0x00000000000001f0 0x00000000000001f0 RW 0x8
GNU_EH_FRAME 0x00000000000007ac 0x00000000000007ac 0x00000000000007ac
0x000000000000003c 0x000000000000003c R 0x4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
GNU_RELRO 0x0000000000000db8 0x0000000000010db8 0x0000000000010db8
0x0000000000000248 0x0000000000000248 R 0x1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .hash .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .note.ABI-tag .eh_frame_hdr .eh_frame
03 .init_array .fini_array .dynamic .got .got.plt .data .bss
04 .dynamic
05 .eh_frame_hdr
06
07 .init_array .fini_array .dynamic .got
.eh_frame
stays in a read-only PT_LOAD segment, consistent with unwind data being immutable.
clang main.c -fuse-ld=ld -o a.out
readelf -l a.out
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x00000000000001f8 0x00000000000001f8 R 0x8
INTERP 0x0000000000000238 0x0000000000000238 0x0000000000000238
0x000000000000001d 0x000000000000001d R 0x1
[Requesting program interpreter: /lib64/ld-linux-aarch64.so.1]
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000834 0x0000000000000834 R E 0x10000
LOAD 0x0000000000000cf8 0x0000000000010cf8 0x0000000000010cf8
0x0000000000000350 0x00000000000003a0 RW 0x10000
DYNAMIC 0x0000000000000dc8 0x0000000000010dc8 0x0000000000010dc8
0x00000000000001f0 0x00000000000001f0 RW 0x8
NOTE 0x0000000000000258 0x0000000000000258 0x0000000000000258
0x0000000000000020 0x0000000000000020 R 0x4
GNU_EH_FRAME 0x0000000000000808 0x0000000000000808 0x0000000000000808
0x000000000000002c 0x000000000000002c R 0x4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
GNU_RELRO 0x0000000000000cf8 0x0000000000010cf8 0x0000000000010cf8
0x0000000000000308 0x0000000000000308 R 0x1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .hash .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr
03 .eh_frame .init_array .fini_array .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag
06 .eh_frame_hdr
07
08 .eh_frame .init_array .fini_array .dynamic .got
.eh_frame
is in a read-write PT_LOAD segment (later covered by GNU_RELRO).
which causes .eh_frame pages to be mapped writable at load time.
Virtual memory usage is higher since those writable mappings cannot be immediately reclaimed after RELRO.
Memory-sensitive systems (containers, embedded devices) may see unnecessary overhead.
GCC uses __EH_FRAME_BEGIN__
with const attributes, so .eh_frame is read-only.
Clang defines __EH_FRAME_LIST__
as a writable array inside .eh_frame, which forces .eh_frame into a writable segment.
Possible fixes:
Declare __EH_FRAME_LIST__
as static void * const []
so the symbol is treated as read-only and .eh_frame does not force a RW PT_LOAD.