x86: Place functions in .ltext section under -mcmodel=large
Checks
Commit Message
When using -mcmodel=large, code can reside anywhere in the 64-bit
address space. Currently GCC places data into .ldata/.lbss/.lrodata
sections (which receive the SHF_X86_64_LARGE ELF flag), but functions
always go to .text regardless of code model. This means .text does
not get the SHF_X86_64_LARGE flag, which can cause issues with linkers
and post-link tools that need to distinguish large sections.
This discrepancy between GCC and Clang came up while adding
-mcmodel=large support for BOLT (https://github.com/llvm/llvm-project/pull/190685).
The difference is visible at https://godbolt.org/z/rhsddfbKv — Clang
emits .ltext while GCC does not.
This patch adds .ltext support: under -mcmodel=large, functions are
emitted into .ltext (or .ltext.<name> with -ffunction-sections), which
GAS recognizes and marks with SHF_X86_64_LARGE. This matches the
behavior of Clang/LLVM.
Only -mcmodel=large is affected; -mcmodel=medium continues to assume
code fits in the low 2GB and uses .text as before.
gcc/ChangeLog:
* config/i386/i386.cc (ix86_function_section): New function.
Returns .ltext section for CM_LARGE and CM_LARGE_PIC code
models, delegates to default_function_section otherwise.
(x86_64_elf_section_type_flags): Recognize .ltext, .ltext.*,
and .gnu.linkonce.lt.* section names and set SECTION_LARGE.
(x86_64_elf_unique_section): Handle FUNCTION_DECL under large
code model by assigning .ltext.<name> section names.
* config/i386/x86-64.h (TARGET_ASM_FUNCTION_SECTION): Define
to ix86_function_section.
gcc/testsuite/ChangeLog:
* gcc.target/i386/large-text.c: New test.
* gcc.target/i386/large-text-fsections.c: New test.
Signed-off-by: Farid Zakaria <fmzakari@meta.com>
---
gcc/config/i386/i386.cc | 43 +++++++++++++++++++
gcc/config/i386/x86-64.h | 3 ++
.../gcc.target/i386/large-text-fsections.c | 7 +++
gcc/testsuite/gcc.target/i386/large-text.c | 7 +++
4 files changed, 60 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/i386/large-text-fsections.c
create mode 100644 gcc/testsuite/gcc.target/i386/large-text.c
@@ -832,6 +832,26 @@ x86_64_elf_select_section (tree decl, int reloc,
return default_elf_select_section (decl, reloc, align);
}
+/* Return the function section for DECL. In the large code model,
+ use .ltext so that GAS applies SHF_X86_64_LARGE. */
+
+static section * ATTRIBUTE_UNUSED
+ix86_function_section (tree decl, enum node_frequency freq,
+ bool startup, bool exit)
+{
+ if (ix86_cmodel != CM_LARGE && ix86_cmodel != CM_LARGE_PIC)
+ return default_function_section (decl, freq, startup, exit);
+
+ /* If the function already has an explicit section name (from an
+ attribute or -ffunction-sections), let hot_function_section
+ pick it up -- x86_64_elf_unique_section already set it to
+ .ltext.<name>. */
+ if (decl && DECL_SECTION_NAME (decl))
+ return NULL;
+
+ return get_named_section (decl, ".ltext", 0);
+}
+
/* Select a set of attributes for section NAME based on the properties
of DECL and whether or not RELOC indicates that DECL's initializer
might contain runtime relocations. */
@@ -854,6 +874,11 @@ x86_64_elf_section_type_flags (tree decl, const char *name, int reloc)
|| startswith (name, ".gnu.linkonce.lb."))
flags |= SECTION_BSS;
+ if (strcmp (name, ".ltext") == 0
+ || startswith (name, ".ltext.")
+ || startswith (name, ".gnu.linkonce.lt."))
+ flags |= SECTION_LARGE;
+
return flags;
}
@@ -918,6 +943,24 @@ x86_64_elf_unique_section (tree decl, int reloc)
return;
}
}
+
+ /* In the large code model, place functions in .ltext sections. */
+ if ((ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC)
+ && TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ const char *prefix;
+ bool one_only = DECL_COMDAT_GROUP (decl) && !HAVE_COMDAT_GROUP;
+ prefix = one_only ? ".lt" : ".ltext";
+
+ const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+ name = targetm.strip_name_encoding (name);
+ const char *linkonce = one_only ? ".gnu.linkonce" : "";
+ char *string = ACONCAT ((linkonce, prefix, ".", name, NULL));
+
+ set_decl_section_name (decl, string);
+ return;
+ }
+
default_unique_section (decl, reloc);
}
@@ -89,3 +89,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#undef TARGET_SECTION_TYPE_FLAGS
#define TARGET_SECTION_TYPE_FLAGS x86_64_elf_section_type_flags
+
+#undef TARGET_ASM_FUNCTION_SECTION
+#define TARGET_ASM_FUNCTION_SECTION ix86_function_section
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-options "-O2 -mcmodel=large -ffunction-sections" } */
+/* { dg-skip-if "PR90698" "*-*-darwin*" } */
+/* { dg-final { scan-assembler {\.ltext\.foo} } } */
+
+void foo (void) {}
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-options "-O2 -mcmodel=large" } */
+/* { dg-skip-if "PR90698" "*-*-darwin*" } */
+/* { dg-final { scan-assembler {\.ltext} } } */
+
+void foo (void) {}