This is the mail archive of the binutils@sourceware.org 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]

Re: [PATCH] Add a do_assignments hook to ldemul


On Sat, Apr 30, 2016 at 7:40 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Fri, Apr 29, 2016 at 5:25 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Fri, Apr 29, 2016 at 6:35 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>> On Fri, Apr 29, 2016 at 5:30 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>>> On Thu, Apr 28, 2016 at 11:35 PM, Alan Modra <amodra@gmail.com> wrote:
>>>>> On Thu, Apr 28, 2016 at 05:59:55PM -0700, H.J. Lu wrote:
>>>>>> On Thu, Apr 28, 2016 at 4:38 PM, Alan Modra <amodra@gmail.com> wrote:
>>>>>> > On Thu, Apr 28, 2016 at 02:01:47PM -0700, H.J. Lu wrote:
>>>>>> >> +      /* Symbol is defined.  Check if it is also defined in a regular
>>>>>> >> +      input file only when it is currently defined in a dynamic
>>>>>> >> +      object, since otherwise, it can't be a __start_<name> nor
>>>>>> >> +      __stop_<name> symbol.  */
>>>>>> >> +      if (!h->def_dynamic)
>>>>>> >>       return NULL;
>>>>>> > [snip]
>>>>>> >> +         if (s != NULL)
>>>>>> >> +           {
>>>>>> >> +             h->root.u.undef.section = s;
>>>>>> >> +             break;
>>>>>> >> +           }
>>>>>> >
>>>>>> > You can't set u.undef here on a defined symbol.  That's just too ugly,
>>>>>> > even if you later set it to undefined.  Better to force it
>>>>>> > bfd_link_hash_undefined here.
>>>>>>
>>>>>> Like this?
>>>>>
>>>>> No, I meant that if you want to make use of the u.undef.section cache,
>>>>> then set it to undefined first.  If you don't intend to set
>>>>> u.undef.section then set to undefined later.
>>>>>
>>>>>> > This is getting quite messy, and I'm wondering if we even need
>>>>>> > _bfd_elf_is_start_stop, except for gc-sections code.
>>>>>
>>>>> Note that when I wrote _bfd_elf_is_start_stop I thought it might come
>>>>> in useful in check_relocs, to prevent __start_* and __stop_* from
>>>>> being seen as dynamic.  Now that you're running both
>>>>> find_statement_assignment and lang_do_assignments before check_relocs,
>>>>> doing anything special with _bfd_elf_is_start_stop should not be
>>>>> necessary.
>>>>
>>>>  __start_* and __stop_* aren't handled properly with shared library:
>>>>
>>>> https://sourceware.org/bugzilla/show_bug.cgi?id=20022
>>>>
>>>> _bfd_elf_is_start_stop needs to check symbols defined in a
>>>> shared library.
>>>>
>>>>> find_statement_assignment has given the bfd backend a look at symbols,
>>>>> and you've processed the PROVIDE (__start_sec = .) linker script
>>>>> statements in lang_do_assignments.  So it ought to be possible to make
>>>>> __start_sec a def_regular normal symbol by that point.  As I said
>>>>> before, I'd expect that to work better if find_statement_assignment
>>>>> ran before lang_do_assignments.  That allows
>>>>> bfd_elf_record_link_assignment to force def_dynamic symbols to
>>>>> bfd_link_hash_undefined so that ldexp.c code handling PROVIDE doesn't
>>>>> need to know ELF specific details.
>>>>>
>>>>> However, you said that doing it that way didn't work.  What didn't
>>>>> work, and what needs to change in bfd_elf_record_link_assignment to
>>>>> make it work?
>>>>
>>>> The failed testcase is ld-elf/ehdr_start-userdef.  We have
>>>>
>>>>          /* Only adjust the export class if the symbol was referenced
>>>>              and not defined, otherwise leave it alone.  */
>>>>           if (h != NULL
>>>>               && (h->root.type == bfd_link_hash_new
>>>>                   || h->root.type == bfd_link_hash_undefined
>>>>                   || h->root.type == bfd_link_hash_undefweak
>>>>                   || h->root.type == bfd_link_hash_common))
>>>>             {
>>>>
>>>> Since this is run before  lang_do_assignments, we don't see
>>>>
>>>> __ehdr_start = 0x12345678;
>>>>
>>>> in linker script and get
>>>>
>>>> (gdb) p *h
>>>> $2 = {root = {root = {next = 0x0, string = 0x859bad "__ehdr_start",
>>>>       hash = 78192523}, type = bfd_link_hash_undefined, non_ir_ref = 0,
>>>>     linker_def = 0, u = {undef = {next = 0x0, abfd = 0x857100, section = 0x0},
>>>>       def = {next = 0x0, section = 0x857100, value = 0}, i = {next = 0x0,
>>>>         link = 0x857100, warning = 0x0}, c = {next = 0x0, p = 0x857100,
>>>>         size = 0}}}, indx = -1, dynindx = -1, got = {refcount = 0, offset = 0,
>>>>     glist = 0x0, plist = 0x0}, plt = {refcount = 0, offset = 0, glist = 0x0,
>>>>     plist = 0x0}, size = 0, type = 0, other = 0, target_internal = 0,
>>>>   ref_regular = 1, def_regular = 0, ref_dynamic = 0, def_dynamic = 0,
>>>>   ref_regular_nonweak = 1, dynamic_adjusted = 0, needs_copy = 0,
>>>>   needs_plt = 0, non_elf = 0, versioned = unversioned, forced_local = 0,
>>>>   dynamic = 0, mark = 0, non_got_ref = 0, dynamic_def = 0,
>>>>   ref_dynamic_nonweak = 0, pointer_equality_needed = 0, unique_global = 0,
>>>>   protected_def = 0, dynstr_index = 0, u = {weakdef = 0x0,
>>>>     elf_hash_value = 0}, verinfo = {verdef = 0x0, vertree = 0x0}, vtable = 0x0}
>>>>
>>>> We get
>>>>
>>>>      3: 0000000012345678     0 NOTYPE  LOCAL  DEFAULT  ABS __ehdr_start
>>>>
>>>>
>>>> instead of
>>>>
>>>>      3: 0000000012345678     0 NOTYPE  GLOBAL  DEFAULT  ABS __ehdr_start
>>>>
>>>> in output.
>>>
>>> I have a fix for it.  But _bfd_elf_is_start_stop still needs fix.
>>
>> Here is the updated patch, which doesn't use _bfd_elf_is_start_stop.
>>
>> OK for master?
>>
>
> Scan over all input files for each start/stop symbol may be too
> expensive.  Assuming there are fewer start/stop symbols than
> input files,  this patch collects all start/stop symbols first and
> only scan over all input files once.
>
> Comments, feedbacks?
>

An updated patch.


-- 
H.J.
From ae878e1cb2ee2d6abc312a0b8e5e7dbe5c533c0f Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Thu, 28 Apr 2016 05:25:17 -0700
Subject: [PATCH] Add a do_assignments hook to ldemul

When ELF relocation check is moved after lang_gc_sections, we should
call bfd_elf_record_link_assignment before ELF relocation check so that
linker defined symbols will be processed earlier to stabilize symbols.
We have to do it in lang_do_assignments just before the call to
lang_do_assignments_1.

bfd/

	* elf-bfd.h (_bfd_elf_record_start_stop): New prototype.
	* elflink.c (start_stop_symbol): New struct.
	(start_stop_symbol_info): Likewise.
	(elf_link_collect_start_stop): New function.
	(_bfd_elf_record_start_stop): Likewise.

ld/

	* ldemul.c (ldemul_do_assignments): New function.
	* ldemul.h (ldemul_do_assignments): New prototype.
	(ld_emulation_xfer_struct): Add do_assignments.
	* ldlang.c (lang_do_assignments): Call ldemul_do_assignments
	just before lang_do_assignments_1 in lang_mark_phase_enum.
	* emultempl/aix.em (ld_${EMULATION_NAME}_emulation): Initialize
	the do_assignments field to NULL.
	* emultempl/armcoff.em (ld_${EMULATION_NAME}_emulation): Likewise.
	* emultempl/beos.em (ld_${EMULATION_NAME}_emulation): Likewise.
	* emultempl/generic.em (ld_${EMULATION_NAME}_emulation): Likewise.
	* emultempl/gld960.em (ld_gld960_emulation): Likewise.
	* emultempl/gld960c.em (ld_gld960coff_emulation): Likewise.
	* emultempl/linux.em (ld_${EMULATION_NAME}_emulation): Likewise.
	* emultempl/lnk960.em (ld_lnk960_emulation): Likewise.
	* emultempl/m68kcoff.em (ld_${EMULATION_NAME}_emulation): Likewise.
	* emultempl/msp430.em (ld_${EMULATION_NAME}_emulation): Likewise.
	* emultempl/pe.em (ld_${EMULATION_NAME}_emulation): Likewise.
	* emultempl/pep.em (ld_${EMULATION_NAME}_emulation): Likewise.
	* emultempl/sunos.em (ld_${EMULATION_NAME}_emulation): Likewise.
	* emultempl/ticoff.em (ld_${EMULATION_NAME}_emulation): Likewise.
	* emultempl/vanilla.em (ld_${EMULATION_NAME}_emulation): Likewise.
	* emultempl/elf32.em (ehdr_start): New variable.
	(ehdr_start_save): Likewise.
	(gld${EMULATION_NAME}_do_assignments): New function.
	(gld${EMULATION_NAME}_restore_ehdr_start): Likewise.
	(ehdr_start_empty): Removed.
	(gld${EMULATION_NAME}_before_allocation): Don't adjust
	__ehdr_start here.  Call gld${EMULATION_NAME}_restore_ehdr_start
	at the end.
	(ld_${EMULATION_NAME}_emulation): Initialize the do_assignments
	field with gld${EMULATION_NAME}_do_assignments by default.
---
 bfd/elf-bfd.h            |   3 +
 bfd/elflink.c            | 127 ++++++++++++++++++++++++++++++++++++++++++
 ld/emultempl/aix.em      |   3 +-
 ld/emultempl/armcoff.em  |   3 +-
 ld/emultempl/beos.em     |   3 +-
 ld/emultempl/elf32.em    | 141 +++++++++++++++++++++++++++--------------------
 ld/emultempl/generic.em  |   3 +-
 ld/emultempl/gld960.em   |   3 +-
 ld/emultempl/gld960c.em  |   3 +-
 ld/emultempl/linux.em    |   3 +-
 ld/emultempl/lnk960.em   |   3 +-
 ld/emultempl/m68kcoff.em |   3 +-
 ld/emultempl/msp430.em   |   3 +-
 ld/emultempl/pe.em       |   3 +-
 ld/emultempl/pep.em      |   3 +-
 ld/emultempl/sunos.em    |   3 +-
 ld/emultempl/ticoff.em   |   3 +-
 ld/emultempl/vanilla.em  |   3 +-
 ld/ldemul.c              |   7 +++
 ld/ldemul.h              |   6 ++
 ld/ldlang.c              |   2 +
 21 files changed, 256 insertions(+), 75 deletions(-)

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 9067dd9..2dafbcf 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -2341,6 +2341,9 @@ extern bfd_boolean bfd_elf_gc_common_final_link
 extern asection *_bfd_elf_is_start_stop
   (const struct bfd_link_info *, struct elf_link_hash_entry *);
 
+extern void _bfd_elf_record_start_stop
+  (struct bfd_link_info *);
+
 extern bfd_boolean bfd_elf_reloc_symbol_deleted_p
   (bfd_vma, void *);
 
diff --git a/bfd/elflink.c b/bfd/elflink.c
index b6ff6b6..a6e5bfb 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -13791,3 +13791,130 @@ elf_append_rel (bfd *abfd, asection *s, Elf_Internal_Rela *rel)
   BFD_ASSERT (loc + bed->s->sizeof_rel <= s->contents + s->size);
   bed->s->swap_reloc_out (abfd, rel, loc);
 }
