diff options
-rw-r--r-- | bfd/ChangeLog | 14 | ||||
-rw-r--r-- | bfd/elf64-alpha.c | 34 | ||||
-rw-r--r-- | bfd/elfxx-ia64.c | 80 | ||||
-rw-r--r-- | gas/ChangeLog | 7 | ||||
-rw-r--r-- | gas/config/tc-alpha.c | 3 | ||||
-rw-r--r-- | gas/config/tc-sparc.c | 5 | ||||
-rw-r--r-- | gas/write.c | 8 |
7 files changed, 129 insertions, 22 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 9a4c516..b126fd7 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,17 @@ +2001-11-28 Jakub Jelinek <jakub@redhat.com> + + * elf64-alpha.c (ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED): Defined. + (elf64_alpha_relocate_section): Translate local_got_entries + for STT_SECTION symbol to SHF_MERGE section the first time + we see it. + * elfxx-ia64.c (struct elfNN_ia64_local_hash_entry): Add + sec_merge_done. + (get_local_sym_hash): New, extracted from get_dyn_sym_info. + (get_dyn_sym_info): Use it. + (elfNN_ia64_relocate_section): Translate local dyn entries + for STT_SECTION symbol to SHF_MERGE section the first time + we see it. + 2001-11-27 H.J. Lu <hjl@gnu.org> * elflink.h (elf_bfd_discard_info): Skip if the input bfd isn't diff --git a/bfd/elf64-alpha.c b/bfd/elf64-alpha.c index 783f010..950d051 100644 --- a/bfd/elf64-alpha.c +++ b/bfd/elf64-alpha.c @@ -170,8 +170,9 @@ struct alpha_elf_link_hash_entry int flags; - /* An additional flag. */ + /* Additional flags. */ #define ALPHA_ELF_GOT_ENTRY_RELOCS_DONE 0x10 +#define ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED 0x20 int use_count; } *got_entries; @@ -3400,6 +3401,37 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, gotent = (alpha_elf_tdata(input_bfd)-> local_got_entries[r_symndx]); dynamic_symbol = false; + + /* Need to adjust local GOT entries' addends for SEC_MERGE + unless it has been done already. */ + if ((sec->flags & SEC_MERGE) + && ELF_ST_TYPE (sym->st_info) == STT_SECTION + && elf_section_data (sec)->merge_info + && (gotent->flags & ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED) == 0) + { + struct alpha_elf_got_entry *ent; + asection *msec; + + for (ent = gotent; ent; ent = ent->next) + { + ent->flags |= ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED; + if (ent->use_count == 0) + continue; + msec = sec; + ent->addend = + _bfd_merged_section_offset (output_bfd, &msec, + elf_section_data (sec)-> + merge_info, + sym->st_value + + ent->addend, + (bfd_vma) 0); + ent->addend -= sym->st_value; + ent->addend += msec->output_section->vma + + msec->output_offset + - sec->output_section->vma + - sec->output_offset; + } + } } BFD_ASSERT(gotent != NULL); diff --git a/bfd/elfxx-ia64.c b/bfd/elfxx-ia64.c index ed06f54..2e34a30 100644 --- a/bfd/elfxx-ia64.c +++ b/bfd/elfxx-ia64.c @@ -111,6 +111,10 @@ struct elfNN_ia64_local_hash_entry { struct bfd_hash_entry root; struct elfNN_ia64_dyn_sym_info *info; + + /* True if this hash entry's addends was translated for + SHF_MERGE optimization. */ + unsigned sec_merge_done : 1; }; struct elfNN_ia64_local_hash_table @@ -216,6 +220,9 @@ static void elfNN_ia64_dyn_sym_traverse PTR info)); static boolean elfNN_ia64_create_dynamic_sections PARAMS ((bfd *abfd, struct bfd_link_info *info)); +static struct elfNN_ia64_local_hash_entry * get_local_sym_hash + PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info, + bfd *abfd, const Elf_Internal_Rela *rel, boolean create)); static struct elfNN_ia64_dyn_sym_info * get_dyn_sym_info PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info, struct elf_link_hash_entry *h, @@ -1719,6 +1726,32 @@ elfNN_ia64_create_dynamic_sections (abfd, info) return true; } +/* Find and/or create a hash entry for local symbol. */ +static struct elfNN_ia64_local_hash_entry * +get_local_sym_hash (ia64_info, abfd, rel, create) + struct elfNN_ia64_link_hash_table *ia64_info; + bfd *abfd; + const Elf_Internal_Rela *rel; + boolean create; +{ + char *addr_name; + size_t len; + + /* Construct a string for use in the elfNN_ia64_local_hash_table. + name describes what was once anonymous memory. */ + + len = sizeof (void*)*2 + 1 + sizeof (bfd_vma)*4 + 1 + 1; + len += 10; /* %p slop */ + + addr_name = alloca (len); + sprintf (addr_name, "%p:%lx", + (void *) abfd, (unsigned long) ELFNN_R_SYM (rel->r_info)); + + /* Collect the canonical entry data for this address. */ + return elfNN_ia64_local_hash_lookup (&ia64_info->loc_hash_table, + addr_name, create, create); +} + /* Find and/or create a descriptor for dynamic symbol info. This will vary based on global or local symbol, and the addend to the reloc. */ @@ -1739,22 +1772,8 @@ get_dyn_sym_info (ia64_info, h, abfd, rel, create) else { struct elfNN_ia64_local_hash_entry *loc_h; - char *addr_name; - size_t len; - - /* Construct a string for use in the elfNN_ia64_local_hash_table. - The name describes what was once anonymous memory. */ - - len = sizeof (void*)*2 + 1 + sizeof (bfd_vma)*4 + 1 + 1; - len += 10; /* %p slop */ - - addr_name = alloca (len); - sprintf (addr_name, "%p:%lx", - (void *) abfd, (unsigned long) ELFNN_R_SYM (rel->r_info)); - /* Collect the canonical entry data for this address. */ - loc_h = elfNN_ia64_local_hash_lookup (&ia64_info->loc_hash_table, - addr_name, create, create); + loc_h = get_local_sym_hash (ia64_info, abfd, rel, create); BFD_ASSERT (loc_h); pp = &loc_h->info; @@ -3482,6 +3501,37 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, sym = local_syms + r_symndx; sym_sec = local_sections[r_symndx]; value = _bfd_elf_rela_local_sym (output_bfd, sym, sym_sec, rel); + if ((sym_sec->flags & SEC_MERGE) + && ELF_ST_TYPE (sym->st_info) == STT_SECTION + && elf_section_data (sym_sec)->merge_info) + { + struct elfNN_ia64_local_hash_entry *loc_h; + + loc_h = get_local_sym_hash (ia64_info, input_bfd, rel, false); + if (loc_h && ! loc_h->sec_merge_done) + { + struct elfNN_ia64_dyn_sym_info *dynent; + asection *msec; + + for (dynent = loc_h->info; dynent; dynent = dynent->next) + { + msec = sym_sec; + dynent->addend = + _bfd_merged_section_offset (output_bfd, &msec, + elf_section_data (msec)-> + merge_info, + sym->st_value + + dynent->addend, + (bfd_vma) 0); + dynent->addend -= sym->st_value; + dynent->addend += msec->output_section->vma + + msec->output_offset + - sym_sec->output_section->vma + - sym_sec->output_offset; + } + loc_h->sec_merge_done = 1; + } + } } else { diff --git a/gas/ChangeLog b/gas/ChangeLog index 261ce4d..b07bb46 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,10 @@ +2001-11-28 Jakub Jelinek <jakub@redhat.com> + + * write.c (adjust_reloc_syms): Mark SEC_MERGE symbols as used + in reloc if it has non-zero addend. + * config/tc-alpha.c (tc_gen_reloc): Reinstall SEC_MERGE check. + * config/tc-sparc.c (md_apply_fix3): Likewise. + 2001-11-28 Andreas Schwab <schwab@suse.de> * as.c (parse_args): Call md_after_parse_args if defined. diff --git a/gas/config/tc-alpha.c b/gas/config/tc-alpha.c index f9908e7..f73c862 100644 --- a/gas/config/tc-alpha.c +++ b/gas/config/tc-alpha.c @@ -1507,7 +1507,8 @@ tc_gen_reloc (sec, fixp) * at assembly time. bfd_perform_reloc doesn't know about this sort * of thing, and as a result we need to fake it out here. */ - if ((S_IS_EXTERN (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy)) + if ((S_IS_EXTERN (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy) + || (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE)) && !S_IS_COMMON (fixp->fx_addsy)) reloc->addend -= symbol_get_bfdsym (fixp->fx_addsy)->value; #endif diff --git a/gas/config/tc-sparc.c b/gas/config/tc-sparc.c index f1639a3..2db2bac 100644 --- a/gas/config/tc-sparc.c +++ b/gas/config/tc-sparc.c @@ -2909,12 +2909,7 @@ md_apply_fix3 (fixP, valP, segment) if (symbol_used_in_reloc_p (sym) && (S_IS_EXTERNAL (sym) || S_IS_WEAK (sym) -#if 0 /* Although fixups against local symbols in SEC_MERGE sections - should be treated as if they were against external symbols - write.c:fixup_segment() will not have included the value of - the symbol under these particular cicumstances. */ || (seg->flags & SEC_MERGE) -#endif || (sparc_pic_code && ! fixP->fx_pcrel) || (seg != segment && (((bfd_get_section_flags (stdoutput, seg) & SEC_LINK_ONCE) != 0) diff --git a/gas/write.c b/gas/write.c index 5397aa0..55db85a 100644 --- a/gas/write.c +++ b/gas/write.c @@ -873,6 +873,14 @@ adjust_reloc_syms (abfd, sec, xxx) symbol_mark_used_in_reloc (fixp->fx_addsy); goto done; } + + /* Never adjust a reloc against local symbol in a merge section + with non-zero addend. */ + if ((symsec->flags & SEC_MERGE) && fixp->fx_offset) + { + symbol_mark_used_in_reloc (fixp->fx_addsy); + goto done; + } #endif /* Is there some other reason we can't adjust this one? (E.g., |