[PATCH v1 1/5] ld: fix segfault caused by untagged stub sections
Matthieu Longo
matthieu.longo@arm.com
Thu Sep 18 15:06:02 GMT 2025
In the case of non-contiguous memory regions, a far-call stub section
must be assigned to the memory of the section it was originally emitted
for. If the stub section does not fit, the section is marked as dropped,
and removed later. To emit a useful message to the user, however, a stub
section needs to be discernible from sections originating from input
objects.
Previously [1], this distinction was made using the SEC_LINKER_CREATED
flag only the AArch32 backend handler <arch>_add_stub_section. Other
backends that didn't set this flag on their stub sections skipped required
checks in ld/ldlang.c:size_input_section(). On AArch64, this caused the
linker to proceed into code paths that assumed output sections were set,
instead of reporting fatal errors, and ultimately led to a segmentation
fault.
However, the SEC_LINKER_CREATED flag does not solely indicate that a
section was created by the linker. Its original meaning also meant that
the section should not be handled by the generic relocation code. Reusing
this flag to identify stub sections, while it appeared to fix the issue,
introduced unintended side effects. On PowerPC, for instance, it skipped
relocations present in the stubs and interpreted them as absolute
addresses.
This patch proposes a new approach: a new boolean attribute 'veneer' added
to 'asection'. The attribute is set on AArch64 and PowerPC immediately
after the creation of the stub section. Others architectures are left
unchanged, as they do not appear to support non-contiguous memory regions
(no tests were found to verify the fix). Additionally, the diagnostic
message was improved when a stub cannot be placed in the same memory
region as its referencing code.
[1]: abf874a, Add support for non-contiguous memory regions.
---
bfd/bfd-in2.h | 6 ++++++
bfd/libbfd.h | 4 ++--
bfd/section.c | 10 ++++++++--
ld/emultempl/aarch64elf.em | 2 ++
ld/emultempl/armelf.em | 5 +++--
ld/emultempl/ppc64elf.em | 2 ++
ld/ldlang.c | 13 +++++++------
ld/testsuite/ld-arm/non-contiguous-arm4.d | 2 +-
ld/testsuite/ld-powerpc/non-contiguous-powerpc64.d | 2 +-
9 files changed, 32 insertions(+), 14 deletions(-)
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 5e7c6ddf1ee..a4049fa0e98 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -834,6 +834,12 @@ typedef struct bfd_section
const char *linked_to_symbol_name;
} map_head, map_tail;
+ /* Indicate that the section contains branch veneers. This is used when
+ support for non-contiguous memory regions is enabled. The veneers have
+ to be allocated to the same memory region as the code they are refered
+ by, i.e. they cannot be moved to a subsequent memory region. */
+ bool veneer;
+
/* Points to the output section this section is already assigned to,
if any. This is used when support for non-contiguous memory
regions is enabled. */
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index f2485d99078..df9d5c8cc19 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -3694,8 +3694,8 @@ bool _bfd_unrecognized_reloc
/* symbol, */ \
(struct bfd_symbol *) SYM, \
\
- /* map_head, map_tail, already_assigned, type */ \
- { NULL }, { NULL }, NULL, 0 \
+ /* map_head, map_tail, veneer, already_assigned, type */ \
+ { NULL }, { NULL }, false, NULL, 0 \
\
}
diff --git a/bfd/section.c b/bfd/section.c
index 5f0cf6e71cb..33524762e7a 100644
--- a/bfd/section.c
+++ b/bfd/section.c
@@ -560,6 +560,12 @@ CODE_FRAGMENT
. const char *linked_to_symbol_name;
. } map_head, map_tail;
.
+. {* Indicate that the section contains branch veneers. This is used when
+. support for non-contiguous memory regions is enabled. The veneers have
+. to be allocated to the same memory region as the code they are refered
+. by, i.e. they cannot be moved to a subsequent memory region. *}
+. bool veneer;
+.
. {* Points to the output section this section is already assigned to,
. if any. This is used when support for non-contiguous memory
. regions is enabled. *}
@@ -747,8 +753,8 @@ INTERNAL
. {* symbol, *} \
. (struct bfd_symbol *) SYM, \
. \
-. {* map_head, map_tail, already_assigned, type *} \
-. { NULL }, { NULL }, NULL, 0 \
+. {* map_head, map_tail, veneer, already_assigned, type *} \
+. { NULL }, { NULL }, false, NULL, 0 \
. \
. }
.
diff --git a/ld/emultempl/aarch64elf.em b/ld/emultempl/aarch64elf.em
index 91d58d8fe5a..08f5c4c7d58 100644
--- a/ld/emultempl/aarch64elf.em
+++ b/ld/emultempl/aarch64elf.em
@@ -200,6 +200,8 @@ elf${ELFSIZE}_aarch64_add_stub_section (const char *stub_sec_name,
if (stub_sec == NULL)
goto err_ret;
+ stub_sec->veneer = true;
+
/* Long branch stubs contain a 64-bit address, so the section requires
8 byte alignment. */
bfd_set_section_alignment (stub_sec, 3);
diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em
index 6f652c59a3c..d946f096faa 100644
--- a/ld/emultempl/armelf.em
+++ b/ld/emultempl/armelf.em
@@ -237,13 +237,14 @@ elf32_arm_add_stub_section (const char * stub_sec_name,
struct hook_stub_info info;
flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
- | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP
- | SEC_LINKER_CREATED);
+ | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP);
stub_sec = bfd_make_section_anyway_with_flags (stub_file->the_bfd,
stub_sec_name, flags);
if (stub_sec == NULL)
goto err_ret;
+ stub_sec->veneer = true;
+
bfd_set_section_alignment (stub_sec, alignment_power);
os = lang_output_section_get (output_section);
diff --git a/ld/emultempl/ppc64elf.em b/ld/emultempl/ppc64elf.em
index 857cf54ad06..8e3f60cb12a 100644
--- a/ld/emultempl/ppc64elf.em
+++ b/ld/emultempl/ppc64elf.em
@@ -440,6 +440,8 @@ ppc_add_stub_section (const char *stub_sec_name, asection *input_section)
: 5)))
goto err_ret;
+ stub_sec->veneer = true;
+
output_section = input_section->output_section;
os = lang_output_section_get (output_section);
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 3c57bf7541c..bdda599a7a4 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -5637,10 +5637,12 @@ size_input_section
if (dot + TO_ADDR (i->size) > end)
{
- if (i->flags & SEC_LINKER_CREATED)
- fatal (_("%P: Output section `%pA' not large enough for "
- "the linker-created stubs section `%pA'.\n"),
- i->output_section, i);
+ if (i->veneer)
+ fatal (_("%P: Memory region `%s' not large enough for the "
+ "linker-created stubs section `%pA' associated to "
+ "output section `%pA'\n"),
+ output_section_statement->region->name_list.name, i,
+ i->output_section);
if (i->rawsize && i->rawsize != i->size)
fatal (_("%P: Relaxation not supported with "
@@ -8239,8 +8241,7 @@ warn_non_contiguous_discards (void)
continue;
for (asection *s = file->the_bfd->sections; s != NULL; s = s->next)
- if (s->output_section == NULL
- && (s->flags & SEC_LINKER_CREATED) == 0)
+ if (s->output_section == NULL && !s->veneer)
einfo (_("%P: warning: --enable-non-contiguous-regions "
"discards section `%pA' from `%pB'\n"),
s, file->the_bfd);
diff --git a/ld/testsuite/ld-arm/non-contiguous-arm4.d b/ld/testsuite/ld-arm/non-contiguous-arm4.d
index a8e9d66caca..d4c4b284dce 100644
--- a/ld/testsuite/ld-arm/non-contiguous-arm4.d
+++ b/ld/testsuite/ld-arm/non-contiguous-arm4.d
@@ -1,4 +1,4 @@
#name: non-contiguous-arm4
#source: non-contiguous-arm.s
#ld: --enable-non-contiguous-regions -T non-contiguous-arm4.ld
-# error: .*Output section .?\.ramu.? not large enough for the linker-created stubs section .?\.code\.3\.__stub.\.?
+# error: Memory region `RAMU' not large enough for the linker-created stubs section `\.code\.3\.__stub' associated to output section `\.ramu'
diff --git a/ld/testsuite/ld-powerpc/non-contiguous-powerpc64.d b/ld/testsuite/ld-powerpc/non-contiguous-powerpc64.d
index 9f903bbea35..1a7e4c5a23b 100644
--- a/ld/testsuite/ld-powerpc/non-contiguous-powerpc64.d
+++ b/ld/testsuite/ld-powerpc/non-contiguous-powerpc64.d
@@ -2,4 +2,4 @@
#source: non-contiguous-powerpc.s
#as: -a64
#ld: -melf64ppc --enable-non-contiguous-regions -T non-contiguous-powerpc.ld
-#error: .*Could not assign .?\.text\.one\.stub.? to an output section\. Retry without --enable-non-contiguous-regions\.
+#error: Memory region `one' not large enough for the linker-created stubs section `\.text\.one\.stub' associated to output section `one'
--
2.51.0
More information about the Binutils
mailing list