mirror of
https://github.com/bminor/binutils-gdb.git
synced 2026-02-06 20:51:29 +00:00
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:
@@ -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
|
||||
|
||||
80
bfd/linker.c
80
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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
93
ld/ldlang.c
93
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;
|
||||
|
||||
12
ld/ldlang.h
12
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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user