Line 1... |
Line 1... |
/* IBM S/390-specific support for 32-bit ELF
|
/* IBM S/390-specific support for 32-bit ELF
|
Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
|
Free Software Foundation, Inc.
|
Free Software Foundation, Inc.
|
Contributed by Carl B. Pedersen and Martin Schwidefsky.
|
Contributed by Carl B. Pedersen and Martin Schwidefsky.
|
|
|
This file is part of BFD, the Binary File Descriptor library.
|
This file is part of BFD, the Binary File Descriptor library.
|
|
|
Line 728... |
Line 728... |
union {
|
union {
|
bfd_signed_vma refcount;
|
bfd_signed_vma refcount;
|
bfd_vma offset;
|
bfd_vma offset;
|
} tls_ldm_got;
|
} tls_ldm_got;
|
|
|
/* Small local sym to section mapping cache. */
|
/* Small local sym cache. */
|
struct sym_sec_cache sym_sec;
|
struct sym_cache sym_cache;
|
};
|
};
|
|
|
/* Get the s390 ELF linker hash table from a link_info structure. */
|
/* Get the s390 ELF linker hash table from a link_info structure. */
|
|
|
#define elf_s390_hash_table(p) \
|
#define elf_s390_hash_table(p) \
|
Line 798... |
Line 798... |
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->tls_ldm_got.refcount = 0;
|
ret->tls_ldm_got.refcount = 0;
|
ret->sym_sec.abfd = NULL;
|
ret->sym_cache.abfd = NULL;
|
|
|
return &ret->elf.root;
|
return &ret->elf.root;
|
}
|
}
|
|
|
/* Create .got, .gotplt, and .rela.got sections in DYNOBJ, and set up
|
/* Create .got, .gotplt, and .rela.got sections in DYNOBJ, and set up
|
Line 819... |
Line 819... |
return FALSE;
|
return FALSE;
|
|
|
htab = elf_s390_hash_table (info);
|
htab = elf_s390_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 .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and
|
/* Create .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and
|
.rela.bss sections in DYNOBJ, and set up shortcuts to them in our
|
.rela.bss sections in DYNOBJ, and set up shortcuts to them in our
|
Line 1259... |
Line 1251... |
&& ((ELF32_R_TYPE (rel->r_info) != R_390_PC16
|
&& ((ELF32_R_TYPE (rel->r_info) != R_390_PC16
|
&& ELF32_R_TYPE (rel->r_info) != R_390_PC16DBL
|
&& ELF32_R_TYPE (rel->r_info) != R_390_PC16DBL
|
&& ELF32_R_TYPE (rel->r_info) != R_390_PC32DBL
|
&& ELF32_R_TYPE (rel->r_info) != R_390_PC32DBL
|
&& ELF32_R_TYPE (rel->r_info) != R_390_PC32)
|
&& ELF32_R_TYPE (rel->r_info) != R_390_PC32)
|
|| (h != NULL
|
|| (h != NULL
|
&& (! info->symbolic
|
&& (! SYMBOLIC_BIND (info, h)
|
|| h->root.type == bfd_link_hash_defweak
|
|| h->root.type == bfd_link_hash_defweak
|
|| !h->def_regular))))
|
|| !h->def_regular))))
|
|| (ELIMINATE_COPY_RELOCS
|
|| (ELIMINATE_COPY_RELOCS
|
&& !info->shared
|
&& !info->shared
|
&& (sec->flags & SEC_ALLOC) != 0
|
&& (sec->flags & SEC_ALLOC) != 0
|
Line 1277... |
Line 1269... |
/* We must copy these reloc types into the output file.
|
/* We must copy these reloc types into the output file.
|
Create a reloc section in dynobj and make room for
|
Create a reloc section in dynobj and make room for
|
this reloc. */
|
this reloc. */
|
if (sreloc == NULL)
|
if (sreloc == NULL)
|
{
|
{
|
const char *name;
|
|
bfd *dynobj;
|
|
|
|
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;
|
|
|
|
if (! CONST_STRNEQ (name, ".rela")
|
|
|| strcmp (bfd_get_section_name (abfd, sec),
|
|
name + 5) != 0)
|
|
{
|
|
(*_bfd_error_handler)
|
|
(_("%B: bad relocation section name `%s\'"),
|
|
abfd, name);
|
|
}
|
|
|
|
if (htab->elf.dynobj == NULL)
|
if (htab->elf.dynobj == NULL)
|
htab->elf.dynobj = abfd;
|
htab->elf.dynobj = abfd;
|
|
|
dynobj = htab->elf.dynobj;
|
sreloc = _bfd_elf_make_dynamic_reloc_section
|
sreloc = bfd_get_section_by_name (dynobj, name);
|
(sec, htab->elf.dynobj, 2, abfd, /*rela?*/ TRUE);
|
if (sreloc == NULL)
|
|
{
|
|
flagword flags;
|
|
|
|
flags = (SEC_HAS_CONTENTS | SEC_READONLY
|
if (sreloc == NULL)
|
| SEC_IN_MEMORY | SEC_LINKER_CREATED);
|
|
if ((sec->flags & SEC_ALLOC) != 0)
|
|
flags |= SEC_ALLOC | SEC_LOAD;
|
|
sreloc = bfd_make_section_with_flags (dynobj,
|
|
name,
|
|
flags);
|
|
if (sreloc == NULL
|
|
|| ! bfd_set_section_alignment (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)
|
{
|
{
|
Line 1332... |
Line 1292... |
/* Track dynamic relocs needed for local syms too.
|
/* Track dynamic relocs needed for local syms too.
|
We really need local syms available to do this
|
We really need local syms available to do this
|
easily. Oh well. */
|
easily. Oh well. */
|
asection *s;
|
asection *s;
|
void *vpp;
|
void *vpp;
|
|
Elf_Internal_Sym *isym;
|
|
|
s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
|
isym = bfd_sym_from_r_symndx (&htab->sym_cache,
|
sec, r_symndx);
|
abfd, r_symndx);
|
if (s == NULL)
|
if (isym == 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_s390_dyn_relocs **) vpp;
|
head = (struct elf_s390_dyn_relocs **) vpp;
|
}
|
}
|
|
|
p = *head;
|
p = *head;
|
Line 1596... |
Line 1561... |
(although we could actually do it here). */
|
(although we could actually do it here). */
|
if (h->type == STT_FUNC
|
if (h->type == STT_FUNC
|
|| h->needs_plt)
|
|| h->needs_plt)
|
{
|
{
|
if (h->plt.refcount <= 0
|
if (h->plt.refcount <= 0
|
|| (! info->shared
|
|| SYMBOL_CALLS_LOCAL (info, h)
|
&& !h->def_dynamic
|
|| (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
|
&& !h->ref_dynamic
|
&& h->root.type != bfd_link_hash_undefweak))
|
&& h->root.type != bfd_link_hash_undefweak
|
|
&& h->root.type != bfd_link_hash_undefined))
|
|
{
|
{
|
/* This case can occur if we saw a PLT32 reloc in an input
|
/* This case can occur if we saw a PLT32 reloc in an input
|
file, but the symbol was never referred to by a dynamic
|
file, but the symbol was never referred to by a dynamic
|
object, or if all references were garbage collected. In
|
object, or if all references were garbage collected. In
|
such a case, we don't actually need to build a procedure
|
such a case, we don't actually need to build a procedure
|
Line 1739... |
Line 1702... |
|
|
info = (struct bfd_link_info *) inf;
|
info = (struct bfd_link_info *) inf;
|
htab = elf_s390_hash_table (info);
|
htab = elf_s390_hash_table (info);
|
|
|
if (htab->elf.dynamic_sections_created
|
if (htab->elf.dynamic_sections_created
|
&& h->plt.refcount > 0
|
&& h->plt.refcount > 0)
|
&& (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|
|
|| h->root.type != bfd_link_hash_undefweak))
|
|
{
|
{
|
/* Make sure this symbol is output as a dynamic symbol.
|
/* Make sure this symbol is output as a dynamic symbol.
|
Undefined weak syms won't yet be marked as dynamic. */
|
Undefined weak syms won't yet be marked as dynamic. */
|
if (h->dynindx == -1
|
if (h->dynindx == -1
|
&& !h->forced_local)
|
&& !h->forced_local)
|
Line 1870... |
Line 1831... |
space for pc-relative relocs that have become local due to symbol
|
space for pc-relative relocs that have become local due to symbol
|
visibility changes. */
|
visibility changes. */
|
|
|
if (info->shared)
|
if (info->shared)
|
{
|
{
|
if (SYMBOL_REFERENCES_LOCAL (info, h))
|
if (SYMBOL_CALLS_LOCAL (info, h))
|
{
|
{
|
struct elf_s390_dyn_relocs **pp;
|
struct elf_s390_dyn_relocs **pp;
|
|
|
for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
|
for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
|
{
|
{
|
Line 2394... |
Line 2355... |
|
|
off = h->got.offset;
|
off = h->got.offset;
|
dyn = htab->elf.dynamic_sections_created;
|
dyn = htab->elf.dynamic_sections_created;
|
if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
|
if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
|
|| (info->shared
|
|| (info->shared
|
&& (info->symbolic
|
&& SYMBOL_REFERENCES_LOCAL (info, h))
|
|| h->dynindx == -1
|
|
|| h->forced_local)
|
|
&& h->def_regular)
|
|
|| (ELF_ST_VISIBILITY (h->other)
|
|| (ELF_ST_VISIBILITY (h->other)
|
&& h->root.type == bfd_link_hash_undefweak))
|
&& h->root.type == bfd_link_hash_undefweak))
|
{
|
{
|
/* This is actually a static link, or it is a
|
/* This is actually a static link, or it is a
|
-Bsymbolic link and the symbol is defined
|
-Bsymbolic link and the symbol is defined
|
Line 2567... |
Line 2525... |
|| h->root.type != bfd_link_hash_undefweak)
|
|| h->root.type != bfd_link_hash_undefweak)
|
&& ((r_type != R_390_PC16
|
&& ((r_type != R_390_PC16
|
&& r_type != R_390_PC16DBL
|
&& r_type != R_390_PC16DBL
|
&& r_type != R_390_PC32DBL
|
&& r_type != R_390_PC32DBL
|
&& r_type != R_390_PC32)
|
&& r_type != R_390_PC32)
|
|| (h != NULL
|
|| !SYMBOL_CALLS_LOCAL (info, h)))
|
&& !SYMBOL_REFERENCES_LOCAL (info, h))))
|
|
|| (ELIMINATE_COPY_RELOCS
|
|| (ELIMINATE_COPY_RELOCS
|
&& !info->shared
|
&& !info->shared
|
&& h != NULL
|
&& h != NULL
|
&& h->dynindx != -1
|
&& h->dynindx != -1
|
&& !h->non_got_ref
|
&& !h->non_got_ref
|
Line 2610... |
Line 2567... |
&& (r_type == R_390_PC16
|
&& (r_type == R_390_PC16
|
|| r_type == R_390_PC16DBL
|
|| r_type == R_390_PC16DBL
|
|| r_type == R_390_PC32DBL
|
|| r_type == R_390_PC32DBL
|
|| r_type == R_390_PC32
|
|| r_type == R_390_PC32
|
|| !info->shared
|
|| !info->shared
|
|| !info->symbolic
|
|| !SYMBOLIC_BIND (info, h)
|
|| !h->def_regular))
|
|| !h->def_regular))
|
{
|
{
|
outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
|
outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
|
outrel.r_addend = rel->r_addend;
|
outrel.r_addend = rel->r_addend;
|
}
|
}
|
Line 3292... |
Line 3249... |
symbol is defined locally or was forced to be local because
|
symbol is defined locally or was forced to be local because
|
of a version file, we just want to emit a RELATIVE reloc.
|
of a version file, we just want to emit a RELATIVE reloc.
|
The entry in the global offset table will already have been
|
The entry in the global offset table will already have been
|
initialized in the relocate_section function. */
|
initialized in the relocate_section function. */
|
if (info->shared
|
if (info->shared
|
&& (info->symbolic
|
&& SYMBOL_REFERENCES_LOCAL (info, h))
|
|| h->dynindx == -1
|
|
|| h->forced_local)
|
|
&& h->def_regular)
|
|
{
|
{
|
|
if (!h->def_regular)
|
|
return FALSE;
|
BFD_ASSERT((h->got.offset & 1) != 0);
|
BFD_ASSERT((h->got.offset & 1) != 0);
|
rela.r_info = ELF32_R_INFO (0, R_390_RELATIVE);
|
rela.r_info = ELF32_R_INFO (0, R_390_RELATIVE);
|
rela.r_addend = (h->root.u.def.value
|
rela.r_addend = (h->root.u.def.value
|
+ h->root.u.def.section->output_section->vma
|
+ h->root.u.def.section->output_section->vma
|
+ h->root.u.def.section->output_offset);
|
+ h->root.u.def.section->output_offset);
|