This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH] Add a record_link_assignments hook to ldemul
- From: "H.J. Lu" <hjl dot tools at gmail dot com>
- To: Alan Modra <amodra at gmail dot com>
- Cc: Nick Clifton <nickc at redhat dot com>, Binutils <binutils at sourceware dot org>
- Date: Thu, 28 Apr 2016 14:01:47 -0700
- Subject: [PATCH] Add a record_link_assignments hook to ldemul
- Authentication-results: sourceware.org; auth=none
On Thu, Apr 28, 2016 at 10:11 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Thu, Apr 28, 2016 at 6:40 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Thu, Apr 28, 2016 at 6:09 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>> On Thu, Apr 28, 2016 at 6:07 AM, Alan Modra <amodra@gmail.com> wrote:
>>>> On Thu, Apr 28, 2016 at 05:49:57AM -0700, H.J. Lu wrote:
>>>>> On Wed, Apr 27, 2016 at 6:11 PM, Alan Modra <amodra@gmail.com> wrote:
>>>>> > On Wed, Apr 27, 2016 at 03:24:48PM -0700, H.J. Lu wrote:
>>>>> >> bfd_elf_record_link_assignment
>>>>> >> is called after check_relocs. bfd_elf_record_link_assignment sets non_elf,
>>>>> >> def_regular and forced_local. For PROVIDE, it also updates root.type. They
>>>>> >> are needed in reloc_checks.
>>>>> >
>>>>> > My guess is that symbol twiddling done in before_allocation should be
>>>>> > moved to a new ldemul hook called at the start of lang_do_assignments.
>>>>> > The idea being to stabilize symbols earlier.
>>>>> >
>>>>> > The hook would twiddle __ehdr_start and call find_statement_assignment
>>>>> > when lang_mark_phase_enum. Reversing the __ehdr_start twiddle stays
>>>>> > in before_allocation.
>>>>> >
>>>>>
>>>>> I tried this. But it doesn't work with __start/__stop symbols. I
>>>>> need to know if they are defined and referenced local in check_relocs.
>>>> [snip]
>>>>
>>>>> --- a/ld/ldlang.c
>>>>> +++ b/ld/ldlang.c
>>>>> @@ -6930,6 +6930,8 @@ lang_process (void)
>>>>> collection in order to make sure that all symbol aliases are resolved. */
>>>>> lang_do_assignments (lang_mark_phase_enum);
>>>>>
>>>>> + ldemul_record_link_assignments (lang_mark_phase_enum);
>>>>> +
>>>>> lang_do_memory_regions();
>>>>> expld.phase = lang_first_phase_enum;
>>>>
>>>> You'll need to run ldemul_record_link_assignments before
>>>> lang_do_assignments if you want provided symbols to be defined.
>>>
>>> I got many more failures when I did that since many assignments
>>> haven't been processed yet.
>>>
>>>> I suggest renaming to ldemul_do_assignments and putting
>>>> ldemul_do_assignments (phase);
>>>> inside lang_do_assignments just before the call to
>>>> lang_do_assignments_1.
>>>>
>>
>> With this patch, I only got 2 failures on x86-64.
>>
>
> This one works for both i386 and x86-64.
>
This is the complete patch. OK for master?
--
H.J.
From e34bcbafec5ec5181440d4abe9a4f43ca5eb50c8 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 record_link_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 after lang_do_assignments to make sure that assignments
in linker scripts are processed first before updating fields in
elf_link_hash_entry.
bfd/
* elf-bfd.h (_bfd_elf_record_start_stop): New prototype.
* elflink.c (_bfd_elf_is_start_stop): Updated to check symbols
currently defined in dynamic objects.
(elf_link_record_start_stop): New function.
(_bfd_elf_record_start_stop): Likewise.
ld/
* ldemul.c (ldemul_record_link_assignments): New function.
* ldemul.h (ldemul_record_link_assignments): New prototype.
(ld_emulation_xfer_struct): Add record_link_assignments.
* ldlang.c (lang_process): Call ldemul_record_link_assignments
after lang_do_assignments.
* emultempl/aix.em (ld_${EMULATION_NAME}_emulation): Initialize
the record_link_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}_record_link_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 record_link_assignments field with
gld${EMULATION_NAME}_record_link_assignments by default.
---
bfd/elf-bfd.h | 3 +
bfd/elflink.c | 87 ++++++++++++++++++++++-------
ld/emultempl/aix.em | 3 +-
ld/emultempl/armcoff.em | 3 +-
ld/emultempl/beos.em | 3 +-
ld/emultempl/elf32.em | 139 +++++++++++++++++++++++++++--------------------
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 | 3 +
21 files changed, 196 insertions(+), 94 deletions(-)
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 6c05b55..49dc70b 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -2339,6 +2339,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..9395052 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -12230,8 +12230,9 @@ _bfd_elf_gc_mark_hook (asection *sec,
return NULL;
}
-/* For undefined __start_<name> and __stop_<name> symbols, return the
- first input section matching <name>. Return NULL otherwise. */
+/* For __start_<name> and __stop_<name> symbols, return the first
+ input section matching <name> in a regular object. Return NULL
+ otherwise. */
asection *
_bfd_elf_is_start_stop (const struct bfd_link_info *info,
@@ -12239,17 +12240,28 @@ _bfd_elf_is_start_stop (const struct bfd_link_info *info,
{
asection *s;
const char *sec_name;
+ bfd_boolean undefined = (h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak);
- if (h->root.type != bfd_link_hash_undefined
- && h->root.type != bfd_link_hash_undefweak)
- return NULL;
-
- s = h->root.u.undef.section;
- if (s != NULL)
+ if (undefined)
+ {
+ s = h->root.u.undef.section;
+ if (s != NULL)
+ {
+ if (s == (asection *) 0 - 1)
+ return NULL;
+ return s;
+ }
+ }
+ else
{
- if (s == (asection *) 0 - 1)
+ /* 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;
- return s;
+ s = NULL;
}
sec_name = NULL;
@@ -12262,18 +12274,21 @@ _bfd_elf_is_start_stop (const struct bfd_link_info *info,
{
bfd *i;
+ /* Only check regular input files. */
for (i = info->input_bfds; i != NULL; i = i->link.next)
- {
- s = bfd_get_section_by_name (i, sec_name);
- if (s != NULL)
- {
- h->root.u.undef.section = s;
- break;
- }
- }
+ if ((i->flags
+ & (DYNAMIC | BFD_LINKER_CREATED | BFD_PLUGIN)) == 0)
+ {
+ s = bfd_get_section_by_name (i, sec_name);
+ if (s != NULL)
+ {
+ h->root.u.undef.section = s;
+ break;
+ }
+ }
}
- if (s == NULL)
+ if (undefined && s == NULL)
h->root.u.undef.section = (asection *) 0 - 1;
return s;
@@ -13791,3 +13806,37 @@ 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);
}
+
+/* Record __start_<name> and __stop_<name> symbols referenced by
+ regular objects. This is called via elf_link_hash_traverse. */
+
+static bfd_boolean
+elf_link_record_start_stop (struct elf_link_hash_entry *h, void *data)
+{
+ if (!h->def_regular && h->ref_regular)
+ {
+ asection *sec
+ = _bfd_elf_is_start_stop ((struct bfd_link_info *) data, h);
+ if (sec != NULL)
+ {
+ h->def_regular = 1;
+ 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 (h->def_dynamic)
+ h->root.type = bfd_link_hash_undefined;
+ }
+ }
+ 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)
+{
+ elf_link_hash_traverse (elf_hash_table (info),
+ elf_link_record_start_stop, info);
+}
diff --git a/ld/emultempl/aix.em b/ld/emultempl/aix.em
index b9cab4e..b625c44 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 /* record_link_assignments */
};
EOF
diff --git a/ld/emultempl/armcoff.em b/ld/emultempl/armcoff.em
index 387a1f7..adfaa1e 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 /* record_link_assignments */
};
EOF
diff --git a/ld/emultempl/beos.em b/ld/emultempl/beos.em
index 6430102..8f861a8 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 /* record_link_assignments */
};
EOF
diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em
index 4f5d1a4..bb73dff 100644
--- a/ld/emultempl/elf32.em
+++ b/ld/emultempl/elf32.em
@@ -1330,6 +1330,7 @@ fragment <<EOF
EOF
fi
+if test x"$LDEMUL_RECORD_LINK_ASSIGNMENTS" != xgld"$EMULATION_NAME"_record_link_assignments; then
fragment <<EOF
/* Look through an expression for an assignment statement. */
@@ -1398,7 +1399,81 @@ 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}_record_link_assignments (lang_phase_type phase)
+{
+ if (phase == lang_mark_phase_enum
+ && is_elf_hash_table (link_info.hash))
+ {
+ /* 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);
+
+ /* Also let the ELF backend know about __start_<name> and
+ __stop_<name> symbols. */
+ _bfd_elf_record_start_stop (&link_info);
+ }
+}
+
+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 +1530,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 +1539,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 +1651,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 +2545,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_RECORD_LINK_ASSIGNMENTS-gld${EMULATION_NAME}_record_link_assignments},
};
EOF
diff --git a/ld/emultempl/generic.em b/ld/emultempl/generic.em
index 7924cdf..cfe2b94 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_RECORD_LINK_ASSIGNMENTS-NULL}
};
EOF
diff --git a/ld/emultempl/gld960.em b/ld/emultempl/gld960.em
index c4c9c55..3b22d1b 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 /* record_link_assignments */
};
EOF
diff --git a/ld/emultempl/gld960c.em b/ld/emultempl/gld960c.em
index 6b80be2..09b09e9 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 /* record_link_assignments */
};
EOF
diff --git a/ld/emultempl/linux.em b/ld/emultempl/linux.em
index c28e978..cc68c23 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 /* record_link_assignments */
};
EOF
diff --git a/ld/emultempl/lnk960.em b/ld/emultempl/lnk960.em
index 4a2bd72..ea4e133 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 /* record_link_assignments */
};
EOF
diff --git a/ld/emultempl/m68kcoff.em b/ld/emultempl/m68kcoff.em
index 594cd56..dd4af3a 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 /* record_link_assignments */
};
EOF
diff --git a/ld/emultempl/msp430.em b/ld/emultempl/msp430.em
index 22e7c42..41d5a48 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_RECORD_LINK_ASSIGNMENTS-NULL}
};
EOF
#
diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em
index c13fa4d..9d63eac 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 /* record_link_assignments */
};
EOF
diff --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em
index ab7c473..62cfb32 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 /* record_link_assignments */
};
EOF
diff --git a/ld/emultempl/sunos.em b/ld/emultempl/sunos.em
index 8be8669..3f6bb23 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 /* record_link_assignments */
};
EOF
diff --git a/ld/emultempl/ticoff.em b/ld/emultempl/ticoff.em
index 9b5495e..b596b8f 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 /* record_link_assignments */
};
EOF
diff --git a/ld/emultempl/vanilla.em b/ld/emultempl/vanilla.em
index d627dfc..e80189c 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 /* record_link_assignments */
};
EOF
diff --git a/ld/ldemul.c b/ld/ldemul.c
index 841a14d..c1a75f1 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_record_link_assignments (lang_phase_type phase)
+{
+ if (ld_emulation->record_link_assignments)
+ ld_emulation->record_link_assignments (phase);
+}
diff --git a/ld/ldemul.h b/ld/ldemul.h
index 937b1c9..7f823d7 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_record_link_assignments
+ (lang_phase_type);
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 record link assignments. */
+ void (*record_link_assignments)
+ (lang_phase_type);
+
} ld_emulation_xfer_type;
typedef enum {
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 96947da..881d0a3 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -6930,6 +6930,9 @@ lang_process (void)
collection in order to make sure that all symbol aliases are resolved. */
lang_do_assignments (lang_mark_phase_enum);
+ /* Record symbols created by linker and linker scripts. */
+ ldemul_record_link_assignments (lang_mark_phase_enum);
+
lang_do_memory_regions();
expld.phase = lang_first_phase_enum;
--
2.5.5