+
+/* A linked list of __start_<name> and __stop_<name> symbols  */
+
+struct start_stop_symbol
+{
+  struct elf_link_hash_entry *h;
+  const char *sec_name;
+  struct start_stop_symbol *next;
+};
+
+struct start_stop_symbol_info
+{
+  struct start_stop_symbol *symbol_list;
+  bfd_boolean failed;
+};
+
+/* Collect __start_<name> and __stop_<name> symbols referenced by
+   regular objects.  This is called via elf_link_hash_traverse.  */
+
+static bfd_boolean
+elf_link_collect_start_stop (struct elf_link_hash_entry *h, void *data)
+{
+  if (!h->def_regular && h->ref_regular)
+    {
+      struct start_stop_symbol_info *info;
+      struct start_stop_symbol *p, **head;
+      const char *sec_name = h->root.root.string;
+
+      if (sec_name[0] == '_'
+	  && sec_name[1] == '_'
+	  && sec_name[2] == 's'
+	  && sec_name[3] == 't')
+	sec_name += 4;
+      else
+	return TRUE;
+
+      if (sec_name[0] == 'a'
+	  && sec_name[1] == 'r'
+	  && sec_name[2] == 't')
+	sec_name += 3;
+      else if (sec_name[0] == 'o'
+	       && sec_name[1] == 'p')
+	sec_name += 2;
+      else
+	return TRUE;
+
+      if (sec_name[0] == '_' && sec_name[1] != '\0')
+	sec_name += 1;
+      else
+	return TRUE;
+
+      info = (struct start_stop_symbol_info *) data;
+
+      p = (struct start_stop_symbol *) bfd_malloc (sizeof (*p));
+      if (p == NULL)
+	{
+	  info->failed = TRUE;
+	  return FALSE;
+	}
+
+      head = &info->symbol_list;
+      p->next = info->symbol_list;
+      p->h = h;
+      p->sec_name = sec_name;
+      *head = p;
+    }
+  return TRUE;
+}
+
+/* Record all __start_<name> and __stop_<name> symbols referenced by
+   regular objects.  */
+
+void
+_bfd_elf_record_start_stop (struct bfd_link_info *info)
+{
+  struct start_stop_symbol_info symbols;
+
+  /* Collect start/stop symbols.  Assuming there are fewer start/stop
+     symbols than input files, avoid scan over all input files for each
+     start/stop symbol.  */
+  symbols.symbol_list = NULL;
+  symbols.failed = FALSE;
+  elf_link_hash_traverse (elf_hash_table (info),
+			  elf_link_collect_start_stop, &symbols);
+
+  if (symbols.failed)
+    info->callbacks->einfo (_("%P%X: collect start/stop symbols: %E\n"));
+  else if (symbols.symbol_list)
+    {
+      bfd *i;
+
+      for (i = info->input_bfds; i != NULL; i = i->link.next)
+	if ((i->flags
+	     & (DYNAMIC | BFD_LINKER_CREATED | BFD_PLUGIN)) == 0)
+	  {
+	    /* Only check regular input files.  */
+	    struct start_stop_symbol *p, **pp;
+
+	    for (pp = &symbols.symbol_list; (p = *pp) != NULL; )
+	      if (bfd_get_section_by_name (i, p->sec_name) != NULL)
+		{
+		  p->h->def_regular = 1;
+		  p->h->type = STT_OBJECT;
+		  /* If it is currently defined by a dynamic object, but
+		     not by a regular object, then mark it as undefined
+		     so that the generic linker will force the correct
+		     value.  */
+		  if (p->h->def_dynamic)
+		    {
+		      p->h->root.type = bfd_link_hash_undefined;
+		      p->h->root.u.undef.abfd
+			= p->h->root.u.def.section->owner;
+		    }
+
+		  /* Remove this from the list.  */
+		  *pp = p->next;
+		  free (p);
+		}
+	      else
+		pp = &p->next;
+
+	    /* Stop when the list is empty.  */
+	    if (symbols.symbol_list == NULL)
+	      break;
+	  }
+    }
+}
diff --git a/ld/emultempl/aix.em b/ld/emultempl/aix.em
index b9cab4e..3c775f9 100644
--- a/ld/emultempl/aix.em
+++ b/ld/emultempl/aix.em
@@ -1554,6 +1554,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = {
   NULL,				/* recognized_file */
   NULL,				/* find potential_libraries */
   NULL,				/* new_vers_pattern */
-  NULL				/* extra_map_file_text */
+  NULL,				/* extra_map_file_text */
+  NULL				/* do_assignments */
 };
 EOF
