[PATCH] AArch64: Optimize zero-valued ADRP relocations for undefined weak symbols
Sivan Shani
sivan.shani@arm.com
Wed Sep 9 16:05:55 GMT 2026
AAELF64 permits R_<CLS>_ADR_PREL_PG_HI21 relocations against
undefined weak symbols to emit MOV with a zero immediate.
When the calculated page value is zero, rewrite the ADRP as MOVZ while
preserving its destination register. Honor --no-relax and restrict the
optimization to genuine undefined weak symbols.
An ADRP may already be recorded as a Cortex-A53 erratum 843419 candidate
before being rewritten. Clear the pending erratum entry for both adr
and full fix modes, since the instruction is no longer an ADRP.
Add LP64 and ILP32 tests, including nonzero-addend, --no-relax, and
Cortex-A53 erratum 843419 coverage.
bfd/ChangeLog:
* elfnn-aarch64.c (AARCH64_MOVZ_ZERO_OPCODE):
(rewrite_adrp_as_mov_zero):
(clear_erratum_843419_entry):
(elfNN_aarch64_final_link_relocate):
(_bfd_aarch64_erratum_843419_clear_stub):
ld/ChangeLog:
* testsuite/ld-aarch64/aarch64-elf.exp:
* testsuite/ld-aarch64/weak-undefined.d:
* testsuite/ld-aarch64/weak-undefined-adrp-erratum-adr.d: New test.
* testsuite/ld-aarch64/weak-undefined-adrp-erratum-full.d: New test.
* testsuite/ld-aarch64/weak-undefined-adrp-erratum.s: New test.
* testsuite/ld-aarch64/weak-undefined-adrp-ilp32.d: New test.
* testsuite/ld-aarch64/weak-undefined-adrp-norelax-ilp32.d: New test.
* testsuite/ld-aarch64/weak-undefined-adrp-norelax.d: New test.
* testsuite/ld-aarch64/weak-undefined-adrp.d: New test.
* testsuite/ld-aarch64/weak-undefined-adrp.s: New test.
---
bfd/elfnn-aarch64.c | 42 +++++++++++++++++--
ld/testsuite/ld-aarch64/aarch64-elf.exp | 6 +++
.../weak-undefined-adrp-erratum-adr.d | 15 +++++++
.../weak-undefined-adrp-erratum-full.d | 15 +++++++
.../ld-aarch64/weak-undefined-adrp-erratum.s | 10 +++++
.../ld-aarch64/weak-undefined-adrp-ilp32.d | 17 ++++++++
.../weak-undefined-adrp-norelax-ilp32.d | 17 ++++++++
.../ld-aarch64/weak-undefined-adrp-norelax.d | 16 +++++++
ld/testsuite/ld-aarch64/weak-undefined-adrp.d | 16 +++++++
ld/testsuite/ld-aarch64/weak-undefined-adrp.s | 10 +++++
ld/testsuite/ld-aarch64/weak-undefined.d | 2 +-
11 files changed, 161 insertions(+), 5 deletions(-)
create mode 100644 ld/testsuite/ld-aarch64/weak-undefined-adrp-erratum-adr.d
create mode 100644 ld/testsuite/ld-aarch64/weak-undefined-adrp-erratum-full.d
create mode 100644 ld/testsuite/ld-aarch64/weak-undefined-adrp-erratum.s
create mode 100644 ld/testsuite/ld-aarch64/weak-undefined-adrp-ilp32.d
create mode 100644 ld/testsuite/ld-aarch64/weak-undefined-adrp-norelax-ilp32.d
create mode 100644 ld/testsuite/ld-aarch64/weak-undefined-adrp-norelax.d
create mode 100644 ld/testsuite/ld-aarch64/weak-undefined-adrp.d
create mode 100644 ld/testsuite/ld-aarch64/weak-undefined-adrp.s
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index e7693da0d95..5ff41b4bd04 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -5739,6 +5739,23 @@ aarch64_relocation_aginst_gp_p (bfd_reloc_code_real_type reloc)
|| reloc == BFD_RELOC_AARCH64_MOVW_GOTOFF_G1);
}
+/* Transform an ADRP instruction to a move instruction. */
+
+#define AARCH64_MOVZ_ZERO_OPCODE 0xd2800000U
+
+static void
+rewrite_adrp_as_mov_zero (bfd_byte *location)
+{
+ uint32_t insn = bfd_getl32 (location);
+ unsigned int rd = insn & 0x1f;
+
+ bfd_putl32 (AARCH64_MOVZ_ZERO_OPCODE | rd, location);
+}
+
+static void
+clear_erratum_843419_entry (struct elf_aarch64_link_hash_table *,
+ bfd_vma, asection *);
+
/* Perform a relocation as part of a final link. The input relocation type
should be TLS relaxed. */
@@ -6554,8 +6571,25 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
if (save_addend)
return bfd_reloc_continue;
- return _bfd_aarch64_elf_put_addend (input_bfd, hit_data, bfd_r_type,
- howto, value, optimize_relocations);
+ bfd_reloc_status_type status
+ = _bfd_aarch64_elf_put_addend (input_bfd, hit_data, bfd_r_type,
+ howto, value,
+ optimize_relocations);
+
+ if (status == bfd_reloc_ok
+ && optimize_relocations
+ && h != NULL
+ && h->root.type == bfd_link_hash_undefweak
+ && bfd_r_type == BFD_RELOC_AARCH64_ADR_HI21_PCREL
+ && value == 0)
+ {
+ rewrite_adrp_as_mov_zero (hit_data);
+ /* We have relaxed the adrp into a mov, we may have to clear any
+ pending erratum fixes. */
+ clear_erratum_843419_entry (globals, rel->r_offset, input_section);
+ }
+
+ return status;
}
/* LP64 and ILP32 operates on x- and w-registers respectively.
@@ -6625,7 +6659,7 @@ _bfd_aarch64_erratum_843419_clear_stub (struct bfd_hash_entry *gen_entry,
return false;
}
-/* TLS Relaxations may relax an adrp sequence that matches the erratum 843419
+/* Relaxations may replace an adrp sequence that matches the erratum 843419
sequence. In this case the erratum no longer applies and we need to remove
the entry from the pending stub generation. This clears matching adrp insn
at ADRP_OFFSET in INPUT_SECTION in the stub table defined in GLOBALS. */
@@ -6634,7 +6668,7 @@ static void
clear_erratum_843419_entry (struct elf_aarch64_link_hash_table *globals,
bfd_vma adrp_offset, asection *input_section)
{
- if (globals->fix_erratum_843419 & ERRAT_ADRP)
+ if (globals->fix_erratum_843419 & (ERRAT_ADR | ERRAT_ADRP))
{
struct erratum_843419_branch_to_stub_clear_data data;
data.adrp_offset = adrp_offset;
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index f4941b01518..33ad7c8ec2e 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -66,10 +66,16 @@ run_dump_test "erratum843419-far-adr"
run_dump_test "erratum843419-far-full"
run_dump_test "erratum843419-full"
run_dump_test "erratum843419-no-args"
+run_dump_test_lp64 "weak-undefined-adrp-erratum-full"
+run_dump_test_lp64 "weak-undefined-adrp-erratum-adr"
run_dump_test "erratum835769-843419"
# Relocation Tests
run_dump_test_lp64 "weak-undefined"
+run_dump_test_lp64 "weak-undefined-adrp"
+run_dump_test_lp64 "weak-undefined-adrp-norelax"
+run_dump_test "weak-undefined-adrp-ilp32"
+run_dump_test "weak-undefined-adrp-norelax-ilp32"
run_dump_test "emit-relocs-22"
run_dump_test "emit-relocs-23"
run_dump_test "emit-relocs-28"
diff --git a/ld/testsuite/ld-aarch64/weak-undefined-adrp-erratum-adr.d b/ld/testsuite/ld-aarch64/weak-undefined-adrp-erratum-adr.d
new file mode 100644
index 00000000000..04a8051713d
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/weak-undefined-adrp-erratum-adr.d
@@ -0,0 +1,15 @@
+#source: weak-undefined-adrp-erratum.s
+#ld: -Ttext=0x400000 --fix-cortex-a53-843419=adr
+#objdump: -dr
+#...
+
+Disassembly of section \.text:
+
+0*400000 <_start>:
+ ...
+ 400ffc: d2800000 mov x0, #0x0.*
+ 401000: f9000042 str x2, \[x2\]
+ 401004: d2800002 mov x2, #0x0.*
+ 401008: f9402001 ldr x1, \[x0, #64\]
+ 40100c: d503201f nop
+#...
diff --git a/ld/testsuite/ld-aarch64/weak-undefined-adrp-erratum-full.d b/ld/testsuite/ld-aarch64/weak-undefined-adrp-erratum-full.d
new file mode 100644
index 00000000000..f7a6f247ca3
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/weak-undefined-adrp-erratum-full.d
@@ -0,0 +1,15 @@
+#source: weak-undefined-adrp-erratum.s
+#ld: -Ttext=0x400000 --fix-cortex-a53-843419=full
+#objdump: -dr
+#...
+
+Disassembly of section \.text:
+
+0*400000 <_start>:
+ ...
+ 400ffc: d2800000 mov x0, #0x0.*
+ 401000: f9000042 str x2, \[x2\]
+ 401004: d2800002 mov x2, #0x0.*
+ 401008: f9402001 ldr x1, \[x0, #64\]
+ 40100c: d503201f nop
+#...
diff --git a/ld/testsuite/ld-aarch64/weak-undefined-adrp-erratum.s b/ld/testsuite/ld-aarch64/weak-undefined-adrp-erratum.s
new file mode 100644
index 00000000000..995866a9bbb
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/weak-undefined-adrp-erratum.s
@@ -0,0 +1,10 @@
+ .balign 0x1000
+ .weak weak_sym
+ .globl _start
+_start:
+ .skip 0xffc
+ adrp x0, weak_sym
+ str x2, [x2]
+ mov x2, #0
+ ldr x1, [x0, #0x40]
+ nop
diff --git a/ld/testsuite/ld-aarch64/weak-undefined-adrp-ilp32.d b/ld/testsuite/ld-aarch64/weak-undefined-adrp-ilp32.d
new file mode 100644
index 00000000000..ae0e8570724
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/weak-undefined-adrp-ilp32.d
@@ -0,0 +1,17 @@
+#source: weak-undefined-adrp.s
+#as: -mabi=ilp32
+#ld: -m [aarch64_choose_ilp32_emul] -Ttext 0xF0000000 -e _start
+#objdump: -d
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+[0-9a-f]+ <_start>:
+ *[0-9a-f]+: d2800000 mov x0, #0x0.*
+ *[0-9a-f]+: d2800007 mov x7, #0x0.*
+ *[0-9a-f]+: b0000004 adrp x4, .*
+ *[0-9a-f]+: 90000003 adrp x3, .*
+
+[0-9a-f]+ <defined_sym>:
+ *[0-9a-f]+: d503201f nop
diff --git a/ld/testsuite/ld-aarch64/weak-undefined-adrp-norelax-ilp32.d b/ld/testsuite/ld-aarch64/weak-undefined-adrp-norelax-ilp32.d
new file mode 100644
index 00000000000..c8c48621a28
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/weak-undefined-adrp-norelax-ilp32.d
@@ -0,0 +1,17 @@
+#source: weak-undefined-adrp.s
+#as: -mabi=ilp32
+#ld: -m [aarch64_choose_ilp32_emul] -Ttext 0xF0000000 -e _start --no-relax
+#objdump: -d
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+[0-9a-f]+ <_start>:
+ *[0-9a-f]+: 90000000 adrp x0, .*
+ *[0-9a-f]+: 90000007 adrp x7, .*
+ *[0-9a-f]+: b0000004 adrp x4, .*
+ *[0-9a-f]+: 90000003 adrp x3, .*
+
+[0-9a-f]+ <defined_sym>:
+ *[0-9a-f]+: d503201f nop
diff --git a/ld/testsuite/ld-aarch64/weak-undefined-adrp-norelax.d b/ld/testsuite/ld-aarch64/weak-undefined-adrp-norelax.d
new file mode 100644
index 00000000000..2c44ca0413e
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/weak-undefined-adrp-norelax.d
@@ -0,0 +1,16 @@
+#source: weak-undefined-adrp.s
+#ld: -Ttext 0xF0000000 -e _start --no-relax
+#objdump: -d
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+[0-9a-f]+ <_start>:
+ *[0-9a-f]+: 90000000 adrp x0, .*
+ *[0-9a-f]+: 90000007 adrp x7, .*
+ *[0-9a-f]+: b0000004 adrp x4, .*
+ *[0-9a-f]+: 90000003 adrp x3, .*
+
+[0-9a-f]+ <defined_sym>:
+ *[0-9a-f]+: d503201f nop
diff --git a/ld/testsuite/ld-aarch64/weak-undefined-adrp.d b/ld/testsuite/ld-aarch64/weak-undefined-adrp.d
new file mode 100644
index 00000000000..9187c728fb5
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/weak-undefined-adrp.d
@@ -0,0 +1,16 @@
+#source: weak-undefined-adrp.s
+#ld: -Ttext 0xF0000000 -e _start
+#objdump: -d
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+[0-9a-f]+ <_start>:
+ *[0-9a-f]+: d2800000 mov x0, #0x0.*
+ *[0-9a-f]+: d2800007 mov x7, #0x0.*
+ *[0-9a-f]+: b0000004 adrp x4, .*
+ *[0-9a-f]+: 90000003 adrp x3, .*
+
+[0-9a-f]+ <defined_sym>:
+ *[0-9a-f]+: d503201f nop
diff --git a/ld/testsuite/ld-aarch64/weak-undefined-adrp.s b/ld/testsuite/ld-aarch64/weak-undefined-adrp.s
new file mode 100644
index 00000000000..aca12ecb16e
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/weak-undefined-adrp.s
@@ -0,0 +1,10 @@
+ .text
+ .weak weak_sym
+ .global _start
+_start:
+ adrp x0, weak_sym
+ adrp x7, weak_sym
+ adrp x4, weak_sym + 0x1000
+ adrp x3, defined_sym
+defined_sym:
+ nop
diff --git a/ld/testsuite/ld-aarch64/weak-undefined.d b/ld/testsuite/ld-aarch64/weak-undefined.d
index 3627d46c82b..fa4ba64e3b9 100644
--- a/ld/testsuite/ld-aarch64/weak-undefined.d
+++ b/ld/testsuite/ld-aarch64/weak-undefined.d
@@ -14,5 +14,5 @@
+f0000024: d503201f nop
+f0000028: 58000000 ldr x0, f0000028 <main\+0x28>
+f000002c: 10000000 adr x0, f000002c <main\+0x2c>
- +f0000030: 90000000 adrp x0, f0000000 <main>
+ +f0000030: d2800000 mov x0, #0x0.*
+f0000034: d503201f nop
--
2.43.0
More information about the Binutils
mailing list