<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">