[PATCH v1 1/5] ld: fix segfault caused by untagged stub sections

Matthieu Longo matthieu.longo@arm.com
Mon Oct 13 15:22:29 GMT 2025


On 2025-09-26 14:13, Jan Beulich wrote:
> On 18.09.2025 17:06, Matthieu Longo wrote:
>> 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(-)
> 
> I'm okay with the approach, yet there is a largely mechanical issue:
> 
>> --- 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;
> 
> Why would you put a bool between two pointer-sized fields, thus introducing
> yet more padding, when in fact existing padding could be used. There's a set
> of bitfields further up from here, and you could simply add a single-bit
> field there, for example. Generic code changes are okay with that change,
> but arch-specific ones will need arch maintainer approval.
> 
> Jan

Hi Jan,

Sorry for the silence, I was on annual leave for about 3 weeks.

Here is the new attribute as a flag:

diff --git a/bfd/section.c b/bfd/section.c
index 5f0cf6e71cb..f110ed77363 100644
--- a/bfd/section.c
+++ b/bfd/section.c
@@ -379,6 +379,12 @@ CODE_FRAGMENT
  .     when memory read flag isn't set. *}
  .#define SEC_COFF_NOREAD            0x40000000
  .
+.  {* 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.  *}
+.#define SEC_VENEER                 0x80000000
+.
  .  {*  End of section flags.  *}
  .
  .  {* Some internal packed boolean fields.  *}


With the tagging of the stub section on AArch64:

diff --git a/ld/emultempl/aarch64elf.em b/ld/emultempl/aarch64elf.em
index 91d58d8fe5a..b00c9460da2 100644
--- a/ld/emultempl/aarch64elf.em
+++ b/ld/emultempl/aarch64elf.em
@@ -193,7 +193,7 @@ elf${ELFSIZE}_aarch64_add_stub_section (const char 
*stub_sec_name,
    lang_output_section_statement_type *os;
    struct hook_stub_info info;

-  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_VENEER
            | 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);

Same thing on AArch32 and PowerPC.

Is this what you suggested ?

Matthieu


More information about the Binutils mailing list