diff --git a/ld/emultempl/armcoff.em b/ld/emultempl/armcoff.em
index 387a1f7..9848995 100644
--- a/ld/emultempl/armcoff.em
+++ b/ld/emultempl/armcoff.em
@@ -280,6 +280,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   NULL,	/* recognized file */
   NULL,	/* find_potential_libraries */
   NULL,	/* new_vers_pattern */
-  NULL	/* extra_map_file_text */
+  NULL,	/* extra_map_file_text */
+  NULL	/* do_assignments */
 };
 EOF
diff --git a/ld/emultempl/beos.em b/ld/emultempl/beos.em
index 6430102..2622688 100644
--- a/ld/emultempl/beos.em
+++ b/ld/emultempl/beos.em
@@ -778,6 +778,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   NULL,	/* recognized file */
   NULL,	/* find_potential_libraries */
   NULL,	/* new_vers_pattern */
-  NULL	/* extra_map_file_text */
+  NULL,	/* extra_map_file_text */
+  NULL	/* do_assignments */
 };
 EOF
diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em
index 4f5d1a4..1b26e1f 100644
--- a/ld/emultempl/elf32.em
+++ b/ld/emultempl/elf32.em
@@ -1330,6 +1330,7 @@ fragment <<EOF
 EOF
 fi
 
