summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog8
-rw-r--r--bfd/elf32-s390.c63
-rw-r--r--bfd/elf64-s390.c1
3 files changed, 61 insertions, 11 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index bd22f4e5275..1a4f31433b3 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,11 @@
+2006-05-05 Martin Schwidefsky <schwidefsky@de.ibm.com>
+
+ * elf32-s390.c (invalid_tls_insn): Call bfd_set_error.
+ (elf_s390_relocate_section): Add code to do the GD->LE and
+ LD->LE TLS linker optimizations if a brasl instruction is used
+ for the __tls_get_offset function call.
+ * elf64-s390.c (invalid_tls_insn): Call bfd_set_error.
+
2006-05-05 Alan Modra <amodra@bigpond.net.au>
* elf64-ppc.c (ppc64_elf_tls_optimize): Only optimize
diff --git a/bfd/elf32-s390.c b/bfd/elf32-s390.c
index eb8e1724fc1..9d7004e5c0e 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);
}
}
diff --git a/bfd/elf64-s390.c b/bfd/elf64-s390.c
index 1fe0c6ca915..bb203970f15 100644
--- a/bfd/elf64-s390.c
+++ b/bfd/elf64-s390.c
@@ -2240,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. */