aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf32-s390.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/elf32-s390.c')
-rw-r--r--bfd/elf32-s390.c157
1 files changed, 111 insertions, 46 deletions
diff --git a/bfd/elf32-s390.c b/bfd/elf32-s390.c
index 97be1db..5b07ab0 100644
--- a/bfd/elf32-s390.c
+++ b/bfd/elf32-s390.c
@@ -40,7 +40,7 @@ static bfd_boolean create_got_section
static bfd_boolean elf_s390_create_dynamic_sections
PARAMS((bfd *, struct bfd_link_info *));
static void elf_s390_copy_indirect_symbol
- PARAMS ((struct elf_backend_data *, struct elf_link_hash_entry *,
+ PARAMS ((const struct elf_backend_data *, struct elf_link_hash_entry *,
struct elf_link_hash_entry *));
static bfd_boolean elf_s390_check_relocs
PARAMS ((bfd *, struct bfd_link_info *, asection *,
@@ -88,6 +88,8 @@ static bfd_vma tpoff
PARAMS ((struct bfd_link_info *, bfd_vma));
static void invalid_tls_insn
PARAMS ((bfd *, asection *, Elf_Internal_Rela *));
+static bfd_reloc_status_type s390_elf_ldisp_reloc
+ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
#include "elf/s390.h"
@@ -119,7 +121,7 @@ static reloc_howto_type elf_howto_table[] =
bfd_elf_generic_reloc, "R_390_32", FALSE, 0,0xffffffff, FALSE),
HOWTO(R_390_PC32, 0, 2, 32, TRUE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_390_PC32", FALSE, 0,0xffffffff, TRUE),
- HOWTO(R_390_GOT12, 0, 1, 12, FALSE, 0, complain_overflow_dont,
+ HOWTO(R_390_GOT12, 0, 1, 12, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_390_GOT12", FALSE, 0,0x00000fff, FALSE),
HOWTO(R_390_GOT32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_390_GOT32", FALSE, 0,0xffffffff, FALSE),
@@ -208,6 +210,14 @@ static reloc_howto_type elf_howto_table[] =
bfd_elf_generic_reloc, "R_390_TLS_DTPOFF", FALSE, 0, 0xffffffff, FALSE),
HOWTO(R_390_TLS_TPOFF, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_390_TLS_TPOFF", FALSE, 0, 0xffffffff, FALSE),
+ HOWTO(R_390_20, 0, 2, 20, FALSE, 8, complain_overflow_dont,
+ s390_elf_ldisp_reloc, "R_390_20", FALSE, 0,0x0fffff00, FALSE),
+ HOWTO(R_390_GOT20, 0, 2, 20, FALSE, 8, complain_overflow_dont,
+ s390_elf_ldisp_reloc, "R_390_GOT20", FALSE, 0,0x0fffff00, FALSE),
+ HOWTO(R_390_GOTPLT20, 0, 2, 20, FALSE, 8, complain_overflow_dont,
+ s390_elf_ldisp_reloc, "R_390_GOTPLT20", FALSE, 0,0x0fffff00, FALSE),
+ HOWTO(R_390_TLS_GOTIE20, 0, 2, 20, FALSE, 8, complain_overflow_dont,
+ s390_elf_ldisp_reloc, "R_390_TLS_GOTIE20", FALSE, 0,0x0fffff00, FALSE),
};
/* GNU extension to record C++ vtable hierarchy. */
@@ -313,6 +323,14 @@ elf_s390_reloc_type_lookup (abfd, code)
return &elf_howto_table[(int) R_390_TLS_DTPOFF];
case BFD_RELOC_390_TLS_TPOFF:
return &elf_howto_table[(int) R_390_TLS_TPOFF];
+ case BFD_RELOC_390_20:
+ return &elf_howto_table[(int) R_390_20];
+ case BFD_RELOC_390_GOT20:
+ return &elf_howto_table[(int) R_390_GOT20];
+ case BFD_RELOC_390_GOTPLT20:
+ return &elf_howto_table[(int) R_390_GOTPLT20];
+ case BFD_RELOC_390_TLS_GOTIE20:
+ return &elf_howto_table[(int) R_390_TLS_GOTIE20];
case BFD_RELOC_VTABLE_INHERIT:
return &elf32_s390_vtinherit_howto;
case BFD_RELOC_VTABLE_ENTRY:
@@ -365,6 +383,59 @@ s390_tls_reloc (abfd, reloc_entry, symbol, data, input_section,
return bfd_reloc_ok;
}
+/* Handle the large displacement relocs. */
+static bfd_reloc_status_type
+s390_elf_ldisp_reloc (abfd, reloc_entry, symbol, data, input_section,
+ output_bfd, error_message)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data ATTRIBUTE_UNUSED;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message ATTRIBUTE_UNUSED;
+{
+ reloc_howto_type *howto = reloc_entry->howto;
+ bfd_vma relocation;
+ bfd_vma insn;
+
+ if (output_bfd != (bfd *) NULL
+ && (symbol->flags & BSF_SECTION_SYM) == 0
+ && (! howto->partial_inplace
+ || reloc_entry->addend == 0))
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+
+ if (output_bfd != NULL)
+ return bfd_reloc_continue;
+
+ if (reloc_entry->address > input_section->_cooked_size)
+ return bfd_reloc_outofrange;
+
+ relocation = (symbol->value
+ + symbol->section->output_section->vma
+ + symbol->section->output_offset);
+ relocation += reloc_entry->addend;
+ if (howto->pc_relative)
+ {
+ relocation -= (input_section->output_section->vma
+ + input_section->output_offset);
+ relocation -= reloc_entry->address;
+ }
+
+ insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
+ insn |= (relocation & 0xfff) << 16 | (relocation & 0xff000) >> 4;
+ bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address);
+
+ if ((bfd_signed_vma) relocation < - 0x80000
+ || (bfd_signed_vma) relocation > 0x7ffff)
+ return bfd_reloc_overflow;
+ else
+ return bfd_reloc_ok;
+}
+
static bfd_boolean
elf_s390_is_local_label_name (abfd, name)
bfd *abfd;
@@ -785,7 +856,7 @@ elf_s390_create_dynamic_sections (dynobj, info)
static void
elf_s390_copy_indirect_symbol (bed, dir, ind)
- struct elf_backend_data *bed;
+ const struct elf_backend_data *bed;
struct elf_link_hash_entry *dir, *ind;
{
struct elf_s390_link_hash_entry *edir, *eind;
@@ -895,7 +966,7 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
bfd_signed_vma *local_got_refcounts;
int tls_type, old_tls_type;
- if (info->relocateable)
+ if (info->relocatable)
return TRUE;
htab = elf_s390_hash_table (info);
@@ -936,14 +1007,17 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
{
case R_390_GOT12:
case R_390_GOT16:
+ case R_390_GOT20:
case R_390_GOT32:
case R_390_GOTENT:
case R_390_GOTPLT12:
case R_390_GOTPLT16:
+ case R_390_GOTPLT20:
case R_390_GOTPLT32:
case R_390_GOTPLTENT:
case R_390_TLS_GD32:
case R_390_TLS_GOTIE12:
+ case R_390_TLS_GOTIE20:
case R_390_TLS_GOTIE32:
case R_390_TLS_IEENT:
case R_390_TLS_IE32:
@@ -1009,6 +1083,7 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
case R_390_GOTPLT12:
case R_390_GOTPLT16:
+ case R_390_GOTPLT20:
case R_390_GOTPLT32:
case R_390_GOTPLTENT:
/* This symbol requires either a procedure linkage table entry
@@ -1035,6 +1110,7 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
case R_390_TLS_IE32:
case R_390_TLS_GOTIE12:
+ case R_390_TLS_GOTIE20:
case R_390_TLS_GOTIE32:
case R_390_TLS_IEENT:
if (info->shared)
@@ -1043,6 +1119,7 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
case R_390_GOT12:
case R_390_GOT16:
+ case R_390_GOT20:
case R_390_GOT32:
case R_390_GOTENT:
case R_390_TLS_GD32:
@@ -1052,6 +1129,7 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
default:
case R_390_GOT12:
case R_390_GOT16:
+ case R_390_GOT20:
case R_390_GOT32:
case R_390_GOTENT:
tls_type = GOT_NORMAL;
@@ -1064,6 +1142,7 @@ elf_s390_check_relocs (abfd, info, sec, relocs)
tls_type = GOT_TLS_IE;
break;
case R_390_TLS_GOTIE12:
+ case R_390_TLS_GOTIE20:
case R_390_TLS_IEENT:
tls_type = GOT_TLS_IE_NLT;
break;
@@ -1390,10 +1469,12 @@ elf_s390_gc_sweep_hook (abfd, info, sec, relocs)
case R_390_TLS_GD32:
case R_390_TLS_IE32:
case R_390_TLS_GOTIE12:
+ case R_390_TLS_GOTIE20:
case R_390_TLS_GOTIE32:
case R_390_TLS_IEENT:
case R_390_GOT12:
case R_390_GOT16:
+ case R_390_GOT20:
case R_390_GOT32:
case R_390_GOTOFF16:
case R_390_GOTOFF32:
@@ -1415,6 +1496,7 @@ elf_s390_gc_sweep_hook (abfd, info, sec, relocs)
case R_390_8:
case R_390_12:
case R_390_16:
+ case R_390_20:
case R_390_32:
case R_390_PC16:
case R_390_PC16DBL:
@@ -1438,6 +1520,7 @@ elf_s390_gc_sweep_hook (abfd, info, sec, relocs)
case R_390_GOTPLT12:
case R_390_GOTPLT16:
+ case R_390_GOTPLT20:
case R_390_GOTPLT32:
case R_390_GOTPLTENT:
if (h != NULL)
@@ -2198,7 +2281,7 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
- if (info->relocateable)
+ if (info->relocatable)
return TRUE;
htab = elf_s390_hash_table (info);
@@ -2248,51 +2331,19 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
}
else
{
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- while (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ bfd_boolean warned ATTRIBUTE_UNUSED;
- if (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- {
- sec = h->root.u.def.section;
- if (sec->output_section == NULL)
- {
- /* Set a flag that will be cleared later if we find a
- relocation value for this symbol. output_section
- is typically NULL for symbols satisfied by a shared
- library. */
- unresolved_reloc = TRUE;
- relocation = 0;
- }
- else
- relocation = (h->root.u.def.value
- + sec->output_section->vma
- + sec->output_offset);
- }
- else if (h->root.type == bfd_link_hash_undefweak)
- relocation = 0;
- else if (info->shared
- && !info->no_undefined
- && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
- relocation = 0;
- else
- {
- if (! ((*info->callbacks->undefined_symbol)
- (info, h->root.root.string, input_bfd,
- input_section, rel->r_offset,
- (!info->shared || info->no_undefined
- || ELF_ST_VISIBILITY (h->other)))))
- return FALSE;
- relocation = 0;
- }
+ RELOC_FOR_GLOBAL_SYMBOL (h, sym_hashes, r_symndx,
+ symtab_hdr, relocation, sec,
+ unresolved_reloc, info,
+ warned);
}
switch (r_type)
{
case R_390_GOTPLT12:
case R_390_GOTPLT16:
+ case R_390_GOTPLT20:
case R_390_GOTPLT32:
case R_390_GOTPLTENT:
/* There are three cases for a GOTPLT relocation. 1) The
@@ -2326,6 +2377,7 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
case R_390_GOT12:
case R_390_GOT16:
+ case R_390_GOT20:
case R_390_GOT32:
case R_390_GOTENT:
/* Relocation is to the entry for this symbol in the global
@@ -2732,6 +2784,7 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
break;
case R_390_TLS_GOTIE12:
+ case R_390_TLS_GOTIE20:
case R_390_TLS_IEENT:
if (h == NULL)
{
@@ -2939,9 +2992,21 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
(long) rel->r_offset,
h->root.root.string);
- r = _bfd_final_link_relocate (howto, input_bfd, input_section,
- contents, rel->r_offset,
- relocation, rel->r_addend);
+ if (r_type == R_390_20
+ || r_type == R_390_GOT20
+ || r_type == R_390_GOTPLT20
+ || r_type == R_390_TLS_GOTIE20)
+ {
+ relocation += rel->r_addend;
+ relocation = (relocation&0xfff) << 8 | (relocation&0xff000) >> 12;
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel->r_offset,
+ relocation, 0);
+ }
+ else
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel->r_offset,
+ relocation, rel->r_addend);
if (r != bfd_reloc_ok)
{