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 4:10 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> 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.

This patch enables the do_assignments hook only if
CALL_LDEMUL_DO_ASSIGNMENTS is yes.

Any comments, feedbacks?

Thanks.

-- 
H.J.
From 50b32e4612460486ec4dc99bedefca057ae7c868 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.
	* emulparams/elf32_x86_64.sh (CALL_LDEMUL_DO_ASSIGNMENTS): New.
	* emulparams/elf_i386.sh (CALL_LDEMUL_DO_ASSIGNMENTS): Likewise.
	* emulparams/elf_i386_be.sh (CALL_LDEMUL_DO_ASSIGNMENTS):
	Likewise.
	* emulparams/elf_i386_chaos.sh (CALL_LDEMUL_DO_ASSIGNMENTS):
	Likewise.
	* emulparams/elf_i386_ldso.sh (CALL_LDEMUL_DO_ASSIGNMENTS):
	Likewise.
	* emulparams/elf_i386_vxworks.sh (CALL_LDEMUL_DO_ASSIGNMENTS):
	Likewise.
	* emulparams/elf_iamcu.sh (CALL_LDEMUL_DO_ASSIGNMENTS):
	Likewise.
	* emulparams/elf_k1om.sh (CALL_LDEMUL_DO_ASSIGNMENTS): Likewise.
	* emulparams/elf_l1om.sh (CALL_LDEMUL_DO_ASSIGNMENTS): Likewise.
	* emulparams/elf_x86_64.sh (CALL_LDEMUL_DO_ASSIGNMENTS):
	Likewise.
	* emulparams/i386nto.sh (CALL_LDEMUL_DO_ASSIGNMENTS): Likewise.
	* 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}_process_assignments): Likewise.
	(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}_process_assignments
	at the start.  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/emulparams/elf32_x86_64.sh     |   1 +
 ld/emulparams/elf_i386.sh         |   1 +
 ld/emulparams/elf_i386_be.sh      |   1 +
 ld/emulparams/elf_i386_chaos.sh   |   1 +
 ld/emulparams/elf_i386_ldso.sh    |   1 +
 ld/emulparams/elf_i386_vxworks.sh |   1 +
 ld/emulparams/elf_iamcu.sh        |   1 +
 ld/emulparams/elf_k1om.sh         |   1 +
 ld/emulparams/elf_l1om.sh         |   1 +
 ld/emulparams/elf_x86_64.sh       |   1 +
 ld/emulparams/i386nto.sh          |   1 +
 ld/emultempl/aix.em               |   3 +-
 ld/emultempl/armcoff.em           |   3 +-
 ld/emultempl/beos.em              |   3 +-
 ld/emultempl/elf32.em             | 167 +++++++++++++++++++++++++-------------
 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 +
 32 files changed, 296 insertions(+), 72 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/emulparams/elf32_x86_64.sh b/ld/emulparams/elf32_x86_64.sh
index 9050730..4fdcffe 100644
--- a/ld/emulparams/elf32_x86_64.sh
+++ b/ld/emulparams/elf32_x86_64.sh
@@ -7,6 +7,7 @@ SCRIPT_NAME=elf
 ELFSIZE=32
 OUTPUT_FORMAT="elf32-x86-64"
 CHECK_RELOCS_AFTER_OPEN_INPUT=yes
+CALL_LDEMUL_DO_ASSIGNMENTS=yes
 NO_REL_RELOCS=yes
 TEXT_START_ADDR=0x400000
 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
diff --git a/ld/emulparams/elf_i386.sh b/ld/emulparams/elf_i386.sh
index b08e661..eade55b 100644
--- a/ld/emulparams/elf_i386.sh
+++ b/ld/emulparams/elf_i386.sh
@@ -5,6 +5,7 @@
 SCRIPT_NAME=elf
 OUTPUT_FORMAT="elf32-i386"
 CHECK_RELOCS_AFTER_OPEN_INPUT=yes
+CALL_LDEMUL_DO_ASSIGNMENTS=yes
 NO_RELA_RELOCS=yes
 TEXT_START_ADDR=0x08048000
 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
diff --git a/ld/emulparams/elf_i386_be.sh b/ld/emulparams/elf_i386_be.sh
index 4a24b02..f13d0c9 100644
--- a/ld/emulparams/elf_i386_be.sh
+++ b/ld/emulparams/elf_i386_be.sh
@@ -4,6 +4,7 @@
 SCRIPT_NAME=elf
 OUTPUT_FORMAT="elf32-i386"
 CHECK_RELOCS_AFTER_OPEN_INPUT=yes
+CALL_LDEMUL_DO_ASSIGNMENTS=yes
 NO_RELA_RELOCS=yes
 TEXT_START_ADDR=0x80000000
 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
diff --git a/ld/emulparams/elf_i386_chaos.sh b/ld/emulparams/elf_i386_chaos.sh
index 5349108..970debd 100644
--- a/ld/emulparams/elf_i386_chaos.sh
+++ b/ld/emulparams/elf_i386_chaos.sh
@@ -5,6 +5,7 @@
 SCRIPT_NAME=elf_chaos
 OUTPUT_FORMAT="elf32-i386"
 CHECK_RELOCS_AFTER_OPEN_INPUT=yes
+CALL_LDEMUL_DO_ASSIGNMENTS=yes
 TEXT_START_ADDR=0x40000000
 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
 ARCH=i386
diff --git a/ld/emulparams/elf_i386_ldso.sh b/ld/emulparams/elf_i386_ldso.sh
index dc4eef4..c89829d 100644
--- a/ld/emulparams/elf_i386_ldso.sh
+++ b/ld/emulparams/elf_i386_ldso.sh
@@ -5,6 +5,7 @@
 SCRIPT_NAME=elf
 OUTPUT_FORMAT="elf32-i386"
 CHECK_RELOCS_AFTER_OPEN_INPUT=yes
