<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/155764>155764</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
.eh_frame mapped writable in Clang builds (due to __EH_FRAME_LIST__), unlike GCC
</td>
</tr>
<tr>
<th>Labels</th>
<td>
compiler-rt
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
dongjianqiang2
</td>
</tr>
</table>
<pre>
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__](https://github.com/gcc-mirror/gcc/blob/master/libgcc/crtstuff.c#L263) with const attributes, so .eh_frame is read-only.
Clang defines [__EH_FRAME_LIST__](https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/crtbegin.c#L22) 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.
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzsWN9v4zYS_mvkl4EFmZId5cEPjvNjg9vNBk6uxT0ZFDmS2FKkS1LO-v76AyXZViyn9Ra3dyhQIVhJn-iZb8gh59uh1opCIc6D6U0wvR3R2pXazLlWxS-Cqt8EVQUZZZrv5j-XqIDpaiOkUAVQsKLaSISN0YWhFbwJV8JSUlUEZAmuRAixXOeGVggWmRNagbCwkZQhB6GcBgpvRjiaST-iqFA5yJDR2iLovDHxRnewXt99Wt-vFl_u1p8fX17Xa2-GYy4U8jCIFg_LpfcoPDvlDLXOvzZ-bI9D59Eg5WOt5G7v0psIosVCulLXRQkPT_9cr-4-r76CpA4NVPRXtA2Zim42PvSDiX2gQgknqASpKfej-m6pPQTph7-VgpUgFDNILVrYCuNqKqHCSpsd1JYWCFRx4CLP0VjIja7Ah3hHgjQKrq8tZFjSrdCmY14wBhUVKmQw1kBDXbsgWniSKHMYywPk_2ZR9xctnruF--RHGhvEfgDA626DcLy-5rlFB_3rJ2HcgnPTg57LnfVQY-HkuhcSX8S_-9AXrE4QgHtJCwuwkKJQjZnnT7er3vfoW_TuSqLLoHOUTkZN2OCHHoLVfnTaGHl8er1bPX9khEQDI-ehCwhFE34OOhKaHIwE05sV_lajdT4195tRKIdmY9ChCeIFBOReimyW-DsfS6Hqb2NKDStnSWh1OAmmt43Bz18Xt7_DahjOeeiCCFM6-KGHYAV3XYQHQ79Pimfpe2jyAXQBKZIO1ytNAVY_wymp2389Lb48Lj8ixYYMzkKXJGc-TM486pFqjfhja39ODo1cUXYZdElyxoMfeuiYnMmB0MvrYvmPH55LH9jqL9uBUXuy__BEStJz0Pv96-28dIXRaXjpKmBXZfbH8R7uRtowDFsC-6mJJo3NsN3yHUb6GIQltSWEhaq7J75Tdle1d2faL1s01lPpv6wNhAYl9QO7p4103q5w0D46_OYgzIUSEBrNqaMQKu0wXNw8jh0tjqVwXXJzfOuIxnuiwq2pMXTX2to_852ilWAQFto1_7ROWzeZtZ2VpLXSje7AaQv23XdfZt396nLnJ7WzfT0GM4vAOrqzXoX0Ncbz67o5vjqt4RUA08oK6_yaNpKpVm_C13sfUob-EBdVVTeCoSvwzIuqQ4nPa4tjyYP4VvK_C_6fLPj5YH966DsLfjzc5Gehvwu-r-5xcg76_oLPTtdu8gF0Aal4OogmptFfo-A_fX29-9gImQ4z8Sx0SXKS4ZqT6GzB_1iBpNHA-3noIkJDBUL--grkv5rZw7n10P9NgbyXBP9jPXJGAnS64_Df9B-pQPqx7xXIe_c9YlfdPf0zBP9YpYi-RHkzwuGpRoGApG3ng-ktGuSQ7Y6JG5DrTpW0nYymW9Pvd2xogdZnU9Y2TJAfmzzUtS0SJ6pG2_x0rvkhLJSiKNGAFYohuFJbPNroktMCo0pp592IqkIuqEO5A4NMUlEhB5r7GBrS3teXxsfYorLCiS2C3VmHlfXhMq0cFcprIrIErDLkHDlw3AqGNiDXUNEdWESolUKG1lKzAz87JVLezcfDcgl-LoLpTb9ldXP38Pi0XvuCS9LSuU2ju8h9QO4L4co6C5mu_Atj40oYo037EpD7TOosIPcVtb6qNxW9_cCMs67O85AFJP5MZrGn2IhJLy4dUOeMyGqHTTxW97tg9qhOQwiiRdOx69pp1ouLQbvtD6lLud3fxhujf0Hm-uyF8pSbxiGasXFtJH5ELaQTyrYRZVh4gdtERHxA1PYbhG22C2UF73UWjy21XJuz_b7TDmO3Ws_aWuHhXHzDTgrf-twxeKbhSK2X904w2GrBISCLbqbbtqmfYlf6lKoyLf0cO4PU-STsTXfT1jvy4xot-AxumAP1xaLbiuGIz2N-HV_TEc4nV9NZPIuTq3RUznM2IROS5ClGZJbnLEuuphOaJDSPojSJJyMxJxGZRilJo1mSxGmI18mEZemMRZikPKdBEmFFhQz9coXaFCNhbY3zyXR6NUtGkmYobdMOJuTdopFgejsy82aVs7qwQRJJYZ09GnLCSZwfIzzd_kK1_WHwC8-bncdr9GfFMOfItV_aWknxK8LDcjmqjZx_dw42ofn86qLbzsl_AgAA__-FjT-P">