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;
}
}
}
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
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)
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;
}
}
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);
}
/*
(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)
(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
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
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
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;
(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; \
(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
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
info_msg,
minfo,
ldlang_override_segment_assignment,
+ ldlang_nearby_section,
ldlang_ctf_acquire_strings,
NULL,
ldlang_ctf_new_dynsym,