On x86-64 the exception handling data in .eh_frame and .gcc_except_table
defaults to 4-byte PC-relative (DW_EH_PE_sdata4) or absolute
(DW_EH_PE_udata4) pointer encodings under the small and medium code
models.  These overflow once the text segment is placed more than 2GB
away from the EH data, which currently forces the use of the large code
model and its performance penalties.

Add -mlarge-eh-encoding (and -mno-large-eh-encoding, the default) which
forces the 8-byte DW_EH_PE_sdata8 regardless of code-model.

This mirrors LLVM's -mlarge-eh-encoding [1]. The option only has an
effect for the 64-bit LP64 ABI, where the encodings are 8 bytes wide.

[1] https://github.com/llvm/llvm-project/pull/174508

gcc/ChangeLog:

        * config/i386/i386.opt (mlarge-eh-encoding): New option.
        * config/i386/i386.cc (asm_preferred_eh_data_format): Keep the
        8-byte sdata8/absolute pointer encodings instead of downgrading to
        sdata4/udata4 when -mlarge-eh-encoding is enabled on LP64.
        * doc/invoke.texi (-mlarge-eh-encoding): Document.

gcc/testsuite/ChangeLog:

        * gcc.target/i386/large-eh-encoding-1.c: New test.
        * gcc.target/i386/large-eh-encoding-2.c: New test.

Signed-off-by: Farid Zakaria <[email protected]>
---
On x86-64, the pointers in .eh_frame FDEs and .gcc_except_table LSDAs use
4-byte encodings under the small and medium code models: DW_EH_PE_sdata4
(PC-relative) for -fPIC and DW_EH_PE_udata4 (absolute) otherwise.  These
overflow once the text segment is placed more than 2GB away from the EH
data, which today forces the large code model and its performance cost.

This patch adds -mlarge-eh-encoding, which keeps the 8-byte
DW_EH_PE_sdata8 and absolute pointer encodings in
asm_preferred_eh_data_format instead of downgrading them to sdata4/udata4,
so the medium code model can be used with a >2GB text segment.

This mirrors LLVM's -mlarge-eh-encoding similar functionality [1].

In order to support sdata8 in the FDE and LSDA we must augment three 
key piecesL 

  1. Compiler: emit 8-byte EH encodings 
  2. Runtime: binary-search an sdata8 .eh_frame_hdr instead of falling
     back to a linear scan.  Already posted:
       libgcc: Add sdata8 binary search support to _Unwind_Find_FDE
       https://gcc.gnu.org/pipermail/gcc-patches/2026-March/711435.html
  3. Linker: auto-expand .eh_frame_hdr generation to sdata8 when 32-bit
     offsets would overflow.  

(1) is covered by this patch series.

(2) was alrady posted to the mailing list [2] and is purely
a performance improvement.

(3) The bfd linker should be augmented to support auto-expansion of the
eh_frame_hdr to sdata8 similar to LLVM [3].

