X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felf32-s390.c;h=1ce327f96d8168c6dd569d4d6933f3bf432675f7;hb=fce00800554c50d3347f19ae0a9cc06c976ece23;hp=857b7a068b3c2599c9727e34259ef77487beadc6;hpb=26e415943a5d0dd3577345b8141eff3a0276d93e;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-s390.c b/bfd/elf32-s390.c index 857b7a068b..1ce327f96d 100644 --- a/bfd/elf32-s390.c +++ b/bfd/elf32-s390.c @@ -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; @@ -383,6 +454,12 @@ elf_s390_is_local_label_name (abfd, name) #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" +/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid + copying dynamic variables from a shared lib into an app's dynbss + section, and instead use a dynamic relocation to point into the + shared lib. */ +#define ELIMINATE_COPY_RELOCS 1 + /* The size in bytes of the first entry in the procedure linkage table. */ #define PLT_FIRST_ENTRY_SIZE 32 /* The size in bytes of an entry in the procedure linkage table. */ @@ -828,7 +905,18 @@ elf_s390_copy_indirect_symbol (bed, dir, ind) eind->tls_type = GOT_UNKNOWN; } - _bfd_elf_link_hash_copy_indirect (bed, dir, ind); + if (ELIMINATE_COPY_RELOCS + && ind->root.type != bfd_link_hash_indirect + && (dir->elf_link_hash_flags & ELF_LINK_HASH_DYNAMIC_ADJUSTED) != 0) + /* If called to transfer flags for a weakdef during processing + of elf_adjust_dynamic_symbol, don't copy ELF_LINK_NON_GOT_REF. + We clear it ourselves for ELIMINATE_COPY_RELOCS. */ + dir->elf_link_hash_flags |= + (ind->elf_link_hash_flags & (ELF_LINK_HASH_REF_DYNAMIC + | ELF_LINK_HASH_REF_REGULAR + | ELF_LINK_HASH_REF_REGULAR_NONWEAK)); + else + _bfd_elf_link_hash_copy_indirect (bed, dir, ind); } static int @@ -878,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); @@ -919,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: @@ -992,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 @@ -1018,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) @@ -1026,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: @@ -1035,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; @@ -1047,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; @@ -1149,7 +1245,8 @@ elf_s390_check_relocs (abfd, info, sec, relocs) || h->root.type == bfd_link_hash_defweak || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)))) - || (!info->shared + || (ELIMINATE_COPY_RELOCS + && !info->shared && (sec->flags & SEC_ALLOC) != 0 && h != NULL && (h->root.type == bfd_link_hash_defweak @@ -1372,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: @@ -1397,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: @@ -1420,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) @@ -1480,8 +1581,6 @@ elf_s390_adjust_dynamic_symbol (info, h) struct elf_link_hash_entry *h; { struct elf_s390_link_hash_table *htab; - struct elf_s390_link_hash_entry * eh; - struct elf_s390_dyn_relocs *p; asection *s; unsigned int power_of_two; @@ -1527,6 +1626,10 @@ elf_s390_adjust_dynamic_symbol (info, h) || h->weakdef->root.type == bfd_link_hash_defweak); h->root.u.def.section = h->weakdef->root.u.def.section; h->root.u.def.value = h->weakdef->root.u.def.value; + if (ELIMINATE_COPY_RELOCS || info->nocopyreloc) + h->elf_link_hash_flags + = ((h->elf_link_hash_flags & ~ELF_LINK_NON_GOT_REF) + | (h->weakdef->elf_link_hash_flags & ELF_LINK_NON_GOT_REF)); return TRUE; } @@ -1552,20 +1655,26 @@ elf_s390_adjust_dynamic_symbol (info, h) return TRUE; } - eh = (struct elf_s390_link_hash_entry *) h; - for (p = eh->dyn_relocs; p != NULL; p = p->next) + if (ELIMINATE_COPY_RELOCS) { - s = p->sec->output_section; - if (s != NULL && (s->flags & SEC_READONLY) != 0) - break; - } + struct elf_s390_link_hash_entry * eh; + struct elf_s390_dyn_relocs *p; - /* If we didn't find any dynamic relocs in read-only sections, then - we'll be keeping the dynamic relocs and avoiding the copy reloc. */ - if (p == NULL) - { - h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF; - return TRUE; + eh = (struct elf_s390_link_hash_entry *) h; + for (p = eh->dyn_relocs; p != NULL; p = p->next) + { + s = p->sec->output_section; + if (s != NULL && (s->flags & SEC_READONLY) != 0) + break; + } + + /* If we didn't find any dynamic relocs in read-only sections, then + we'll be keeping the dynamic relocs and avoiding the copy reloc. */ + if (p == NULL) + { + h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF; + return TRUE; + } } /* We must allocate the symbol in our .dynbss section, which will @@ -1618,9 +1727,9 @@ elf_s390_adjust_dynamic_symbol (info, h) will be called from elflink.h. If elflink.h doesn't call our finish_dynamic_symbol routine, we'll need to do something about initializing any .plt and .got entries in elf_s390_relocate_section. */ -#define WILL_CALL_FINISH_DYNAMIC_SYMBOL(DYN, INFO, H) \ +#define WILL_CALL_FINISH_DYNAMIC_SYMBOL(DYN, SHARED, H) \ ((DYN) \ - && ((INFO)->shared \ + && ((SHARED) \ || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) \ && ((H)->dynindx != -1 \ || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)) @@ -1651,7 +1760,9 @@ allocate_dynrelocs (h, inf) htab = elf_s390_hash_table (info); 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. Undefined weak syms won't yet be marked as dynamic. */ @@ -1662,7 +1773,8 @@ allocate_dynrelocs (h, inf) return FALSE; } - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info, h)) + if (info->shared + || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) { asection *s = htab->splt; @@ -1758,7 +1870,10 @@ allocate_dynrelocs (h, inf) htab->srelgot->_raw_size += sizeof (Elf32_External_Rela); else if (tls_type == GOT_TLS_GD) htab->srelgot->_raw_size += 2 * sizeof (Elf32_External_Rela); - else if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h)) + else if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak) + && (info->shared + || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))) htab->srelgot->_raw_size += sizeof (Elf32_External_Rela); } else @@ -1792,8 +1907,14 @@ allocate_dynrelocs (h, inf) pp = &p->next; } } + + /* Also discard relocs on undefined weak syms with non-default + visibility. */ + if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT + && h->root.type == bfd_link_hash_undefweak) + eh->dyn_relocs = NULL; } - else + else if (ELIMINATE_COPY_RELOCS) { /* For the non-shared case, discard space for relocs against symbols which turn out to need copy relocs or are not @@ -1889,7 +2010,7 @@ elf_s390_size_dynamic_sections (output_bfd, info) if (htab->elf.dynamic_sections_created) { /* Set the contents of the .interp section to the interpreter. */ - if (! info->shared) + if (info->executable) { s = bfd_get_section_by_name (dynobj, ".interp"); if (s == NULL) @@ -2047,7 +2168,7 @@ elf_s390_size_dynamic_sections (output_bfd, info) #define add_dynamic_entry(TAG, VAL) \ bfd_elf32_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL)) - if (! info->shared) + if (info->executable) { if (!add_dynamic_entry (DT_DEBUG, 0)) return FALSE; @@ -2160,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); @@ -2235,7 +2356,7 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section, } else if (h->root.type == bfd_link_hash_undefweak) relocation = 0; - else if (info->shared + else if (!info->executable && !info->no_undefined && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) relocation = 0; @@ -2255,6 +2376,7 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section, { 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 @@ -2288,6 +2410,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 @@ -2301,12 +2424,14 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section, off = h->got.offset; dyn = htab->elf.dynamic_sections_created; - if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h) + if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) || (info->shared && (info->symbolic || h->dynindx == -1 || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL)) - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))) + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)) + || (ELF_ST_VISIBILITY (h->other) + && h->root.type == bfd_link_hash_undefweak)) { /* This is actually a static link, or it is a -Bsymbolic link and the symbol is defined @@ -2471,6 +2596,9 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section, break; if ((info->shared + && (h == NULL + || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak) && ((r_type != R_390_PC16 && r_type != R_390_PC16DBL && r_type != R_390_PC32DBL @@ -2480,7 +2608,8 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section, && (! info->symbolic || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)))) - || (!info->shared + || (ELIMINATE_COPY_RELOCS + && !info->shared && h != NULL && h->dynindx != -1 && (h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0 @@ -2688,6 +2817,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) { @@ -2895,9 +3025,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) {