diff options
Diffstat (limited to 'bfd/elf32-s390.c')
-rw-r--r-- | bfd/elf32-s390.c | 63 |
1 files changed, 52 insertions, 11 deletions
diff --git a/bfd/elf32-s390.c b/bfd/elf32-s390.c index eb8e172..9d7004e 100644 --- a/bfd/elf32-s390.c +++ b/bfd/elf32-s390.c @@ -2268,6 +2268,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. */ @@ -2982,16 +2983,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 +3030,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); } } |