[1] https://github.com/llvm/llvm-project/pull/174508
[2] https://gcc.gnu.org/pipermail/gcc-patches/2026-March/711435.html
[3] https://github.com/llvm/llvm-project/pull/179089
---
 gcc/config/i386/i386.cc                             | 14 +++++++++-----
 gcc/config/i386/i386.opt                            |  4 ++++
 gcc/doc/invoke.texi                                 | 12 ++++++++++++
 gcc/testsuite/gcc.target/i386/large-eh-encoding-1.c | 18 ++++++++++++++++++
 gcc/testsuite/gcc.target/i386/large-eh-encoding-2.c | 11 +++++++++++
 5 files changed, 54 insertions(+), 5 deletions(-)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index b137f5c22dc..c898d71522c 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -25826,19 +25826,23 @@ ix86_stack_protect_fail (void)
 int
 asm_preferred_eh_data_format (int code, int global)
 {
+  bool large_eh = ix86_large_eh_encoding && ptr_mode == DImode;
+
   /* PE-COFF is effectively always -fPIC because of the .reloc section.  */
   if (flag_pic || TARGET_PECOFF || !ix86_direct_extern_access)
     {
       int type = DW_EH_PE_sdata8;
-      if (ptr_mode == SImode
-         || ix86_cmodel == CM_SMALL_PIC
-         || (ix86_cmodel == CM_MEDIUM_PIC && (global || code)))
+      if (!large_eh
+         && (ptr_mode == SImode
+             || ix86_cmodel == CM_SMALL_PIC
+             || (ix86_cmodel == CM_MEDIUM_PIC && (global || code))))
        type = DW_EH_PE_sdata4;
       return (global ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | type;
     }
 
-  if (ix86_cmodel == CM_SMALL
-      || (ix86_cmodel == CM_MEDIUM && code))
+  if (!large_eh
+      && (ix86_cmodel == CM_SMALL
+         || (ix86_cmodel == CM_MEDIUM && code)))
     return DW_EH_PE_udata4;
 
   return DW_EH_PE_absptr;
diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
index 158090c2bde..456c8f2ff20 100644
--- a/gcc/config/i386/i386.opt
+++ b/gcc/config/i386/i386.opt
@@ -1213,6 +1213,10 @@ mdirect-extern-access
 Target Var(ix86_direct_extern_access) Init(1)
 Do not use GOT to access external symbols.
 
+mlarge-eh-encoding
+Target Var(ix86_large_eh_encoding) Init(0)
+Use 8-byte pointer encodings for exception handling data so that the medium 
code model can be used with a text segment larger than 2GB.
+
 -param=x86-stlf-window-ninsns=
 Target Joined UInteger Var(x86_stlf_window_ninsns) Init(64) Param
 Instructions number above which STFL stall penalty can be compensated.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 78052b229a5..5137bf932f1 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -27986,6 +27986,18 @@ kernels, executables linked with @option{-static} or 
@option{-static-pie}.
 @option{-mdirect-extern-access} is not compatible with @option{-fPIC} or
 @option{-fpic}.
 
+@opindex mlarge-eh-encoding
+@opindex mno-large-eh-encoding
+@item -mlarge-eh-encoding
+@itemx -mno-large-eh-encoding
+Use (do not use) 8-byte pointer encodings for exception handling data.
+The default is @option{-mno-large-eh-encoding}.
+
+@option{-mlarge-eh-encoding} forces the 8-byte @code{sdata8}
+(PC-relative) and absolute pointer encodings for the @code{.eh_frame} and
+@code{.gcc_except_table} exception handling sections.  This option has no
+effect for 32-bit or x32 targets.
+
 @opindex mrelax
 @opindex mno-relax
 @item -mrelax
diff --git a/gcc/testsuite/gcc.target/i386/large-eh-encoding-1.c 
b/gcc/testsuite/gcc.target/i386/large-eh-encoding-1.c
new file mode 100644
index 00000000000..c515ddff5b1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/large-eh-encoding-1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile { target lp64 } } */
+/* { dg-require-effective-target fpic } */
+/* { dg-options "-O2 -fPIC -mcmodel=small -mlarge-eh-encoding -fexceptions 
-fno-dwarf2-cfi-asm -dA" } */
+
+extern void may_throw (void);
+extern void cl (void *);
+
+void
+foo (void)
+{
+  char *p __attribute__((cleanup (cl))) = 0;
+  may_throw ();
+  (void) p;
+}
+
+/* { dg-final { scan-assembler "FDE Encoding \\(pcrel sdata8\\)" } } */
+/* { dg-final { scan-assembler "Personality \\(indirect pcrel sdata8\\)" } } */
+/* { dg-final { scan-assembler-not "sdata4" } } */
diff --git a/gcc/testsuite/gcc.target/i386/large-eh-encoding-2.c 
b/gcc/testsuite/gcc.target/i386/large-eh-encoding-2.c
new file mode 100644
index 00000000000..aa726363e55
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/large-eh-encoding-2.c
@@ -0,0 +1,11 @@
+/* { dg-do compile { target lp64 } } */
+/* { dg-options "-O2 -fno-pic -mcmodel=small -mlarge-eh-encoding 
-fno-dwarf2-cfi-asm -dA" } */
+
+int
+foo (int x)
+{
+  return x + 1;
+}
+
+/* { dg-final { scan-assembler {\.quad[^\n]*FDE initial location} } } */
+/* { dg-final { scan-assembler-not "FDE Encoding \\(udata4\\)" } } */

---
base-commit: 9022362282b915165296ae3abc77eb12e5d964a0
change-id: 20260714-i386-large-eh-encoding-05de0caaa9ab

Best regards,
-- 
Farid Zakaria <[email protected]>

Reply via email to