aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2017-09-09 05:05:16 -0700
committerH.J. Lu <hjl.tools@gmail.com>2017-09-09 05:05:29 -0700
commit0a27fed72d4190cc70025c671b5133e6c58d9c09 (patch)
tree3d9d0bc8ad47eba702a00a23ebd00c8e64da165c /bfd
parent90d499086b5d35ac5b58c925f23513f6af2c3639 (diff)
downloadgdb-0a27fed72d4190cc70025c671b5133e6c58d9c09.zip
gdb-0a27fed72d4190cc70025c671b5133e6c58d9c09.tar.gz
gdb-0a27fed72d4190cc70025c671b5133e6c58d9c09.tar.bz2
x86: Properly handle __ehdr_start
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-i386/pr22115-1c.d: Likewise. * testsuite/ld-i386/pr22115-1d.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. * testsuite/ld-x86-64/pr22115-1c-x32.d: Likewise. * testsuite/ld-x86-64/pr22115-1c.d: Likewise. * testsuite/ld-x86-64/pr22115-1d-x32.d: Likewise. * testsuite/ld-x86-64/pr22115-1d.d: Likewise.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog16
-rw-r--r--bfd/elf32-i386.c20
-rw-r--r--bfd/elf64-x86-64.c16
-rw-r--r--bfd/elfxx-x86.c45
-rw-r--r--bfd/elfxx-x86.h3
5 files changed, 77 insertions, 23 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 99c4503..9549e84 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,19 @@
+2017-09-09 H.J. Lu <hongjiu.lu@intel.com>
+
+ 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.
+
2017-09-08 H.J. Lu <hongjiu.lu@intel.com>
* elfxx-x86.h: Update comments.
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index dcf07d9..0100662 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 cab086d..4faa78b 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 86e26f9..e056c3c 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,13 +1698,19 @@ _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
- || info->dynamic_undefined_weak == 0)
- && h->root.type == bfd_link_hash_undefweak)
+ || (h->root.type == bfd_link_hash_undefweak
+ && (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->def_regular || ELF_COMMON_DEF_P (h))
&& h->versioned == unversioned
&& info->version_info != NULL
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index ccc72da..57f7862 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;