[PATCH v1 1/1] AArch64: Optimize ADD relocations that resolve to zero

Sivan Shani sivan.shani@arm.com
Tue Aug 18 16:00:44 GMT 2026


The "ELF for the Arm 64-bit Architecture" specification, section 5.7.9,
recommends that linkers optimize ADD instructions whose immediate becomes
zero after relocation.  In particular:

   ADD x0, x1, 0
   ADD x2, x2, 0

may be replaced with:

   MOV x0, x1
   NOP

Apply this optimization to all supported relocations that set an ADD
immediate field.

Rewrite additions between different registers as MOV.  Rewrite 64-bit
additions whose source and destination registers are the same as NOP.
Keep the 32-bit same-register form as MOV because writing to a W register
clears the upper 32 bits.  Do not rewrite instructions that use SP, since
ADD and the ORR encoding underlying MOV interpret register 31 differently.

For input relocations and linker-generated stubs, the optimization honors
--no-relax.  Pass an explicit boolean to _bfd_aarch64_elf_put_addend
because this low-level BFD helper has no access to bfd_link_info.  Other
relocation paths pass the same flag for a uniform interface, although they
cannot reach the ADD-immediate cases.

Continue optimizing linker-generated PLT entries unconditionally.  These
instructions have no retained input relocations and therefore do not
present a relocation reapplication problem.

Add a test verifying that --no-relax preserves zero-immediate ADD
instructions while still applying their relocation values normally.

Add coverage for every affected relocation and update existing tests.

bfd/

	* elfnn-aarch64.c (aarch64_relocate): Add optimize_add_zero
	argument.
	(aarch64_build_one_stub): Honor --no-relax when relocating
	linker-generated stubs.
	(elfNN_aarch64_final_link_relocate): Pass the ADD-zero
	optimization policy to _bfd_aarch64_elf_put_addend.
	(elf_aarch64_update_plt_entry): Enable the optimization for
	linker-generated PLT entries.
	* elfxx-aarch64.c (AARCH64_MOV_REG_OPCODE)
	(AARCH64_NOP_OPCODE): Define.
	(reencode_add_to_mov): Accept the decoded register fields.
	(_bfd_aarch64_elf_put_addend): Add an optimize_add_zero argument.
	Optimize ADD relocations whose encoded immediate is zero when
	enabled.  Validate the expected ADD-immediate encoding before
	rewriting it.
	* elfxx-aarch64.h (_bfd_aarch64_elf_put_addend): Update
	declaration.

ld/testsuite/

	* ld-aarch64/aarch64-elf.exp: Run the new ADD-immediate
	optimization tests.
	* ld-aarch64/add-imm-zero-opt.ld: New test linker script.
	* ld-aarch64/add-imm-zero-opt.s: New test.
	* ld-aarch64/add-imm-zero-opt.d: New expected output.
	* ld-aarch64/add-imm-zero-opt-norelax.d: New test.
	* ld-aarch64/add-imm-zero-opt-tlsgd.s: New test.
	* ld-aarch64/add-imm-zero-opt-tlsgd.d: New expected output.
	* ld-aarch64/add-imm-zero-opt-tlsld.s: New test.
	* ld-aarch64/add-imm-zero-opt-tlsld.d: New expected output.
	* ld-aarch64/add-imm-zero-opt-tlsdesc.s: New test.
	* ld-aarch64/add-imm-zero-opt-tlsdesc.d: New expected output.
	* ld-aarch64/erratum843419.d: Expect NOP.
	* ld-aarch64/erratum843419_tls_ie.d: Likewise.
	* ld-aarch64/farcall-b-defsym.d: Likewise.
	* ld-aarch64/farcall-b-none-function.d: Likewise.
	* ld-aarch64/farcall-b-section.d: Likewise.
	* ld-aarch64/farcall-b.d: Likewise.
	* ld-aarch64/farcall-back.d: Likewise.
	* ld-aarch64/farcall-bl-defsym.d: Likewise.
	* ld-aarch64/farcall-bl-none-function.d: Likewise.
	* ld-aarch64/farcall-bl-section.d: Likewise.
	* ld-aarch64/farcall-bl.d: Likewise.
	* ld-aarch64/tls-relax-ld-le-small-ilp32.d: Expect MOV and NOP.
	* ld-aarch64/tls-relax-ld-le-small.d: Likewise.
	* ld-aarch64/tls-relax-ld-le-tiny-ilp32.d: Likewise.
	* ld-aarch64/tls-relax-ld-le-tiny.d: Likewise.
	* ld-aarch64/weak-undefined.d: Expect NOP.
