Line 1... |
Line 1... |
/* Renesas / SuperH SH specific support for 32-bit ELF
|
/* Renesas / SuperH SH specific support for 32-bit ELF
|
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
|
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
|
2006, 2007, 2008 Free Software Foundation, Inc.
|
2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
Contributed by Ian Lance Taylor, Cygnus Support.
|
Contributed by Ian Lance Taylor, Cygnus Support.
|
|
|
This file is part of BFD, the Binary File Descriptor library.
|
This file is part of BFD, the Binary File Descriptor library.
|
|
|
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
Line 2185... |
Line 2185... |
asection *srelbss;
|
asection *srelbss;
|
|
|
/* The (unloaded but important) VxWorks .rela.plt.unloaded section. */
|
/* The (unloaded but important) VxWorks .rela.plt.unloaded section. */
|
asection *srelplt2;
|
asection *srelplt2;
|
|
|
/* Small local sym to section mapping cache. */
|
/* Small local sym cache. */
|
struct sym_sec_cache sym_sec;
|
struct sym_cache sym_cache;
|
|
|
/* A counter or offset to track a TLS got entry. */
|
/* A counter or offset to track a TLS got entry. */
|
union
|
union
|
{
|
{
|
bfd_signed_vma refcount;
|
bfd_signed_vma refcount;
|
Line 2279... |
Line 2279... |
ret->splt = NULL;
|
ret->splt = NULL;
|
ret->srelplt = NULL;
|
ret->srelplt = NULL;
|
ret->sdynbss = NULL;
|
ret->sdynbss = NULL;
|
ret->srelbss = NULL;
|
ret->srelbss = NULL;
|
ret->srelplt2 = NULL;
|
ret->srelplt2 = NULL;
|
ret->sym_sec.abfd = NULL;
|
ret->sym_cache.abfd = NULL;
|
ret->tls_ldm_got.refcount = 0;
|
ret->tls_ldm_got.refcount = 0;
|
ret->plt_info = NULL;
|
ret->plt_info = NULL;
|
ret->vxworks_p = vxworks_object_p (abfd);
|
ret->vxworks_p = vxworks_object_p (abfd);
|
|
|
return &ret->root.root;
|
return &ret->root.root;
|
Line 2301... |
Line 2301... |
return FALSE;
|
return FALSE;
|
|
|
htab = sh_elf_hash_table (info);
|
htab = sh_elf_hash_table (info);
|
htab->sgot = bfd_get_section_by_name (dynobj, ".got");
|
htab->sgot = bfd_get_section_by_name (dynobj, ".got");
|
htab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
|
htab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
|
if (! htab->sgot || ! htab->sgotplt)
|
htab->srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
|
|
if (! htab->sgot || ! htab->sgotplt || ! htab->srelgot)
|
abort ();
|
abort ();
|
|
|
htab->srelgot = bfd_make_section_with_flags (dynobj, ".rela.got",
|
|
(SEC_ALLOC | SEC_LOAD
|
|
| SEC_HAS_CONTENTS
|
|
| SEC_IN_MEMORY
|
|
| SEC_LINKER_CREATED
|
|
| SEC_READONLY));
|
|
if (htab->srelgot == NULL
|
|
|| ! bfd_set_section_alignment (dynobj, htab->srelgot, 2))
|
|
return FALSE;
|
|
return TRUE;
|
return TRUE;
|
}
|
}
|
|
|
/* Create dynamic sections when linking against a dynamic object. */
|
/* Create dynamic sections when linking against a dynamic object. */
|
|
|
Line 2815... |
Line 2806... |
else
|
else
|
pp = &p->next;
|
pp = &p->next;
|
}
|
}
|
}
|
}
|
|
|
|
if (htab->vxworks_p)
|
|
{
|
|
struct elf_sh_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
|
/* Also discard relocs on undefined weak syms with non-default
|
visibility. */
|
visibility. */
|
if (eh->dyn_relocs != NULL
|
if (eh->dyn_relocs != NULL
|
&& h->root.type == bfd_link_hash_undefweak)
|
&& h->root.type == bfd_link_hash_undefweak)
|
{
|
{
|
Line 2975... |
Line 2979... |
/* Input section has been discarded, either because
|
/* Input section has been discarded, either because
|
it is a copy of a linkonce section or due to
|
it is a copy of a linkonce section or due to
|
linker script /DISCARD/, so we'll be discarding
|
linker script /DISCARD/, so we'll be discarding
|
the relocs too. */
|
the relocs too. */
|
}
|
}
|
|
else if (htab->vxworks_p
|
|
&& 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)
|
else if (p->count != 0)
|
{
|
{
|
srel = elf_section_data (p->sec)->sreloc;
|
srel = elf_section_data (p->sec)->sreloc;
|
srel->size += p->count * sizeof (Elf32_External_Rela);
|
srel->size += p->count * sizeof (Elf32_External_Rela);
|
if ((p->sec->output_section->flags & SEC_READONLY) != 0)
|
if ((p->sec->output_section->flags & SEC_READONLY) != 0)
|
Line 3164... |
Line 3175... |
asection *sgot;
|
asection *sgot;
|
asection *sgotplt;
|
asection *sgotplt;
|
asection *splt;
|
asection *splt;
|
asection *sreloc;
|
asection *sreloc;
|
asection *srelgot;
|
asection *srelgot;
|
|
bfd_boolean is_vxworks_tls;
|
|
|
BFD_ASSERT (is_sh_elf (input_bfd));
|
BFD_ASSERT (is_sh_elf (input_bfd));
|
|
|
htab = sh_elf_hash_table (info);
|
htab = sh_elf_hash_table (info);
|
symtab_hdr = &elf_symtab_hdr (input_bfd);
|
symtab_hdr = &elf_symtab_hdr (input_bfd);
|
Line 3178... |
Line 3190... |
sgot = htab->sgot;
|
sgot = htab->sgot;
|
sgotplt = htab->sgotplt;
|
sgotplt = htab->sgotplt;
|
splt = htab->splt;
|
splt = htab->splt;
|
sreloc = NULL;
|
sreloc = NULL;
|
srelgot = NULL;
|
srelgot = NULL;
|
|
/* We have to handle relocations in vxworks .tls_vars sections
|
|
specially, because the dynamic loader is 'weird'. */
|
|
is_vxworks_tls = (htab->vxworks_p && info->shared
|
|
&& !strcmp (input_section->output_section->name,
|
|
".tls_vars"));
|
|
|
rel = relocs;
|
rel = relocs;
|
relend = relocs + input_section->reloc_count;
|
relend = relocs + input_section->reloc_count;
|
for (; rel < relend; rel++)
|
for (; rel < relend; rel++)
|
{
|
{
|
Line 3584... |
Line 3601... |
&& (h == NULL
|
&& (h == NULL
|
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|
|| h->root.type != bfd_link_hash_undefweak)
|
|| h->root.type != bfd_link_hash_undefweak)
|
&& r_symndx != 0
|
&& r_symndx != 0
|
&& (input_section->flags & SEC_ALLOC) != 0
|
&& (input_section->flags & SEC_ALLOC) != 0
|
|
&& !is_vxworks_tls
|
&& (r_type == R_SH_DIR32
|
&& (r_type == R_SH_DIR32
|
|| !SYMBOL_CALLS_LOCAL (info, h)))
|
|| !SYMBOL_CALLS_LOCAL (info, h)))
|
{
|
{
|
Elf_Internal_Rela outrel;
|
Elf_Internal_Rela outrel;
|
bfd_byte *loc;
|
bfd_byte *loc;
|
Line 3597... |
Line 3615... |
are copied into the output file to be resolved at run
|
are copied into the output file to be resolved at run
|
time. */
|
time. */
|
|
|
if (sreloc == NULL)
|
if (sreloc == NULL)
|
{
|
{
|
const char *name;
|
sreloc = _bfd_elf_get_dynamic_reloc_section
|
|
(input_bfd, input_section, /*rela?*/ TRUE);
|
name = (bfd_elf_string_from_elf_section
|
if (sreloc == NULL)
|
(input_bfd,
|
|
elf_elfheader (input_bfd)->e_shstrndx,
|
|
elf_section_data (input_section)->rel_hdr.sh_name));
|
|
if (name == NULL)
|
|
return FALSE;
|
return FALSE;
|
|
|
BFD_ASSERT (CONST_STRNEQ (name, ".rela")
|
|
&& strcmp (bfd_get_section_name (input_bfd,
|
|
input_section),
|
|
name + 5) == 0);
|
|
|
|
sreloc = bfd_get_section_by_name (dynobj, name);
|
|
BFD_ASSERT (sreloc != NULL);
|
|
}
|
}
|
|
|
skip = FALSE;
|
skip = FALSE;
|
relocate = FALSE;
|
relocate = FALSE;
|
|
|
Line 4323... |
Line 4329... |
goto final_link_relocate;
|
goto final_link_relocate;
|
}
|
}
|
|
|
if (sreloc == NULL)
|
if (sreloc == NULL)
|
{
|
{
|
const char *name;
|
sreloc = _bfd_elf_get_dynamic_reloc_section
|
|
(input_bfd, input_section, /*rela?*/ TRUE);
|
name = (bfd_elf_string_from_elf_section
|
if (sreloc == NULL)
|
(input_bfd,
|
|
elf_elfheader (input_bfd)->e_shstrndx,
|
|
elf_section_data (input_section)->rel_hdr.sh_name));
|
|
if (name == NULL)
|
|
return FALSE;
|
return FALSE;
|
|
|
BFD_ASSERT (CONST_STRNEQ (name, ".rela")
|
|
&& strcmp (bfd_get_section_name (input_bfd,
|
|
input_section),
|
|
name + 5) == 0);
|
|
|
|
sreloc = bfd_get_section_by_name (dynobj, name);
|
|
BFD_ASSERT (sreloc != NULL);
|
|
}
|
}
|
|
|
if (h == NULL || h->dynindx == -1)
|
if (h == NULL || h->dynindx == -1)
|
indx = 0;
|
indx = 0;
|
else
|
else
|
Line 5194... |
Line 5188... |
/* When creating a shared object, we must copy these
|
/* When creating a shared object, we must copy these
|
reloc types into the output file. We create a reloc
|
reloc types into the output file. We create a reloc
|
section in dynobj and make room for this reloc. */
|
section in dynobj and make room for this reloc. */
|
if (sreloc == NULL)
|
if (sreloc == NULL)
|
{
|
{
|
const char *name;
|
sreloc = _bfd_elf_make_dynamic_reloc_section
|
|
(sec, htab->root.dynobj, 2, abfd, /*rela?*/ TRUE);
|
name = (bfd_elf_string_from_elf_section
|
|
(abfd,
|
|
elf_elfheader (abfd)->e_shstrndx,
|
|
elf_section_data (sec)->rel_hdr.sh_name));
|
|
if (name == NULL)
|
|
return FALSE;
|
|
|
|
BFD_ASSERT (CONST_STRNEQ (name, ".rela")
|
|
&& strcmp (bfd_get_section_name (abfd, sec),
|
|
name + 5) == 0);
|
|
|
|
sreloc = bfd_get_section_by_name (htab->root.dynobj, name);
|
|
if (sreloc == NULL)
|
if (sreloc == NULL)
|
{
|
|
flagword flags;
|
|
|
|
flags = (SEC_HAS_CONTENTS | SEC_READONLY
|
|
| SEC_IN_MEMORY | SEC_LINKER_CREATED);
|
|
if ((sec->flags & SEC_ALLOC) != 0)
|
|
flags |= SEC_ALLOC | SEC_LOAD;
|
|
sreloc = bfd_make_section_with_flags (htab->root.dynobj,
|
|
name,
|
|
flags);
|
|
if (sreloc == NULL
|
|
|| ! bfd_set_section_alignment (htab->root.dynobj,
|
|
sreloc, 2))
|
|
return FALSE;
|
return FALSE;
|
}
|
}
|
elf_section_data (sec)->sreloc = sreloc;
|
|
}
|
|
|
|
/* If this is a global symbol, we count the number of
|
/* If this is a global symbol, we count the number of
|
relocations we need for this symbol. */
|
relocations we need for this symbol. */
|
if (h != NULL)
|
if (h != NULL)
|
head = &((struct elf_sh_link_hash_entry *) h)->dyn_relocs;
|
head = &((struct elf_sh_link_hash_entry *) h)->dyn_relocs;
|
else
|
else
|
{
|
{
|
|
/* Track dynamic relocs needed for local syms too. */
|
asection *s;
|
asection *s;
|
void *vpp;
|
void *vpp;
|
|
Elf_Internal_Sym *isym;
|
|
|
/* Track dynamic relocs needed for local syms too. */
|
isym = bfd_sym_from_r_symndx (&htab->sym_cache,
|
s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
|
abfd, r_symndx);
|
sec, r_symndx);
|
if (isym == NULL)
|
if (s == NULL)
|
|
return FALSE;
|
return FALSE;
|
|
|
|
s = bfd_section_from_elf_index (abfd, isym->st_shndx);
|
|
if (s == NULL)
|
|
s = sec;
|
|
|
vpp = &elf_section_data (s)->local_dynrel;
|
vpp = &elf_section_data (s)->local_dynrel;
|
head = (struct elf_sh_dyn_relocs **) vpp;
|
head = (struct elf_sh_dyn_relocs **) vpp;
|
}
|
}
|
|
|
p = *head;
|
p = *head;
|