+if test x"$LDEMUL_DO_ASSIGNMENTS" != xgld"$EMULATION_NAME"_do_assignments; then
 fragment <<EOF
 
 /* Look through an expression for an assignment statement.  */
@@ -1398,7 +1399,83 @@ gld${EMULATION_NAME}_find_statement_assignment (lang_statement_union_type *s)
     gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp);
 }
 
+static struct elf_link_hash_entry *ehdr_start;
+static struct bfd_link_hash_entry ehdr_start_save;
+
+static void
+gld${EMULATION_NAME}_do_assignments (void)
+{
+  if (is_elf_hash_table (link_info.hash))
+    {
+      /* If we are going to make any variable assignments, we need to
+	 let the ELF backend know about them in case the variables are
+	 referred to by dynamic objects.  */
+      lang_for_each_statement (gld${EMULATION_NAME}_find_statement_assignment);
+
+      /* Also let the ELF backend know about __start_<name> and
+	 __stop_<name> symbols.  */
+      _bfd_elf_record_start_stop (&link_info);
+
+      /* Make __ehdr_start hidden if it has been referenced, to
+	 prevent the symbol from being dynamic.  */
+      if (!bfd_link_relocatable (&link_info))
+	{
+	  struct elf_link_hash_entry *h
+	    = elf_link_hash_lookup (elf_hash_table (&link_info),
+				    "__ehdr_start", FALSE, FALSE, TRUE);
+
+	  /* Only adjust the export class if the symbol was referenced
+	     and not defined, otherwise leave it alone.  def_regular is
+	     set by the ELF backend if __ehdr_start is defined in linker
+	     script.  */
+	  if (h != NULL
+	      && !h->def_regular
+	      && (h->root.type == bfd_link_hash_new
+		  || h->root.type == bfd_link_hash_undefined
+		  || h->root.type == bfd_link_hash_undefweak
+		  || h->root.type == bfd_link_hash_common))
+	    {
+	      _bfd_elf_link_hash_hide_symbol (&link_info, h, TRUE);
+	      if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL)
+		h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
+	      /* Don't leave the symbol undefined.  Undefined hidden
+		 symbols typically won't have dynamic relocations, but
+		 we most likely will need dynamic relocations for
+		 __ehdr_start if we are building a PIE or shared
+		 library.  */
+	      ehdr_start = h;
+	      ehdr_start_save = h->root;
+	      h->root.type = bfd_link_hash_defined;
+	      h->root.u.def.section = bfd_abs_section_ptr;
+	      h->root.u.def.value = 0;
+	    }
+	}
+    }
+}
+
+static void
+gld${EMULATION_NAME}_restore_ehdr_start (void)
+{
+  if (ehdr_start != NULL)
+    {
+      /* If we twiddled __ehdr_start to defined earlier, put it back
+	 as it was.  */
+      ehdr_start->root.type = ehdr_start_save.type;
+      ehdr_start->root.u = ehdr_start_save.u;
+    }
+}
+
+EOF
+else
+fragment <<EOF
+
+static
+gld${EMULATION_NAME}_restore_ehdr_start (void)
+{
+}
+
 EOF