+CALL_LDEMUL_DO_ASSIGNMENTS=yes
 NO_RELA_RELOCS=yes
 TEXT_START_ADDR=0x08048000
 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
diff --git a/ld/emulparams/elf_i386_vxworks.sh b/ld/emulparams/elf_i386_vxworks.sh
index ac1bbeb..a9da03e 100644
--- a/ld/emulparams/elf_i386_vxworks.sh
+++ b/ld/emulparams/elf_i386_vxworks.sh
@@ -1,6 +1,7 @@
 SCRIPT_NAME=elf
 OUTPUT_FORMAT="elf32-i386-vxworks"
 CHECK_RELOCS_AFTER_OPEN_INPUT=yes
+CALL_LDEMUL_DO_ASSIGNMENTS=yes
 NO_RELA_RELOCS=yes
 TEXT_START_ADDR=0x08048000
 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
diff --git a/ld/emulparams/elf_iamcu.sh b/ld/emulparams/elf_iamcu.sh
index 45953e7..29c0e60 100644
--- a/ld/emulparams/elf_iamcu.sh
+++ b/ld/emulparams/elf_iamcu.sh
@@ -5,6 +5,7 @@
 SCRIPT_NAME=elf
 OUTPUT_FORMAT="elf32-iamcu"
 CHECK_RELOCS_AFTER_OPEN_INPUT=yes
+CALL_LDEMUL_DO_ASSIGNMENTS=yes
 NO_RELA_RELOCS=yes
 TEXT_START_ADDR=0x08048000
 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
diff --git a/ld/emulparams/elf_k1om.sh b/ld/emulparams/elf_k1om.sh
index 828c10e..c62741d 100644
--- a/ld/emulparams/elf_k1om.sh
+++ b/ld/emulparams/elf_k1om.sh
@@ -6,6 +6,7 @@ SCRIPT_NAME=elf
 ELFSIZE=64
 OUTPUT_FORMAT="elf64-k1om"
 CHECK_RELOCS_AFTER_OPEN_INPUT=yes
+CALL_LDEMUL_DO_ASSIGNMENTS=yes
 NO_REL_RELOCS=yes
 TEXT_START_ADDR=0x400000
 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
diff --git a/ld/emulparams/elf_l1om.sh b/ld/emulparams/elf_l1om.sh
index 9c59dc0..c82eb5a 100644
--- a/ld/emulparams/elf_l1om.sh
+++ b/ld/emulparams/elf_l1om.sh
@@ -6,6 +6,7 @@ SCRIPT_NAME=elf
 ELFSIZE=64
 OUTPUT_FORMAT="elf64-l1om"
 CHECK_RELOCS_AFTER_OPEN_INPUT=yes
+CALL_LDEMUL_DO_ASSIGNMENTS=yes
 NO_REL_RELOCS=yes
 TEXT_START_ADDR=0x400000
 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
diff --git a/ld/emulparams/elf_x86_64.sh b/ld/emulparams/elf_x86_64.sh
index 6055204..5c2f36b 100644
--- a/ld/emulparams/elf_x86_64.sh
+++ b/ld/emulparams/elf_x86_64.sh
@@ -7,6 +7,7 @@ SCRIPT_NAME=elf
 ELFSIZE=64
 OUTPUT_FORMAT="elf64-x86-64"
 CHECK_RELOCS_AFTER_OPEN_INPUT=yes
+CALL_LDEMUL_DO_ASSIGNMENTS=yes
 NO_REL_RELOCS=yes
 TEXT_START_ADDR=0x400000
 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
diff --git a/ld/emulparams/i386nto.sh b/ld/emulparams/i386nto.sh
index 51284be..9f24f3c 100644
--- a/ld/emulparams/i386nto.sh
+++ b/ld/emulparams/i386nto.sh
@@ -1,6 +1,7 @@
 SCRIPT_NAME=elf
 OUTPUT_FORMAT="elf32-i386"
 CHECK_RELOCS_AFTER_OPEN_INPUT=yes
+CALL_LDEMUL_DO_ASSIGNMENTS=yes
 NO_RELA_RELOCS=yes
 TEXT_START_ADDR=0x08048000
 TEXT_START_SYMBOLS='_btext = .;'
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..99086b7 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,112 @@ 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
+
+  if test x"$CALL_LDEMUL_DO_ASSIGNMENTS" = xyes; then
+fragment <<EOF
+static void
+gld${EMULATION_NAME}_process_assignments (void)
+{
+}
+
+EOF
+  else
+  # Call gld${EMULATION_NAME}_do_assignments from
+  # gld${EMULATION_NAME}_process_assignments.
+fragment <<EOF
+static void
+gld${EMULATION_NAME}_process_assignments (void)
+{
+  gld${EMULATION_NAME}_do_assignments ();
+}
+
+EOF
+  # Don't call gld${EMULATION_NAME}_do_assignments from the
+  # do_assignments hook.
+  LDEMUL_DO_ASSIGNMENTS=NULL
+  fi
+else
+fragment <<EOF
+
+static void
+gld${EMULATION_NAME}_process_assignments (void)
+{
+}
+
+static void
+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 +1561,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,54 +1570,11 @@ 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);
+      gld${EMULATION_NAME}_process_assignments ();
     }
 
   /* Let the ELF backend work out the sizes of any sections required
@@ -1627,13 +1685,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 +2579,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 1cbba39..770a2f1 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]