summaryrefslogtreecommitdiff
path: root/bfd/elf32-s390.c
diff options
context:
space:
mode:
authorAndreas Krebbel <Andreas.Krebbel@de.ibm.com>2012-02-17 08:38:05 +0000
committerAndreas Krebbel <Andreas.Krebbel@de.ibm.com>2012-02-17 08:38:05 +0000
commitf881039ececc2a2b7d28ee9523f47436d47a7141 (patch)
tree6b2d988fc176de11d361dd8ffbd38e81a6eff57a /bfd/elf32-s390.c
parentc7229086148cacaa984b05b84b5ad1771ebf4106 (diff)
downloadbinutils-redhat-f881039ececc2a2b7d28ee9523f47436d47a7141.tar.gz
2012-02-17 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
* elf32-s390.c (elf_s390_relocate_section): Support basr in the GD->LE and LD->LE optimizations.
Diffstat (limited to 'bfd/elf32-s390.c')
-rw-r--r--bfd/elf32-s390.c32
1 files changed, 26 insertions, 6 deletions
diff --git a/bfd/elf32-s390.c b/bfd/elf32-s390.c
index bb586708f3..85a20bdc46 100644
--- a/bfd/elf32-s390.c
+++ b/bfd/elf32-s390.c
@@ -2919,11 +2919,18 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
if ((insn & 0xff000fff) != 0x4d000000 &&
- (insn & 0xffff0000) != 0xc0e50000)
+ (insn & 0xffff0000) != 0xc0e50000 &&
+ (insn & 0xff000000) != 0x0d000000)
invalid_tls_insn (input_bfd, input_section, rel);
if (!info->shared && (h == NULL || h->dynindx == -1))
{
- if ((insn & 0xff000000) == 0x4d000000)
+ if ((insn & 0xff000000) == 0x0d000000)
+ {
+ /* GD->LE transition.
+ basr rx, ry -> nopr r7 */
+ insn = 0x07070000 | (insn & 0xffff);
+ }
+ else if ((insn & 0xff000000) == 0x4d000000)
{
/* GD->LE transition.
bas %r14,0(%rx,%r13) -> bc 0,0 */
@@ -2932,7 +2939,7 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
else
{
/* GD->LE transition.
- brasl %r14,_tls_get_addr@plt -> brcl 0,. */
+ brasl %r14,_tls_get_offset@plt -> brcl 0,. */
insn = 0xc0040000;
bfd_put_16 (output_bfd, 0x0000,
contents + rel->r_offset + 4);
@@ -2940,6 +2947,11 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
}
else
{
+ /* If basr is used in the pic case to invoke
+ _tls_get_offset, something went wrong before. */
+ if ((insn & 0xff000000) == 0x0d000000)
+ invalid_tls_insn (input_bfd, input_section, rel);
+
if ((insn & 0xff000000) == 0x4d000000)
{
/* GD->IE transition.
@@ -2966,9 +2978,17 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
if ((insn & 0xff000fff) != 0x4d000000 &&
- (insn & 0xffff0000) != 0xc0e50000)
+ (insn & 0xffff0000) != 0xc0e50000 &&
+ (insn & 0xff000000) != 0x0d000000)
invalid_tls_insn (input_bfd, input_section, rel);
- if ((insn & 0xff000000) == 0x4d000000)
+
+ if ((insn & 0xff000000) == 0x0d000000)
+ {
+ /* LD->LE transition.
+ basr rx, ry -> nopr r7 */
+ insn = 0x07070000 | (insn & 0xffff);
+ }
+ else if ((insn & 0xff000000) == 0x4d000000)
{
/* LD->LE transition.
bas %r14,0(%rx,%r13) -> bc 0,0 */
@@ -2977,7 +2997,7 @@ elf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
else
{
/* LD->LE transition.
- brasl %r14,__tls_get_addr@plt -> brcl 0,. */
+ brasl %r14,__tls_get_offset@plt -> brcl 0,. */
insn = 0xc0040000;
bfd_put_16 (output_bfd, 0x0000,
contents + rel->r_offset + 4);