+fi
 
 if test x"$LDEMUL_BEFORE_ALLOCATION" != xgld"$EMULATION_NAME"_before_allocation; then
   if test x"${ELF_INTERPRETER_NAME+set}" = xset; then
@@ -1455,11 +1532,6 @@ gld${EMULATION_NAME}_append_to_separated_string (char **to, char *op_arg)
     }
 }
 
-#if defined(__GNUC__) && GCC_VERSION < 4006
-  /* Work around a GCC uninitialized warning bug fixed in GCC 4.6.  */
-static struct bfd_link_hash_entry ehdr_start_empty;
-#endif
-
 /* This is called after the sections have been attached to output
    sections, but before any sizes or addresses have been set.  */
 
@@ -1469,55 +1541,9 @@ gld${EMULATION_NAME}_before_allocation (void)
   const char *rpath;
   asection *sinterp;
   bfd *abfd;
-  struct elf_link_hash_entry *ehdr_start = NULL;
-#if defined(__GNUC__) && GCC_VERSION < 4006
-  /* Work around a GCC uninitialized warning bug fixed in GCC 4.6.  */
-  struct bfd_link_hash_entry ehdr_start_save = ehdr_start_empty;
-#else
-  struct bfd_link_hash_entry ehdr_start_save;
-#endif
 
   if (is_elf_hash_table (link_info.hash))
