This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Allow STT_SECTION + offset for SHF_MERGE sections (fix)


Hi!

I'm sorry for the tree beeing in a bad shape that long.
The following patch is what I sent yesterday evening (the gas part,
note that avoiding adjust in fixup_segment for SEC_MERGE not only doesn't
work with local weak symbols (which is very strange thing to do,
admittedly), but e.g. -K PIC is broken on SPARC too. So, IMHO it is
better done in the relevant ports where they have full control over it,
than to do it in fixup_segments generically and have each such port
(there are just few) to check for SEC_MERGE anyway and not do undo what
has not been done in the first case), plus Alpha and IA-64 fixes (the two
keep addends to local symbols in hash tables and that needs to be adjusted).
I believe elf64-hppa.c might have the same issue, though I have no way
to test such change.

Ok to commit this?

2001-11-27  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.

        * 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.

--- bfd/elf64-alpha.c.jj	Tue Nov 27 12:09:07 2001
+++ bfd/elf64-alpha.c	Tue Nov 27 13:40:19 2001
@@ -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
 		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);
--- bfd/elfxx-ia64.c.jj	Tue Nov 27 12:09:07 2001
+++ bfd/elfxx-ia64.c	Tue Nov 27 21:56:42 2001
@@ -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
   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, re
   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,
 	  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
 	{
--- gas/config/tc-alpha.c.jj	Tue Nov 27 12:09:07 2001
+++ gas/config/tc-alpha.c	Fri Nov 16 23:05:52 2001
@@ -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
--- gas/config/tc-sparc.c.jj	Fri Nov 16 23:05:52 2001
+++ gas/config/tc-sparc.c	Tue Nov 27 13:49:34 2001
@@ -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)
--- gas/write.c.jj	Tue Nov 27 12:09:07 2001
+++ gas/write.c	Tue Nov 27 13:48:50 2001
@@ -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.,

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]