ld: Don't define section symbols for excluded sections
Checks
Commit Message
When the SEC_EXCLUDE bit is set on a section, the contents of the section
are excluded by the linker for non-relocatable output. Define __start,
__stop, .startof. and .sizeof. symbols for relocatable link or if the
SEC_EXCLUDE bit on the section is cleared.
PR ld/34448
* ldlang.c (lang_init_start_stop): Call lang_define_start_stop
for relocatable link or if the SEC_EXCLUDE bit on the section
is cleared.
Comments
On Thu, Jul 30, 2026 at 03:17:45PM +0800, H.J. Lu wrote:
> When the SEC_EXCLUDE bit is set on a section, the contents of the section
> are excluded by the linker for non-relocatable output. Define __start,
> __stop, .startof. and .sizeof. symbols for relocatable link or if the
> SEC_EXCLUDE bit on the section is cleared.
Looks good to me. You might like to mention the ELF SHF_EXCLUDE flag
in the description too, since it was that flag being set that
triggered the segfault in bug_4.o from the pr. bug_4.o didn't even
need --gc-sections to fail.
> PR ld/34448
> * ldlang.c (lang_init_start_stop): Call lang_define_start_stop
> for relocatable link or if the SEC_EXCLUDE bit on the section
> is cleared.
>
> Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
> ---
> ld/ldlang.c | 39 +++++++++++++++++++++------------------
> 1 file changed, 21 insertions(+), 18 deletions(-)
>
> diff --git a/ld/ldlang.c b/ld/ldlang.c
> index 354fa635ba8..7dc331c04cd 100644
> --- a/ld/ldlang.c
> +++ b/ld/ldlang.c
> @@ -7283,28 +7283,31 @@ lang_init_start_stop (void)
>
> for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link.next)
> for (s = abfd->sections; s != NULL; s = s->next)
> - {
> - const char *ps;
> - const char *secname = s->name;
> + if (bfd_link_relocatable (&link_info)
> + || (s->flags & SEC_EXCLUDE) == 0)
> + {
> + const char *ps;
> + const char *secname = s->name;
>
> - for (ps = secname; *ps != '\0'; ps++)
> - if (!ISALNUM ((unsigned char) *ps) && *ps != '_')
> - break;
> - if (*ps == '\0')
> - {
> - char *symbol = (char *) xmalloc (10 + strlen (secname));
> + for (ps = secname; *ps != '\0'; ps++)
> + if (!ISALNUM ((unsigned char) *ps) && *ps != '_')
> + break;
> + if (*ps == '\0')
> + {
> + char *symbol = (char *) xmalloc (10 + strlen (secname));
>
> - symbol[0] = leading_char;
> - sprintf (symbol + (leading_char != 0), "__start_%s", secname);
> - lang_define_start_stop (symbol, s);
> + symbol[0] = leading_char;
> + sprintf (symbol + (leading_char != 0), "__start_%s",
> + secname);
> + lang_define_start_stop (symbol, s);
>
> - symbol[1] = leading_char;
> - memcpy (symbol + 1 + (leading_char != 0), "__stop", 6);
> - lang_define_start_stop (symbol + 1, s);
> + symbol[1] = leading_char;
> + memcpy (symbol + 1 + (leading_char != 0), "__stop", 6);
> + lang_define_start_stop (symbol + 1, s);
>
> - free (symbol);
> - }
> - }
> + free (symbol);
> + }
> + }
> }
>
> /* Iterate over start_stop_syms. */
> --
> 2.55.0
>
On Thu, Jul 30, 2026 at 6:34 PM Alan Modra <amodra@gmail.com> wrote:
>
> On Thu, Jul 30, 2026 at 03:17:45PM +0800, H.J. Lu wrote:
> > When the SEC_EXCLUDE bit is set on a section, the contents of the section
> > are excluded by the linker for non-relocatable output. Define __start,
> > __stop, .startof. and .sizeof. symbols for relocatable link or if the
> > SEC_EXCLUDE bit on the section is cleared.
>
> Looks good to me. You might like to mention the ELF SHF_EXCLUDE flag
> in the description too, since it was that flag being set that
> triggered the segfault in bug_4.o from the pr. bug_4.o didn't even
> need --gc-sections to fail.
I am checking it in with the updated commit message:
When the SEC_EXCLUDE bit is set on a section, for example, sections with
the SHF_EXCLUDE flag bit set in ELF input, the contents of the section
are excluded by the linker for non-relocatable output. Define __start,
__stop, .startof. and .sizeof. symbols for relocatable link or if the
SEC_EXCLUDE bit on the section is cleared.
> > PR ld/34448
> > * ldlang.c (lang_init_start_stop): Call lang_define_start_stop
> > for relocatable link or if the SEC_EXCLUDE bit on the section
> > is cleared.
> >
>
On 30.07.2026 09:17, H.J. Lu wrote:
> When the SEC_EXCLUDE bit is set on a section, the contents of the section
> are excluded by the linker for non-relocatable output. Define __start,
> __stop, .startof. and .sizeof. symbols for relocatable link or if the
> SEC_EXCLUDE bit on the section is cleared.
>
> PR ld/34448
> * ldlang.c (lang_init_start_stop): Call lang_define_start_stop
> for relocatable link or if the SEC_EXCLUDE bit on the section
> is cleared.
Feels like there is "only" missing in the sentences, to properly describe
what the change actually does (introduce an extra constraint rather than
provide those symbols anew).
For changes like this I would also wish that they were done with less
churn, and without needlessly increasing indentation depth:
for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link.next)
for (s = abfd->sections; s != NULL; s = s->next)
{
const char *ps;
const char *secname = s->name;
if (!bfd_link_relocatable (&link_info)
&& (s->flags & SEC_EXCLUDE) != 0)
continue;
...
Jan
From e939d1e0426535a864c75e56e93f1301d38f4341 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Thu, 30 Jul 2026 15:10:36 +0800
Subject: [PATCH] ld: Don't define section symbols for excluded sections
When the SEC_EXCLUDE bit is set on a section, the contents of the section
are excluded by the linker for non-relocatable output. Define __start,
__stop, .startof. and .sizeof. symbols for relocatable link or if the
SEC_EXCLUDE bit on the section is cleared.
PR ld/34448
* ldlang.c (lang_init_start_stop): Call lang_define_start_stop
for relocatable link or if the SEC_EXCLUDE bit on the section
is cleared.
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
ld/ldlang.c | 39 +++++++++++++++++++++------------------
1 file changed, 21 insertions(+), 18 deletions(-)
@@ -7283,28 +7283,31 @@ lang_init_start_stop (void)
for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link.next)
for (s = abfd->sections; s != NULL; s = s->next)
- {
- const char *ps;
- const char *secname = s->name;
+ if (bfd_link_relocatable (&link_info)
+ || (s->flags & SEC_EXCLUDE) == 0)
+ {
+ const char *ps;
+ const char *secname = s->name;
- for (ps = secname; *ps != '\0'; ps++)
- if (!ISALNUM ((unsigned char) *ps) && *ps != '_')
- break;
- if (*ps == '\0')
- {
- char *symbol = (char *) xmalloc (10 + strlen (secname));
+ for (ps = secname; *ps != '\0'; ps++)
+ if (!ISALNUM ((unsigned char) *ps) && *ps != '_')
+ break;
+ if (*ps == '\0')
+ {
+ char *symbol = (char *) xmalloc (10 + strlen (secname));
- symbol[0] = leading_char;
- sprintf (symbol + (leading_char != 0), "__start_%s", secname);
- lang_define_start_stop (symbol, s);
+ symbol[0] = leading_char;
+ sprintf (symbol + (leading_char != 0), "__start_%s",
+ secname);
+ lang_define_start_stop (symbol, s);
- symbol[1] = leading_char;
- memcpy (symbol + 1 + (leading_char != 0), "__stop", 6);
- lang_define_start_stop (symbol + 1, s);
+ symbol[1] = leading_char;
+ memcpy (symbol + 1 + (leading_char != 0), "__stop", 6);
+ lang_define_start_stop (symbol + 1, s);
- free (symbol);
- }
- }
+ free (symbol);
+ }
+ }
}
/* Iterate over start_stop_syms. */
--
2.55.0