/* Intel 80386/80486-specific support for 32-bit ELF
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
section, plus whatever space is used by the jump slots. */
bfd_vma sgotplt_jump_table_size;
- /* Small local sym to section mapping cache. */
- struct sym_sec_cache sym_sec;
+ /* Small local sym cache. */
+ struct sym_cache sym_cache;
/* _TLS_MODULE_BASE_ symbol. */
struct bfd_link_hash_entry *tls_module_base;
subclass. */
if (entry == NULL)
{
- entry = bfd_hash_allocate (table,
- sizeof (struct elf_i386_link_hash_entry));
+ entry = (struct bfd_hash_entry *)
+ bfd_hash_allocate (table, sizeof (struct elf_i386_link_hash_entry));
if (entry == NULL)
return entry;
}
struct elf_i386_link_hash_table *ret;
bfd_size_type amt = sizeof (struct elf_i386_link_hash_table);
- ret = bfd_malloc (amt);
+ ret = (struct elf_i386_link_hash_table *) bfd_malloc (amt);
if (ret == NULL)
return 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->sym_cache.abfd = NULL;
ret->is_vxworks = 0;
ret->srelplt2 = NULL;
ret->plt0_pad_byte = 0;
unsigned int *r_type, int tls_type,
const Elf_Internal_Rela *rel,
const Elf_Internal_Rela *relend,
- struct elf_link_hash_entry *h)
+ struct elf_link_hash_entry *h,
+ unsigned long r_symndx)
{
unsigned int from_type = *r_type;
unsigned int to_type = from_type;
case R_386_TLS_IE_32:
case R_386_TLS_IE:
case R_386_TLS_GOTIE:
- if (!info->shared)
+ if (info->executable)
{
if (h == NULL)
to_type = R_386_TLS_LE_32;
{
unsigned int new_to_type = to_type;
- if (!info->shared
+ if (info->executable
&& h != NULL
&& h->dynindx == -1
&& (tls_type & GOT_TLS_IE))
break;
case R_386_TLS_LDM:
- if (!info->shared)
+ if (info->executable)
to_type = R_386_TLS_LE_32;
break;
from_type, rel, relend))
{
reloc_howto_type *from, *to;
+ const char *name;
from = elf_i386_rtype_to_howto (abfd, from_type);
to = elf_i386_rtype_to_howto (abfd, to_type);
+ if (h)
+ name = h->root.root.string;
+ else
+ {
+ Elf_Internal_Sym *isym;
+ struct elf_i386_link_hash_table *htab;
+ htab = elf_i386_hash_table (info);
+ isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+ abfd, r_symndx);
+ name = bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL);
+ }
+
(*_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",
+ abfd, sec, from->name, to->name, name,
(unsigned long) rel->r_offset);
bfd_set_error (bfd_error_bad_value);
return FALSE;
const Elf_Internal_Rela *rel;
const Elf_Internal_Rela *rel_end;
asection *sreloc;
- Elf_Internal_Sym *isymbuf;
if (info->relocatable)
return TRUE;
htab = elf_i386_hash_table (info);
symtab_hdr = &elf_symtab_hdr (abfd);
- isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
sym_hashes = elf_sym_hashes (abfd);
sreloc = NULL;
unsigned int r_type;
unsigned long r_symndx;
struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *isym;
+ const char *name;
r_symndx = ELF32_R_SYM (rel->r_info);
r_type = ELF32_R_TYPE (rel->r_info);
if (r_symndx < symtab_hdr->sh_info)
{
/* A local symbol. */
- Elf_Internal_Sym *isym;
-
- /* Read this BFD's local symbols. */
- if (isymbuf == NULL)
- {
- if (isymbuf == NULL)
- isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
- symtab_hdr->sh_info, 0,
- NULL, NULL, NULL);
- if (isymbuf == NULL)
- return FALSE;
- }
+ isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+ abfd, r_symndx);
+ if (isym == NULL)
+ return FALSE;
/* Check relocation against local STT_GNU_IFUNC symbol. */
- isym = isymbuf + r_symndx;
if (ELF32_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
{
h = elf_i386_get_local_sym_hash (htab, abfd, rel,
TRUE);
if (h == NULL)
- goto error_return;
+ return FALSE;
/* Fake a STT_GNU_IFUNC symbol. */
h->type = STT_GNU_IFUNC;
}
else
{
+ isym = NULL;
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
case R_386_GOT32:
case R_386_GOTOFF:
if (!_bfd_elf_create_ifunc_sections (abfd, info))
- goto error_return;
+ return FALSE;
break;
}
{
/* It is referenced by a non-shared object. */
h->ref_regular = 1;
+ h->needs_plt = 1;
/* STT_GNU_IFUNC symbol must go through PLT. */
h->plt.refcount += 1;
switch (r_type)
{
default:
+ if (h->root.root.string)
+ name = h->root.root.string;
+ else
+ name = bfd_elf_sym_name (abfd, symtab_hdr, isym,
+ NULL);
(*_bfd_error_handler)
(_("%B: relocation %s against STT_GNU_IFUNC "
"symbol `%s' isn't handled by %s"), abfd,
elf_howto_table[r_type].name,
- (h->root.root.string
- ? h->root.root.string : "a local symbol"),
- __FUNCTION__);
+ name, __FUNCTION__);
bfd_set_error (bfd_error_bad_value);
- goto error_return;
+ return FALSE;
case R_386_32:
h->non_got_ref = 1;
(abfd, info, sec, sreloc,
&((struct elf_i386_link_hash_entry *) h)->dyn_relocs);
if (sreloc == NULL)
- goto error_return;
+ return FALSE;
}
break;
if (htab->elf.sgot == NULL
&& !_bfd_elf_create_got_section (htab->elf.dynobj,
info))
- goto error_return;
+ return FALSE;
break;
}
if (! elf_i386_tls_transition (info, abfd, sec, NULL,
symtab_hdr, sym_hashes,
&r_type, GOT_UNKNOWN,
- rel, rel_end, h))
- goto error_return;
+ rel, rel_end, h, r_symndx))
+ return FALSE;
switch (r_type)
{
case R_386_TLS_IE_32:
case R_386_TLS_IE:
case R_386_TLS_GOTIE:
- if (info->shared)
+ if (!info->executable)
info->flags |= DF_STATIC_TLS;
/* Fall through */
size = symtab_hdr->sh_info;
size *= (sizeof (bfd_signed_vma)
+ sizeof (bfd_vma) + sizeof(char));
- local_got_refcounts = bfd_zalloc (abfd, size);
+ local_got_refcounts = (bfd_signed_vma *)
+ bfd_zalloc (abfd, size);
if (local_got_refcounts == NULL)
- goto error_return;
+ return FALSE;
elf_local_got_refcounts (abfd) = local_got_refcounts;
elf_i386_local_tlsdesc_gotent (abfd)
= (bfd_vma *) (local_got_refcounts + symtab_hdr->sh_info);
tls_type |= old_tls_type;
else
{
+ if (h)
+ name = h->root.root.string;
+ else
+ name = bfd_elf_sym_name (abfd, symtab_hdr, isym,
+ NULL);
(*_bfd_error_handler)
(_("%B: `%s' accessed both as normal and "
"thread local symbol"),
- abfd,
- h ? h->root.root.string : "<local>");
- goto error_return;
+ abfd, name);
+ return FALSE;
}
}
if (htab->elf.dynobj == NULL)
htab->elf.dynobj = abfd;
if (!_bfd_elf_create_got_section (htab->elf.dynobj, info))
- goto error_return;
+ return FALSE;
}
if (r_type != R_386_TLS_IE)
break;
case R_386_TLS_LE_32:
case R_386_TLS_LE:
- if (!info->shared)
+ if (info->executable)
break;
info->flags |= DF_STATIC_TLS;
/* Fall through */
(sec, htab->elf.dynobj, 2, abfd, /*rela?*/ FALSE);
if (sreloc == NULL)
- goto error_return;
+ return FALSE;
}
/* If this is a global symbol, we count the number of
}
else
{
- void **vpp;
/* Track dynamic relocs needed for local syms too.
We really need local syms available to do this
easily. Oh well. */
-
+ void **vpp;
asection *s;
- s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
- sec, r_symndx);
+ Elf_Internal_Sym *isym;
+
+ isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+ abfd, r_symndx);
+ if (isym == NULL)
+ return FALSE;
+
+ s = bfd_section_from_elf_index (abfd, isym->st_shndx);
if (s == NULL)
- goto error_return;
+ s = sec;
vpp = &elf_section_data (s)->local_dynrel;
head = (struct elf_dyn_relocs **)vpp;
if (p == NULL || p->sec != sec)
{
bfd_size_type amt = sizeof *p;
- p = bfd_alloc (htab->elf.dynobj, amt);
+ p = (struct elf_dyn_relocs *) bfd_alloc (htab->elf.dynobj,
+ amt);
if (p == NULL)
- goto error_return;
+ return FALSE;
p->next = *head;
*head = p;
p->sec = sec;
Reconstruct it for later use during GC. */
case R_386_GNU_VTINHERIT:
if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
- goto error_return;
+ return FALSE;
break;
/* This relocation describes which C++ vtable entries are actually
BFD_ASSERT (h != NULL);
if (h != NULL
&& !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
- goto error_return;
+ return FALSE;
break;
default:
}
}
- if (isymbuf != NULL
- && (unsigned char *) isymbuf != symtab_hdr->contents)
- {
- if (!info->keep_memory)
- free (isymbuf);
- else
- {
- /* Cache the symbols for elf_link_input_bfd. */
- symtab_hdr->contents = (unsigned char *) isymbuf;
- }
- }
-
return TRUE;
-
-error_return:
- if (isymbuf != NULL
- && (unsigned char *) isymbuf != symtab_hdr->contents)
- free (isymbuf);
- return FALSE;
}
/* Return the section that should be marked against GC for a given
if (! elf_i386_tls_transition (info, abfd, sec, NULL,
symtab_hdr, sym_hashes,
&r_type, GOT_UNKNOWN,
- rel, relend, h))
+ rel, relend, h, r_symndx))
return FALSE;
switch (r_type)
/* If R_386_TLS_{IE_32,IE,GOTIE} symbol is now local to the binary,
make it a R_386_TLS_LE_32 requiring no TLS entry. */
if (h->got.refcount > 0
- && !info->shared
+ && info->executable
&& h->dynindx == -1
&& (elf_i386_hash_entry(h)->tls_type & GOT_TLS_IE))
h->got.offset = (bfd_vma) -1;
section's contents are written out. This should not happen,
but this way if it does, we get a R_386_NONE reloc instead
of garbage. */
- s->contents = bfd_zalloc (dynobj, s->size);
+ s->contents = (unsigned char *) bfd_zalloc (dynobj, s->size);
if (s->contents == NULL)
return FALSE;
}
break;
}
}
- else if (ELF32_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+ else if (!info->relocatable
+ && ELF32_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
{
/* Relocate against local STT_GNU_IFUNC symbol. */
h = elf_i386_get_local_sym_hash (htab, input_bfd,
{
asection *plt, *gotplt, *base_got;
bfd_vma plt_index;
+ const char *name;
if ((input_section->flags & SEC_ALLOC) == 0
|| h->plt.offset == (bfd_vma) -1)
switch (r_type)
{
default:
+ if (h->root.root.string)
+ name = h->root.root.string;
+ else
+ name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym,
+ NULL);
(*_bfd_error_handler)
(_("%B: relocation %s against STT_GNU_IFUNC "
"symbol `%s' isn't handled by %s"), input_bfd,
elf_howto_table[r_type].name,
- (h->root.root.string
- ? h->root.root.string : "a local symbol"),
- __FUNCTION__);
+ name, __FUNCTION__);
bfd_set_error (bfd_error_bad_value);
return FALSE;
break;
case R_386_TLS_IE:
- if (info->shared)
+ if (!info->executable)
{
Elf_Internal_Rela outrel;
bfd_byte *loc;
input_section, contents,
symtab_hdr, sym_hashes,
&r_type, tls_type, rel,
- relend, h))
+ relend, h, r_symndx))
return FALSE;
if (r_type == R_386_TLS_LE_32)
input_section, contents,
symtab_hdr, sym_hashes,
&r_type, GOT_UNKNOWN, rel,
- relend, h))
+ relend, h, r_symndx))
return FALSE;
if (r_type != R_386_TLS_LDM)
case R_386_TLS_LE_32:
case R_386_TLS_LE:
- if (info->shared)
+ if (!info->executable)
{
Elf_Internal_Rela outrel;
asection *sreloc;
}
else
{
+ asection *plt;
+
if (!h->pointer_equality_needed)
abort ();
/* For non-shared object, we can't use .got.plt, which
contains the real function addres if we need pointer
equality. We load the GOT entry with the PLT entry. */
- asection *plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt;
+ plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt;
bfd_put_32 (output_bfd,
(plt->output_section->vma
+ plt->output_offset + h->plt.offset),