---
 bfd/elfnn-aarch64.c                           | 33 ++++++++++-----
 bfd/elfxx-aarch64.c                           | 40 +++++++++++++++----
 bfd/elfxx-aarch64.h                           |  2 +-
 ld/testsuite/ld-aarch64/aarch64-elf.exp       |  6 +++
 .../ld-aarch64/add-imm-zero-opt-norelax.d     | 22 ++++++++++
 .../ld-aarch64/add-imm-zero-opt-tlsdesc.d     | 16 ++++++++
 .../ld-aarch64/add-imm-zero-opt-tlsdesc.s     | 16 ++++++++
 .../ld-aarch64/add-imm-zero-opt-tlsgd.d       | 15 +++++++
 .../ld-aarch64/add-imm-zero-opt-tlsgd.s       | 16 ++++++++
 .../ld-aarch64/add-imm-zero-opt-tlsld.d       | 15 +++++++
 .../ld-aarch64/add-imm-zero-opt-tlsld.s       | 15 +++++++
 ld/testsuite/ld-aarch64/add-imm-zero-opt.d    | 22 ++++++++++
 ld/testsuite/ld-aarch64/add-imm-zero-opt.ld   | 16 ++++++++
 ld/testsuite/ld-aarch64/add-imm-zero-opt.s    | 34 ++++++++++++++++
 ld/testsuite/ld-aarch64/erratum843419.d       |  4 +-
 .../ld-aarch64/erratum843419_tls_ie.d         |  2 +-
 ld/testsuite/ld-aarch64/farcall-b-defsym.d    |  2 +-
 .../ld-aarch64/farcall-b-none-function.d      |  2 +-
 ld/testsuite/ld-aarch64/farcall-b-section.d   |  2 +-
 ld/testsuite/ld-aarch64/farcall-b.d           |  2 +-
 ld/testsuite/ld-aarch64/farcall-back-be.d     |  2 +-
 ld/testsuite/ld-aarch64/farcall-back.d        |  2 +-
 ld/testsuite/ld-aarch64/farcall-bl-defsym.d   |  2 +-
 .../ld-aarch64/farcall-bl-none-function.d     |  2 +-
 ld/testsuite/ld-aarch64/farcall-bl-section.d  |  2 +-
 ld/testsuite/ld-aarch64/farcall-bl.d          |  2 +-
 .../non-contiguous-mem/non-contiguous-ok-2.d  |  2 +-
 .../non-contiguous-mem/non-contiguous-ok-4.d  |  2 +-
 .../non-contiguous-mem/non-contiguous-ok-5.d  |  2 +-
 .../ld-aarch64/tls-relax-ld-le-small-ilp32.d  |  4 +-
 .../ld-aarch64/tls-relax-ld-le-small.d        |  4 +-
 .../ld-aarch64/tls-relax-ld-le-tiny-ilp32.d   |  4 +-
 .../ld-aarch64/tls-relax-ld-le-tiny.d         |  4 +-
 .../ld-aarch64/tls-tiny-gd-le-ilp32.d         |  2 +-
 ld/testsuite/ld-aarch64/tls-tiny-gd-le.d      |  2 +-
 ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.d  | 14 +++++++
 ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.s  | 13 ++++++
 ld/testsuite/ld-aarch64/weak-undefined.d      |  2 +-
 38 files changed, 303 insertions(+), 46 deletions(-)
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt-norelax.d
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsdesc.d
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsdesc.s
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsgd.d
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsgd.s
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsld.d
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsld.s
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt.d
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt.ld
 create mode 100644 ld/testsuite/ld-aarch64/add-imm-zero-opt.s
 create mode 100644 ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.d
 create mode 100644 ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.s

diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index cbd4abea122..632e62e9e1a 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -2967,7 +2967,7 @@ elfNN_aarch64_link_hash_table_create (bfd *abfd)
 
 static bool
 aarch64_relocate (unsigned int r_type, bfd *input_bfd, asection *input_section,
-		  bfd_vma offset, bfd_vma value)
+		  bfd_vma offset, bfd_vma value, bool optimize_add_zero)
 {
   reloc_howto_type *howto;
   bfd_vma place;
@@ -2981,7 +2981,7 @@ aarch64_relocate (unsigned int r_type, bfd *input_bfd, asection *input_section,
 					       value, 0, false);
   return _bfd_aarch64_elf_put_addend (input_bfd,
 				      input_section->contents + offset, r_type,
-				      howto, value) == bfd_reloc_ok;
+				      howto, value, optimize_add_zero) == bfd_reloc_ok;
 }
 
 /* Determine the type of stub needed, if any, for a call.  */
@@ -3256,6 +3256,7 @@ aarch64_build_one_stub (struct bfd_hash_entry *gen_entry,
   unsigned int pad_size = 0;
   const uint32_t *template;
   unsigned int i;
+  bool optimize_add_zero;
   struct bfd_link_info *info;
   struct elf_aarch64_link_hash_table *htab;
 
@@ -3349,17 +3350,18 @@ aarch64_build_one_stub (struct bfd_hash_entry *gen_entry,
   template_size = (template_size + 7) & ~7;
   stub_sec->size += template_size;
 
+  optimize_add_zero = info->disable_target_specific_optimizations <= 1;
   switch (stub_entry->stub_type)
     {
     case aarch64_stub_adrp_branch:
       if (!aarch64_relocate (AARCH64_R (ADR_PREL_PG_HI21), stub_bfd, stub_sec,
-			     stub_entry->stub_offset, sym_value))
+			     stub_entry->stub_offset, sym_value, optimize_add_zero))
 	/* The stub would not have been relaxed if the offset was out
 	   of range.  */
 	BFD_FAIL ();
 
       if (!aarch64_relocate (AARCH64_R (ADD_ABS_LO12_NC), stub_bfd, stub_sec,
-			     stub_entry->stub_offset + 4, sym_value))
+			     stub_entry->stub_offset + 4, sym_value, optimize_add_zero))
 	BFD_FAIL ();
       break;
 
@@ -3367,13 +3369,14 @@ aarch64_build_one_stub (struct bfd_hash_entry *gen_entry,
       /* We want the value relative to the address 12 bytes back from the
 	 value itself.  */
       if (!aarch64_relocate (AARCH64_R (PRELNN), stub_bfd, stub_sec,
-			     stub_entry->stub_offset + 16, sym_value + 12))
+			     stub_entry->stub_offset + 16, sym_value + 12,
+			     optimize_add_zero))
 	BFD_FAIL ();
       break;
 
     case aarch64_stub_bti_direct_branch:
       if (!aarch64_relocate (AARCH64_R (JUMP26), stub_bfd, stub_sec,
-			     stub_entry->stub_offset + 4, sym_value))
+			     stub_entry->stub_offset + 4, sym_value, optimize_add_zero))
 	BFD_FAIL ();
       break;
 
@@ -3395,7 +3398,8 @@ aarch64_build_one_stub (struct bfd_hash_entry *gen_entry,
 
     case aarch64_stub_erratum_843419_veneer:
       if (!aarch64_relocate (AARCH64_R (JUMP26), stub_bfd, stub_sec,
-			     stub_entry->stub_offset + 4, sym_value + 4))
+			     stub_entry->stub_offset + 4, sym_value + 4,
+			     optimize_add_zero))
 	BFD_FAIL ();
       break;
 
