/* This section symbol should be included in the symbol table. */
#define BSF_SECTION_SYM_USED (1 << 24)
+ /* This symbol underwent section merge resolution. */
+#define BSF_MERGE_RESOLVED (1 << 25)
+
flagword flags;
/* A pointer to the section to which this symbol is
unsigned int);
extern bool _bfd_elf_slurp_version_tables
(bfd *, bool);
-extern bool _bfd_elf_merge_sections
- (bfd *, struct bfd_link_info *);
extern bool _bfd_elf_match_sections_by_type
(bfd *, const asection *, bfd *, const asection *);
extern bool bfd_elf_is_group_section
return true;
}
\f
-/* Make sure sec_info_type is cleared if sec_info is cleared too. */
-
-static void
-merge_sections_remove_hook (bfd *abfd ATTRIBUTE_UNUSED,
- asection *sec)
-{
- BFD_ASSERT (sec->sec_info_type == SEC_INFO_TYPE_MERGE);
- sec->sec_info_type = SEC_INFO_TYPE_NONE;
-}
-
-/* Finish SHF_MERGE section merging. */
-
-bool
-_bfd_elf_merge_sections (bfd *obfd, struct bfd_link_info *info)
-{
- bfd *ibfd;
- asection *sec;
-
- if (ENABLE_CHECKING && !is_elf_hash_table (info->hash))
- abort ();
-
- for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
- if ((ibfd->flags & DYNAMIC) == 0
- && bfd_get_flavour (ibfd) == bfd_target_elf_flavour
- && (elf_elfheader (ibfd)->e_ident[EI_CLASS]
- == get_elf_backend_data (obfd)->s->elfclass))
- for (sec = ibfd->sections; sec != NULL; sec = sec->next)
- if ((sec->flags & SEC_MERGE) != 0
- && !bfd_is_abs_section (sec->output_section)
- && !_bfd_add_merge_section (obfd,
- &info->hash->merge_info,
- sec))
- return false;
-
- if (info->hash->merge_info != NULL)
- return _bfd_merge_sections (obfd, info, info->hash->merge_info,
- merge_sections_remove_hook);
- return true;
-}
-
/* Create an entry in an ELF linker hash table. */
struct bfd_hash_entry *
#define bfd_elfNN_bfd_final_link bfd_elf_final_link
#endif
#ifndef bfd_elfNN_bfd_merge_sections
-#define bfd_elfNN_bfd_merge_sections _bfd_elf_merge_sections
+#define bfd_elfNN_bfd_merge_sections _bfd_merge_sections
#endif
#else /* ! defined (elf_backend_relocate_section) */
/* If no backend relocate_section routine, use the generic linker.
extern bfd_reloc_status_type _bfd_clear_contents
(reloc_howto_type *, bfd *, asection *, bfd_byte *, bfd_vma) ATTRIBUTE_HIDDEN;
-/* Register a SEC_MERGE section as a candidate for merging. */
-
-extern bool _bfd_add_merge_section
- (bfd *, void **, asection *) ATTRIBUTE_HIDDEN;
-
/* Attempt to merge SEC_MERGE sections. */
extern bool _bfd_merge_sections
- (bfd *, struct bfd_link_info *, void *, void (*) (bfd *, asection *))
- ATTRIBUTE_HIDDEN;
+ (bfd *, struct bfd_link_info *) ATTRIBUTE_HIDDEN;
/* Write out a merged section. */
extern bfd_reloc_status_type _bfd_clear_contents
(reloc_howto_type *, bfd *, asection *, bfd_byte *, bfd_vma) ATTRIBUTE_HIDDEN;
-/* Register a SEC_MERGE section as a candidate for merging. */
-
-extern bool _bfd_add_merge_section
- (bfd *, void **, asection *) ATTRIBUTE_HIDDEN;
-
/* Attempt to merge SEC_MERGE sections. */
extern bool _bfd_merge_sections
- (bfd *, struct bfd_link_info *, void *, void (*) (bfd *, asection *))
- ATTRIBUTE_HIDDEN;
+ (bfd *, struct bfd_link_info *) ATTRIBUTE_HIDDEN;
/* Write out a merged section. */
hash table entry. */
static void
-set_symbol_from_hash (asymbol *sym, struct bfd_link_hash_entry *h)
+set_symbol_from_hash (bfd *output_bfd,
+ asymbol *sym,
+ struct bfd_link_hash_entry *h)
{
switch (h->type)
{
sym->flags |= BSF_WEAK;
break;
case bfd_link_hash_defined:
+ sym->flags |= BSF_GLOBAL;
sym->section = h->u.def.section;
sym->value = h->u.def.value;
+ if (sym->section->sec_info_type == SEC_INFO_TYPE_MERGE)
+ {
+ sym->value =
+ _bfd_merged_section_offset (output_bfd, &sym->section, sym->value);
+ sym->flags |= BSF_MERGE_RESOLVED;
+ }
break;
case bfd_link_hash_defweak:
sym->flags |= BSF_WEAK;
sym->section = h->u.def.section;
sym->value = h->u.def.value;
+ if (sym->section->sec_info_type == SEC_INFO_TYPE_MERGE)
+ {
+ sym->value =
+ _bfd_merged_section_offset (output_bfd, &sym->section, sym->value);
+ sym->flags |= BSF_MERGE_RESOLVED;
+ }
break;
case bfd_link_hash_common:
sym->value = h->u.c.size;
sym->flags = 0;
}
- set_symbol_from_hash (sym, &h->root);
+ set_symbol_from_hash (wginfo->output_bfd, sym, &h->root);
sym->flags |= BSF_GLOBAL;
for (; sympp < symppend; sympp++)
{
asymbol *sym;
- struct bfd_link_hash_entry *h;
+ struct bfd_link_hash_entry *h = NULL;
sym = *sympp;
bfd_asymbol_name (sym),
false, false, true);
if (h != NULL)
- set_symbol_from_hash (sym, h);
+ set_symbol_from_hash (output_bfd, sym, h);
+ }
+
+ if (h == NULL
+ && sym->section->sec_info_type == SEC_INFO_TYPE_MERGE
+ && !(sym->flags & (BSF_SECTION_SYM | BSF_MERGE_RESOLVED)))
+ {
+ sym->value = _bfd_merged_section_offset (output_bfd,
+ &sym->section,
+ sym->value);
+ sym->flags |= BSF_MERGE_RESOLVED;
}
}
+
+ if (input_section->sec_info_type == SEC_INFO_TYPE_MERGE)
+ return _bfd_write_merged_section (output_bfd, input_section);
}
if ((output_section->flags & (SEC_GROUP | SEC_LINKER_CREATED)) == SEC_GROUP
/* Register a SEC_MERGE section as a candidate for merging.
This function is called for all non-dynamic SEC_MERGE input sections. */
-bool
+static bool
_bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec)
{
struct sec_merge_info *sinfo;
/* This function is called once after all SEC_MERGE sections are registered
with _bfd_merge_section. */
-bool
-_bfd_merge_sections (bfd *abfd,
- struct bfd_link_info *info ATTRIBUTE_UNUSED,
- void *xsinfo,
- void (*remove_hook) (bfd *, asection *))
+static bool
+merge_sections (bfd *abfd,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ void *xsinfo)
{
struct sec_merge_info *sinfo;
if (secinfo->sec->flags & SEC_EXCLUDE
|| !record_section (sinfo, secinfo))
{
+ BFD_ASSERT (secinfo->sec->sec_info_type == SEC_INFO_TYPE_MERGE);
secinfo->sec->sec_info = NULL;
- if (remove_hook)
- (*remove_hook) (abfd, secinfo->sec);
+ secinfo->sec->sec_info_type = SEC_INFO_TYPE_NONE;
}
else if (align)
{
return true;
}
+/* Finish SEC_MERGE section merging. */
+
+bool
+_bfd_merge_sections (bfd *obfd, struct bfd_link_info *info)
+{
+ const bfd *ibfd;
+ asection *sec;
+
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+ if ((ibfd->flags & DYNAMIC) == 0)
+ for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+ if ((sec->flags & SEC_MERGE) != 0
+ && !bfd_is_abs_section (sec->output_section)
+ && !_bfd_add_merge_section (obfd,
+ &info->hash->merge_info,
+ sec))
+ return false;
+
+ if (info->hash->merge_info == NULL)
+ return true;
+
+ return merge_sections (obfd, info, info->hash->merge_info);
+}
+
/* Write out the merged section. */
bool
r = bfd_reloc_ok;
}
else
- r = bfd_perform_relocation (input_bfd,
- *parent,
- data,
- input_section,
- relocatable ? abfd : NULL,
- &error_message);
+ {
+ if ((symbol->flags & BSF_SECTION_SYM)
+ && symbol->section->sec_info_type == SEC_INFO_TYPE_MERGE
+ /* This, while apparently necessary, feels bogus. */
+ && !(symbol->section->flags & SEC_DEBUGGING))
+ {
+ asection *sec = symbol->section;
+
+ (*parent)->addend =
+ _bfd_merged_section_offset (abfd, &sec, (*parent)->addend);
+ /* We may not change symbol->section, so the output_offset
+ adjustment done in bfd_perform_relocation() needs taking
+ care of (and compensating) here. */
+ (*parent)->addend +=
+ sec->output_offset - symbol->section->output_offset;
+ }
+
+ r = bfd_perform_relocation (input_bfd,
+ *parent,
+ data,
+ input_section,
+ relocatable ? abfd : NULL,
+ &error_message);
+ }
if (relocatable)
{
. {* This section symbol should be included in the symbol table. *}
.#define BSF_SECTION_SYM_USED (1 << 24)
.
+. {* This symbol underwent section merge resolution. *}
+.#define BSF_MERGE_RESOLVED (1 << 25)
+.
. flagword flags;
.
. {* A pointer to the section to which this symbol is
#as: --x32
#ld: --oformat elf32-i386 -m elf32_x86_64
#objdump: -s -j .rodata
-
-#...
- [0-9a-f]+ 02030041 42434400 +...ABCD. +
-#pass
+#dump: pr19013.d
#objdump: -s -j .rodata
#...
- [0-9a-f]+ 00000203 00414243 4400 +.....ABCD. +
+Contents of section \.rodata:
+ [0-9a-f]+ 02030041 42434400 +...ABCD. +
#pass