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.
This commit is contained in:
Alan Modra
2025-12-25 22:17:10 +10:30
parent 2254b6eb07
commit 4dc7130975
7 changed files with 112 additions and 93 deletions

View File

@@ -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

View File

@@ -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);
}
/*