@@ -5764,6 +5768,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
   bfd_vma orig_value = value;
   bool resolved_to_zero;
   bool abs_symbol_p;
+  bool optimize_add_zero;
 
   globals = elf_aarch64_hash_table (info);
 
@@ -5785,6 +5790,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
 		  : bfd_is_und_section (sym_sec));
   abs_symbol_p = h != NULL && bfd_is_abs_symbol (&h->root);
 
+  optimize_add_zero = info->disable_target_specific_optimizations <= 1;
 
   /* Since STT_GNU_IFUNC symbol must go through PLT, we handle
      it here if it is defined in a non-shared object.  */
@@ -5917,7 +5923,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
 						       signed_addend,
 						       weak_undef_p);
 	  return _bfd_aarch64_elf_put_addend (input_bfd, hit_data, bfd_r_type,
-					      howto, value);
+					      howto, value, optimize_add_zero);
 	case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
 	case BFD_RELOC_AARCH64_GOT_LD_PREL19:
 	case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
@@ -5993,7 +5999,9 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
 	  value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type,
 						       place, value,
 						       addend, weak_undef_p);
-	  return _bfd_aarch64_elf_put_addend (input_bfd, hit_data, bfd_r_type, howto, value);
+	  return _bfd_aarch64_elf_put_addend (input_bfd, hit_data,
+					      bfd_r_type, howto, value,
+					      optimize_add_zero);
 	case BFD_RELOC_AARCH64_ADD_LO12:
 	case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
 	  break;
@@ -6542,7 +6550,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
     return bfd_reloc_continue;
 
   return _bfd_aarch64_elf_put_addend (input_bfd, hit_data, bfd_r_type,
-				      howto, value);
+				      howto, value, optimize_add_zero);
 }
 
 /* LP64 and ILP32 operates on x- and w-registers respectively.
@@ -9893,7 +9901,10 @@ elf_aarch64_update_plt_entry (bfd *output_bfd,
   reloc_howto_type *howto = elfNN_aarch64_howto_from_bfd_reloc (r_type);
 
   /* FIXME: We should check the return value from this function call.  */
-  (void) _bfd_aarch64_elf_put_addend (output_bfd, plt_entry, r_type, howto, value);
+  /* PLT entries are linker generated and have no retained input
+     relocations.  */
+  (void) _bfd_aarch64_elf_put_addend (output_bfd, plt_entry, r_type,
+				      howto, value, true);
 }
 
 static void
diff --git a/bfd/elfxx-aarch64.c b/bfd/elfxx-aarch64.c
index 69ef148bf9c..c9b8b01990b 100644
--- a/bfd/elfxx-aarch64.c
+++ b/bfd/elfxx-aarch64.c
@@ -57,6 +57,18 @@ reencode_add_imm (uint32_t insn, uint32_t imm)
   return (insn & ~(MASK (12) << 10)) | ((imm & MASK (12)) << 10);
 }
 
+/* Base encoding for MOV Wd, Wm (ORR Wd, WZR, Wm).  */
+#define AARCH64_MOV_REG_OPCODE 0x2a0003e0U
+/* NOP encoding  */
+#define AARCH64_NOP_OPCODE 0xd503201fU
+
+/* Reencode ADD immediate as MOV-register (ORR Rd, ZR, Rm).  */
+static inline uint32_t
+reencode_add_to_mov (uint32_t insn, unsigned int rd, unsigned int rn)
+{
+  return ((insn & (1U << 31)) | AARCH64_MOV_REG_OPCODE | (rn << 16) | rd);
+}
+
 /* Reencode the IMM field of ADR.  */
 
 uint32_t
