diff options
Diffstat (limited to 'bfd/elf32-s390.c')
-rw-r--r-- | bfd/elf32-s390.c | 157 |
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) { |