/* IBM S/390-specific support for 32-bit ELF
- Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
Contributed by Carl B. Pedersen and Martin Schwidefsky.
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,
#define elf_s390_hash_entry(ent) \
((struct elf_s390_link_hash_entry *)(ent))
+/* NOTE: Keep this structure in sync with
+ the one declared in elf64-s390.c. */
struct elf_s390_obj_tdata
{
struct elf_obj_tdata root;
- /* tls_type for each local got entry. */
+ /* TLS type for each local got entry. */
char *local_got_tls_type;
};
#define elf_s390_local_got_tls_type(abfd) \
(elf_s390_tdata (abfd)->local_got_tls_type)
+#define is_s390_elf(bfd) \
+ (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
+ && elf_tdata (bfd) != NULL \
+ && elf_object_id (bfd) == S390_ELF_DATA)
+
static bfd_boolean
elf_s390_mkobject (bfd *abfd)
{
- if (abfd->tdata.any == NULL)
- {
- bfd_size_type amt = sizeof (struct elf_s390_obj_tdata);
- abfd->tdata.any = bfd_zalloc (abfd, amt);
- if (abfd->tdata.any == NULL)
- return FALSE;
- }
- return bfd_elf_mkobject (abfd);
+ return bfd_elf_allocate_object (abfd, sizeof (struct elf_s390_obj_tdata),
+ S390_ELF_DATA);
}
static bfd_boolean
bfd_vma offset;
} tls_ldm_got;
- /* Small local sym to section mapping cache. */
- struct sym_sec_cache sym_sec;
+ /* Small local sym cache. */
+ struct sym_cache sym_cache;
};
/* Get the s390 ELF linker hash table from a link_info structure. */
#define elf_s390_hash_table(p) \
- ((struct elf_s390_link_hash_table *) ((p)->hash))
+ (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
+ == S390_ELF_DATA ? ((struct elf_s390_link_hash_table *) ((p)->hash)) : NULL)
/* Create an entry in an s390 ELF linker hash table. */
return NULL;
if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc,
- sizeof (struct elf_s390_link_hash_entry)))
+ sizeof (struct elf_s390_link_hash_entry),
+ S390_ELF_DATA))
{
free (ret);
return NULL;
ret->sdynbss = NULL;
ret->srelbss = NULL;
ret->tls_ldm_got.refcount = 0;
- ret->sym_sec.abfd = NULL;
+ ret->sym_cache.abfd = NULL;
return &ret->elf.root;
}
htab = elf_s390_hash_table (info);
htab->sgot = bfd_get_section_by_name (dynobj, ".got");
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 ();
- 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;
}
if (info->relocatable)
return TRUE;
+ BFD_ASSERT (is_s390_elf (abfd));
+
htab = elf_s390_hash_table (info);
- 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);
&& ELF32_R_TYPE (rel->r_info) != R_390_PC32DBL
&& ELF32_R_TYPE (rel->r_info) != R_390_PC32)
|| (h != NULL
- && (! info->symbolic
+ && (! SYMBOLIC_BIND (info, h)
|| h->root.type == bfd_link_hash_defweak
|| !h->def_regular))))
|| (ELIMINATE_COPY_RELOCS
this reloc. */
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)
htab->elf.dynobj = abfd;
- dynobj = htab->elf.dynobj;
- sreloc = bfd_get_section_by_name (dynobj, name);
+ sreloc = _bfd_elf_make_dynamic_reloc_section
+ (sec, htab->elf.dynobj, 2, abfd, /*rela?*/ TRUE);
+
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 (dynobj,
- name,
- flags);
- if (sreloc == NULL
- || ! bfd_set_section_alignment (dynobj, sreloc, 2))
- return FALSE;
- }
- elf_section_data (sec)->sreloc = sreloc;
+ return FALSE;
}
/* If this is a global symbol, we count the number of
easily. Oh well. */
asection *s;
void *vpp;
+ Elf_Internal_Sym *isym;
- s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
- sec, r_symndx);
- if (s == NULL)
+ 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)
+ s = sec;
+
vpp = &elf_section_data (s)->local_dynrel;
head = (struct elf_s390_dyn_relocs **) vpp;
}
/* This relocation describes which C++ vtable entries are actually
used. Record for later use during GC. */
case R_390_GNU_VTENTRY:
- if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+ BFD_ASSERT (h != NULL);
+ if (h != NULL
+ && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
return FALSE;
break;
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);
|| h->needs_plt)
{
if (h->plt.refcount <= 0
- || (! info->shared
- && !h->def_dynamic
- && !h->ref_dynamic
- && h->root.type != bfd_link_hash_undefweak
- && h->root.type != bfd_link_hash_undefined))
+ || SYMBOL_CALLS_LOCAL (info, h)
+ || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ && h->root.type != bfd_link_hash_undefweak))
{
/* This case can occur if we saw a PLT32 reloc in an input
file, but the symbol was never referred to by a dynamic
htab = elf_s390_hash_table (info);
if (htab->elf.dynamic_sections_created
- && h->plt.refcount > 0
- && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- || h->root.type != bfd_link_hash_undefweak))
+ && h->plt.refcount > 0)
{
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
if (info->shared)
{
- if (SYMBOL_REFERENCES_LOCAL (info, h))
+ if (SYMBOL_CALLS_LOCAL (info, h))
{
struct elf_s390_dyn_relocs **pp;
Elf_Internal_Shdr *symtab_hdr;
asection *srela;
- if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+ if (! is_s390_elf (ibfd))
continue;
for (s = ibfd->sections; s != NULL; s = s->next)
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_s390_local_got_tls_type (ibfd);
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
+ BFD_ASSERT (is_s390_elf (input_bfd));
+
htab = elf_s390_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);
dyn = htab->elf.dynamic_sections_created;
if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
|| (info->shared
- && (info->symbolic
- || h->dynindx == -1
- || h->forced_local)
- && h->def_regular)
+ && SYMBOL_REFERENCES_LOCAL (info, h))
|| (ELF_ST_VISIBILITY (h->other)
&& h->root.type == bfd_link_hash_undefweak))
{
&& r_type != R_390_PC16DBL
&& r_type != R_390_PC32DBL
&& r_type != R_390_PC32)
- || (h != NULL
- && !SYMBOL_REFERENCES_LOCAL (info, h))))
+ || !SYMBOL_CALLS_LOCAL (info, h)))
|| (ELIMINATE_COPY_RELOCS
&& !info->shared
&& h != NULL
|| r_type == R_390_PC32DBL
|| r_type == R_390_PC32
|| !info->shared
- || !info->symbolic
+ || !SYMBOLIC_BIND (info, h)
|| !h->def_regular))
{
outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
The entry in the global offset table will already have been
initialized in the relocate_section function. */
if (info->shared
- && (info->symbolic
- || h->dynindx == -1
- || h->forced_local)
- && h->def_regular)
+ && SYMBOL_REFERENCES_LOCAL (info, h))
{
+ if (!h->def_regular)
+ return FALSE;
BFD_ASSERT((h->got.offset & 1) != 0);
rela.r_info = ELF32_R_INFO (0, R_390_RELATIVE);
rela.r_addend = (h->root.u.def.value
return plt->vma + PLT_FIRST_ENTRY_SIZE + i * PLT_ENTRY_SIZE;
}
+static bfd_boolean
+elf32_s390_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+{
+ elf_elfheader (obfd)->e_flags |= elf_elfheader (ibfd)->e_flags;
+ return TRUE;
+}
+
#define TARGET_BIG_SYM bfd_elf32_s390_vec
#define TARGET_BIG_NAME "elf32-s390"
#define bfd_elf32_bfd_reloc_type_lookup elf_s390_reloc_type_lookup
#define bfd_elf32_bfd_reloc_name_lookup elf_s390_reloc_name_lookup
+#define bfd_elf32_bfd_merge_private_bfd_data elf32_s390_merge_private_bfd_data
+
#define elf_backend_adjust_dynamic_symbol elf_s390_adjust_dynamic_symbol
#define elf_backend_check_relocs elf_s390_check_relocs
#define elf_backend_copy_indirect_symbol elf_s390_copy_indirect_symbol