summaryrefslogtreecommitdiffstats
path: root/contrib/binutils/bfd/elf32-s390.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/binutils/bfd/elf32-s390.c')
-rw-r--r--contrib/binutils/bfd/elf32-s390.c223
1 files changed, 124 insertions, 99 deletions
diff --git a/contrib/binutils/bfd/elf32-s390.c b/contrib/binutils/bfd/elf32-s390.c
index eb8e172..9e36a5d 100644
--- a/contrib/binutils/bfd/elf32-s390.c
+++ b/contrib/binutils/bfd/elf32-s390.c
@@ -1,5 +1,5 @@
/* IBM S/390-specific support for 32-bit ELF
- Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
Contributed by Carl B. Pedersen and Martin Schwidefsky.
@@ -20,8 +20,8 @@
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"
@@ -46,12 +46,6 @@ static void elf_s390_copy_indirect_symbol
static bfd_boolean elf_s390_check_relocs
PARAMS ((bfd *, struct bfd_link_info *, asection *,
const Elf_Internal_Rela *));
-static asection *elf_s390_gc_mark_hook
- PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
- struct elf_link_hash_entry *, Elf_Internal_Sym *));
-static bfd_boolean elf_s390_gc_sweep_hook
- PARAMS ((bfd *, struct bfd_link_info *, asection *,
- const Elf_Internal_Rela *));
struct elf_s390_link_hash_entry;
static void elf_s390_adjust_gotplt
PARAMS ((struct elf_s390_link_hash_entry *));
@@ -73,8 +67,6 @@ static enum elf_reloc_type_class elf_s390_reloc_type_class
PARAMS ((const Elf_Internal_Rela *));
static bfd_boolean elf_s390_finish_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
-static bfd_boolean elf_s390_mkobject
- PARAMS ((bfd *));
static bfd_boolean elf_s390_object_p
PARAMS ((bfd *));
static bfd_boolean elf_s390_grok_prstatus
@@ -342,6 +334,25 @@ elf_s390_reloc_type_lookup (abfd, code)
return 0;
}
+static reloc_howto_type *
+elf_s390_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];
+
+ if (strcasecmp (elf32_s390_vtinherit_howto.name, r_name) == 0)
+ return &elf32_s390_vtinherit_howto;
+ if (strcasecmp (elf32_s390_vtentry_howto.name, r_name) == 0)
+ return &elf32_s390_vtentry_howto;
+
+ return NULL;
+}
+
/* We need to use ELF32_R_TYPE so we have our own copy of this function,
and elf32-s390.c has its own copy. */
@@ -678,14 +689,16 @@ struct elf_s390_obj_tdata
(elf_s390_tdata (abfd)->local_got_tls_type)
static bfd_boolean
-elf_s390_mkobject (abfd)
- bfd *abfd;
+elf_s390_mkobject (bfd *abfd)
{
- 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 TRUE;
+ {
+ 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);
}
static bfd_boolean
@@ -1273,7 +1286,7 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
if (name == NULL)
return FALSE;
- if (strncmp (name, ".rela", 5) != 0
+ if (! CONST_STRNEQ (name, ".rela")
|| strcmp (bfd_get_section_name (abfd, sec),
name + 5) != 0)
{
@@ -1379,50 +1392,30 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
relocation. */
static asection *
-elf_s390_gc_mark_hook (sec, info, rel, h, sym)
- asection *sec;
- struct bfd_link_info *info ATTRIBUTE_UNUSED;
- Elf_Internal_Rela *rel;
- struct elf_link_hash_entry *h;
- Elf_Internal_Sym *sym;
+elf_s390_gc_mark_hook (asection *sec,
+ 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_390_GNU_VTINHERIT:
- case R_390_GNU_VTENTRY:
- break;
-
- default:
- switch (h->root.type)
- {
- case bfd_link_hash_defined:
- case bfd_link_hash_defweak:
- return h->root.u.def.section;
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_390_GNU_VTINHERIT:
+ case R_390_GNU_VTENTRY:
+ return NULL;
+ }
+ return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
- 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;
}
/* Update the got entry reference counts for the section being removed. */
static bfd_boolean
-elf_s390_gc_sweep_hook (abfd, info, sec, relocs)
- bfd *abfd;
- struct bfd_link_info *info;
- asection *sec;
- const Elf_Internal_Rela *relocs;
+elf_s390_gc_sweep_hook (bfd *abfd,
+ struct bfd_link_info *info,
+ asection *sec,
+ const Elf_Internal_Rela *relocs)
{
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
@@ -1589,7 +1582,6 @@ elf_s390_adjust_dynamic_symbol (info, h)
{
struct elf_s390_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
@@ -1710,29 +1702,9 @@ elf_s390_adjust_dynamic_symbol (info, h)
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
@@ -2126,7 +2098,7 @@ elf_s390_size_dynamic_sections (output_bfd, info)
/* Strip this section if we don't need it; see the
comment below. */
}
- else if (strncmp (bfd_get_section_name (dynobj, s), ".rela", 5) == 0)
+ else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela"))
{
if (s->size != 0)
relocs = TRUE;
@@ -2268,6 +2240,7 @@ invalid_tls_insn (input_bfd, input_section, rel)
input_section,
(long) rel->r_offset,
howto->name);
+ bfd_set_error (bfd_error_bad_value);
}
/* Relocate a 390 ELF section. */
@@ -2291,9 +2264,6 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
- if (info->relocatable)
- return TRUE;
-
htab = elf_s390_hash_table (info);
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
@@ -2328,7 +2298,6 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
howto = elf_howto_table + r_type;
r_symndx = ELF32_R_SYM (rel->r_info);
- /* This is a final link. */
h = NULL;
sym = NULL;
sec = NULL;
@@ -2349,6 +2318,20 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
unresolved_reloc, warned);
}
+ if (sec != NULL && elf_discarded_section (sec))
+ {
+ /* 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_390_GOTPLT12:
@@ -2565,11 +2548,7 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
case R_390_PC16DBL:
case R_390_PC32DBL:
case R_390_PC32:
- /* r_symndx will be zero only for relocs against symbols
- from removed linkonce sections, or sections discarded by
- a linker script. */
- if (r_symndx == 0
- || (input_section->flags & SEC_ALLOC) == 0)
+ if ((input_section->flags & SEC_ALLOC) == 0)
break;
if ((info->shared
@@ -2655,14 +2634,18 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
osec = sec->output_section;
sindx = elf_section_data (osec)->dynindx;
- BFD_ASSERT (sindx > 0);
+ if (sindx == 0)
+ {
+ osec = htab->elf.text_index_section;
+ sindx = elf_section_data (osec)->dynindx;
+ }
+ BFD_ASSERT (sindx != 0);
/* We are turning this relocation into one
against a section symbol, so subtract out
the output section's address but not the
offset of the input section in the output
section. */
-
outrel.r_addend -= osec->vma;
}
outrel.r_info = ELF32_R_INFO (sindx, r_type);
@@ -2926,7 +2909,7 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
continue;
case R_390_TLS_LDO32:
- if (info->shared || (input_section->flags & SEC_CODE) == 0)
+ if (info->shared)
relocation -= dtpoff_base (info);
else
/* When converting LDO to LE, we must negate. */
@@ -2982,16 +2965,44 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
unsigned int insn;
insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
- if ((insn & 0xff000fff) != 0x4d000000)
+ if ((insn & 0xff000fff) != 0x4d000000 &&
+ (insn & 0xffff0000) != 0xc0e50000)
invalid_tls_insn (input_bfd, input_section, rel);
if (!info->shared && (h == NULL || h->dynindx == -1))
- /* GD->LE transition.
- bas %r14,0(%rx,%r13) -> bc 0,0 */
- insn = 0x47000000;
+ {
+ if ((insn & 0xff000000) == 0x4d000000)
+ {
+ /* GD->LE transition.
+ bas %r14,0(%rx,%r13) -> bc 0,0 */
+ insn = 0x47000000;
+ }
+ else
+ {
+ /* GD->LE transition.
+ brasl %r14,_tls_get_addr@plt -> brcl 0,. */
+ insn = 0xc0040000;
+ bfd_put_16 (output_bfd, 0x0000,
+ contents + rel->r_offset + 4);
+ }
+ }
else
- /* GD->IE transition.
- bas %r14,0(%rx,%r13) -> l %r2,0(%r2,%r12) */
- insn = 0x5822c000;
+ {
+ if ((insn & 0xff000000) == 0x4d000000)
+ {
+ /* GD->IE transition.
+ bas %r14,0(%rx,%r13) -> l %r2,0(%r2,%r12) */
+ insn = 0x5822c000;
+ }
+ else
+ {
+ /* GD->IE transition.
+ brasl %r14,__tls_get_addr@plt ->
+ l %r2,0(%r2,%r12) ; bcr 0,0 */
+ insn = 0x5822c000;
+ bfd_put_16 (output_bfd, 0x0700,
+ contents + rel->r_offset + 4);
+ }
+ }
bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
}
else if (r_type == R_390_TLS_LDCALL)
@@ -3001,11 +3012,23 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
unsigned int insn;
insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
- if ((insn & 0xff000fff) != 0x4d000000)
+ if ((insn & 0xff000fff) != 0x4d000000 &&
+ (insn & 0xffff0000) != 0xc0e50000)
invalid_tls_insn (input_bfd, input_section, rel);
- /* LD->LE transition.
- bas %r14,0(%rx,%r13) -> bc 0,0 */
- insn = 0x47000000;
+ if ((insn & 0xff000000) == 0x4d000000)
+ {
+ /* LD->LE transition.
+ bas %r14,0(%rx,%r13) -> bc 0,0 */
+ insn = 0x47000000;
+ }
+ else
+ {
+ /* LD->LE transition.
+ brasl %r14,__tls_get_addr@plt -> brcl 0,. */
+ insn = 0xc0040000;
+ bfd_put_16 (output_bfd, 0x0000,
+ contents + rel->r_offset + 4);
+ }
bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
}
}
@@ -3515,6 +3538,7 @@ elf_s390_plt_sym_val (bfd_vma i, const asection *plt,
#define bfd_elf32_bfd_is_local_label_name elf_s390_is_local_label_name
#define bfd_elf32_bfd_link_hash_table_create elf_s390_link_hash_table_create
#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 elf_backend_adjust_dynamic_symbol elf_s390_adjust_dynamic_symbol
#define elf_backend_check_relocs elf_s390_check_relocs
@@ -3527,6 +3551,7 @@ elf_s390_plt_sym_val (bfd_vma i, const asection *plt,
#define elf_backend_reloc_type_class elf_s390_reloc_type_class
#define elf_backend_relocate_section elf_s390_relocate_section
#define elf_backend_size_dynamic_sections elf_s390_size_dynamic_sections
+#define elf_backend_init_index_section _bfd_elf_init_1_index_section
#define elf_backend_reloc_type_class elf_s390_reloc_type_class
#define elf_backend_grok_prstatus elf_s390_grok_prstatus
#define elf_backend_plt_sym_val elf_s390_plt_sym_val
OpenPOWER on IntegriCloud