[binutils-gdb] PR 33726, symbols in excluded sections
Alan Modra
amodra@sourceware.org
Fri Dec 26 01:04:55 GMT 2025
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=4dc7130975cfcbc263f5bad2aa9e35fc3eb10d5c
commit 4dc7130975cfcbc263f5bad2aa9e35fc3eb10d5c
Author: Alan Modra <amodra@gmail.com>
Date: Thu Dec 25 22:17:10 2025 +1030
PR 33726, symbols in excluded sections
This improves "nearby" section choice when memory regions are active,
preferring a section in the same region as the excluded section over
other sections.
PR 33726
include/
* bfdlink.h (struct bfd_link_callbacks): Add nearby_section.
(_bfd_nearby_section): Delete.
(bfd_fix_excluded_sec_syms): Rename and remove bfd param from
_bfd_fix_excluded_sec_syms.
bfd/
* linker.c (_bfd_nearby_section): Delete.
(fix_syms): Use linker callback.
* elflink.c (elf_link_input_bfd): Likewise.
(_bfd_elf_final_link): Update.
ld/
* ldemul.c (finish_default): Update.
* ldlang.c (lang_output_section_get): Delete.
(ldlang_nearby_section): New function.
* ldlang.h (ldlang_nearby_section): Declare.
(lang_output_section_get): New static inline.
* ldmain.c (link_callbacks): Add ldlang_nearby_section.
Diff:
---
bfd/elflink.c | 6 ++--
bfd/linker.c | 80 ++++-------------------------------------------
include/bfdlink.h | 11 ++++---
ld/ldemul.c | 2 +-
ld/ldlang.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
ld/ldlang.h | 12 +++++--
ld/ldmain.c | 1 +
7 files changed, 112 insertions(+), 93 deletions(-)
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 3f60dba1fef..d3084720382 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -12113,8 +12113,8 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
if (r_symndx == STN_UNDEF)
{
irela->r_addend += osec->vma;
- osec = _bfd_nearby_section (output_bfd, osec,
- osec->vma);
+ osec = flinfo->info->callbacks->nearby_section
+ (output_bfd, osec, osec->vma);
irela->r_addend -= osec->vma;
r_symndx = osec->target_index;
}
@@ -12755,7 +12755,7 @@ _bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
}
}
if (sections_removed)
- _bfd_fix_excluded_sec_syms (abfd, info);
+ bfd_fix_excluded_sec_syms (info);
/* Count up the number of relocations we will output for each output
section, so that we know the sizes of the reloc sections. We
diff --git a/bfd/linker.c b/bfd/linker.c
index 247c259a95e..137184a6c12 100644
--- a/bfd/linker.c
+++ b/bfd/linker.c
@@ -3093,82 +3093,13 @@ _bfd_generic_section_already_linked (bfd *abfd ATTRIBUTE_UNUSED,
return false;
}
-/* Choose a neighbouring section to S in OBFD that will be output, or
- the absolute section if ADDR is out of bounds of the neighbours. */
-
-asection *
-_bfd_nearby_section (bfd *obfd, asection *s, bfd_vma addr)
-{
- asection *next, *prev, *best;
-
- /* Find preceding kept section. */
- for (prev = s->prev; prev != NULL; prev = prev->prev)
- if ((prev->flags & SEC_EXCLUDE) == 0
- && !bfd_section_removed_from_list (obfd, prev))
- break;
-
- /* Find following kept section. Start at prev->next because
- other sections may have been added after S was removed. */
- if (s->prev != NULL)
- next = s->prev->next;
- else
- next = s->owner->sections;
- for (; next != NULL; next = next->next)
- if ((next->flags & SEC_EXCLUDE) == 0
- && !bfd_section_removed_from_list (obfd, next))
- break;
-
- /* Choose better of two sections, based on flags. The idea
- is to choose a section that will be in the same segment
- as S would have been if it was kept. */
- best = next;
- if (prev == NULL)
- {
- if (next == NULL)
- best = bfd_abs_section_ptr;
- }
- else if (next == NULL)
- best = prev;
- else if (((prev->flags ^ next->flags)
- & (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_LOAD)) != 0)
- {
- if (((next->flags ^ s->flags)
- & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0
- /* We prefer to choose a loaded section. Section S
- doesn't have SEC_LOAD set (it being excluded, that
- part of the flag processing didn't happen) so we
- can't compare that flag to those of NEXT and PREV. */
- || ((prev->flags & SEC_LOAD) != 0
- && (next->flags & SEC_LOAD) == 0))
- best = prev;
- }
- else if (((prev->flags ^ next->flags) & SEC_READONLY) != 0)
- {
- if (((next->flags ^ s->flags) & SEC_READONLY) != 0)
- best = prev;
- }
- else if (((prev->flags ^ next->flags) & SEC_CODE) != 0)
- {
- if (((next->flags ^ s->flags) & SEC_CODE) != 0)
- best = prev;
- }
- else
- {
- /* Flags we care about are the same. Prefer the following
- section if that will result in a positive valued sym. */
- if (addr < next->vma)
- best = prev;
- }
-
- return best;
-}
-
/* Convert symbols in excluded output sections to use a kept section. */
static bool
fix_syms (struct bfd_link_hash_entry *h, void *data)
{
- bfd *obfd = (bfd *) data;
+ struct bfd_link_info *info = data;
+ bfd *obfd = info->output_bfd;
if (h->type == bfd_link_hash_defined
|| h->type == bfd_link_hash_defweak)
@@ -3182,7 +3113,8 @@ fix_syms (struct bfd_link_hash_entry *h, void *data)
asection *op;
h->u.def.value += s->output_offset + s->output_section->vma;
- op = _bfd_nearby_section (obfd, s->output_section, h->u.def.value);
+ op = info->callbacks->nearby_section (obfd, s->output_section,
+ h->u.def.value);
h->u.def.value -= op->vma;
h->u.def.section = op;
}
@@ -3192,9 +3124,9 @@ fix_syms (struct bfd_link_hash_entry *h, void *data)
}
void
-_bfd_fix_excluded_sec_syms (bfd *obfd, struct bfd_link_info *info)
+bfd_fix_excluded_sec_syms (struct bfd_link_info *info)
{
- bfd_link_hash_traverse (info->hash, fix_syms, obfd);
+ bfd_link_hash_traverse (info->hash, fix_syms, info);
}
/*
diff --git a/include/bfdlink.h b/include/bfdlink.h
index 00fe0f8c7c8..0bd2132df7c 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -900,6 +900,11 @@ struct bfd_link_callbacks
(struct bfd_link_info *, bfd * abfd,
asection * current_section, asection * previous_section,
bool new_segment);
+ /* Choose a neighbouring section to the given excluded section, or
+ the absolute section if no suitable neighbours are found that
+ will be output. */
+ asection *(*nearby_section)
+ (bfd *, asection *, bfd_vma);
/* This callback provides a chance for callers of the BFD to examine the
ELF (dynamic) string table once it is complete. */
void (*examine_strtab)
@@ -1028,11 +1033,7 @@ extern bool _bfd_handle_already_linked
(struct bfd_section *, struct bfd_section_already_linked *,
struct bfd_link_info *);
-extern struct bfd_section *_bfd_nearby_section
- (bfd *, struct bfd_section *, bfd_vma);
-
-extern void _bfd_fix_excluded_sec_syms
- (bfd *, struct bfd_link_info *);
+extern void bfd_fix_excluded_sec_syms (struct bfd_link_info *);
/* These structures are used to describe version information for the
ELF linker. These structures could be manipulated entirely inside
diff --git a/ld/ldemul.c b/ld/ldemul.c
index 35f91a287ca..b8517a917e1 100644
--- a/ld/ldemul.c
+++ b/ld/ldemul.c
@@ -314,7 +314,7 @@ finish_default (void)
os->data = NULL;
}
if (!bfd_link_relocatable (&link_info))
- _bfd_fix_excluded_sec_syms (link_info.output_bfd, &link_info);
+ bfd_fix_excluded_sec_syms (&link_info);
}
void
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 9963d5eb98f..17fb249ef1a 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -1578,14 +1578,6 @@ lang_memory_default (asection *section)
return lang_memory_region_lookup (DEFAULT_MEMORY_REGION, false);
}
-/* Get the output section statement directly from the userdata. */
-
-lang_output_section_statement_type *
-lang_output_section_get (const asection *output_section)
-{
- return bfd_section_userdata (output_section);
-}
-
/* Find or create an output_section_statement with the given NAME.
If CONSTRAINT is non-zero match one with that constraint, otherwise
match any non-negative constraint. If CREATE is 0 return NULL when
@@ -6983,6 +6975,91 @@ section_for_dot (void)
return bfd_abs_section_ptr;
}
+/* Choose a neighbouring section to S in OBFD that will be output, or
+ the absolute section if no suitable neighbours are found. This is
+ used to give symbols in excluded sections another section. */
+
+asection *
+ldlang_nearby_section (bfd *obfd, asection *s, bfd_vma addr)
+{
+ asection *next, *prev, *best;
+ lang_memory_region_type *region = lang_output_section_get (s)->region;
+ int match;
+
+ /* Try for a neighbour in the same region first. If there are none,
+ then accept sections in other regions. */
+ for (match = 1; match >= 0; --match)
+ {
+ /* Find preceding kept section. */
+ for (prev = s->prev; prev != NULL; prev = prev->prev)
+ if ((prev->flags & SEC_EXCLUDE) == 0
+ && !bfd_section_removed_from_list (obfd, prev)
+ && (lang_output_section_get (prev)->region == region || !match))
+ break;
+
+ /* Find following kept section. Start at prev->next because
+ other sections may have been added after S was removed. */
+ if (s->prev != NULL)
+ next = s->prev->next;
+ else
+ next = s->owner->sections;
+ for (; next != NULL; next = next->next)
+ if ((next->flags & SEC_EXCLUDE) == 0
+ && !bfd_section_removed_from_list (obfd, next)
+ && (lang_output_section_get (next)->region == region || !match))
+ break;
+
+ /* Choose better of two sections, based on flags. The idea
+ is to choose a section that will be in the same segment
+ as S would have been if it was kept. */
+ best = next;
+ if (prev == NULL)
+ ;
+ else if (next == NULL)
+ best = prev;
+ else if (((prev->flags ^ next->flags)
+ & (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_LOAD)) != 0)
+ {
+ if (((next->flags ^ s->flags)
+ & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0
+ /* We prefer to choose a loaded section. Section S
+ doesn't have SEC_LOAD set (it being excluded, that
+ part of the flag processing didn't happen) so we
+ can't compare that flag to those of NEXT and PREV. */
+ || ((prev->flags & SEC_LOAD) != 0
+ && (next->flags & SEC_LOAD) == 0))
+ best = prev;
+ }
+ else if (((prev->flags ^ next->flags) & SEC_READONLY) != 0)
+ {
+ if (((next->flags ^ s->flags) & SEC_READONLY) != 0)
+ best = prev;
+ }
+ else if (((prev->flags ^ next->flags) & SEC_CODE) != 0)
+ {
+ if (((next->flags ^ s->flags) & SEC_CODE) != 0)
+ best = prev;
+ }
+ else
+ {
+ /* Flags we care about are the same. Prefer the following
+ section if that will result in a positive valued sym. */
+ if (addr < next->vma)
+ best = prev;
+ }
+ if (best != NULL)
+ return best;
+ }
+ /* For those targets that implement absolute symbols "properly" in
+ ld and ld.so, ie. their value is not relocated, it is very likely
+ wrong to transform a symbol in a removed section to an absolute
+ symbol. In a PIE or shared library a symbol value in an
+ allocated section ought to be relocated by the base address.
+ However, we will only get here if there are no sections at all,
+ so this should not be a concern except in odd testcases. */
+ return bfd_abs_section_ptr;
+}
+
/* Array of __start/__stop/.startof./.sizeof/ symbols. */
static struct bfd_link_hash_entry **start_stop_syms;
diff --git a/ld/ldlang.h b/ld/ldlang.h
index a9607bef765..ea7654fad2a 100644
--- a/ld/ldlang.h
+++ b/ld/ldlang.h
@@ -607,6 +607,8 @@ extern void lang_do_assignments
(lang_phase_type);
extern asection *section_for_dot
(void);
+extern asection *ldlang_nearby_section
+ (bfd *, asection *, bfd_vma);
#define LANG_FOR_EACH_INPUT_STATEMENT(statement) \
lang_input_statement_type *statement; \
@@ -631,8 +633,6 @@ extern lang_input_statement_type *lang_add_input_file
(const char *, lang_input_file_enum_type, const char *);
extern void lang_add_keepsyms_file
(const char *);
-extern lang_output_section_statement_type *lang_output_section_get
- (const asection *);
extern lang_output_section_statement_type *lang_output_section_statement_lookup
(const char *, int, int);
extern lang_output_section_statement_type *next_matching_output_section_statement
@@ -794,4 +794,12 @@ extern void cmdline_emit_object_only_section (void);
extern void cmdline_check_object_only_section (bfd *, bool);
extern void cmdline_remove_object_only_files (void);
+/* Get the output section statement from section userdata. */
+
+static inline lang_output_section_statement_type *
+lang_output_section_get (const asection *output_section)
+{
+ return bfd_section_userdata (output_section);
+}
+
#endif
diff --git a/ld/ldmain.c b/ld/ldmain.c
index afffdd2e43d..bfd3923024b 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -155,6 +155,7 @@ static struct bfd_link_callbacks link_callbacks =
info_msg,
minfo,
ldlang_override_segment_assignment,
+ ldlang_nearby_section,
ldlang_ctf_acquire_strings,
NULL,
ldlang_ctf_new_dynsym,
More information about the Binutils-cvs
mailing list