-    {
-      _bfd_elf_tls_setup (link_info.output_bfd, &link_info);
-
-      /* Make __ehdr_start hidden if it has been referenced, to
-	 prevent the symbol from being dynamic.  */
-      if (!bfd_link_relocatable (&link_info))
-       {
-         struct elf_link_hash_entry *h
-           = elf_link_hash_lookup (elf_hash_table (&link_info), "__ehdr_start",
-                                   FALSE, FALSE, TRUE);
-
-         /* Only adjust the export class if the symbol was referenced
-            and not defined, otherwise leave it alone.  */
-         if (h != NULL
-             && (h->root.type == bfd_link_hash_new
-                 || h->root.type == bfd_link_hash_undefined
-                 || h->root.type == bfd_link_hash_undefweak
-                 || h->root.type == bfd_link_hash_common))
-           {
-             _bfd_elf_link_hash_hide_symbol (&link_info, h, TRUE);
-             if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL)
-               h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
-	     /* Don't leave the symbol undefined.  Undefined hidden
-		symbols typically won't have dynamic relocations, but
-		we most likely will need dynamic relocations for
-		__ehdr_start if we are building a PIE or shared
-		library.  */
-	     ehdr_start = h;
-	     ehdr_start_save = h->root;
-	     h->root.type = bfd_link_hash_defined;
-	     h->root.u.def.section = bfd_abs_section_ptr;
-	     h->root.u.def.value = 0;
-           }
-       }
-
-      /* If we are going to make any variable assignments, we need to
-	 let the ELF backend know about them in case the variables are
-	 referred to by dynamic objects.  */
-      lang_for_each_statement (gld${EMULATION_NAME}_find_statement_assignment);
-    }
+    _bfd_elf_tls_setup (link_info.output_bfd, &link_info);
 
   /* Let the ELF backend work out the sizes of any sections required
      by dynamic linking.  */
@@ -1627,13 +1653,7 @@ ${ELF_INTERPRETER_SET_DEFAULT}
   if (!bfd_elf_size_dynsym_hash_dynstr (link_info.output_bfd, &link_info))
     einfo ("%P%F: failed to set dynamic section sizes: %E\n");
 
-  if (ehdr_start != NULL)
-    {
-      /* If we twiddled __ehdr_start to defined earlier, put it back
-	 as it was.  */
-      ehdr_start->root.type = ehdr_start_save.type;
-      ehdr_start->root.u = ehdr_start_save.u;
-    }
+  gld${EMULATION_NAME}_restore_ehdr_start ();
 }
 
 EOF
@@ -2527,6 +2547,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   ${LDEMUL_RECOGNIZED_FILE-gld${EMULATION_NAME}_load_symbols},
   ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
   ${LDEMUL_NEW_VERS_PATTERN-NULL},
-  ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL}
+  ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL},
+  ${LDEMUL_DO_ASSIGNMENTS-gld${EMULATION_NAME}_do_assignments},
 };
 EOF
