aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog14
-rw-r--r--bfd/elf64-alpha.c34
-rw-r--r--bfd/elfxx-ia64.c80
-rw-r--r--gas/ChangeLog7
-rw-r--r--gas/config/tc-alpha.c3
-rw-r--r--gas/config/tc-sparc.c5
-rw-r--r--gas/write.c8
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.,