[v1,1/1] AArch64: Optimize ADD relocations that resolve to zero
Checks
| Context |
Check |
Description |
| linaro-tcwg-bot/tcwg_binutils_build--master-arm |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 |
success
|
Test passed
|
| linaro-tcwg-bot/tcwg_binutils_check--master-arm |
success
|
Test passed
|
Commit Message
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
Comments
On Tue, Aug 18, 2026 at 04:00:44PM +0000, Sivan Shani wrote:
> 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.
Please rename the bool optimize_add_zero to optimize_relocations, wherever it
occurs. This will be a more appropriate name if/when any further optimisations
are implemented.
Ok with that change.
Thanks,
Alice
>
> 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
>
@@ -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
@@ -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:
@@ -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
@@ -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"
new file mode 100644
@@ -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
new file mode 100644
@@ -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
+#...
new file mode 100644
@@ -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
+
new file mode 100644
@@ -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
new file mode 100644
@@ -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
+
new file mode 100644
@@ -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
new file mode 100644
@@ -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
+
new file mode 100644
@@ -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
new file mode 100644
@@ -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.*)
+ }
+}
new file mode 100644
@@ -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
@@ -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
...
@@ -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
...
@@ -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
...
@@ -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
...
@@ -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
@@ -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
...
@@ -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
...
@@ -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
...
@@ -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
...
@@ -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
...
@@ -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
@@ -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
...
@@ -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
\.\.\.
@@ -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
...
@@ -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
...
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
new file mode 100644
@@ -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
new file mode 100644
@@ -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
@@ -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