/* Intel 80386/80486-specific support for 32-bit ELF
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
-#include "bfd.h"
#include "sysdep.h"
+#include "bfd.h"
#include "bfdlink.h"
#include "libbfd.h"
#include "elf-bfd.h"
#include "elf-vxworks.h"
+#include "bfd_stdint.h"
/* 386 uses REL relocations instead of RELA. */
#define USE_REL 1
return 0;
}
-static void
-elf_i386_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
- arelent *cache_ptr,
- Elf_Internal_Rela *dst)
+static reloc_howto_type *
+elf_i386_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ const char *r_name)
+{
+ unsigned int i;
+
+ for (i = 0; i < sizeof (elf_howto_table) / sizeof (elf_howto_table[0]); i++)
+ if (elf_howto_table[i].name != NULL
+ && strcasecmp (elf_howto_table[i].name, r_name) == 0)
+ return &elf_howto_table[i];
+
+ return NULL;
+}
+
+static reloc_howto_type *
+elf_i386_rtype_to_howto (bfd *abfd, unsigned r_type)
{
- unsigned int r_type = ELF32_R_TYPE (dst->r_info);
unsigned int indx;
if ((indx = r_type) >= R_386_standard
abfd, (int) r_type);
indx = R_386_NONE;
}
- cache_ptr->howto = &elf_howto_table[indx];
+ BFD_ASSERT (elf_howto_table [indx].type == r_type);
+ return &elf_howto_table[indx];
+}
+
+static void
+elf_i386_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
+ arelent *cache_ptr,
+ Elf_Internal_Rela *dst)
+{
+ unsigned int r_type = ELF32_R_TYPE (dst->r_info);
+ cache_ptr->howto = elf_i386_rtype_to_howto (abfd, r_type);
}
/* Return whether a symbol name implies a local label. The UnixWare
#define elf_i386_local_tlsdesc_gotent(abfd) \
(elf_i386_tdata (abfd)->local_tlsdesc_gotent)
+#define is_i386_elf(bfd) \
+ (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
+ && elf_tdata (bfd) != NULL \
+ && elf_object_id (bfd) == I386_ELF_TDATA)
+
static bfd_boolean
elf_i386_mkobject (bfd *abfd)
{
- bfd_size_type amt = sizeof (struct elf_i386_obj_tdata);
- abfd->tdata.any = bfd_zalloc (abfd, amt);
- if (abfd->tdata.any == NULL)
- return FALSE;
- return TRUE;
+ return bfd_elf_allocate_object (abfd, sizeof (struct elf_i386_obj_tdata),
+ I386_ELF_TDATA);
}
/* i386 ELF linker hash table. */
/* The (unloaded but important) .rel.plt.unloaded section on VxWorks. */
asection *srelplt2;
- /* Short-cuts to frequently used symbols for VxWorks targets. */
- struct elf_link_hash_entry *hgot, *hplt;
-
/* True if the target system is VxWorks. */
int is_vxworks;
/* Value used to fill the last word of the first plt entry. */
bfd_byte plt0_pad_byte;
+ /* The index of the next unused R_386_TLS_DESC slot in .rel.plt. */
+ bfd_vma next_tls_desc_index;
+
union {
bfd_signed_vma refcount;
bfd_vma offset;
/* Small local sym to section mapping cache. */
struct sym_sec_cache sym_sec;
+
+ /* _TLS_MODULE_BASE_ symbol. */
+ struct bfd_link_hash_entry *tls_module_base;
};
/* Get the i386 ELF linker hash table from a link_info structure. */
((struct elf_i386_link_hash_table *) ((p)->hash))
#define elf_i386_compute_jump_table_size(htab) \
- ((htab)->srelplt->reloc_count * 4)
+ ((htab)->next_tls_desc_index * 4)
/* Create an entry in an i386 ELF linker hash table. */
if (ret == NULL)
return NULL;
- if (! _bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc))
+ if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc,
+ sizeof (struct elf_i386_link_hash_entry)))
{
free (ret);
return NULL;
ret->sdynbss = NULL;
ret->srelbss = NULL;
ret->tls_ldm_got.refcount = 0;
+ ret->next_tls_desc_index = 0;
ret->sgotplt_jump_table_size = 0;
ret->sym_sec.abfd = NULL;
ret->is_vxworks = 0;
ret->srelplt2 = NULL;
- ret->hgot = NULL;
- ret->hplt = NULL;
ret->plt0_pad_byte = 0;
+ ret->tls_module_base = NULL;
return &ret->elf.root;
}
elf_i386_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
{
struct elf_i386_link_hash_table *htab;
- asection * s;
- int flags;
- const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
htab = elf_i386_hash_table (info);
if (!htab->sgot && !create_got_section (dynobj, info))
|| (!info->shared && !htab->srelbss))
abort ();
- if (htab->is_vxworks && !info->shared)
- {
- s = bfd_make_section (dynobj, ".rel.plt.unloaded");
- flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_READONLY
- | SEC_LINKER_CREATED);
- if (s == NULL
- || ! bfd_set_section_flags (dynobj, s, flags)
- || ! bfd_set_section_alignment (dynobj, s, bed->s->log_file_align))
- return FALSE;
- htab->srelplt2 = s;
- }
+ if (htab->is_vxworks
+ && !elf_vxworks_create_dynamic_sections (dynobj, info, &htab->srelplt2))
+ return FALSE;
return TRUE;
}
_bfd_elf_link_hash_copy_indirect (info, dir, ind);
}
-static int
-elf_i386_tls_transition (struct bfd_link_info *info, int r_type, int is_local)
+typedef union
+ {
+ unsigned char c[2];
+ uint16_t i;
+ }
+i386_opcode16;
+
+/* Return TRUE if the TLS access code sequence support transition
+ from R_TYPE. */
+
+static bfd_boolean
+elf_i386_check_tls_transition (bfd *abfd, asection *sec,
+ bfd_byte *contents,
+ Elf_Internal_Shdr *symtab_hdr,
+ struct elf_link_hash_entry **sym_hashes,
+ unsigned int r_type,
+ const Elf_Internal_Rela *rel,
+ const Elf_Internal_Rela *relend)
{
- if (info->shared)
- return r_type;
+ unsigned int val, type;
+ unsigned long r_symndx;
+ struct elf_link_hash_entry *h;
+ bfd_vma offset;
+ /* Get the section contents. */
+ if (contents == NULL)
+ {
+ if (elf_section_data (sec)->this_hdr.contents != NULL)
+ contents = elf_section_data (sec)->this_hdr.contents;
+ else
+ {
+ /* FIXME: How to better handle error condition? */
+ if (!bfd_malloc_and_get_section (abfd, sec, &contents))
+ return FALSE;
+
+ /* Cache the section contents for elf_link_input_bfd. */
+ elf_section_data (sec)->this_hdr.contents = contents;
+ }
+ }
+
+ offset = rel->r_offset;
switch (r_type)
+ {
+ case R_386_TLS_GD:
+ case R_386_TLS_LDM:
+ if (offset < 2 || (rel + 1) >= relend)
+ return FALSE;
+
+ type = bfd_get_8 (abfd, contents + offset - 2);
+ if (r_type == R_386_TLS_GD)
+ {
+ /* Check transition from LD access model. Only
+ leal foo@tlsgd(,%reg,1), %eax; call ___tls_get_addr
+ leal foo@tlsgd(%reg), %eax; call ___tls_get_addr; nop
+ can transit to different access model. */
+ if ((offset + 10) > sec->size ||
+ (type != 0x8d && type != 0x04))
+ return FALSE;
+
+ val = bfd_get_8 (abfd, contents + offset - 1);
+ if (type == 0x04)
+ {
+ /* leal foo@tlsgd(,%reg,1), %eax; call ___tls_get_addr */
+ if (offset < 3)
+ return FALSE;
+
+ if (bfd_get_8 (abfd, contents + offset - 3) != 0x8d)
+ return FALSE;
+
+ if ((val & 0xc7) != 0x05 || val == (4 << 3))
+ return FALSE;
+ }
+ else
+ {
+ /* leal foo@tlsgd(%reg), %eax; call ___tls_get_addr; nop */
+ if ((val & 0xf8) != 0x80 || (val & 7) == 4)
+ return FALSE;
+
+ if (bfd_get_8 (abfd, contents + offset + 9) != 0x90)
+ return FALSE;
+ }
+ }
+ else
+ {
+ /* Check transition from LD access model. Only
+ leal foo@tlsgd(%reg), %eax; call ___tls_get_addr
+ can transit to different access model. */
+ if (type != 0x8d || (offset + 9) > sec->size)
+ return FALSE;
+
+ val = bfd_get_8 (abfd, contents + offset - 1);
+ if ((val & 0xf8) != 0x80 || (val & 7) == 4)
+ return FALSE;
+ }
+
+ if (bfd_get_8 (abfd, contents + offset + 4) != 0xe8)
+ return FALSE;
+
+ r_symndx = ELF32_R_SYM (rel[1].r_info);
+ if (r_symndx < symtab_hdr->sh_info)
+ return FALSE;
+
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ return (h != NULL
+ && h->root.root.string != NULL
+ && (ELF32_R_TYPE (rel[1].r_info) == R_386_PC32
+ || ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32)
+ && (strcmp (h->root.root.string, "___tls_get_addr") == 0));
+
+ case R_386_TLS_IE:
+ /* Check transition from IE access model:
+ movl foo@indntpoff(%rip), %eax
+ movl foo@indntpoff(%rip), %reg
+ addl foo@indntpoff(%rip), %reg
+ */
+
+ if (offset < 1 || (offset + 4) > sec->size)
+ return FALSE;
+
+ /* Check "movl foo@tpoff(%rip), %eax" first. */
+ val = bfd_get_8 (abfd, contents + offset - 1);
+ if (val == 0xa1)
+ return TRUE;
+
+ if (offset < 2)
+ return FALSE;
+
+ /* Check movl|addl foo@tpoff(%rip), %reg. */
+ type = bfd_get_8 (abfd, contents + offset - 2);
+ return ((type == 0x8b || type == 0x03)
+ && (val & 0xc7) == 0x05);
+
+ case R_386_TLS_GOTIE:
+ case R_386_TLS_IE_32:
+ /* Check transition from {IE_32,GOTIE} access model:
+ subl foo@{tpoff,gontoff}(%reg1), %reg2
+ movl foo@{tpoff,gontoff}(%reg1), %reg2
+ addl foo@{tpoff,gontoff}(%reg1), %reg2
+ */
+
+ if (offset < 2 || (offset + 4) > sec->size)
+ return FALSE;
+
+ val = bfd_get_8 (abfd, contents + offset - 1);
+ if ((val & 0xc0) != 0x80 || (val & 7) == 4)
+ return FALSE;
+
+ type = bfd_get_8 (abfd, contents + offset - 2);
+ return type == 0x8b || type == 0x2b || type == 0x03;
+
+ case R_386_TLS_GOTDESC:
+ /* Check transition from GDesc access model:
+ leal x@tlsdesc(%ebx), %eax
+
+ Make sure it's a leal adding ebx to a 32-bit offset
+ into any register, although it's probably almost always
+ going to be eax. */
+
+ if (offset < 2 || (offset + 4) > sec->size)
+ return FALSE;
+
+ if (bfd_get_8 (abfd, contents + offset - 2) != 0x8d)
+ return FALSE;
+
+ val = bfd_get_8 (abfd, contents + offset - 1);
+ return (val & 0xc7) == 0x83;
+
+ case R_386_TLS_DESC_CALL:
+ /* Check transition from GDesc access model:
+ call *x@tlsdesc(%rax)
+ */
+ if (offset + 2 <= sec->size)
+ {
+ /* Make sure that it's a call *x@tlsdesc(%rax). */
+ static i386_opcode16 call = { { 0xff, 0x10 } };
+ return bfd_get_16 (abfd, contents + offset) == call.i;
+ }
+
+ return FALSE;
+
+ default:
+ abort ();
+ }
+}
+
+/* Return TRUE if the TLS access transition is OK or no transition
+ will be performed. Update R_TYPE if there is a transition. */
+
+static bfd_boolean
+elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd,
+ asection *sec, bfd_byte *contents,
+ Elf_Internal_Shdr *symtab_hdr,
+ struct elf_link_hash_entry **sym_hashes,
+ unsigned int *r_type, int tls_type,
+ const Elf_Internal_Rela *rel,
+ const Elf_Internal_Rela *relend,
+ struct elf_link_hash_entry *h)
+{
+ unsigned int from_type = *r_type;
+ unsigned int to_type = from_type;
+ bfd_boolean check = TRUE;
+
+ switch (from_type)
{
case R_386_TLS_GD:
case R_386_TLS_GOTDESC:
case R_386_TLS_DESC_CALL:
case R_386_TLS_IE_32:
- if (is_local)
- return R_386_TLS_LE_32;
- return R_386_TLS_IE_32;
case R_386_TLS_IE:
case R_386_TLS_GOTIE:
- if (is_local)
- return R_386_TLS_LE_32;
- return r_type;
+ if (!info->shared)
+ {
+ if (h == NULL)
+ to_type = R_386_TLS_LE_32;
+ else if (from_type != R_386_TLS_IE
+ && from_type != R_386_TLS_GOTIE)
+ to_type = R_386_TLS_IE_32;
+ }
+
+ /* When we are called from elf_i386_relocate_section, CONTENTS
+ isn't NULL and there may be additional transitions based on
+ TLS_TYPE. */
+ if (contents != NULL)
+ {
+ unsigned int new_to_type = to_type;
+
+ if (!info->shared
+ && h != NULL
+ && h->dynindx == -1
+ && (tls_type & GOT_TLS_IE))
+ new_to_type = R_386_TLS_LE_32;
+
+ if (to_type == R_386_TLS_GD
+ || to_type == R_386_TLS_GOTDESC
+ || to_type == R_386_TLS_DESC_CALL)
+ {
+ if (tls_type == GOT_TLS_IE_POS)
+ new_to_type = R_386_TLS_GOTIE;
+ else if (tls_type & GOT_TLS_IE)
+ new_to_type = R_386_TLS_IE_32;
+ }
+
+ /* We checked the transition before when we were called from
+ elf_i386_check_relocs. We only want to check the new
+ transition which hasn't been checked before. */
+ check = new_to_type != to_type && from_type == to_type;
+ to_type = new_to_type;
+ }
+
+ break;
+
case R_386_TLS_LDM:
- return R_386_TLS_LE_32;
+ if (!info->shared)
+ to_type = R_386_TLS_LE_32;
+ break;
+
+ default:
+ return TRUE;
+ }
+
+ /* Return TRUE if there is no transition. */
+ if (from_type == to_type)
+ return TRUE;
+
+ /* Check if the transition can be performed. */
+ if (check
+ && ! elf_i386_check_tls_transition (abfd, sec, contents,
+ symtab_hdr, sym_hashes,
+ from_type, rel, relend))
+ {
+ reloc_howto_type *from, *to;
+
+ from = elf_i386_rtype_to_howto (abfd, from_type);
+ to = elf_i386_rtype_to_howto (abfd, to_type);
+
+ (*_bfd_error_handler)
+ (_("%B: TLS transition from %s to %s against `%s' at 0x%lx "
+ "in section `%A' failed"),
+ abfd, sec, from->name, to->name,
+ h ? h->root.root.string : "a local symbol",
+ (unsigned long) rel->r_offset);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
}
- return r_type;
+ *r_type = to_type;
+ return TRUE;
}
/* Look through the relocs for a section during the first phase, and
if (info->relocatable)
return TRUE;
+ BFD_ASSERT (is_i386_elf (abfd));
+
htab = elf_i386_hash_table (info);
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ symtab_hdr = &elf_symtab_hdr (abfd);
sym_hashes = elf_sym_hashes (abfd);
sreloc = NULL;
h = (struct elf_link_hash_entry *) h->root.u.i.link;
}
- r_type = elf_i386_tls_transition (info, r_type, h == NULL);
+ if (! elf_i386_tls_transition (info, abfd, sec, NULL,
+ symtab_hdr, sym_hashes,
+ &r_type, GOT_UNKNOWN,
+ rel, rel_end, h))
+ return FALSE;
switch (r_type)
{
&& (sec->flags & SEC_ALLOC) != 0
&& (r_type != R_386_PC32
|| (h != NULL
- && (! info->symbolic
+ && (! SYMBOLIC_BIND (info, h)
|| h->root.type == bfd_link_hash_defweak
|| !h->def_regular))))
|| (ELIMINATE_COPY_RELOCS
if (name == NULL)
return FALSE;
- if (strncmp (name, ".rel", 4) != 0
+ if (! CONST_STRNEQ (name, ".rel")
|| strcmp (bfd_get_section_name (abfd, sec),
name + 4) != 0)
{
/* This relocation describes which C++ vtable entries are actually
used. Record for later use during GC. */
case R_386_GNU_VTENTRY:
- if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
+ BFD_ASSERT (h != NULL);
+ if (h != NULL
+ && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
return FALSE;
break;
static asection *
elf_i386_gc_mark_hook (asection *sec,
- struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info,
Elf_Internal_Rela *rel,
struct elf_link_hash_entry *h,
Elf_Internal_Sym *sym)
{
if (h != NULL)
- {
- switch (ELF32_R_TYPE (rel->r_info))
- {
- case R_386_GNU_VTINHERIT:
- case R_386_GNU_VTENTRY:
- break;
-
- default:
- switch (h->root.type)
- {
- case bfd_link_hash_defined:
- case bfd_link_hash_defweak:
- return h->root.u.def.section;
-
- case bfd_link_hash_common:
- return h->root.u.c.p->section;
-
- default:
- break;
- }
- }
- }
- else
- return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
-
- return NULL;
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_386_GNU_VTINHERIT:
+ case R_386_GNU_VTENTRY:
+ return NULL;
+ }
+
+ return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
}
/* Update the got entry reference counts for the section being removed. */
bfd_signed_vma *local_got_refcounts;
const Elf_Internal_Rela *rel, *relend;
+ if (info->relocatable)
+ return TRUE;
+
elf_section_data (sec)->local_dynrel = NULL;
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ symtab_hdr = &elf_symtab_hdr (abfd);
sym_hashes = elf_sym_hashes (abfd);
local_got_refcounts = elf_local_got_refcounts (abfd);
}
r_type = ELF32_R_TYPE (rel->r_info);
- r_type = elf_i386_tls_transition (info, r_type, h != NULL);
+ if (! elf_i386_tls_transition (info, abfd, sec, NULL,
+ symtab_hdr, sym_hashes,
+ &r_type, GOT_UNKNOWN,
+ rel, relend, h))
+ return FALSE;
+
switch (r_type)
{
case R_386_TLS_LDM:
{
struct elf_i386_link_hash_table *htab;
asection *s;
- unsigned int power_of_two;
/* If this is a function, put it in the procedure linkage table. We
will fill in the contents of the procedure linkage table later,
h->needs_copy = 1;
}
- /* We need to figure out the alignment required for this symbol. I
- have no idea how ELF linkers handle this. */
- power_of_two = bfd_log2 (h->size);
- if (power_of_two > 3)
- power_of_two = 3;
-
- /* Apply the required alignment. */
s = htab->sdynbss;
- s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two));
- if (power_of_two > bfd_get_section_alignment (htab->elf.dynobj, s))
- {
- if (! bfd_set_section_alignment (htab->elf.dynobj, s, power_of_two))
- return FALSE;
- }
-
- /* Define the symbol as being at this point in the section. */
- h->root.u.def.section = s;
- h->root.u.def.value = s->size;
- /* Increment the section size to make room for the symbol. */
- s->size += h->size;
-
- return TRUE;
+ return _bfd_elf_adjust_dynamic_copy (h, s);
}
/* Allocate space in .plt, .got and associated reloc sections for
/* We also need to make an entry in the .rel.plt section. */
htab->srelplt->size += sizeof (Elf32_External_Rel);
- htab->srelplt->reloc_count++;
+ htab->next_tls_desc_index++;
if (htab->is_vxworks && !info->shared)
{
}
}
+ if (htab->is_vxworks)
+ {
+ struct elf_i386_dyn_relocs **pp;
+ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+ {
+ if (strcmp (p->sec->output_section->name, ".tls_vars") == 0)
+ *pp = p->next;
+ else
+ pp = &p->next;
+ }
+ }
+
/* Also discard relocs on undefined weak syms with non-default
- visibility. */
- if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ visibility. */
+ if (eh->dyn_relocs != NULL
&& h->root.type == bfd_link_hash_undefweak)
- eh->dyn_relocs = NULL;
+ {
+ if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+ eh->dyn_relocs = NULL;
+
+ /* Make sure undefined weak symbols are output as a dynamic
+ symbol in PIEs. */
+ else if (h->dynindx == -1
+ && !h->forced_local)
+ {
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
+ }
}
else if (ELIMINATE_COPY_RELOCS)
{
Elf_Internal_Shdr *symtab_hdr;
asection *srel;
- if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+ if (! is_i386_elf (ibfd))
continue;
for (s = ibfd->sections; s != NULL; s = s->next)
linker script /DISCARD/, so we'll be discarding
the relocs too. */
}
+ else if (htab->is_vxworks
+ && strcmp (p->sec->output_section->name,
+ ".tls_vars") == 0)
+ {
+ /* Relocations in vxworks .tls_vars sections are
+ handled specially by the loader. */
+ }
else if (p->count != 0)
{
srel = elf_section_data (p->sec)->sreloc;
if (!local_got)
continue;
- symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
+ symtab_hdr = &elf_symtab_hdr (ibfd);
locsymcount = symtab_hdr->sh_info;
end_local_got = local_got + locsymcount;
local_tls_type = elf_i386_local_got_tls_type (ibfd);
else
htab->tls_ldm_got.offset = -1;
- if (htab->is_vxworks)
- {
- /* Save the GOT and PLT symbols in the hash table for easy access.
- Mark them as having relocations; they might not, but we won't
- know for sure until we build the GOT in finish_dynamic_symbol. */
-
- htab->hgot = elf_link_hash_lookup (elf_hash_table (info),
- "_GLOBAL_OFFSET_TABLE_",
- FALSE, FALSE, FALSE);
- if (htab->hgot)
- htab->hgot->indx = -2;
- htab->hplt = elf_link_hash_lookup (elf_hash_table (info),
- "_PROCEDURE_LINKAGE_TABLE_",
- FALSE, FALSE, FALSE);
- if (htab->hplt)
- htab->hplt->indx = -2;
-
- if (htab->is_vxworks && htab->hplt && htab->splt->flags & SEC_CODE)
- htab->hplt->type = STT_FUNC;
- }
-
/* Allocate global sym .plt and .got entries, and space for global
sym dynamic relocs. */
elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, (PTR) info);
for them, it suffices to multiply the reloc count by the jump
slot size. */
if (htab->srelplt)
- htab->sgotplt_jump_table_size = htab->srelplt->reloc_count * 4;
+ htab->sgotplt_jump_table_size = htab->next_tls_desc_index * 4;
/* We now have determined the sizes of the various dynamic sections.
Allocate memory for them. */
we've exported dynamic symbols from them we must leave them.
It's too late to tell BFD to get rid of the symbols. */
- if (htab->hplt != NULL)
+ if (htab->elf.hplt != NULL)
strip_section = FALSE;
}
- else if (strncmp (bfd_get_section_name (dynobj, s), ".rel", 4) == 0)
+ else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rel"))
{
if (s->size != 0 && s != htab->srelplt && s != htab->srelplt2)
relocs = TRUE;
/* We use the reloc_count field as a counter if we need
to copy relocs into the output file. */
- if (s != htab->srelplt)
- s->reloc_count = 0;
+ s->reloc_count = 0;
}
else
{
return FALSE;
}
}
+ if (htab->is_vxworks
+ && !elf_vxworks_add_dynamic_entries (output_bfd, info))
+ return FALSE;
}
#undef add_dynamic_entry
tls_sec, 0, NULL, FALSE,
bed->collect, &bh)))
return FALSE;
+
+ elf_i386_hash_table (info)->tls_module_base = bh;
+
tlsbase = (struct elf_link_hash_entry *)bh;
tlsbase->def_regular = 1;
tlsbase->other = STV_HIDDEN;
return TRUE;
}
+/* _TLS_MODULE_BASE_ needs to be treated especially when linking
+ executables. Rather than setting it to the beginning of the TLS
+ section, we have to set it to the end. This function may be called
+ multiple times, it is idempotent. */
+
+static void
+set_tls_module_base (struct bfd_link_info *info)
+{
+ struct bfd_link_hash_entry *base;
+
+ if (!info->executable)
+ return;
+
+ base = elf_i386_hash_table (info)->tls_module_base;
+
+ if (!base)
+ return;
+
+ base->u.def.value = elf_hash_table (info)->tls_size;
+}
+
/* Return the base VMA address which should be subtracted from real addresses
when resolving @dtpoff relocation.
This is PT_TLS segment p_vaddr. */
bfd_vma *local_tlsdesc_gotents;
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
+ bfd_boolean is_vxworks_tls;
+ BFD_ASSERT (is_i386_elf (input_bfd));
+
htab = elf_i386_hash_table (info);
- symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ symtab_hdr = &elf_symtab_hdr (input_bfd);
sym_hashes = elf_sym_hashes (input_bfd);
local_got_offsets = elf_local_got_offsets (input_bfd);
local_tlsdesc_gotents = elf_i386_local_tlsdesc_gotent (input_bfd);
+ /* We have to handle relocations in vxworks .tls_vars sections
+ specially, because the dynamic loader is 'weird'. */
+ is_vxworks_tls = (htab->is_vxworks && info->shared
+ && !strcmp (input_section->output_section->name,
+ ".tls_vars"));
+
+ set_tls_module_base (info);
rel = relocs;
relend = relocs + input_section->reloc_count;
howto = elf_howto_table + indx;
r_symndx = ELF32_R_SYM (rel->r_info);
-
- if (info->relocatable)
- {
- bfd_vma val;
- bfd_byte *where;
-
- /* This is a relocatable link. We don't have to change
- anything, unless the reloc is against a section symbol,
- in which case we have to adjust according to where the
- section symbol winds up in the output section. */
- if (r_symndx >= symtab_hdr->sh_info)
- continue;
-
- sym = local_syms + r_symndx;
- if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
- continue;
-
- sec = local_sections[r_symndx];
- val = sec->output_offset;
- if (val == 0)
- continue;
-
- where = contents + rel->r_offset;
- switch (howto->size)
- {
- /* FIXME: overflow checks. */
- case 0:
- val += bfd_get_8 (input_bfd, where);
- bfd_put_8 (input_bfd, val, where);
- break;
- case 1:
- val += bfd_get_16 (input_bfd, where);
- bfd_put_16 (input_bfd, val, where);
- break;
- case 2:
- val += bfd_get_32 (input_bfd, where);
- bfd_put_32 (input_bfd, val, where);
- break;
- default:
- abort ();
- }
- continue;
- }
-
- /* This is a final link. */
h = NULL;
sym = NULL;
sec = NULL;
relocation = (sec->output_section->vma
+ sec->output_offset
+ sym->st_value);
- if ((sec->flags & SEC_MERGE)
- && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+
+ if (ELF_ST_TYPE (sym->st_info) == STT_SECTION
+ && ((sec->flags & SEC_MERGE) != 0
+ || (info->relocatable
+ && sec->output_offset != 0)))
{
- asection *msec;
bfd_vma addend;
bfd_byte *where = contents + rel->r_offset;
abort ();
}
- msec = sec;
- addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend);
- addend -= relocation;
- addend += msec->output_section->vma + msec->output_offset;
+ if (info->relocatable)
+ addend += sec->output_offset;
+ else
+ {
+ asection *msec = sec;
+ addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec,
+ addend);
+ addend -= relocation;
+ addend += msec->output_section->vma + msec->output_offset;
+ }
switch (howto->size)
{
unresolved_reloc, warned);
}
- if (r_symndx == 0)
+ if (sec != NULL && elf_discarded_section (sec))
{
- /* r_symndx will be zero only for relocs against symbols from
- removed linkonce sections, or sections discarded by a linker
- script. For these relocs, we just want the section contents
- zeroed. Avoid any special processing in the switch below. */
- r_type = R_386_NONE;
-
- relocation = 0;
- if (howto->pc_relative)
- relocation = (input_section->output_section->vma
- + input_section->output_offset
- + rel->r_offset);
+ /* For relocs against symbols from removed linkonce sections,
+ or sections discarded by a linker script, we just want the
+ section contents zeroed. Avoid any special processing. */
+ _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
+ rel->r_info = 0;
+ rel->r_addend = 0;
+ continue;
}
+ if (info->relocatable)
+ continue;
+
switch (r_type)
{
case R_386_GOT32:
/* Check to make sure it isn't a protected function symbol
for shared library since it may not be local when used
- as function address. */
- if (info->shared
- && !info->executable
- && h
- && h->def_regular
- && h->type == STT_FUNC
- && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED)
+ as function address. We also need to make sure that a
+ symbol is defined locally. */
+ if (info->shared && h)
{
- (*_bfd_error_handler)
- (_("%B: relocation R_386_GOTOFF against protected function `%s' can not be used when making a shared object"),
- input_bfd, h->root.root.string);
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ if (!h->def_regular)
+ {
+ const char *v;
+
+ switch (ELF_ST_VISIBILITY (h->other))
+ {
+ case STV_HIDDEN:
+ v = _("hidden symbol");
+ break;
+ case STV_INTERNAL:
+ v = _("internal symbol");
+ break;
+ case STV_PROTECTED:
+ v = _("protected symbol");
+ break;
+ default:
+ v = _("symbol");
+ break;
+ }
+
+ (*_bfd_error_handler)
+ (_("%B: relocation R_386_GOTOFF against undefined %s `%s' can not be used when making a shared object"),
+ input_bfd, v, h->root.root.string);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ else if (!info->executable
+ && h->type == STT_FUNC
+ && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED)
+ {
+ (*_bfd_error_handler)
+ (_("%B: relocation R_386_GOTOFF against protected function `%s' can not be used when making a shared object"),
+ input_bfd, h->root.root.string);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
}
/* Note that sgot is not involved in this
case R_386_32:
case R_386_PC32:
- if ((input_section->flags & SEC_ALLOC) == 0)
+ if ((input_section->flags & SEC_ALLOC) == 0
+ || is_vxworks_tls)
break;
if ((info->shared
&& h->dynindx != -1
&& (r_type == R_386_PC32
|| !info->shared
- || !info->symbolic
+ || !SYMBOLIC_BIND (info, h)
|| !h->def_regular))
outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
else
case R_386_TLS_DESC_CALL:
case R_386_TLS_IE_32:
case R_386_TLS_GOTIE:
- r_type = elf_i386_tls_transition (info, r_type, h == NULL);
tls_type = GOT_UNKNOWN;
if (h == NULL && local_got_offsets)
tls_type = elf_i386_local_got_tls_type (input_bfd) [r_symndx];
else if (h != NULL)
- {
- tls_type = elf_i386_hash_entry(h)->tls_type;
- if (!info->shared && h->dynindx == -1 && (tls_type & GOT_TLS_IE))
- r_type = R_386_TLS_LE_32;
- }
+ tls_type = elf_i386_hash_entry(h)->tls_type;
if (tls_type == GOT_TLS_IE)
tls_type = GOT_TLS_IE_NEG;
- if (r_type == R_386_TLS_GD
- || r_type == R_386_TLS_GOTDESC
- || r_type == R_386_TLS_DESC_CALL)
- {
- if (tls_type == GOT_TLS_IE_POS)
- r_type = R_386_TLS_GOTIE;
- else if (tls_type & GOT_TLS_IE)
- r_type = R_386_TLS_IE_32;
- }
+
+ if (! elf_i386_tls_transition (info, input_bfd,
+ input_section, contents,
+ symtab_hdr, sym_hashes,
+ &r_type, tls_type, rel,
+ relend, h))
+ return FALSE;
if (r_type == R_386_TLS_LE_32)
{
BFD_ASSERT (! unresolved_reloc);
if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD)
{
- unsigned int val, type;
+ unsigned int type;
bfd_vma roff;
/* GD->LE transition. */
- BFD_ASSERT (rel->r_offset >= 2);
type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
- BFD_ASSERT (type == 0x8d || type == 0x04);
- BFD_ASSERT (rel->r_offset + 9 <= input_section->size);
- BFD_ASSERT (bfd_get_8 (input_bfd,
- contents + rel->r_offset + 4)
- == 0xe8);
- BFD_ASSERT (rel + 1 < relend);
- BFD_ASSERT (ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32);
- roff = rel->r_offset + 5;
- val = bfd_get_8 (input_bfd,
- contents + rel->r_offset - 1);
if (type == 0x04)
{
/* leal foo(,%reg,1), %eax; call ___tls_get_addr
Change it into:
movl %gs:0, %eax; subl $foo@tpoff, %eax
(6 byte form of subl). */
- BFD_ASSERT (rel->r_offset >= 3);
- BFD_ASSERT (bfd_get_8 (input_bfd,
- contents + rel->r_offset - 3)
- == 0x8d);
- BFD_ASSERT ((val & 0xc7) == 0x05 && val != (4 << 3));
memcpy (contents + rel->r_offset - 3,
"\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
+ roff = rel->r_offset + 5;
}
else
{
- BFD_ASSERT ((val & 0xf8) == 0x80 && (val & 7) != 4);
- if (rel->r_offset + 10 <= input_section->size
- && bfd_get_8 (input_bfd,
- contents + rel->r_offset + 9) == 0x90)
- {
- /* leal foo(%reg), %eax; call ___tls_get_addr; nop
- Change it into:
- movl %gs:0, %eax; subl $foo@tpoff, %eax
- (6 byte form of subl). */
- memcpy (contents + rel->r_offset - 2,
- "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
- roff = rel->r_offset + 6;
- }
- else
- {
- /* leal foo(%reg), %eax; call ___tls_get_addr
- Change it into:
- movl %gs:0, %eax; subl $foo@tpoff, %eax
- (5 byte form of subl). */
- memcpy (contents + rel->r_offset - 2,
- "\x65\xa1\0\0\0\0\x2d\0\0\0", 11);
- }
+ /* leal foo(%reg), %eax; call ___tls_get_addr; nop
+ Change it into:
+ movl %gs:0, %eax; subl $foo@tpoff, %eax
+ (6 byte form of subl). */
+ memcpy (contents + rel->r_offset - 2,
+ "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
+ roff = rel->r_offset + 6;
}
bfd_put_32 (output_bfd, tpoff (info, relocation),
contents + roff);
- /* Skip R_386_PLT32. */
+ /* Skip R_386_PC32/R_386_PLT32. */
rel++;
continue;
}
Registers other than %eax may be set up here. */
- unsigned int val, type;
+ unsigned int val;
bfd_vma roff;
- /* First, make sure it's a leal adding ebx to a
- 32-bit offset into any register, although it's
- probably almost always going to be eax. */
roff = rel->r_offset;
- BFD_ASSERT (roff >= 2);
- type = bfd_get_8 (input_bfd, contents + roff - 2);
- BFD_ASSERT (type == 0x8d);
val = bfd_get_8 (input_bfd, contents + roff - 1);
- BFD_ASSERT ((val & 0xc7) == 0x83);
- BFD_ASSERT (roff + 4 <= input_section->size);
/* Now modify the instruction as appropriate. */
/* aoliva FIXME: remove the above and xor the byte
It's originally:
call *(%eax)
Turn it into:
- nop; nop */
+ xchg %ax,%ax */
- unsigned int val, type;
bfd_vma roff;
-
- /* First, make sure it's a call *(%eax). */
+
roff = rel->r_offset;
- BFD_ASSERT (roff + 2 <= input_section->size);
- type = bfd_get_8 (input_bfd, contents + roff);
- BFD_ASSERT (type == 0xff);
- val = bfd_get_8 (input_bfd, contents + roff + 1);
- BFD_ASSERT (val == 0x10);
-
- /* Now modify the instruction as appropriate. */
- bfd_put_8 (output_bfd, 0x90, contents + roff);
+ bfd_put_8 (output_bfd, 0x66, contents + roff);
bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
continue;
}
else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_IE)
{
- unsigned int val, type;
+ unsigned int val;
/* IE->LE transition:
Originally it can be one of:
movl $foo, %eax
movl $foo, %reg
addl $foo, %reg. */
- BFD_ASSERT (rel->r_offset >= 1);
val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
- BFD_ASSERT (rel->r_offset + 4 <= input_section->size);
if (val == 0xa1)
{
/* movl foo, %eax. */
}
else
{
- BFD_ASSERT (rel->r_offset >= 2);
+ unsigned int type;
+
type = bfd_get_8 (input_bfd,
contents + rel->r_offset - 2);
switch (type)
{
case 0x8b:
/* movl */
- BFD_ASSERT ((val & 0xc7) == 0x05);
bfd_put_8 (output_bfd, 0xc7,
contents + rel->r_offset - 2);
bfd_put_8 (output_bfd,
break;
case 0x03:
/* addl */
- BFD_ASSERT ((val & 0xc7) == 0x05);
bfd_put_8 (output_bfd, 0x81,
contents + rel->r_offset - 2);
bfd_put_8 (output_bfd,
subl $foo, %reg2
movl $foo, %reg2 (6 byte form)
addl $foo, %reg2. */
- BFD_ASSERT (rel->r_offset >= 2);
type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
- BFD_ASSERT (rel->r_offset + 4 <= input_section->size);
- BFD_ASSERT ((val & 0xc0) == 0x80 && (val & 7) != 4);
if (type == 0x8b)
{
/* movl */
+ htab->sgotplt_jump_table_size);
sreloc = htab->srelplt;
loc = sreloc->contents;
- loc += sreloc->reloc_count++
- * sizeof (Elf32_External_Rel);
+ loc += (htab->next_tls_desc_index++
+ * sizeof (Elf32_External_Rel));
BFD_ASSERT (loc + sizeof (Elf32_External_Rel)
<= sreloc->contents + sreloc->size);
bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
bfd_vma roff;
/* GD->IE transition. */
- BFD_ASSERT (rel->r_offset >= 2);
type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
- BFD_ASSERT (type == 0x8d || type == 0x04);
- BFD_ASSERT (rel->r_offset + 9 <= input_section->size);
- BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4)
- == 0xe8);
- BFD_ASSERT (rel + 1 < relend);
- BFD_ASSERT (ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32);
- roff = rel->r_offset - 3;
val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
if (type == 0x04)
{
/* leal foo(,%reg,1), %eax; call ___tls_get_addr
Change it into:
movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax. */
- BFD_ASSERT (rel->r_offset >= 3);
- BFD_ASSERT (bfd_get_8 (input_bfd,
- contents + rel->r_offset - 3)
- == 0x8d);
- BFD_ASSERT ((val & 0xc7) == 0x05 && val != (4 << 3));
val >>= 3;
+ roff = rel->r_offset - 3;
}
else
{
/* leal foo(%reg), %eax; call ___tls_get_addr; nop
Change it into:
movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax. */
- BFD_ASSERT (rel->r_offset + 10 <= input_section->size);
- BFD_ASSERT ((val & 0xf8) == 0x80 && (val & 7) != 4);
- BFD_ASSERT (bfd_get_8 (input_bfd,
- contents + rel->r_offset + 9)
- == 0x90);
roff = rel->r_offset - 2;
}
memcpy (contents + roff,
subl $foo@gottpoff(%reg), %eax
into:
addl $foo@gotntpoff(%reg), %eax. */
- if (r_type == R_386_TLS_GOTIE)
- {
- contents[roff + 6] = 0x03;
- if (tls_type == GOT_TLS_IE_BOTH)
- off += 4;
- }
+ if (tls_type == GOT_TLS_IE_POS)
+ contents[roff + 6] = 0x03;
bfd_put_32 (output_bfd,
htab->sgot->output_section->vma
+ htab->sgot->output_offset + off
leal x@tlsdesc(%ebx), %eax
Change it to:
- movl x@gotntpoff(%ebx), %eax # before nop; nop
+ movl x@gotntpoff(%ebx), %eax # before xchg %ax,%ax
or:
movl x@gottpoff(%ebx), %eax # before negl %eax
Registers other than %eax may be set up here. */
- unsigned int val, type;
bfd_vma roff;
/* First, make sure it's a leal adding ebx to a 32-bit
offset into any register, although it's probably
almost always going to be eax. */
roff = rel->r_offset;
- BFD_ASSERT (roff >= 2);
- type = bfd_get_8 (input_bfd, contents + roff - 2);
- BFD_ASSERT (type == 0x8d);
- val = bfd_get_8 (input_bfd, contents + roff - 1);
- BFD_ASSERT ((val & 0xc7) == 0x83);
- BFD_ASSERT (roff + 4 <= input_section->size);
/* Now modify the instruction as appropriate. */
/* To turn a leal into a movl in the form we use it, it
call *(%eax)
Change it to:
- nop; nop
+ xchg %ax,%ax
or
negl %eax
depending on how we transformed the TLS_GOTDESC above.
*/
- unsigned int val, type;
bfd_vma roff;
- /* First, make sure it's a call *(%eax). */
roff = rel->r_offset;
- BFD_ASSERT (roff + 2 <= input_section->size);
- type = bfd_get_8 (input_bfd, contents + roff);
- BFD_ASSERT (type == 0xff);
- val = bfd_get_8 (input_bfd, contents + roff + 1);
- BFD_ASSERT (val == 0x10);
/* Now modify the instruction as appropriate. */
if (tls_type != GOT_TLS_IE_NEG)
{
- /* nop; nop */
- bfd_put_8 (output_bfd, 0x90, contents + roff);
+ /* xchg %ax,%ax */
+ bfd_put_8 (output_bfd, 0x66, contents + roff);
bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
}
else
break;
case R_386_TLS_LDM:
- if (! info->shared)
- {
- unsigned int val;
+ if (! elf_i386_tls_transition (info, input_bfd,
+ input_section, contents,
+ symtab_hdr, sym_hashes,
+ &r_type, GOT_UNKNOWN, rel,
+ relend, h))
+ return FALSE;
+ if (r_type != R_386_TLS_LDM)
+ {
/* LD->LE transition:
- Ensure it is:
leal foo(%reg), %eax; call ___tls_get_addr.
We change it into:
movl %gs:0, %eax; nop; leal 0(%esi,1), %esi. */
- BFD_ASSERT (rel->r_offset >= 2);
- BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 2)
- == 0x8d);
- val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
- BFD_ASSERT ((val & 0xf8) == 0x80 && (val & 7) != 4);
- BFD_ASSERT (rel->r_offset + 9 <= input_section->size);
- BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4)
- == 0xe8);
- BFD_ASSERT (rel + 1 < relend);
- BFD_ASSERT (ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32);
+ BFD_ASSERT (r_type == R_386_TLS_LE_32);
memcpy (contents + rel->r_offset - 2,
"\x65\xa1\0\0\0\0\x90\x8d\x74\x26", 11);
- /* Skip R_386_PLT32. */
+ /* Skip R_386_PC32/R_386_PLT32. */
rel++;
continue;
}
rel.r_offset = (htab->splt->output_section->vma
+ htab->splt->output_offset
+ h->plt.offset + 2),
- rel.r_info = ELF32_R_INFO (htab->hgot->indx, R_386_32);
+ rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_386_32);
bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
/* Create the R_386_32 relocation referencing the beginning of
rel.r_offset = (htab->sgotplt->output_section->vma
+ htab->sgotplt->output_offset
+ got_offset);
- rel.r_info = ELF32_R_INFO (htab->hplt->indx, R_386_32);
+ rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_386_32);
bfd_elf32_swap_reloc_out (output_bfd, &rel,
loc + sizeof (Elf32_External_Rel));
}
On VxWorks, the _GLOBAL_OFFSET_TABLE_ symbol is not absolute: it
is relative to the ".got" section. */
if (strcmp (h->root.root.string, "_DYNAMIC") == 0
- || (strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
- && !htab->is_vxworks))
+ || (!htab->is_vxworks && h == htab->elf.hgot))
sym->st_shndx = SHN_ABS;
return TRUE;
switch (dyn.d_tag)
{
default:
+ if (htab->is_vxworks
+ && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn))
+ break;
continue;
case DT_PLTGOT:
if (htab->is_vxworks)
{
Elf_Internal_Rela rel;
- struct elf_link_hash_entry *hgot;
-
- /* The VxWorks GOT is relocated by the dynamic linker.
- Therefore, we must emit relocations rather than
- simply computing the values now. */
- hgot = elf_link_hash_lookup (elf_hash_table (info),
- "_GLOBAL_OFFSET_TABLE_",
- FALSE, FALSE, FALSE);
+
/* Generate a relocation for _GLOBAL_OFFSET_TABLE_ + 4.
On IA32 we use REL relocations so the addend goes in
the PLT directly. */
rel.r_offset = (htab->splt->output_section->vma
+ htab->splt->output_offset
+ 2);
- rel.r_info = ELF32_R_INFO (hgot->indx, R_386_32);
+ rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_386_32);
bfd_elf32_swap_reloc_out (output_bfd, &rel,
htab->srelplt2->contents);
/* Generate a relocation for _GLOBAL_OFFSET_TABLE_ + 8. */
rel.r_offset = (htab->splt->output_section->vma
+ htab->splt->output_offset
+ 8);
- rel.r_info = ELF32_R_INFO (hgot->indx, R_386_32);
+ rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_386_32);
bfd_elf32_swap_reloc_out (output_bfd, &rel,
htab->srelplt2->contents +
sizeof (Elf32_External_Rel));
{
Elf_Internal_Rela rel;
bfd_elf32_swap_reloc_in (output_bfd, p, &rel);
- rel.r_info = ELF32_R_INFO (htab->hgot->indx, R_386_32);
+ rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_386_32);
bfd_elf32_swap_reloc_out (output_bfd, &rel, p);
p += sizeof (Elf32_External_Rel);
bfd_elf32_swap_reloc_in (output_bfd, p, &rel);
- rel.r_info = ELF32_R_INFO (htab->hplt->indx, R_386_32);
+ rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_386_32);
bfd_elf32_swap_reloc_out (output_bfd, &rel, p);
p += sizeof (Elf32_External_Rel);
}
return plt->vma + (i + 1) * PLT_ENTRY_SIZE;
}
+/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */
+
+static bfd_boolean
+elf_i386_hash_symbol (struct elf_link_hash_entry *h)
+{
+ if (h->plt.offset != (bfd_vma) -1
+ && !h->def_regular
+ && !h->pointer_equality_needed)
+ return FALSE;
+
+ return _bfd_elf_hash_symbol (h);
+}
#define TARGET_LITTLE_SYM bfd_elf32_i386_vec
#define TARGET_LITTLE_NAME "elf32-i386"
#define bfd_elf32_bfd_is_local_label_name elf_i386_is_local_label_name
#define bfd_elf32_bfd_link_hash_table_create elf_i386_link_hash_table_create
#define bfd_elf32_bfd_reloc_type_lookup elf_i386_reloc_type_lookup
+#define bfd_elf32_bfd_reloc_name_lookup elf_i386_reloc_name_lookup
#define elf_backend_adjust_dynamic_symbol elf_i386_adjust_dynamic_symbol
+#define elf_backend_relocs_compatible _bfd_elf_relocs_compatible
#define elf_backend_check_relocs elf_i386_check_relocs
#define elf_backend_copy_indirect_symbol elf_i386_copy_indirect_symbol
#define elf_backend_create_dynamic_sections elf_i386_create_dynamic_sections
#define elf_backend_relocate_section elf_i386_relocate_section
#define elf_backend_size_dynamic_sections elf_i386_size_dynamic_sections
#define elf_backend_always_size_sections elf_i386_always_size_sections
+#define elf_backend_omit_section_dynsym \
+ ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
#define elf_backend_plt_sym_val elf_i386_plt_sym_val
+#define elf_backend_hash_symbol elf_i386_hash_symbol
#include "elf32-target.h"
#define TARGET_LITTLE_SYM bfd_elf32_i386_freebsd_vec
#undef TARGET_LITTLE_NAME
#define TARGET_LITTLE_NAME "elf32-i386-freebsd"
+#undef ELF_OSABI
+#define ELF_OSABI ELFOSABI_FREEBSD
/* The kernel recognizes executables as valid only if they carry a
"FreeBSD" label in the ELF header. So we put this label on all
i_ehdrp = elf_elfheader (abfd);
/* Put an ABI label supported by FreeBSD >= 4.1. */
- i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
+ i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi;
#ifdef OLD_FREEBSD_ABI_LABEL
/* The ABI label supported by FreeBSD <= 4.0 is quite nonstandard. */
memcpy (&i_ehdrp->e_ident[EI_ABIVERSION], "FreeBSD", 8);
#define TARGET_LITTLE_SYM bfd_elf32_i386_vxworks_vec
#undef TARGET_LITTLE_NAME
#define TARGET_LITTLE_NAME "elf32-i386-vxworks"
-
+#undef ELF_OSABI
/* Like elf_i386_link_hash_table_create but with tweaks for VxWorks. */
}
-/* Tweak magic VxWorks symbols as they are written to the output file. */
-static bfd_boolean
-elf_i386_vxworks_link_output_symbol_hook (struct bfd_link_info *info
- ATTRIBUTE_UNUSED,
- const char *name,
- Elf_Internal_Sym *sym,
- asection *input_sec ATTRIBUTE_UNUSED,
- struct elf_link_hash_entry *h
- ATTRIBUTE_UNUSED)
-{
- /* Ignore the first dummy symbol. */
- if (!name)
- return TRUE;
-
- return elf_vxworks_link_output_symbol_hook (name, sym);
-}
-
-#undef elf_backend_post_process_headers
+#undef elf_backend_relocs_compatible
+#undef elf_backend_post_process_headers
#undef bfd_elf32_bfd_link_hash_table_create
#define bfd_elf32_bfd_link_hash_table_create \
elf_i386_vxworks_link_hash_table_create
elf_vxworks_add_symbol_hook
#undef elf_backend_link_output_symbol_hook
#define elf_backend_link_output_symbol_hook \
- elf_i386_vxworks_link_output_symbol_hook
+ elf_vxworks_link_output_symbol_hook
#undef elf_backend_emit_relocs
#define elf_backend_emit_relocs elf_vxworks_emit_relocs
#undef elf_backend_final_write_processing