This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [PATCH] Add a do_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, 5 May 2016 09:26:43 -0700
- Subject: Re: [PATCH] Add a do_assignments hook to ldemul
- Authentication-results: sourceware.org; auth=none
- References: <CAMe9rOqC0dMFQkD2+-uvpLh+9zzS2FSbazPab9JqayJOCiVRzw at mail dot gmail dot com> <CAMe9rOo1H=m9P7Je8UgBy5Y_Xw=A5_-onmHjbUhpDy4tBiNqfg at mail dot gmail dot com> <CAMe9rOq_5gRm_N=rB7B-DJY9KYXxFL5ObhtTD_EdkgZ_LtMESg at mail dot gmail dot com>
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