diff --git a/ld/emultempl/generic.em b/ld/emultempl/generic.em
index 7924cdf..66e35f7 100644
--- a/ld/emultempl/generic.em
+++ b/ld/emultempl/generic.em
@@ -156,6 +156,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   ${LDEMUL_RECOGNIZED_FILE-NULL},
   ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
   ${LDEMUL_NEW_VERS_PATTERN-NULL},
-  ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL}
+  ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL},
+  ${LDEMUL_DO_ASSIGNMENTS-NULL}
 };
 EOF
diff --git a/ld/emultempl/gld960.em b/ld/emultempl/gld960.em
index c4c9c55..0281969 100644
--- a/ld/emultempl/gld960.em
+++ b/ld/emultempl/gld960.em
@@ -149,6 +149,7 @@ struct ld_emulation_xfer_struct ld_gld960_emulation =
   NULL,	/* recognized file */
   NULL,	/* find_potential_libraries */
   NULL,	/* new_vers_pattern */
-  NULL	/* extra_map_file_text */
+  NULL,	/* extra_map_file_text */
+  NULL	/* do_assignments */
 };
 EOF
diff --git a/ld/emultempl/gld960c.em b/ld/emultempl/gld960c.em
index 6b80be2..3fede68 100644
--- a/ld/emultempl/gld960c.em
+++ b/ld/emultempl/gld960c.em
@@ -162,6 +162,7 @@ struct ld_emulation_xfer_struct ld_gld960coff_emulation =
   NULL,	/* recognized file */
   NULL,	/* find_potential_libraries */
   NULL,	/* new_vers_pattern */
-  NULL	/* extra_map_file_text */
+  NULL,	/* extra_map_file_text */
+  NULL	/* do_assignments */
 };
 EOF
diff --git a/ld/emultempl/linux.em b/ld/emultempl/linux.em
index c28e978..da8d9a9 100644
--- a/ld/emultempl/linux.em
+++ b/ld/emultempl/linux.em
@@ -206,6 +206,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   NULL,	/* recognized file */
   NULL,	/* find_potential_libraries */
   NULL,	/* new_vers_pattern */
-  NULL	/* extra_map_file_text */
+  NULL,	/* extra_map_file_text */
+  NULL	/* do_assignments */
 };
 EOF
diff --git a/ld/emultempl/lnk960.em b/ld/emultempl/lnk960.em
index 4a2bd72..ef345af 100644
--- a/ld/emultempl/lnk960.em
+++ b/ld/emultempl/lnk960.em
@@ -343,6 +343,7 @@ struct ld_emulation_xfer_struct ld_lnk960_emulation =
   NULL,	/* recognized file */
   NULL,	/* find_potential_libraries */
   NULL,	/* new_vers_pattern */
-  NULL	/* extra_map_file_text */
+  NULL, /* extra_map_file_text */
+  NULL	/* do_assignments */
 };
 EOF
diff --git a/ld/emultempl/m68kcoff.em b/ld/emultempl/m68kcoff.em
index 594cd56..a6c7fda 100644
--- a/ld/emultempl/m68kcoff.em
+++ b/ld/emultempl/m68kcoff.em
@@ -240,6 +240,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   NULL,	/* recognized file */
   NULL,	/* find_potential_libraries */
   NULL,	/* new_vers_pattern */
-  NULL	/* extra_map_file_text */
+  NULL,	/* extra_map_file_text */
+  NULL	/* do_assignments */
 };
 EOF
diff --git a/ld/emultempl/msp430.em b/ld/emultempl/msp430.em
index 22e7c42..0810181 100644
--- a/ld/emultempl/msp430.em
+++ b/ld/emultempl/msp430.em
@@ -295,7 +295,8 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   ${LDEMUL_RECOGNIZED_FILE-NULL},
   ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
   ${LDEMUL_NEW_VERS_PATTERN-NULL},
-  ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL}
+  ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL},
+  ${LDEMUL_DO_ASSIGNMENTS-NULL}
 };
 EOF
 # 
diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em
index c13fa4d..f67a701 100644
--- a/ld/emultempl/pe.em
+++ b/ld/emultempl/pe.em
@@ -2483,6 +2483,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   gld_${EMULATION_NAME}_recognized_file,
   gld_${EMULATION_NAME}_find_potential_libraries,
   NULL,	/* new_vers_pattern.  */
-  NULL	/* extra_map_file_text.  */
+  NULL,	/* extra_map_file_text.  */
+  NULL	/* do_assignments */
 };
 EOF
