This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH] x86: Properly handle __ehdr_start
- From: "H.J. Lu" <hongjiu dot lu at intel dot com>
- To: binutils at sourceware dot org
- Date: Fri, 8 Sep 2017 14:34:32 -0700
- Subject: [PATCH] x86: Properly handle __ehdr_start
- Authentication-results: sourceware.org; auth=none
- Reply-to: "H.J. Lu" <hjl dot tools at gmail dot com>
After _bfd_i386_elf_convert_load and _bfd_x86_64_elf_convert_load are
removed, elf_i386_convert_load_reloc and elf_x86_64_convert_load_reloc
see __ehdr_start as an undefined symbol when they are called from
check_relocs to convert GOT relocations against local symbols. But
__ehdr_start will be defined as a hidden symbol by linker at the later
stage if it is referenced. This patch marks __ehdr_start as a defined
local symbol at the start of check_relocs if it is referenced and not
defined.
bfd/
PR ld/22115
* elf32-i386.c (elf_i386_convert_load_reloc): Check linker_def.
Don't use UNDEFINED_WEAK_RESOLVED_TO_ZERO.
* elf64-x86-64.c (elf_x86_64_convert_load_reloc): Check
linker_def. Don't use UNDEFINED_WEAK_RESOLVED_TO_ZERO.
* elfxx-x86.c (_bfd_x86_elf_link_check_relocs): Set local_ref
and linker_def on __ehdr_start if it is referenced and not
defined.
(_bfd_x86_elf_link_symbol_references_local): Also set local_ref
and return TRUE when building executable, if a symbol has
non-GOT/non-PLT relocations in text section or there is no
dynamic linker.
* elfxx-x86.h (elf_x86_link_hash_entry): Add linker_def.
ld/
PR ld/22115
* ld-i386/i386.exp: Run PR ld/22115 tests,
* ld/testsuite/ld-x86-64/x86-64.exp: Likewise.
* testsuite/ld-i386/pr22115-1.s: New file.
* testsuite/ld-i386/pr22115-1a.d: Likewise.
* testsuite/ld-i386/pr22115-1b.d: Likewise.
* testsuite/ld-x86-64/pr22115-1.s: Likewise.
* testsuite/ld-x86-64/pr22115-1a-x32.d: Likewise.
* testsuite/ld-x86-64/pr22115-1a.d: Likewise.
* testsuite/ld-x86-64/pr22115-1b-x32.d: Likewise.
* testsuite/ld-x86-64/pr22115-1b.d: Likewise.
---
bfd/elf32-i386.c | 20 +++++++++++------
bfd/elf64-x86-64.c | 16 ++++++++-----
bfd/elfxx-x86.c | 40 ++++++++++++++++++++++++++-------
bfd/elfxx-x86.h | 3 +++
ld/testsuite/ld-i386/i386.exp | 2 ++
ld/testsuite/ld-i386/pr22115-1.s | 7 ++++++
ld/testsuite/ld-i386/pr22115-1a.d | 13 +++++++++++
ld/testsuite/ld-i386/pr22115-1b.d | 6 +++++
ld/testsuite/ld-x86-64/pr22115-1.s | 7 ++++++
ld/testsuite/ld-x86-64/pr22115-1a-x32.d | 13 +++++++++++
ld/testsuite/ld-x86-64/pr22115-1a.d | 13 +++++++++++
ld/testsuite/ld-x86-64/pr22115-1b-x32.d | 6 +++++
ld/testsuite/ld-x86-64/pr22115-1b.d | 6 +++++
ld/testsuite/ld-x86-64/x86-64.exp | 4 ++++
14 files changed, 136 insertions(+), 20 deletions(-)
create mode 100644 ld/testsuite/ld-i386/pr22115-1.s
create mode 100644 ld/testsuite/ld-i386/pr22115-1a.d
create mode 100644 ld/testsuite/ld-i386/pr22115-1b.d
create mode 100644 ld/testsuite/ld-x86-64/pr22115-1.s
create mode 100644 ld/testsuite/ld-x86-64/pr22115-1a-x32.d
create mode 100644 ld/testsuite/ld-x86-64/pr22115-1a.d
create mode 100644 ld/testsuite/ld-x86-64/pr22115-1b-x32.d
create mode 100644 ld/testsuite/ld-x86-64/pr22115-1b.d
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index dcf07d95d8..0100662040 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -1229,6 +1229,8 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
unsigned int r_type;
unsigned int r_symndx;
bfd_vma roff = irel->r_offset;
+ bfd_boolean local_ref;
+ struct elf_x86_link_hash_entry *eh;
if (roff < 2)
return TRUE;
@@ -1276,6 +1278,8 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
register. */
to_reloc_32 = !is_pic || baseless;
+ eh = elf_x86_hash_entry (h);
+
/* Try to convert R_386_GOT32X. Get the symbol referred to by the
reloc. */
if (h == NULL)
@@ -1290,10 +1294,14 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
goto convert_load;
}
+ /* NB: Also set linker_def via SYMBOL_REFERENCES_LOCAL_P. */
+ local_ref = SYMBOL_REFERENCES_LOCAL_P (link_info, h);
+
/* Undefined weak symbol is only bound locally in executable
and its reference is resolved as 0. */
- if (UNDEFINED_WEAK_RESOLVED_TO_ZERO (link_info, I386_ELF_DATA, TRUE,
- elf_x86_hash_entry (h)))
+ if (h->root.type == bfd_link_hash_undefweak
+ && !eh->linker_def
+ && local_ref)
{
if (opcode == 0xff)
{
@@ -1316,16 +1324,13 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
/* We have "call/jmp *foo@GOT[(%reg)]". */
if ((h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
- && SYMBOL_REFERENCES_LOCAL_P (link_info, h))
+ && local_ref)
{
/* The function is locally defined. */
convert_branch:
/* Convert R_386_GOT32X to R_386_PC32. */
if (modrm == 0x15 || (modrm & 0xf8) == 0x90)
{
- struct elf_x86_link_hash_entry *eh
- = (struct elf_x86_link_hash_entry *) h;
-
/* Convert to "nop call foo". ADDR_PREFIX_OPCODE
is a nop prefix. */
modrm = 0xe8;
@@ -1381,10 +1386,11 @@ convert_branch:
bfd_elf_record_link_assignment. start_stop is set on
__start_SECNAME/__stop_SECNAME which mark section SECNAME. */
if (h->start_stop
+ || eh->linker_def
|| ((h->def_regular
|| h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
- && SYMBOL_REFERENCES_LOCAL_P (link_info, h)))
+ && local_ref))
{
convert_load:
if (opcode == 0x8b)
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index cab086db05..4faa78bf52 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -1537,11 +1537,15 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
GOTPCRELX relocations since we need to modify REX byte.
It is OK convert mov with R_X86_64_GOTPCREL to
R_X86_64_PC32. */
+ bfd_boolean local_ref;
+ struct elf_x86_link_hash_entry *eh = elf_x86_hash_entry (h);
+
+ /* NB: Also set linker_def via SYMBOL_REFERENCES_LOCAL_P. */
+ local_ref = SYMBOL_REFERENCES_LOCAL_P (link_info, h);
if ((relocx || opcode == 0x8b)
- && UNDEFINED_WEAK_RESOLVED_TO_ZERO (link_info,
- X86_64_ELF_DATA,
- TRUE,
- elf_x86_hash_entry (h)))
+ && (h->root.type == bfd_link_hash_undefweak
+ && !eh->linker_def
+ && local_ref))
{
if (opcode == 0xff)
{
@@ -1568,11 +1572,12 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
/* Avoid optimizing GOTPCREL relocations againt _DYNAMIC since
ld.so may use its link-time address. */
else if (h->start_stop
+ || eh->linker_def
|| ((h->def_regular
|| h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
&& h != htab->elf.hdynamic
- && SYMBOL_REFERENCES_LOCAL_P (link_info, h)))
+ && local_ref))
{
/* bfd_link_hash_new or bfd_link_hash_undefined is
set by an assignment in a linker script in
@@ -1580,6 +1585,7 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
on __start_SECNAME/__stop_SECNAME which mark section
SECNAME. */
if (h->start_stop
+ || eh->linker_def
|| (h->def_regular
&& (h->root.type == bfd_link_hash_new
|| h->root.type == bfd_link_hash_undefined
diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
index 86e26f9852..828ce91314 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -845,12 +845,28 @@ _bfd_x86_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
htab = elf_x86_hash_table (info, bed->target_id);
if (htab)
{
- struct elf_link_hash_entry *h
- = elf_link_hash_lookup (elf_hash_table (info),
+ struct elf_link_hash_entry *h;
+
+ h = elf_link_hash_lookup (elf_hash_table (info),
htab->tls_get_addr,
FALSE, FALSE, FALSE);
if (h != NULL)
- ((struct elf_x86_link_hash_entry *) h)->tls_get_addr = 1;
+ elf_x86_hash_entry (h)->tls_get_addr = 1;
+
+ /* "__ehdr_start" will be defined by linker as a hidden symbol
+ later if it is referenced and not defined. */
+ h = elf_link_hash_lookup (elf_hash_table (info),
+ "__ehdr_start",
+ FALSE, FALSE, FALSE);
+ 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))
+ {
+ elf_x86_hash_entry (h)->local_ref = 2;
+ elf_x86_hash_entry (h)->linker_def = 1;
+ }
}
}
@@ -1671,8 +1687,9 @@ bfd_boolean
_bfd_x86_elf_link_symbol_references_local (struct bfd_link_info *info,
struct elf_link_hash_entry *h)
{
- struct elf_x86_link_hash_entry *eh
- = (struct elf_x86_link_hash_entry *) h;
+ struct elf_x86_link_hash_entry *eh = elf_x86_hash_entry (h);
+ struct elf_x86_link_hash_table *htab
+ = (struct elf_x86_link_hash_table *) info->hash;
if (eh->local_ref > 1)
return TRUE;
@@ -1681,11 +1698,18 @@ _bfd_x86_elf_link_symbol_references_local (struct bfd_link_info *info,
return FALSE;
/* Unversioned symbols defined in regular objects can be forced local
- by linker version script. A weak undefined symbol can fored local
- if it has non-default visibility or "-z nodynamic-undefined-weak"
- is used. */
+ by linker version script. A weak undefined symbol is forced local
+ if
+ 1. It has non-default visibility. Or
+ 2. When building executable, it has non-GOT/non-PLT relocations
+ in text section or there is no dynamic linker. Or
+ 3. or "-z nodynamic-undefined-weak" is used.
+ */
if (SYMBOL_REFERENCES_LOCAL (info, h)
|| ((ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ || (bfd_link_executable (info)
+ && (htab->interp == NULL
+ || eh->has_non_got_reloc))
|| info->dynamic_undefined_weak == 0)
&& h->root.type == bfd_link_hash_undefweak)
|| ((h->def_regular || ELF_COMMON_DEF_P (h))
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index ccc72dabf5..57f7862151 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -108,6 +108,9 @@ struct elf_x86_link_hash_entry
*/
unsigned int local_ref : 2;
+ /* TRUE if symbol is defined by linker. */
+ unsigned int linker_def : 1;
+
/* Terue if symbol is referenced by R_386_GOTOFF relocation. This is
only used by i386. */
unsigned int gotoff_ref : 1;
diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp
index bd1561024c..6f5be51e69 100644
--- a/ld/testsuite/ld-i386/i386.exp
+++ b/ld/testsuite/ld-i386/i386.exp
@@ -440,6 +440,8 @@ run_dump_test "pie1"
run_dump_test "pie1-nacl"
run_dump_test "pr21884"
run_dump_test "pr21884-nacl"
+run_dump_test "pr22115-1a"
+run_dump_test "pr22115-1b"
if { !([istarget "i?86-*-linux*"]
|| [istarget "i?86-*-gnu*"]
diff --git a/ld/testsuite/ld-i386/pr22115-1.s b/ld/testsuite/ld-i386/pr22115-1.s
new file mode 100644
index 0000000000..341eedec89
--- /dev/null
+++ b/ld/testsuite/ld-i386/pr22115-1.s
@@ -0,0 +1,7 @@
+ .text
+ .globl _start
+ .type _start, @function
+_start:
+ movl __ehdr_start@GOT(%eax), %eax
+ .size _start, .-_start
+ .weak __ehdr_start
diff --git a/ld/testsuite/ld-i386/pr22115-1a.d b/ld/testsuite/ld-i386/pr22115-1a.d
new file mode 100644
index 0000000000..4857952b65
--- /dev/null
+++ b/ld/testsuite/ld-i386/pr22115-1a.d
@@ -0,0 +1,13 @@
+#source: pr22115-1.s
+#as: --32 -mrelax-relocations=yes
+#ld: -pie -z text -m elf_i386
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+[a-f0-9]+ <_start>:
+ +[a-f0-9]+: 8d 80 ([0-9a-f]{2} ){4} * lea -?0x[a-f0-9]+\(%eax\),%eax
+#pass
diff --git a/ld/testsuite/ld-i386/pr22115-1b.d b/ld/testsuite/ld-i386/pr22115-1b.d
new file mode 100644
index 0000000000..bb05851678
--- /dev/null
+++ b/ld/testsuite/ld-i386/pr22115-1b.d
@@ -0,0 +1,6 @@
+#source: pr22115-1.s
+#as: --32 -mrelax-relocations=yes
+#ld: -pie -z text -m elf_i386
+#readelf: -r
+
+There are no relocations in this file.
diff --git a/ld/testsuite/ld-x86-64/pr22115-1.s b/ld/testsuite/ld-x86-64/pr22115-1.s
new file mode 100644
index 0000000000..8c01e5065e
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22115-1.s
@@ -0,0 +1,7 @@
+ .text
+ .globl _start
+ .type _start, @function
+_start:
+ movq __ehdr_start@GOTPCREL(%rip), %rax
+ .size _start, .-_start
+ .weak __ehdr_start
diff --git a/ld/testsuite/ld-x86-64/pr22115-1a-x32.d b/ld/testsuite/ld-x86-64/pr22115-1a-x32.d
new file mode 100644
index 0000000000..8232589211
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22115-1a-x32.d
@@ -0,0 +1,13 @@
+#source: pr22115-1.s
+#as: --x32 -mrelax-relocations=yes
+#ld: -pie -z text -m elf32_x86_64
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+[a-f0-9]+ <_start>:
+ +[a-f0-9]+: 48 8d 05 ([0-9a-f]{2} ){4} * lea -?0x[a-f0-9]+\(%rip\),%rax # [a-f0-9]+ <__ehdr_start>
+#pass
diff --git a/ld/testsuite/ld-x86-64/pr22115-1a.d b/ld/testsuite/ld-x86-64/pr22115-1a.d
new file mode 100644
index 0000000000..43dc787a53
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22115-1a.d
@@ -0,0 +1,13 @@
+#source: pr22115-1.s
+#as: --64 -mrelax-relocations=yes
+#ld: -pie -z text -m elf_x86_64
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+[a-f0-9]+ <_start>:
+ +[a-f0-9]+: 48 8d 05 ([0-9a-f]{2} ){4} * lea -?0x[a-f0-9]+\(%rip\),%rax # [a-f0-9]+ <__ehdr_start>
+#pass
diff --git a/ld/testsuite/ld-x86-64/pr22115-1b-x32.d b/ld/testsuite/ld-x86-64/pr22115-1b-x32.d
new file mode 100644
index 0000000000..949dc5f836
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22115-1b-x32.d
@@ -0,0 +1,6 @@
+#source: pr22115-1.s
+#as: --x32 -mrelax-relocations=yes
+#ld: -pie -z text -m elf32_x86_64
+#readelf: -r
+
+There are no relocations in this file.
diff --git a/ld/testsuite/ld-x86-64/pr22115-1b.d b/ld/testsuite/ld-x86-64/pr22115-1b.d
new file mode 100644
index 0000000000..f1aaf72663
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22115-1b.d
@@ -0,0 +1,6 @@
+#source: pr22115-1.s
+#as: --64 -mrelax-relocations=yes
+#ld: -pie -z text -m elf_x86_64
+#readelf: -r
+
+There are no relocations in this file.
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index 46b3ec7979..59fbc8b117 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -369,6 +369,10 @@ run_dump_test "property-x86-shstk5-x32"
run_dump_test "pr21884"
run_dump_test "pr21884-nacl"
run_dump_test "pr22071"
+run_dump_test "pr22115-1a"
+run_dump_test "pr22115-1a-x32"
+run_dump_test "pr22115-1b"
+run_dump_test "pr22115-1b-x32"
if { ![istarget "x86_64-*-linux*"] && ![istarget "x86_64-*-nacl*"]} {
return
--
2.13.5