This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCHv2] [Bug 20868] ld: aarch64: fix GD->IE relaxation in ilp32 mode
- From: Yury Norov <ynorov at caviumnetworks dot com>
- To: <binutils at sourceware dot org>
- Cc: Yury Norov <ynorov at caviumnetworks dot com>, Jiong Wang <jiwang at gcc dot gnu dot org>, Ramana Radhakrishnan <ramana dot gcc at googlemail dot com>, Andrew Pinski <pinskia at gmail dot com>
- Date: Mon, 28 Nov 2016 23:15:50 +0530
- Subject: [PATCHv2] [Bug 20868] ld: aarch64: fix GD->IE relaxation in ilp32 mode
- Authentication-results: sourceware.org; auth=none
- Authentication-results: spf=none (sender IP is ) smtp.mailfrom=Yuri dot Norov at caviumnetworks dot com;
- Spamdiagnosticmetadata: NSPM
- Spamdiagnosticoutput: 1:99
LD detects the access to TLS that it can optimize, but does it wrong
in ilp32 mode - actual address differs from expected.
It's because ld it calculates the address with "ldr x0, [x0, #:gottprel_lo12:var]"
which is correct for lp64, but for ilp32 it should be "ldr w0, [x0, #:gottprel_lo12:var]".
This patch fixes it by checking arch info. Also it replaces "add x0, x1, x0" with
"add w0, w1, w0". This instruction doesn't make troubles now, but in ilp32 mode
32-bit registers should be used in this case.
Test that reproduses the bug is here:
https://sourceware.org/bugzilla/attachment.cgi?id=9669
v2: add test to the testsuite.
* bfd/elfnn-aarch64.c: Fix gd-ie relocation in ilp32 mode
* ld/testsuite/ld-aarch64/aarch64-elf.exp: Add new test
* ld/testsuite/ld-aarch64/relocs-ilp32.ld: New file
* ld/testsuite/ld-aarch64/tls-relax-gd-ie-ilp32.d: Likewise.
Signed-off-by: Yury Norov <ynorov@caviumnetworks.com>
---
bfd/elfnn-aarch64.c | 20 +++++++++++++++-----
ld/testsuite/ld-aarch64/aarch64-elf.exp | 1 +
ld/testsuite/ld-aarch64/relocs-ilp32.ld | 19 +++++++++++++++++++
ld/testsuite/ld-aarch64/tls-relax-gd-ie-ilp32.d | 10 ++++++++++
4 files changed, 45 insertions(+), 5 deletions(-)
create mode 100644 ld/testsuite/ld-aarch64/relocs-ilp32.ld
create mode 100644 ld/testsuite/ld-aarch64/tls-relax-gd-ie-ilp32.d
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 99b2a04..c1da097 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -5841,10 +5841,12 @@ elfNN_aarch64_tls_relax (struct elf_aarch64_link_hash_table *globals,
else
{
/* GD->IE relaxation
- ADD x0, #:tlsgd_lo12:var => ldr x0, [x0, #:gottprel_lo12:var]
+ ADD x0, #:tlsgd_lo12:var => ldr R0, [x0, #:gottprel_lo12:var]
BL __tls_get_addr => mrs x1, tpidr_el0
R_AARCH64_CALL26
- NOP => add x0, x1, x0
+ NOP => add R0, R1, R0
+
+ Where R is x for lp64 mode, and w for ilp32 mode.
*/
BFD_ASSERT (ELFNN_R_TYPE (rel[1].r_info) == AARCH64_R (CALL26));
@@ -5852,13 +5854,21 @@ elfNN_aarch64_tls_relax (struct elf_aarch64_link_hash_table *globals,
/* Remove the relocation on the BL instruction. */
rel[1].r_info = ELFNN_R_INFO (STN_UNDEF, R_AARCH64_NONE);
- bfd_putl32 (0xf9400000, contents + rel->r_offset);
-
/* We choose to fixup the BL and NOP instructions using the
offset from the second relocation to allow flexibility in
scheduling instructions between the ADD and BL. */
+ if (bfd_get_arch_info (input_bfd)->mach & bfd_mach_aarch64_ilp32)
+ {
+ bfd_putl32 (0xb9400000, contents + rel->r_offset);
+ bfd_putl32 (0x0b000020, contents + rel[1].r_offset + 4);
+ }
+ else
+ {
+ bfd_putl32 (0xf9400000, contents + rel->r_offset);
+ bfd_putl32 (0x8b000020, contents + rel[1].r_offset + 4);
+ }
+
bfd_putl32 (0xd53bd041, contents + rel[1].r_offset);
- bfd_putl32 (0x8b000020, contents + rel[1].r_offset + 4);
return bfd_reloc_continue;
}
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index d4d7f5a..e2d064f 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -190,6 +190,7 @@ run_dump_test "tls-relax-all"
run_dump_test "tls-relax-gd-le"
run_dump_test "tls-relax-gdesc-le"
run_dump_test "tls-relax-gd-ie"
+run_dump_test "tls-relax-gd-ie-ilp32"
run_dump_test "tls-relax-large-gd-ie"
run_dump_test "tls-relax-large-gd-ie-be"
run_dump_test "tls-relax-large-gd-le"
diff --git a/ld/testsuite/ld-aarch64/relocs-ilp32.ld b/ld/testsuite/ld-aarch64/relocs-ilp32.ld
new file mode 100644
index 0000000..98044f7
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/relocs-ilp32.ld
@@ -0,0 +1,19 @@
+/* Script for ld testsuite */
+OUTPUT_ARCH(aarch64:ilp32)
+ENTRY(_start)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ PROVIDE (__executable_start = 0x8000); . = 0x10000;
+ .text :
+ {
+ *(.before)
+ *(.text)
+ *(.after)
+ } =0
+ . = 0x20000;
+ .got : { *(.got) *(.got.plt)}
+ . = 0x12340000;
+ .far : { *(.far) }
+ .ARM.attributes 0 : { *(.ARM.atttributes) }
+}
diff --git a/ld/testsuite/ld-aarch64/tls-relax-gd-ie-ilp32.d b/ld/testsuite/ld-aarch64/tls-relax-gd-ie-ilp32.d
new file mode 100644
index 0000000..ab08c61
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/tls-relax-gd-ie-ilp32.d
@@ -0,0 +1,10 @@
+#source: tls-relax-gd-ie.s
+#as: -mabi=ilp32
+#ld: -m [aarch64_choose_ilp32_emul] -T relocs-ilp32.ld -e0
+#objdump: -dr
+#...
+ +10000: 90000080 adrp x0, 20000 <_GLOBAL_OFFSET_TABLE_>
+ +10004: b9400400 ldr w0, \[x0, #4\]
+ +10008: d53bd041 mrs x1, tpidr_el0
+ +1000c: 0b000020 add w0, w1, w0
+ +10010: b9400000 ldr w0, \[x0\]
--
2.7.4