aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/elf32-s390.c30
-rw-r--r--bfd/elf64-s390.c31
-rw-r--r--ld/testsuite/ld-s390/gotreloc-1.s11
-rw-r--r--ld/testsuite/ld-s390/gotreloc-1.ver1
-rw-r--r--ld/testsuite/ld-s390/gotreloc_31-1.dd14
-rw-r--r--ld/testsuite/ld-s390/gotreloc_64-1.dd12
-rw-r--r--ld/testsuite/ld-s390/s390.exp11
7 files changed, 110 insertions, 0 deletions
diff --git a/bfd/elf32-s390.c b/bfd/elf32-s390.c
index bee532d..6467b03 100644
--- a/bfd/elf32-s390.c
+++ b/bfd/elf32-s390.c
@@ -2536,6 +2536,36 @@ elf_s390_relocate_section (bfd *output_bfd,
base_got->contents + off);
h->got.offset |= 1;
}
+
+ if ((h->def_regular
+ && info->shared
+ && SYMBOL_REFERENCES_LOCAL (info, h))
+ /* lrl rx,sym@GOTENT -> larl rx, sym */
+ && ((r_type == R_390_GOTENT
+ && (bfd_get_16 (input_bfd,
+ contents + rel->r_offset - 2)
+ & 0xff0f) == 0xc40d)
+ /* ly rx, sym@GOT(r12) -> larl rx, sym */
+ || (r_type == R_390_GOT20
+ && (bfd_get_32 (input_bfd,
+ contents + rel->r_offset - 2)
+ & 0xff00f000) == 0xe300c000
+ && bfd_get_8 (input_bfd,
+ contents + rel->r_offset + 3) == 0x58)))
+ {
+ unsigned short new_insn =
+ (0xc000 | (bfd_get_8 (input_bfd,
+ contents + rel->r_offset - 1) & 0xf0));
+ bfd_put_16 (output_bfd, new_insn,
+ contents + rel->r_offset - 2);
+ r_type = R_390_PC32DBL;
+ rel->r_addend = 2;
+ howto = elf_howto_table + r_type;
+ relocation = h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset;
+ goto do_relocation;
+ }
}
else
unresolved_reloc = FALSE;
diff --git a/bfd/elf64-s390.c b/bfd/elf64-s390.c
index bba6cec..75413e0 100644
--- a/bfd/elf64-s390.c
+++ b/bfd/elf64-s390.c
@@ -2496,6 +2496,37 @@ elf_s390_relocate_section (bfd *output_bfd,
base_got->contents + off);
h->got.offset |= 1;
}
+
+ if ((h->def_regular
+ && info->shared
+ && SYMBOL_REFERENCES_LOCAL (info, h))
+ /* lgrl rx,sym@GOTENT -> larl rx, sym */
+ && ((r_type == R_390_GOTENT
+ && (bfd_get_16 (input_bfd,
+ contents + rel->r_offset - 2)
+ & 0xff0f) == 0xc408)
+ /* lg rx, sym@GOT(r12) -> larl rx, sym */
+ || (r_type == R_390_GOT20
+ && (bfd_get_32 (input_bfd,
+ contents + rel->r_offset - 2)
+ & 0xff00f000) == 0xe300c000
+ && bfd_get_8 (input_bfd,
+ contents + rel->r_offset + 3) == 0x04)))
+
+ {
+ unsigned short new_insn =
+ (0xc000 | (bfd_get_8 (input_bfd,
+ contents + rel->r_offset - 1) & 0xf0));
+ bfd_put_16 (output_bfd, new_insn,
+ contents + rel->r_offset - 2);
+ r_type = R_390_PC32DBL;
+ rel->r_addend = 2;
+ howto = elf_howto_table + r_type;
+ relocation = h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset;
+ goto do_relocation;
+ }
}
else
unresolved_reloc = FALSE;
diff --git a/ld/testsuite/ld-s390/gotreloc-1.s b/ld/testsuite/ld-s390/gotreloc-1.s
new file mode 100644
index 0000000..b60d6c1
--- /dev/null
+++ b/ld/testsuite/ld-s390/gotreloc-1.s
@@ -0,0 +1,11 @@
+ .text
+ .globl foo
+foo:
+ lgrl %r1,bar@GOTENT
+ lg %r1,bar@GOT(%r12)
+ lrl %r1,bar@GOTENT
+ l %r1,bar@GOT(%r12)
+ ly %r1,bar@GOT(%r12)
+
+.globl bar
+bar: .long 0x123
diff --git a/ld/testsuite/ld-s390/gotreloc-1.ver b/ld/testsuite/ld-s390/gotreloc-1.ver
new file mode 100644
index 0000000..1cb06d6
--- /dev/null
+++ b/ld/testsuite/ld-s390/gotreloc-1.ver
@@ -0,0 +1 @@
+{ local: bar; };
diff --git a/ld/testsuite/ld-s390/gotreloc_31-1.dd b/ld/testsuite/ld-s390/gotreloc_31-1.dd
new file mode 100644
index 0000000..4df4aa5
--- /dev/null
+++ b/ld/testsuite/ld-s390/gotreloc_31-1.dd
@@ -0,0 +1,14 @@
+
+tmpdir/gotreloc_31-1: file format elf32-s390
+
+Disassembly of section .text:
+
+.* <foo>:
+.*: c4 18 00 00 .long 0xc4180000
+.*: 08 4e e3 10 .long 0x084ee310
+.*: c0 0c 00 04 .long 0xc00c0004
+.*: c0 10 00 00 00 08 [ ]*larl %r1,168 <bar>
+.*: 58 10 c0 0c [ ]*l %r1,12\(%r12\)
+.*: c0 10 00 00 00 03 [ ]*larl %r1,168 <bar>
+.* <bar>:
+.*: 00 00 01 23 .long 0x00000123
diff --git a/ld/testsuite/ld-s390/gotreloc_64-1.dd b/ld/testsuite/ld-s390/gotreloc_64-1.dd
new file mode 100644
index 0000000..8c8c619
--- /dev/null
+++ b/ld/testsuite/ld-s390/gotreloc_64-1.dd
@@ -0,0 +1,12 @@
+tmpdir/gotreloc_64-1: file format elf64-s390
+
+Disassembly of section .text:
+
+.* <foo>:
+.*: c0 10 00 00 00 0e [ ]*larl %r1,.* <bar>
+.*: c0 10 00 00 00 0b [ ]*larl %r1,.* <bar>
+.*: c4 1d 00 00 08 86 [ ]*lrl %r1,.* <_GLOBAL_OFFSET_TABLE_\+0x18>
+.*: 58 10 c0 18 [ ]*l %r1,24\(%r12\)
+.*: e3 10 c0 18 00 58 [ ]*ly %r1,24\(%r12\)
+.* <bar>:
+.*: 00 00 01 23 .long 0x00000123
diff --git a/ld/testsuite/ld-s390/s390.exp b/ld/testsuite/ld-s390/s390.exp
index 34c5b33..1ac11c7 100644
--- a/ld/testsuite/ld-s390/s390.exp
+++ b/ld/testsuite/ld-s390/s390.exp
@@ -48,6 +48,11 @@ set s390tests {
{{readelf -Ssrl tlsbin.rd} {objdump -dzrj.text tlsbin.dd}
{objdump -sj.got tlsbin.sd} {objdump -sj.tdata tlsbin.td}}
"tlsbin"}
+ {"GOT: symbol address load from got to larl"
+ "-shared -melf_s390 --version-script=gotreloc-1.ver" ""
+ "-m31" {gotreloc-1.s}
+ {{objdump -dzrj.text gotreloc_31-1.dd}}
+ "gotreloc_31-1"}
}
set s390xtests {
@@ -64,6 +69,11 @@ set s390xtests {
{{readelf -WSsrl tlsbin_64.rd} {objdump -dzrj.text tlsbin_64.dd}
{objdump -sj.got tlsbin_64.sd} {objdump -sj.tdata tlsbin_64.td}}
"tlsbin_64"}
+ {"GOT: symbol address load from got to larl"
+ "-shared -melf64_s390 --version-script=gotreloc-1.ver" ""
+ "-m64" {gotreloc-1.s}
+ {{objdump -dzrj.text gotreloc_64-1.dd}}
+ "gotreloc_64-1"}
}
if [istarget "s390-*-*"] {
@@ -71,5 +81,6 @@ if [istarget "s390-*-*"] {
}
if [istarget "s390x-*-*"] {
+ run_ld_link_tests $s390tests
run_ld_link_tests $s390xtests
}