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