diff --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em
index ab7c473..33fd95d 100644
--- a/ld/emultempl/pep.em
+++ b/ld/emultempl/pep.em
@@ -2257,6 +2257,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   gld_${EMULATION_NAME}_recognized_file,
   gld_${EMULATION_NAME}_find_potential_libraries,
   NULL,	/* new_vers_pattern.  */
-  NULL	/* extra_map_file_text */
+  NULL,	/* extra_map_file_text */
+  NULL	/* do_assignments */
 };
 EOF
diff --git a/ld/emultempl/sunos.em b/ld/emultempl/sunos.em
index 8be8669..a019d6f 100644
--- a/ld/emultempl/sunos.em
+++ b/ld/emultempl/sunos.em
@@ -1036,6 +1036,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   NULL,	/* recognized file */
   NULL,	/* find_potential_libraries */
   NULL,	/* new_vers_pattern */
-  NULL	/* extra_map_file_text */
+  NULL,	/* extra_map_file_text */
+  NULL	/* do_assignments */
 };
 EOF
diff --git a/ld/emultempl/ticoff.em b/ld/emultempl/ticoff.em
index 9b5495e..eb9d3e7 100644
--- a/ld/emultempl/ticoff.em
+++ b/ld/emultempl/ticoff.em
@@ -181,6 +181,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   NULL, /* recognized file */
   NULL,	/* find_potential_libraries */
   NULL,	/* new_vers_pattern */
-  NULL  /* extra_map_file_text */
+  NULL, /* extra_map_file_text */
+  NULL	/* do_assignments */
 };
 EOF
diff --git a/ld/emultempl/vanilla.em b/ld/emultempl/vanilla.em
index d627dfc..b986ae9 100644
--- a/ld/emultempl/vanilla.em
+++ b/ld/emultempl/vanilla.em
@@ -82,6 +82,7 @@ struct ld_emulation_xfer_struct ld_vanilla_emulation =
   NULL,	/* recognized file */
   NULL,	/* find_potential_libraries */
   NULL,	/* new_vers_pattern */
-  NULL	/* extra_map_file_text */
+  NULL,	/* extra_map_file_text */
+  NULL	/* do_assignments */
 };
 EOF
diff --git a/ld/ldemul.c b/ld/ldemul.c
index 841a14d..c2532cb 100644
--- a/ld/ldemul.c
+++ b/ld/ldemul.c
@@ -355,3 +355,10 @@ ldemul_extra_map_file_text (bfd *abfd, struct bfd_link_info *info, FILE *mapf)
   if (ld_emulation->extra_map_file_text)
     ld_emulation->extra_map_file_text (abfd, info, mapf);
 }
+
+void
+ldemul_do_assignments (void)
+{
+  if (ld_emulation->do_assignments)
+    ld_emulation->do_assignments ();
+}
diff --git a/ld/ldemul.h b/ld/ldemul.h
index 937b1c9..cbc6355 100644
--- a/ld/ldemul.h
+++ b/ld/ldemul.h
@@ -96,6 +96,8 @@ extern struct bfd_elf_version_expr *ldemul_new_vers_pattern
   (struct bfd_elf_version_expr *);
 extern void ldemul_extra_map_file_text
   (bfd *, struct bfd_link_info *, FILE *);
+extern void ldemul_do_assignments
+  (void);
 
 typedef struct ld_emulation_xfer_struct {
   /* Run before parsing the command line and script file.
@@ -201,6 +203,10 @@ typedef struct ld_emulation_xfer_struct {
   void (*extra_map_file_text)
     (bfd *, struct bfd_link_info *, FILE *);
 
+  /* Called to do assignments.  */
+  void (*do_assignments)
+    (void);
+
 } ld_emulation_xfer_type;
 
 typedef enum {
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 96947da..53d6192 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -5760,6 +5760,8 @@ lang_do_assignments (lang_phase_type phase)
   prefer_next_section = FALSE;
   expld.phase = phase;
   lang_statement_iteration++;
+  if (phase == lang_mark_phase_enum)
+    ldemul_do_assignments ();
   lang_do_assignments_1 (statement_list.head,
 			 abs_output_section, NULL, 0, &found_end);
 }
-- 
2.5.5


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