@@ -161,7 +173,8 @@ aarch64_signed_overflow (bfd_vma value, unsigned int bits)
 bfd_reloc_status_type
 _bfd_aarch64_elf_put_addend (bfd *abfd,
 			     bfd_byte *address, bfd_reloc_code_real_type r_type,
-			     reloc_howto_type *howto, bfd_signed_vma addend)
+			     reloc_howto_type *howto, bfd_signed_vma addend,
+			     bool optimize_add_zero)
 {
   bfd_reloc_status_type status = bfd_reloc_ok;
   bfd_signed_vma old_addend = addend;
@@ -261,12 +274,25 @@ _bfd_aarch64_elf_put_addend (bfd *abfd,
     case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12:
     case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12:
     case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
-      /* Corresponds to: add rd, rn, #uimm12 to provide the low order
-	 12 bits of the page offset following
-	 BFD_RELOC_AARCH64_ADR_HI21_PCREL which computes the
-	 (pc-relative) page base.  */
-      contents = reencode_add_imm (contents, addend);
-      break;
+      /* Optimize an ADD whose relocated 12-bit immediate is zero.  */
+      {
+	unsigned int rd = contents & MASK (5);
+	unsigned int rn = (contents >> 5) & MASK (5);
+
+	if (optimize_add_zero && (addend & MASK (12)) == 0
+	    && (contents & 0x7f800000) == 0x11000000
+	    && rd != 31
+	    && rn != 31)
+	  {
+	    if (rd == rn && (contents & (1U << 31)) != 0)
+	      contents = AARCH64_NOP_OPCODE;
+	    else
+	      contents = reencode_add_to_mov (contents, rd, rn);
+	  }
+	else
+	  contents = reencode_add_imm (contents, addend);
+	break;
+      }
 
     case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
     case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
diff --git a/bfd/elfxx-aarch64.h b/bfd/elfxx-aarch64.h
index a312427bc75..8345086f9f4 100644
--- a/bfd/elfxx-aarch64.h
+++ b/bfd/elfxx-aarch64.h
@@ -218,7 +218,7 @@ _bfd_aarch64_reencode_adr_imm (uint32_t, uint32_t) ATTRIBUTE_HIDDEN;
 
 extern bfd_reloc_status_type
 _bfd_aarch64_elf_put_addend (bfd *, bfd_byte *, bfd_reloc_code_real_type,
-			     reloc_howto_type *, bfd_signed_vma)
+			     reloc_howto_type *, bfd_signed_vma, bool)
 			    ATTRIBUTE_HIDDEN;
 
 extern bfd_vma
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index fa80210500e..f4941b01518 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -284,6 +284,12 @@ run_dump_test_lp64 "tls-large-desc-be"
 run_dump_test "tls-tiny-ld"
 run_dump_test "tls-small-ld"
 run_dump_test_lp64 "tlsle"
+run_dump_test_lp64 "tlsle-add-hi12-opt"
+run_dump_test_lp64 "add-imm-zero-opt"
+run_dump_test_lp64 "add-imm-zero-opt-norelax"
+run_dump_test_lp64 "add-imm-zero-opt-tlsgd"
+run_dump_test_lp64 "add-imm-zero-opt-tlsld"
+run_dump_test_lp64 "add-imm-zero-opt-tlsdesc"
 run_dump_test "tlsle-symbol-offset"
 run_dump_test "gc-got-relocs"
 run_dump_test "gc-tls-relocs"
diff --git a/ld/testsuite/ld-aarch64/add-imm-zero-opt-norelax.d b/ld/testsuite/ld-aarch64/add-imm-zero-opt-norelax.d
new file mode 100644
index 00000000000..2b28bcbe2ba
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt-norelax.d
@@ -0,0 +1,22 @@
+#source: add-imm-zero-opt.s
+#target: [check_shared_lib_support]
+#ld: -shared -T add-imm-zero-opt.ld --defsym=got_base=0x20000 -e0 --no-relax
+#objdump: -dr
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+10000 <test>:
+ +10000:	91000000 	add	x0, x0, #0x0
+ +10004:	91400041 	add	x1, x2, #0x0, lsl #12
+ +10008:	91000063 	add	x3, x3, #0x0
+ +1000c:	910000a4 	add	x4, x5, #0x0
+ +10010:	914000e6 	add	x6, x7, #0x0, lsl #12
+ +10014:	91000108 	add	x8, x8, #0x0
+ +10018:	91000149 	add	x9, x10, #0x0
+ +1001c:	1100016b 	add	w11, w11, #0x0
+ +10020:	910003ec 	mov	x12, sp
+ +10024:	910001bf 	mov	sp, x13
+ +10028:	910021ce 	add	x14, x14, #0x8
+ +1002c:	d65f03c0 	ret
diff --git a/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsdesc.d b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsdesc.d
new file mode 100644
index 00000000000..092f891395f
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsdesc.d
@@ -0,0 +1,16 @@
+#source: add-imm-zero-opt-tlsdesc.s
+#target: [check_shared_lib_support]
+#ld: -shared -T add-imm-zero-opt.ld --defsym=got_base=0x1ffd8 -e0 --no-warn-rwx-segments
+#objdump: -dr
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+10000 <test>:
+ +10000:	aa0103e0 	mov	x0, x1
+ +10004:	d503201f 	nop
+ +10008:	910003e3 	mov	x3, sp
+ +1000c:	9100009f 	mov	sp, x4
+ +10010:	d65f03c0 	ret
+#...
diff --git a/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsdesc.s b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsdesc.s
new file mode 100644
index 00000000000..6fa1f19314c
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsdesc.s
@@ -0,0 +1,16 @@
+	.section .tbss,"awT",%nobits
+	.global tls_desc
+tls_desc:
+	.zero 8
+
+	.text
+	.global test
+	.type test, %function
+test:
+	add	x0, x1, #:tlsdesc_lo12:tls_desc
+	add	x2, x2, #:tlsdesc_lo12:tls_desc
+	add	x3, sp, #:tlsdesc_lo12:tls_desc
+	add	sp, x4, #:tlsdesc_lo12:tls_desc
+	ret
+	.size test, .-test
+
diff --git a/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsgd.d b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsgd.d
new file mode 100644
index 00000000000..cba5d38f3af
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsgd.d
@@ -0,0 +1,15 @@
+#source: add-imm-zero-opt-tlsgd.s
+#target: [check_shared_lib_support]
+#ld: -shared -T add-imm-zero-opt.ld --defsym=got_base=0x1fff8 -e0 --no-warn-rwx-segments
+#objdump: -dr
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+10000 <test>:
+ +10000:	aa0103e0 	mov	x0, x1
+ +10004:	d503201f 	nop
+ +10008:	910003e3 	mov	x3, sp
+ +1000c:	9100009f 	mov	sp, x4
+ +10010:	d65f03c0 	ret
diff --git a/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsgd.s b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsgd.s
new file mode 100644
index 00000000000..349f92cfbd8
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsgd.s
@@ -0,0 +1,16 @@
+	.section .tbss,"awT",%nobits
+	.global tls_gd
+tls_gd:
+	.zero 8
+
+	.text
+	.global test
+	.type test, %function
+test:
+	add	x0, x1, #:tlsgd_lo12:tls_gd
+	add	x2, x2, #:tlsgd_lo12:tls_gd
+	add	x3, sp, #:tlsgd_lo12:tls_gd
+	add	sp, x4, #:tlsgd_lo12:tls_gd
+	ret
+	.size test, .-test
+
diff --git a/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsld.d b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsld.d
new file mode 100644
index 00000000000..ad08392b798
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsld.d
@@ -0,0 +1,15 @@
+#source: add-imm-zero-opt-tlsld.s
+#target: [check_shared_lib_support]
+#ld: -shared -T add-imm-zero-opt.ld --defsym=got_base=0x1fff8 -e0 --no-warn-rwx-segments
+#objdump: -dr
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+10000 <test>:
+ +10000:	aa0103e0 	mov	x0, x1
+ +10004:	d503201f 	nop
+ +10008:	910003e3 	mov	x3, sp
+ +1000c:	9100009f 	mov	sp, x4
+ +10010:	d65f03c0 	ret
diff --git a/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsld.s b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsld.s
new file mode 100644
index 00000000000..a08675f6ffc
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt-tlsld.s
@@ -0,0 +1,15 @@
+	.section .tbss,"awT",%nobits
+tls_ld:
+	.zero 8
+
+	.text
+	.global test
+	.type test, %function
+test:
+	add	x0, x1, #:tlsldm_lo12_nc:tls_ld
+	add	x2, x2, #:tlsldm_lo12_nc:tls_ld
+	add	x3, sp, #:tlsldm_lo12_nc:tls_ld
+	add	sp, x4, #:tlsldm_lo12_nc:tls_ld
+	ret
+	.size test, .-test
+
diff --git a/ld/testsuite/ld-aarch64/add-imm-zero-opt.d b/ld/testsuite/ld-aarch64/add-imm-zero-opt.d
new file mode 100644
index 00000000000..4395bd01ab2
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt.d
@@ -0,0 +1,22 @@
+#source: add-imm-zero-opt.s
+#target: [check_shared_lib_support]
+#ld: -shared -T add-imm-zero-opt.ld --defsym=got_base=0x20000 -e0
+#objdump: -dr
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+10000 <test>:
+ +10000:	d503201f 	nop
+ +10004:	aa0203e1 	mov	x1, x2
+ +10008:	d503201f 	nop
+ +1000c:	aa0503e4 	mov	x4, x5
+ +10010:	aa0703e6 	mov	x6, x7
+ +10014:	d503201f 	nop
+ +10018:	aa0a03e9 	mov	x9, x10
+ +1001c:	2a0b03eb 	mov	w11, w11
+ +10020:	910003ec 	mov	x12, sp
+ +10024:	910001bf 	mov	sp, x13
+ +10028:	910021ce 	add	x14, x14, #0x8
+ +1002c:	d65f03c0 	ret
diff --git a/ld/testsuite/ld-aarch64/add-imm-zero-opt.ld b/ld/testsuite/ld-aarch64/add-imm-zero-opt.ld
new file mode 100644
index 00000000000..666ec64e47a
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt.ld
@@ -0,0 +1,16 @@
+OUTPUT_ARCH(aarch64)
+SECTIONS
+{
+  . = 0x10000;
+  .text : { *(.text) }
+  . = got_base;
+  .got : { *(.got) *(.got.plt) }
+  . = 0x30000;
+  .tdata : { *(.tdata) }
+  .tbss : { *(.tbss) }
+  .data :
+  {
+    *(.data)
+    *(.data.*)
+  }
+}
diff --git a/ld/testsuite/ld-aarch64/add-imm-zero-opt.s b/ld/testsuite/ld-aarch64/add-imm-zero-opt.s
new file mode 100644
index 00000000000..8f71acb3a7d
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/add-imm-zero-opt.s
@@ -0,0 +1,34 @@
+	.section .tbss,"awT",%nobits
+tls0:
+	.zero 4096
+tls_page:
+	.zero 8
+
+	.section .data.page,"aw"
+	.p2align 12
+page_sym:
+	.xword 0
+
+	.text
+	.global test
+	.type test, %function
+test:
+	add	x0, x0, #:lo12:page_sym
+	add	x1, x2, #:dtprel_hi12:tls0, lsl #12
+	add	x3, x3, #:dtprel_lo12:tls0
+	add	x4, x5, #:dtprel_lo12_nc:tls_page
+	add	x6, x7, #:tprel_hi12:tls0, lsl #12
+	add	x8, x8, #:tprel_lo12:tls0-16
+	add	x9, x10, #:tprel_lo12_nc:tls_page-16
+
+	/* A 32-bit write must not be replaced with NOP.  */
+	add	w11, w11, #:lo12:page_sym
+
+	/* Uses of SP must remain ADD instructions.  */
+	add	x12, sp, #:lo12:page_sym
+	add	sp, x13, #:lo12:page_sym
+
+	/* A nonzero immediate must remain an ADD instruction.  */
+	add	x14, x14, #:lo12:page_sym+8
+	ret
+	.size test, .-test
diff --git a/ld/testsuite/ld-aarch64/erratum843419.d b/ld/testsuite/ld-aarch64/erratum843419.d
index 7adfafde95a..2127194ac39 100644
--- a/ld/testsuite/ld-aarch64/erratum843419.d
+++ b/ld/testsuite/ld-aarch64/erratum843419.d
@@ -33,7 +33,7 @@ Disassembly of section .e843419:
 
 0*20001030 <__e835769_veneer>:
 [ ]*20001030:	f0f17ff0 	adrp	x16, 3000000 <e835769>
-[ ]*20001034:	91000210 	add	x16, x16, #0x0
+[ ]*20001034:	d503201f 	nop
 [ ]*20001038:	d61f0200 	br	x16
 	...
 
@@ -68,6 +68,6 @@ Disassembly of section .text:
 
 0*400020 <__e843419_veneer>:
 [ ]*400020:	900fe010 	adrp	x16, 20000000 <e843419>
-[ ]*400024:	91000210 	add	x16, x16, #0x0
+[ ]*400024:	d503201f 	nop
 [ ]*400028:	d61f0200 	br	x16
 	...
diff --git a/ld/testsuite/ld-aarch64/erratum843419_tls_ie.d b/ld/testsuite/ld-aarch64/erratum843419_tls_ie.d
index 4d2b1116442..bd18d629ef6 100644
--- a/ld/testsuite/ld-aarch64/erratum843419_tls_ie.d
+++ b/ld/testsuite/ld-aarch64/erratum843419_tls_ie.d
@@ -44,6 +44,6 @@ Disassembly of section .text:
 
 0*400020 <__farbranch_veneer>:
 [ ]*400020:	900fe010 	adrp	x16, 20000000 <farbranch>
-[ ]*400024:	91000210 	add	x16, x16, #0x0
+[ ]*400024:	d503201f 	nop
 [ ]*400028:	d61f0200 	br	x16
 	...
diff --git a/ld/testsuite/ld-aarch64/farcall-b-defsym.d b/ld/testsuite/ld-aarch64/farcall-b-defsym.d
index f6b092116cd..da049f9badc 100644
--- a/ld/testsuite/ld-aarch64/farcall-b-defsym.d
+++ b/ld/testsuite/ld-aarch64/farcall-b-defsym.d
@@ -14,6 +14,6 @@ Disassembly of section .text:
 [ \t]+100c:[ \t]+d503201f[ \t]+nop
 0+1010 <__bar_veneer>:
     1010:	90040010 	adrp	x16, 8001000 <bar>
-    1014:	91000210 	add	x16, x16, #0x0
+    1014:	d503201f 	nop
     1018:	d61f0200 	br	x16
 	...
diff --git a/ld/testsuite/ld-aarch64/farcall-b-none-function.d b/ld/testsuite/ld-aarch64/farcall-b-none-function.d
index e06936c347a..54738452e61 100644
--- a/ld/testsuite/ld-aarch64/farcall-b-none-function.d
+++ b/ld/testsuite/ld-aarch64/farcall-b-none-function.d
@@ -15,7 +15,7 @@ Disassembly of section .text:
 
 .* <__bar_veneer>:
     1010:	90040010 	adrp	x16, 8001000 <bar>
-    1014:	91000210 	add	x16, x16, #0x0
+    1014:	d503201f 	nop
     1018:	d61f0200 	br	x16
 	...
 
diff --git a/ld/testsuite/ld-aarch64/farcall-b-section.d b/ld/testsuite/ld-aarch64/farcall-b-section.d
index 3872cd0b7c6..2c9df42d0a7 100644
--- a/ld/testsuite/ld-aarch64/farcall-b-section.d
+++ b/ld/testsuite/ld-aarch64/farcall-b-section.d
@@ -17,7 +17,7 @@ Disassembly of section .text:
 
 .* <__bar_veneer>:
     1018:	90040010 	adrp	x16, 8001000 <bar>
-    101c:	91000210 	add	x16, x16, #0x0
+    101c:	d503201f 	nop
     1020:	d61f0200 	br	x16
     1024:	00000000 	udf	#0
 
diff --git a/ld/testsuite/ld-aarch64/farcall-b.d b/ld/testsuite/ld-aarch64/farcall-b.d
index cfa0688646e..05bc7c29ece 100644
--- a/ld/testsuite/ld-aarch64/farcall-b.d
+++ b/ld/testsuite/ld-aarch64/farcall-b.d
@@ -14,7 +14,7 @@ Disassembly of section .text:
 [ \t]+100c:[ \t]+d503201f[ \t]+nop
 0+1010 <__bar_veneer>:
     1010:	90040010 	adrp	x16, 8001000 <bar>
-    1014:	91000210 	add	x16, x16, #0x0
+    1014:	d503201f 	nop
     1018:	d61f0200 	br	x16
 	...
 
diff --git a/ld/testsuite/ld-aarch64/farcall-back-be.d b/ld/testsuite/ld-aarch64/farcall-back-be.d
index 80992aab67c..42bd5913e09 100644
--- a/ld/testsuite/ld-aarch64/farcall-back-be.d
+++ b/ld/testsuite/ld-aarch64/farcall-back-be.d
@@ -38,7 +38,7 @@ Disassembly of section .text:
 
 000000000000204c <__bar1_veneer>:
     204c:	d07ffff0 	adrp	x16, 100000000 <bar1>
-    2050:	91000210 	add	x16, x16, #0x0
+    2050:	d503201f 	nop
     2054:	d61f0200 	br	x16
 	...
 
diff --git a/ld/testsuite/ld-aarch64/farcall-back.d b/ld/testsuite/ld-aarch64/farcall-back.d
index 20204eef5e2..2eea4bb19d1 100644
--- a/ld/testsuite/ld-aarch64/farcall-back.d
+++ b/ld/testsuite/ld-aarch64/farcall-back.d
@@ -39,7 +39,7 @@ Disassembly of section .text:
 
 0000000000002050 <__bar1_veneer>:
     2050:	d07ffff0 	adrp	x16, 100000000 <bar1>
-    2054:	91000210 	add	x16, x16, #0x0
+    2054:	d503201f 	nop
     2058:	d61f0200 	br	x16
 	...
 
diff --git a/ld/testsuite/ld-aarch64/farcall-bl-defsym.d b/ld/testsuite/ld-aarch64/farcall-bl-defsym.d
index 4a3ab80d85a..1d682169a45 100644
--- a/ld/testsuite/ld-aarch64/farcall-bl-defsym.d
+++ b/ld/testsuite/ld-aarch64/farcall-bl-defsym.d
@@ -14,6 +14,6 @@ Disassembly of section .text:
 [ \t]+100c:[ \t]+d503201f[ \t]+nop
 0+1010 <__bar_veneer>:
 [ \t]+1010:[ \t]+90040010[ \t]+adrp[ \t]+x16, 8001000 <bar>
-[ \t]+1014:[ \t]+91000210[ \t]+add[ \t]+x16, x16, #0x0
+[ \t]+1014:[ \t]+d503201f[ \t]+nop
 [ \t]+1018:[ \t]+d61f0200[ \t]+br[ \t]+x16
 	...
diff --git a/ld/testsuite/ld-aarch64/farcall-bl-none-function.d b/ld/testsuite/ld-aarch64/farcall-bl-none-function.d
index 4ab9c7eed40..6c9385ea689 100644
--- a/ld/testsuite/ld-aarch64/farcall-bl-none-function.d
+++ b/ld/testsuite/ld-aarch64/farcall-bl-none-function.d
@@ -15,7 +15,7 @@ Disassembly of section .text:
 
 .* <__bar_veneer>:
     1010:	90040010 	adrp	x16, 8001000 <bar>
-    1014:	91000210 	add	x16, x16, #0x0
+    1014:	d503201f 	nop
     1018:	d61f0200 	br	x16
 	...
 
diff --git a/ld/testsuite/ld-aarch64/farcall-bl-section.d b/ld/testsuite/ld-aarch64/farcall-bl-section.d
index 03ebe2991d6..c2cf3da903d 100644
--- a/ld/testsuite/ld-aarch64/farcall-bl-section.d
+++ b/ld/testsuite/ld-aarch64/farcall-bl-section.d
@@ -17,7 +17,7 @@ Disassembly of section .text:
 
 .* <__bar_veneer>:
     1018:	90040010 	adrp	x16, 8001000 <bar>
-    101c:	91000210 	add	x16, x16, #0x0
+    101c:	d503201f 	nop
     1020:	d61f0200 	br	x16
     1024:	00000000 	udf	#0
 
diff --git a/ld/testsuite/ld-aarch64/farcall-bl.d b/ld/testsuite/ld-aarch64/farcall-bl.d
index 637225be4dd..971d61dfef1 100644
--- a/ld/testsuite/ld-aarch64/farcall-bl.d
+++ b/ld/testsuite/ld-aarch64/farcall-bl.d
@@ -14,7 +14,7 @@ Disassembly of section .text:
 [ \t]+100c:[ \t]+d503201f[ \t]+nop
 0+1010 <__bar_veneer>:
 [ \t]+1010:[ \t]+90040010[ \t]+adrp[ \t]+x16, 8001000 <bar>
-[ \t]+1014:[ \t]+91000210[ \t]+add[ \t]+x16, x16, #0x0
+[ \t]+1014:[ \t]+d503201f[ \t]+nop
 [ \t]+1018:[ \t]+d61f0200[ \t]+br[ \t]+x16
 	...
 
diff --git a/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-2.d b/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-2.d
index 74131fb5b58..43fb330c637 100644
--- a/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-2.d
+++ b/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-2.d
@@ -58,7 +58,7 @@ Disassembly of section \.ramu:
 
 0000000020000010 \<__code4_veneer\>:
     20000010:	90080210 	adrp	x16, 30040000 \<code4\>
-    20000014:	91000210 	add	x16, x16, #0x0
+    20000014:	d503201f 	nop
     20000018:	d61f0200 	br	x16
 	\.\.\.
 
diff --git a/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-4.d b/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-4.d
index 18a46b79acc..d6f2dc391d7 100644
--- a/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-4.d
+++ b/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-4.d
@@ -53,7 +53,7 @@ Disassembly of section \.raml:
 
 000000001fff0028 \<__code4_veneer\>:
     1fff0028:	90100290 	adrp	x16, 40040000 \<code4\>
-    1fff002c:	91000210 	add	x16, x16, #0x0
+    1fff002c:	d503201f 	nop
     1fff0030:	d61f0200 	br	x16
 	...
 
diff --git a/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-5.d b/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-5.d
index 5dd222ea342..dea3fad1f17 100644
--- a/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-5.d
+++ b/ld/testsuite/ld-aarch64/non-contiguous-mem/non-contiguous-ok-5.d
@@ -57,7 +57,7 @@ Disassembly of section \.raml:
 
 000000001fff0028 \<__code4_veneer\>:
     1fff0028:	90100290 	adrp	x16, 40040000 \<code4\>
-    1fff002c:	91000210 	add	x16, x16, #0x0
+    1fff002c:	d503201f 	nop
     1fff0030:	d61f0200 	br	x16
 	...
 
diff --git a/ld/testsuite/ld-aarch64/tls-relax-ld-le-small-ilp32.d b/ld/testsuite/ld-aarch64/tls-relax-ld-le-small-ilp32.d
index 2b80db5a542..ac80543d897 100644
--- a/ld/testsuite/ld-aarch64/tls-relax-ld-le-small-ilp32.d
+++ b/ld/testsuite/ld-aarch64/tls-relax-ld-le-small-ilp32.d
@@ -9,7 +9,7 @@
  +10008:	11002000 	add	w0, w0, #0x8
  +1000c:	d503201f 	nop
  +10010:	d503201f 	nop
- +10014:	91400001 	add	x1, x0, #0x0, lsl #12
- +10018:	91000021 	add	x1, x1, #0x0
+ +10014:	aa0003e1 	mov	x1, x0
+ +10018:	d503201f 	nop
  +1001c:	90000000 	adrp	x0, 10000 <.*>
  +10020:	d65f03c0 	ret
diff --git a/ld/testsuite/ld-aarch64/tls-relax-ld-le-small.d b/ld/testsuite/ld-aarch64/tls-relax-ld-le-small.d
index fa648291fdb..b8094889fda 100644
--- a/ld/testsuite/ld-aarch64/tls-relax-ld-le-small.d
+++ b/ld/testsuite/ld-aarch64/tls-relax-ld-le-small.d
@@ -7,7 +7,7 @@
  +10008:	91004000 	add	x0, x0, #0x10
  +1000c:	d503201f 	nop
  +10010:	d503201f 	nop
- +10014:	91400001 	add	x1, x0, #0x0, lsl #12
- +10018:	91000021 	add	x1, x1, #0x0
+ +10014:	aa0003e1 	mov	x1, x0
+ +10018:	d503201f 	nop
  +1001c:	90000000 	adrp	x0, 10000 <.*>
  +10020:	d65f03c0 	ret
diff --git a/ld/testsuite/ld-aarch64/tls-relax-ld-le-tiny-ilp32.d b/ld/testsuite/ld-aarch64/tls-relax-ld-le-tiny-ilp32.d
index 445e79dccf6..7ed81e247f0 100644
--- a/ld/testsuite/ld-aarch64/tls-relax-ld-le-tiny-ilp32.d
+++ b/ld/testsuite/ld-aarch64/tls-relax-ld-le-tiny-ilp32.d
@@ -8,7 +8,7 @@
  +10004:	d53bd040 	mrs	x0, tpidr_el0
  +10008:	11002000 	add	w0, w0, #0x8
  +1000c:	d503201f 	nop
- +10010:	91400001 	add	x1, x0, #0x0, lsl #12
- +10014:	91000021 	add	x1, x1, #0x0
+ +10010:	aa0003e1 	mov	x1, x0
+ +10014:	d503201f 	nop
  +10018:	90000000 	adrp	x0, 10000 <main>
  +1001c:	d65f03c0 	ret
diff --git a/ld/testsuite/ld-aarch64/tls-relax-ld-le-tiny.d b/ld/testsuite/ld-aarch64/tls-relax-ld-le-tiny.d
index db226775346..c6d1a9884a0 100644
--- a/ld/testsuite/ld-aarch64/tls-relax-ld-le-tiny.d
+++ b/ld/testsuite/ld-aarch64/tls-relax-ld-le-tiny.d
@@ -6,7 +6,7 @@
  +10004:	d53bd040 	mrs	x0, tpidr_el0
  +10008:	91004000 	add	x0, x0, #0x10
  +1000c:	d503201f 	nop
- +10010:	91400001 	add	x1, x0, #0x0, lsl #12
- +10014:	91000021 	add	x1, x1, #0x0
+ +10010:	aa0003e1 	mov	x1, x0
+ +10014:	d503201f 	nop
  +10018:	90000000 	adrp	x0, 10000 <main>
  +1001c:	d65f03c0 	ret
diff --git a/ld/testsuite/ld-aarch64/tls-tiny-gd-le-ilp32.d b/ld/testsuite/ld-aarch64/tls-tiny-gd-le-ilp32.d
index cc13bbde21b..8d7cc6866e6 100644
--- a/ld/testsuite/ld-aarch64/tls-tiny-gd-le-ilp32.d
+++ b/ld/testsuite/ld-aarch64/tls-tiny-gd-le-ilp32.d
@@ -9,5 +9,5 @@ Disassembly of section .text:
 
 00010000 \<test\>:
  +10000:	d53bd041 	mrs	x1, tpidr_el0
- +10004:	11400020 	add	w0, w1, #0x0, lsl #12
+ +10004:	2a0103e0 	mov	w0, w1
  +10008:	11002000 	add	w0, w0, #0x8
diff --git a/ld/testsuite/ld-aarch64/tls-tiny-gd-le.d b/ld/testsuite/ld-aarch64/tls-tiny-gd-le.d
index 016ca70658f..6a1777e5c06 100644
--- a/ld/testsuite/ld-aarch64/tls-tiny-gd-le.d
+++ b/ld/testsuite/ld-aarch64/tls-tiny-gd-le.d
@@ -7,5 +7,5 @@ Disassembly of section .text:
 
 0000000000010000 \<test\>:
  +10000:	d53bd041 	mrs	x1, tpidr_el0
- +10004:	91400020 	add	x0, x1, #0x0, lsl #12
+ +10004:	aa0103e0 	mov	x0, x1
  +10008:	91004000 	add	x0, x0, #0x10
diff --git a/ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.d b/ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.d
new file mode 100644
index 00000000000..0f2c90a4cc4
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.d
@@ -0,0 +1,14 @@
+#source: tlsle-add-hi12-opt.s
+#target: [check_shared_lib_support]
+#ld: -shared -T relocs.ld -e0
+#objdump: -dr
+
+.*: .*
+
+Disassembly of section .text:
+
+0+10000 <test>:
+ +10000:	aa0103e0 	mov	x0, x1
+ +10004:	914003e2 	add	x2, sp, #0x0, lsl #12
+ +10008:	9140007f 	add	sp, x3, #0x0, lsl #12
+ +1000c:	914004a4 	add	x4, x5, #0x1, lsl #12
diff --git a/ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.s b/ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.s
new file mode 100644
index 00000000000..f7a8d876122
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/tlsle-add-hi12-opt.s
@@ -0,0 +1,13 @@
+	.global	test
+	.section	.tbss,"awT",%nobits
+tlsvar:
+	.zero	4080
+tlsvar_hi12:
+	.zero	8
+
+	.text
+test:
+	add	x0, x1, #:tprel_hi12:tlsvar
+	add	x2, sp, #:tprel_hi12:tlsvar
+	add	sp, x3, #:tprel_hi12:tlsvar
+	add	x4, x5, #:tprel_hi12:tlsvar_hi12
diff --git a/ld/testsuite/ld-aarch64/weak-undefined.d b/ld/testsuite/ld-aarch64/weak-undefined.d
index 29ba2e5c672..3627d46c82b 100644
--- a/ld/testsuite/ld-aarch64/weak-undefined.d
+++ b/ld/testsuite/ld-aarch64/weak-undefined.d
@@ -15,4 +15,4 @@
  +f0000028:	58000000 	ldr	x0, f0000028 <main\+0x28>
  +f000002c:	10000000 	adr	x0, f000002c <main\+0x2c>
  +f0000030:	90000000 	adrp	x0, f0000000 <main>
- +f0000034:	91000000 	add	x0, x0, #0x0
+ +f0000034:	d503201f 	nop
-- 
2.43.0



More information about the Binutils mailing list