[PATCH v2 1/1] aarch64: mingw: Auto-import implementation

Alice Carlotti alice.carlotti@arm.com
Tue Sep 8 14:44:08 GMT 2026


On Fri, Jul 31, 2026 at 04:46:55PM +0200, Evgeny Karpov wrote:
> Auto-import is needed to resolve symbols during dynamic linking.
> 
> For example,
> 
>   adrp	x0, dyn_v + 2
>   add	x0, x0, :lo12:dyn_v + 2
> 
> or
> 
>   adrp  x0, dyn_v + 8
>   ldr   x0, [x0, :lo12:dyn_v + 8]
> 
> or
> 
>   b init_dyn_v
>   bl init_dyn_v
> 
> init_dyn_v and dyn_v are undefined at compile time and are getting resolved
> during linking with a dynamic library to the IAT (import address table).
> 
> In case of b or bl, it can be done by using a jump table
> 
> init_dyn_v:
>   adrp	x16, __imp_init_dyn_v
>   add	x16, x16, :lo12:__imp_init_dyn_v
>   ldr	x16, [x16]
>   br	x16
> 
> "adrp", "add" and "ldr" are handled differently. The codegen usually
> creates a reference to a symbol without an offset:
> adrp x0, <symbol>
> add x0, x0, :lo12:<symbol> / ldr x0, [x0, :lo12:<symbol>]
> 
> however it might be necessary to support offsets in some cases:
>   adrp  x0, <symbol> +/- offset
>   add   x0, x0, :lo12:<symbol> +/- offset / ldr   x0, [x0, :lo12:<symbol> +/- offset]
> 
> It is handled by detecting relocations that have symbols that are resolved
> during dynamic linking.
> "adrp" is replaced by an unconditional branching to a place where a symbol address
> will be loaded from the IAT and then returning back.
> Relocation for the "add" and "ldr" instructions is not needed in this case.
> 
>   adrp	x0, dyn_v + 8
>   add	x0, x0, :lo12:dyn_v + 8  /  ldr   x0, [x0, :lo12:dyn_v + 8]
> 
> turns into
> 
> __fu1_dyn_v:
>   b     __imp_dyn_v_10_8
>   add	x0, x0, 8  /  ldr   x0, [x0, 8]
>   ...
> 
> __imp_dyn_v_10_8:
>    adrp	x0, __imp_dyn_v
>    ldr	x0, [x0, :lo12:__imp_dyn_v]
>    add	x0, x0, offset_4k, lsl #12
>    b	__fu1_dyn_v + 0x4
> 
> Another option that was considered is using bl / ret.
> However, in this case, an edge case will not be handled properly:
>   adrp x30, dyn_v
> 
> Signed-off-by: Evgeny Karpov <evgeny@kmaps.co>
> 
> bfd/ChangeLog:
> 
> 	* coff-aarch64.c (coff_pe_aarch64_relocate_section): Add relocation
> 	handling for dynamic linking.
> 
> ld/ChangeLog:
> 
> 	* emultempl/pep.em: Update read_addend for aarch64 relocations.
> 	* pe-dll.c (aarch64_make_jump_stub): Add jump stub.
> 	(aarch64_make_imp_offset): Add adrp handler for dynamic linking.
> 	(pe_create_import_fixup): Add fixups for aarch64.
> 	* testsuite/ld-pe/pe.exp: Add auto-import-aarch64 test.
> 	* testsuite/ld-pe/auto-import-aarch64.d: New test.
> 	* testsuite/ld-pe/auto-import-aarch64.s: New test.
> 	* testsuite/ld-pe/auto-import-dll-aarch64.s: New test.
> ---
>  bfd/coff-aarch64.c                           |  56 +++---
>  ld/emultempl/pep.em                          |  17 +-
>  ld/pe-dll.c                                  | 171 +++++++++++++++++++
>  ld/testsuite/ld-pe/auto-import-aarch64.d     | 167 ++++++++++++++++++
>  ld/testsuite/ld-pe/auto-import-aarch64.s     |  61 +++++++
>  ld/testsuite/ld-pe/auto-import-dll-aarch64.s |  13 ++
>  ld/testsuite/ld-pe/pe.exp                    |  15 +-
>  7 files changed, 473 insertions(+), 27 deletions(-)
>  create mode 100644 ld/testsuite/ld-pe/auto-import-aarch64.d
>  create mode 100644 ld/testsuite/ld-pe/auto-import-aarch64.s
>  create mode 100644 ld/testsuite/ld-pe/auto-import-dll-aarch64.s
> 
> diff --git a/bfd/coff-aarch64.c b/bfd/coff-aarch64.c
> index d889359a6fc..cd194034839 100644
> --- a/bfd/coff-aarch64.c
> +++ b/bfd/coff-aarch64.c
> @@ -521,6 +521,38 @@ coff_pe_aarch64_relocate_section (bfd *output_bfd,
>  
>        h = obj_coff_sym_hashes (input_bfd)[symndx];
>  
> +      if (h && h->root.type == bfd_link_hash_defweak)
> +	switch (rel->r_type)
> +	  {
> +	  case IMAGE_REL_ARM64_PAGEOFFSET_12A:
> +	  case IMAGE_REL_ARM64_PAGEOFFSET_12L:
> +	    {
> +	      rel->r_ignore = 1;
> +	      continue;
> +	    }
> +	  case IMAGE_REL_ARM64_BRANCH26:
> +	    {
> +	      h = (struct coff_link_hash_entry*)
> +		  bfd_link_hash_lookup (info->hash, h->root.root.string + 6,
> +					0, 0, 1);

This could benefit from a comment noting that it's stripping the '__imp_'
prefix.

> +	      break;
> +	    }
> +	  case IMAGE_REL_ARM64_PAGEBASE_REL21:
> +	    {
> +	      uint32_t opcode = 0x14000000; /* b <label>.  */
> +	      bfd_putl32 (opcode, contents + rel->r_vaddr);
> +	      rel->r_type = IMAGE_REL_ARM64_BRANCH26;
> +
> +	      char* imp_label = xasprintf("%s_%x_%lx", h->root.root.string,
> +					  input_section->id,
> +					  (long unsigned) rel->r_vaddr);
> +	      h = (struct coff_link_hash_entry*)
> +		  bfd_link_hash_lookup (info->hash, imp_label, 0, 0, 1);
> +	      free(imp_label);
> +	      break;
> +	    }
> +	  }
> +
>        if (h && h->root.type == bfd_link_hash_defined)
>  	{
>  	  sec = h->root.u.def.section;
> @@ -557,6 +589,7 @@ coff_pe_aarch64_relocate_section (bfd *output_bfd,
>  	  continue;
>  	}
>  

The changes below are a refactoring with no functional change, so shouldn't be
part of this patch.  If you want to post this as a separate patch, I think it
might make more sense to move the rel->r_ignore assignment after the switch
instead.

> +      rel->r_ignore = 1;
>        switch (rel->r_type)
>  	{
>  	case IMAGE_REL_ARM64_ADDR32NB:
> @@ -578,8 +611,6 @@ coff_pe_aarch64_relocate_section (bfd *output_bfd,
>  		input_section, rel->r_vaddr - input_section->vma);
>  
>  	    bfd_putl32 (val, contents + rel->r_vaddr);
> -	    rel->r_ignore = 1;
> -
>  	    break;
>  	  }
>  
> @@ -613,8 +644,6 @@ coff_pe_aarch64_relocate_section (bfd *output_bfd,
>  	    opcode |= val & 0x3ffffff;
>  
>  	    bfd_putl32 (opcode, contents + rel->r_vaddr);
> -	    rel->r_ignore = 1;
> -
>  	    break;
>  	  }
>  
> @@ -648,8 +677,6 @@ coff_pe_aarch64_relocate_section (bfd *output_bfd,
>  	    opcode |= (val & 0x7ffff) << 5;
>  
>  	    bfd_putl32 (opcode, contents + rel->r_vaddr);
> -	    rel->r_ignore = 1;
> -
>  	    break;
>  	  }
>  
> @@ -683,8 +710,6 @@ coff_pe_aarch64_relocate_section (bfd *output_bfd,
>  	    opcode |= (val & 0x3fff) << 5;
>  
>  	    bfd_putl32 (opcode, contents + rel->r_vaddr);
> -	    rel->r_ignore = 1;
> -
>  	    break;
>  	  }
>  
> @@ -720,8 +745,6 @@ coff_pe_aarch64_relocate_section (bfd *output_bfd,
>  	    opcode |= (val & 0x1ffffc) << 3;
>  
>  	    bfd_putl32 (opcode, contents + rel->r_vaddr);
> -	    rel->r_ignore = 1;
> -
>  	    break;
>  	  }
>  
> @@ -757,8 +780,6 @@ coff_pe_aarch64_relocate_section (bfd *output_bfd,
>  	    opcode |= (val & 0x1ffffc) << 3;
>  
>  	    bfd_putl32 (opcode, contents + rel->r_vaddr);
> -	    rel->r_ignore = 1;
> -
>  	    break;
>  	  }
>  
> @@ -786,8 +807,6 @@ coff_pe_aarch64_relocate_section (bfd *output_bfd,
>  		input_section, rel->r_vaddr - input_section->vma);
>  
>  	    bfd_putl32 (val, contents + rel->r_vaddr);
> -	    rel->r_ignore = 1;
> -
>  	    break;
>  	  }
>  
> @@ -831,8 +850,6 @@ coff_pe_aarch64_relocate_section (bfd *output_bfd,
>  	    opcode |= val << 10;
>  
>  	    bfd_putl32 (opcode, contents + rel->r_vaddr);
> -	    rel->r_ignore = 1;
> -
>  	    break;
>  	  }
>  
> @@ -854,8 +871,6 @@ coff_pe_aarch64_relocate_section (bfd *output_bfd,
>  	    opcode |= val << 10;
>  
>  	    bfd_putl32 (opcode, contents + rel->r_vaddr);
> -	    rel->r_ignore = 1;
> -
>  	    break;
>  	  }
>  
> @@ -875,8 +890,6 @@ coff_pe_aarch64_relocate_section (bfd *output_bfd,
>  		input_section, rel->r_vaddr - input_section->vma);
>  
>  	    bfd_putl32 (val, contents + rel->r_vaddr);
> -	    rel->r_ignore = 1;
> -
>  	    break;
>  	  }
>  
> @@ -898,10 +911,7 @@ coff_pe_aarch64_relocate_section (bfd *output_bfd,
>  		s = s->next;
>  	      }
>  
> -
>  	    bfd_putl16 (idx, contents + rel->r_vaddr);
> -	    rel->r_ignore = 1;
> -
>  	    break;
>  	  }
>  
> diff --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em
> index 25ce3963b36..c74192ae32b 100644
> --- a/ld/emultempl/pep.em
> +++ b/ld/emultempl/pep.em
> @@ -1160,10 +1160,22 @@ pep_fixup_stdcalls (void)
>  static bfd_vma
>  read_addend (arelent *rel, asection *s)
>  {
> -  char buf[8];
>    bfd_vma addend = 0;
>    bool ok = false;
>  
> +#if defined (COFF_WITH_peAArch64)
> +  switch (rel->howto->bitsize)
> +    {
> +    case 12:
> +    case 21:
> +    case 26:
> +      ok = true;
> +      break;
> +    }

This could use a comment noting that the original addend is added in a separate
instructions, so the addend in this location is 0.

I also wonder whether this change would be better placed in make_import_fixup
as:

+#if defined (COFF_WITH_peAArch64)
+  addend = 0;
+#else
   addend = read_addend (rel, s);
+#endif


You're also changing the existing behaviour of the 26 case.  I understand that
this is AArch64-specific, but was that dead code before this patch (or only
used in broken unimplemented functionality)?  It doesn't appear to be used in
the existing testsuite.  If it is unused code, then it might be worth removing
the existing handling in a separate preliminary patch.

> +
> +#else
> +  char buf[8];
> +
>    switch (rel->howto->bitsize)
>      {
>      case 8:
> @@ -1186,7 +1198,6 @@ read_addend (arelent *rel, asection *s)
>  	    addend = bfd_get_16 (s->owner, buf);
>  	}
>        break;
> -    case 26:
>      case 32:
>        ok = bfd_get_section_contents (s->owner, s, buf, rel->address, 4);
>        if (ok)
> @@ -1203,6 +1214,8 @@ read_addend (arelent *rel, asection *s)
>  	addend = bfd_get_64 (s->owner, buf);
>        break;
>      }
> +#endif
> +
>    if (!ok)
>      einfo (_("%P: %H: cannot get section contents - auto-import exception\n"),
>  	   s->owner, s, rel->address);
> diff --git a/ld/pe-dll.c b/ld/pe-dll.c
> index f43bd14896e..b0a86f070d8 100644
> --- a/ld/pe-dll.c
> +++ b/ld/pe-dll.c
> @@ -2842,10 +2842,181 @@ pe_create_runtime_relocator_reference (bfd *parent)
>    return abfd;
>  }
>  
> +static void
> +aarch64_make_jump_stub(const char* symbol_name, bfd* parent)
> +{
> +  static struct bfd_hash_table *stub_hash = NULL;
> +  if (!stub_hash)
> +    {
> +      stub_hash = (struct bfd_hash_table *) xmalloc
> +		  (sizeof (struct bfd_hash_table));
> +      bfd_hash_table_init (stub_hash, bfd_hash_newfunc,
> +			  sizeof (struct bfd_hash_entry));
> +    }
> +
> +  if (pe_dll_extra_pe_debug)
> +    printf ("validate jump stub for %s\n", symbol_name);

"validate" seems like the wrong word.  Perhaps "searching for existing" would
be better?

> +
> +  if (bfd_hash_lookup(stub_hash, symbol_name, false, false))
> +    return;
> +
> +  if (pe_dll_extra_pe_debug)
> +    printf ("creating jump stub for %s\n", symbol_name);
> +  bfd_hash_lookup(stub_hash, symbol_name, true, true);
> +
> +  static unsigned tmp_stub_seq = 0;
> +  char *oname = xasprintf ("jump_stub_d%06d.o", tmp_stub_seq);
> +  ++tmp_stub_seq;
> +
> +  bfd *abfd = bfd_create (oname, parent);
> +  free (oname);
> +  bfd_make_writable (abfd);
> +
> +  bfd_set_format (abfd, bfd_object);
> +  bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0);
> +
> +  symptr = 0;
> +  symtab = xmalloc (12 * sizeof (asymbol *));

This only needs 4 * sizeof, not 12.

> +
> +  asection *tx  = quick_section (abfd, ".text", SEC_CODE | SEC_HAS_CONTENTS
> +				 | SEC_READONLY, 2);
> +  quick_symbol (abfd, "", symbol_name, "", tx, BSF_GLOBAL, 0);
> +  quick_symbol (abfd, "__imp_", symbol_name, "", bfd_und_section_ptr,
> +		BSF_GLOBAL, 0);
> +
> +  const unsigned jmp_byte_count = sizeof (jmp_aarch64_bytes);
> +  bfd_set_section_size (tx, jmp_byte_count);
> +  unsigned char *td = xmalloc (jmp_byte_count);
> +  tx->contents = td;
> +  memcpy (td, jmp_aarch64_bytes, jmp_byte_count);
> +
> +  quick_reloc (abfd, 0, BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL, 2);

Is there a reason to skip the overflow check?  I'd expect the non-NC version
to be more appropriate here.

> +  quick_reloc (abfd, 4, BFD_RELOC_AARCH64_ADD_LO12, 2);
> +  save_relocs (tx);
> +
> +  bfd_set_symtab (abfd, symtab, symptr);
> +
> +  bfd_set_section_contents (abfd, tx, td, 0, jmp_byte_count);
> +  bfd_make_readable (abfd);
> +  add_bfd_to_link (abfd, bfd_get_filename (abfd), &link_info);
> +}
> +
> +static void
> +aarch64_make_imp_offset(const char* imp_symbol_name,
> +			const char* imp_offset_name, const int offset,
> +			unsigned rd, const char* caller_label, bfd* parent)
> +{
> +  if (pe_dll_extra_pe_debug)
> +    printf("symbol: %s imp_offset_name: %s offset: %u rs: %u caller: %s\n",
> +	   imp_symbol_name, imp_offset_name, offset, rd, caller_label);
> +
> +  static const unsigned char imp_offset_bytes[] =
> +    {
> +      0x00, 0x00, 0x00, 0x90, /* adrp x0, <imp_symbol_name>		*/
> +      0x00, 0x00, 0x40, 0xf9, /* ldr x0, [x0, :lo12:<imp_symbol_name>]	*/
> +      0x00, 0x00, 0x40, 0x91, /* add x0, x0, 0, lsl 12			*/
> +      0x01, 0x00, 0x00, 0x14  /* b <caller_label> + 4			*/
> +    };
> +
> +  static unsigned tmp_stub_seq = 0;
> +  char *oname = xasprintf ("imp_offset_stub_d%06d.o", tmp_stub_seq);
> +  ++tmp_stub_seq;
> +
> +  bfd *abfd = bfd_create (oname, parent);
> +  free (oname);
> +  bfd_make_writable (abfd);
> +
> +  bfd_set_format (abfd, bfd_object);
> +  bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0);
> +
> +  symptr = 0;
> +  symtab = xmalloc (12 * sizeof (asymbol *));

This only needs 5 * sizeof.

> +
> +  asection *tx = quick_section (abfd, ".text", SEC_CODE | SEC_HAS_CONTENTS
> +				| SEC_READONLY, 2);
> +  quick_symbol (abfd, "", imp_offset_name, "", tx, BSF_GLOBAL, 0);
> +  quick_symbol (abfd, "", imp_symbol_name, "", UNDSEC, BSF_GLOBAL, 0);
> +  quick_symbol (abfd, "", caller_label, "", UNDSEC, BSF_GLOBAL, 0);
> +
> +  const unsigned imp_offset_byte_count = sizeof (imp_offset_bytes);
> +  bfd_set_section_size (tx, imp_offset_byte_count);
> +  uint32_t *td = xmalloc (imp_offset_byte_count);
> +  tx->contents = (bfd_byte*) td;
> +  memcpy (td, imp_offset_bytes, imp_offset_byte_count);
> +
> +  rd &= (1 << 5) - 1;
> +  td[0] |= rd;
> +  td[1] |= (rd << 5) | rd;
> +
> +  unsigned imm = 0;
> +  if (offset >= 0)
> +    imm = offset;
> +  else
> +  {
> +    imm = -offset + 4096;
> +/* Change "add x0, x0, 0, lsl 12" to "sub x0, x0, 0, lsl 12".  */
> +    td[2] |= 1 << 30;
> +  }
> +  imm >>= 12;

This gives the wrong value for negative multiples of 4096.
I think '-offset + 4095' gives the correct value, but it would be clearer to
rewrite this block as:

+  /* The bottom 12 bits are handled outside the thunk.  */
+  unsigned imm = offset & -4096;
+  if (imm < 0)
+  {
+    /* Change ADD (immediate) to SUB (immediate).  */
+    td[2] |= 1 << 30;
+    imm = -imm;
+  }
+  imm >>= 12;

> +  imm &= ((1 << 12) - 1);

This looks like it might silently truncate an out-of-range immediate.  However,
at this point we already know that (imm <= 1 << 8), because the offset is
extracted from an ADRP instruction.  Could you therefore delete this line, and
add a comment clarifying why the range is ok.

> +  td[2] |= (rd << 5) | rd;
> +  td[2] |= imm << 10;
> +
> +  quick_reloc (abfd, 0, BFD_RELOC_AARCH64_ADR_HI21_PCREL, 2);
> +  quick_reloc (abfd, 4, BFD_RELOC_AARCH64_LDST64_LO12, 2);
> +  quick_reloc (abfd, 12, BFD_RELOC_AARCH64_CALL26, 3);
> +  save_relocs (tx);
> +
> +  bfd_set_symtab (abfd, symtab, symptr);
> +
> +  bfd_set_section_contents (abfd, tx, td, 0, imp_offset_byte_count);
> +  bfd_make_readable (abfd);
> +  add_bfd_to_link (abfd, bfd_get_filename (abfd), &link_info);
> +}
> +
>  void
>  pe_create_import_fixup (arelent *rel, asection *s, bfd_vma addend, char *name,
>  			const char *symname)
>  {
> + if (pe_details->pe_arch == PE_ARCH_aarch64)
> +   {
> +      if (rel->howto->bitsize == 12)

This could use a comment explaining that the :lo12: bits are added within the
replacement for the adrp instruction, so no change is needed to the instruction
here.

> +	return;
> +      else if (rel->howto->bitsize == 26)
> +	{
> +/* On AArch64, a single opcode is not sufficient for relocation
> +   in dynamic linking. The linker generates a jump stub instead.  */
> +	  aarch64_make_jump_stub(name, s->owner);
> +	  return;
> +	}
> +      else if (rel->howto->bitsize == 21)
> +	{
> +	  uint32_t opcode;
> +	  if (!bfd_get_section_contents (s->owner, s, &opcode,
> +					 rel->address, 4))
> +	    return;
> +
> +	  int32_t imm = (opcode >> 5) & ((1 << 19) - 1);
> +	  imm <<= 2;
> +	  imm |= (opcode >> 29) & ((1 << 2) - 1);
> +	  if (imm & (1 << 20))
> +	    imm |= ~((1 << 21) - 1);

I think I would find 'imm -= (1 << 21)' slightly clearer, but I don't mind
either way.


> +
> +	  char *imp_offset_label = xasprintf("__imp_%s", name);
> +	  char *imp_label = xasprintf("%s_%x_%lx", imp_offset_label,
> +				      current_sec->id,
> +				      (long unsigned) rel->address);
> +	  const char *fixup_name = make_import_fixup_mark (rel, name);
> +	  unsigned rd = opcode & ((1 << 5) - 1);
> +	  aarch64_make_imp_offset(imp_offset_label, imp_label, imm, rd,
> +				  fixup_name, s->owner);
> +
> +	  free(imp_label);
> +	  free(imp_offset_label);
> +	  return;
> +	}
> +   }
> +
>    const char *fixup_name = make_import_fixup_mark (rel, name);
>    bfd *b;
>  
> diff --git a/ld/testsuite/ld-pe/auto-import-aarch64.d b/ld/testsuite/ld-pe/auto-import-aarch64.d
> new file mode 100644
> index 00000000000..4b70cfedd2a
> --- /dev/null
> +++ b/ld/testsuite/ld-pe/auto-import-aarch64.d
> @@ -0,0 +1,167 @@
> +
> +.*:     file format pei-aarch64-little
> +
> +
> +Disassembly of section .text:
> +
> +0000000140001000 <.*>:
> +   140001000:	14000030 	b	1400010c0 <__imp_dyn_v_10_0>
> +   140001004:	91000000 	add	x0, x0, #0x0
> +   140001008:	f9400000 	ldr	x0, \[x0\]
> +
> +000000014000100c <__fu1_dyn_v>:
> +   14000100c:	14000031 	b	1400010d0 <__imp_dyn_v_10_c>
> +   140001010:	91000800 	add	x0, x0, #0x2
> +   140001014:	f9400400 	ldr	x0, \[x0, #8\]
> +
> +0000000140001018 <__fu2_dyn_v>:
> +   140001018:	14000032 	b	1400010e0 <__imp_dyn_v_10_18>
> +   14000101c:	913ffc00 	add	x0, x0, #0xfff
> +   140001020:	f947fc00 	ldr	x0, \[x0, #4088\]
> +
> +0000000140001024 <__fu3_dyn_v>:
> +   140001024:	14000033 	b	1400010f0 <__imp_dyn_v_10_24>
> +   140001028:	91000000 	add	x0, x0, #0x0
> +   14000102c:	f9400000 	ldr	x0, \[x0\]
> +
> +0000000140001030 <__fu4_dyn_v>:
> +   140001030:	14000034 	b	140001100 <__imp_dyn_v_10_30>
> +   140001034:	912eb000 	add	x0, x0, #0xbac
> +   140001038:	f945d800 	ldr	x0, \[x0, #2992\]
> +
> +000000014000103c <__fu5_dyn_v>:
> +   14000103c:	14000035 	b	140001110 <__imp_dyn_v_10_3c>
> +   140001040:	913ffc00 	add	x0, x0, #0xfff
> +   140001044:	f947fc00 	ldr	x0, \[x0, #4088\]
> +
> +0000000140001048 <__fu6_dyn_v>:
> +   140001048:	14000036 	b	140001120 <__imp_dyn_v_10_48>
> +   14000104c:	913ff800 	add	x0, x0, #0xffe
> +   140001050:	f947fc00 	ldr	x0, \[x0, #4088\]
> +
> +0000000140001054 <__fu7_dyn_v>:
> +   140001054:	14000037 	b	140001130 <__imp_dyn_v_10_54>
> +   140001058:	91000400 	add	x0, x0, #0x1
> +   14000105c:	f9400400 	ldr	x0, \[x0, #8\]
> +
> +0000000140001060 <__fu8_dyn_v>:
> +   140001060:	14000038 	b	140001140 <__imp_dyn_v_10_60>
> +   140001064:	91000000 	add	x0, x0, #0x0
> +   140001068:	f9400000 	ldr	x0, \[x0\]
> +
> +000000014000106c <__fu9_dyn_v>:
> +   14000106c:	14000039 	b	140001150 <__imp_dyn_v_10_6c>
> +   140001070:	91115000 	add	x0, x0, #0x454
> +   140001074:	f9422800 	ldr	x0, \[x0, #1104\]
> +
> +0000000140001078 <__fu10_dyn_v>:
> +   140001078:	1400003a 	b	140001160 <__imp_dyn_v_10_78>
> +   14000107c:	91000000 	add	x0, x0, #0x0
> +   140001080:	f9400000 	ldr	x0, \[x0\]
> +
> +0000000140001084 <__fu11_dyn_v>:
> +   140001084:	1400003b 	b	140001170 <__imp_dyn_v_10_84>
> +   140001088:	91000821 	add	x1, x1, #0x2
> +   14000108c:	f9400421 	ldr	x1, \[x1, #8\]
> +
> +0000000140001090 <__fu12_dyn_v>:
> +   140001090:	1400003c 	b	140001180 <__imp_dyn_v_10_90>
> +   140001094:	91000820 	add	x0, x1, #0x2
> +   140001098:	f9400420 	ldr	x0, \[x1, #8\]
> +
> +000000014000109c <__fu13_dyn_v>:
> +   14000109c:	1400003d 	b	140001190 <__imp_dyn_v_10_9c>
> +   1400010a0:	913ff821 	add	x1, x1, #0xffe
> +   1400010a4:	f947fc21 	ldr	x1, \[x1, #4088\]
> +   1400010a8:	14000002 	b	1400010b0 <init_dyn_v>
> +   1400010ac:	94000001 	bl	1400010b0 <init_dyn_v>
> +
> +00000001400010b0 <init_dyn_v>:
> +   1400010b0:	d0000010 	adrp	x16, 140003000 <.*>
> +   1400010b4:	91012210 	add	x16, x16, #0x48
> +   1400010b8:	f9400210 	ldr	x16, \[x16\]
> +   1400010bc:	d61f0200 	br	x16
> +
> +00000001400010c0 <__imp_dyn_v_10_0>:
> +   1400010c0:	d0000000 	adrp	x0, 140003000 <.*>
> +   1400010c4:	f9402000 	ldr	x0, \[x0, #64\]
> +   1400010c8:	91400000 	add	x0, x0, #0x0, lsl #12
> +   1400010cc:	17ffffce 	b	140001004 <.*\+0x4>
> +
> +00000001400010d0 <__imp_dyn_v_10_c>:
> +   1400010d0:	d0000000 	adrp	x0, 140003000 <.*>
> +   1400010d4:	f9402000 	ldr	x0, \[x0, #64\]
> +   1400010d8:	91400000 	add	x0, x0, #0x0, lsl #12
> +   1400010dc:	17ffffcd 	b	140001010 <__fu1_dyn_v\+0x4>
> +
> +00000001400010e0 <__imp_dyn_v_10_18>:
> +   1400010e0:	d0000000 	adrp	x0, 140003000 <.*>
> +   1400010e4:	f9402000 	ldr	x0, \[x0, #64\]
> +   1400010e8:	91400000 	add	x0, x0, #0x0, lsl #12
> +   1400010ec:	17ffffcc 	b	14000101c <__fu2_dyn_v\+0x4>
> +
> +00000001400010f0 <__imp_dyn_v_10_24>:
> +   1400010f0:	d0000000 	adrp	x0, 140003000 <.*>
> +   1400010f4:	f9402000 	ldr	x0, \[x0, #64\]
> +   1400010f8:	91400400 	add	x0, x0, #0x1, lsl #12
> +   1400010fc:	17ffffcb 	b	140001028 <__fu3_dyn_v\+0x4>
> +
> +0000000140001100 <__imp_dyn_v_10_30>:
> +   140001100:	d0000000 	adrp	x0, 140003000 <.*>
> +   140001104:	f9402000 	ldr	x0, \[x0, #64\]
> +   140001108:	91436c00 	add	x0, x0, #0xdb, lsl #12
> +   14000110c:	17ffffca 	b	140001034 <__fu4_dyn_v\+0x4>
> +
> +0000000140001110 <__imp_dyn_v_10_3c>:
> +   140001110:	d0000000 	adrp	x0, 140003000 <.*>
> +   140001114:	f9402000 	ldr	x0, \[x0, #64\]
> +   140001118:	9143fc00 	add	x0, x0, #0xff, lsl #12
> +   14000111c:	17ffffc9 	b	140001040 <__fu5_dyn_v\+0x4>
> +
> +0000000140001120 <__imp_dyn_v_10_48>:
> +   140001120:	d0000000 	adrp	x0, 140003000 <.*>
> +   140001124:	f9402000 	ldr	x0, \[x0, #64\]
> +   140001128:	d1400400 	sub	x0, x0, #0x1, lsl #12
> +   14000112c:	17ffffc8 	b	14000104c <__fu6_dyn_v\+0x4>
> +
> +0000000140001130 <__imp_dyn_v_10_54>:
> +   140001130:	d0000000 	adrp	x0, 140003000 <.*>
> +   140001134:	f9402000 	ldr	x0, \[x0, #64\]
> +   140001138:	d1400400 	sub	x0, x0, #0x1, lsl #12
> +   14000113c:	17ffffc7 	b	140001058 <__fu7_dyn_v\+0x4>
> +
> +0000000140001140 <__imp_dyn_v_10_60>:
> +   140001140:	d0000000 	adrp	x0, 140003000 <.*>
> +   140001144:	f9402000 	ldr	x0, \[x0, #64\]
> +   140001148:	d1400800 	sub	x0, x0, #0x2, lsl #12
> +   14000114c:	17ffffc6 	b	140001064 <__fu8_dyn_v\+0x4>
> +
> +0000000140001150 <__imp_dyn_v_10_6c>:
> +   140001150:	d0000000 	adrp	x0, 140003000 <.*>
> +   140001154:	f9402000 	ldr	x0, \[x0, #64\]
> +   140001158:	d1437000 	sub	x0, x0, #0xdc, lsl #12
> +   14000115c:	17ffffc5 	b	140001070 <__fu9_dyn_v\+0x4>
> +
> +0000000140001160 <__imp_dyn_v_10_78>:
> +   140001160:	d0000000 	adrp	x0, 140003000 <.*>
> +   140001164:	f9402000 	ldr	x0, \[x0, #64\]
> +   140001168:	d1440400 	sub	x0, x0, #0x101, lsl #12
> +   14000116c:	17ffffc4 	b	14000107c <__fu10_dyn_v\+0x4>
> +
> +0000000140001170 <__imp_dyn_v_10_84>:
> +   140001170:	d0000001 	adrp	x1, 140003000 <.*>
> +   140001174:	f9402021 	ldr	x1, \[x1, #64\]
> +   140001178:	91400021 	add	x1, x1, #0x0, lsl #12
> +   14000117c:	17ffffc3 	b	140001088 <__fu11_dyn_v\+0x4>
> +
> +0000000140001180 <__imp_dyn_v_10_90>:
> +   140001180:	d0000001 	adrp	x1, 140003000 <.*>
> +   140001184:	f9402021 	ldr	x1, \[x1, #64\]
> +   140001188:	91400021 	add	x1, x1, #0x0, lsl #12
> +   14000118c:	17ffffc2 	b	140001094 <__fu12_dyn_v\+0x4>
> +
> +0000000140001190 <__imp_dyn_v_10_9c>:
> +   140001190:	d0000001 	adrp	x1, 140003000 <.*>
> +   140001194:	f9402021 	ldr	x1, \[x1, #64\]
> +   140001198:	d1400421 	sub	x1, x1, #0x1, lsl #12
> +   14000119c:	17ffffc1 	b	1400010a0 <__fu13_dyn_v\+0x4>
> diff --git a/ld/testsuite/ld-pe/auto-import-aarch64.s b/ld/testsuite/ld-pe/auto-import-aarch64.s
> new file mode 100644
> index 00000000000..411669e9d9e
> --- /dev/null
> +++ b/ld/testsuite/ld-pe/auto-import-aarch64.s
> @@ -0,0 +1,61 @@
> +	.text
> +	.global main
> +main:
> +	adrp	x0, dyn_v
> +	add	x0, x0, :lo12:dyn_v
> +	ldr	x0, [x0, :lo12:dyn_v]
> +
> +	adrp	x0, dyn_v + 2
> +	add	x0, x0, :lo12:dyn_v + 2
> +	ldr	x0, [x0, :lo12:dyn_v + 8]
> +
> +	adrp	x0, dyn_v + 4095
> +	add	x0, x0, :lo12:dyn_v + 4095
> +	ldr	x0, [x0, :lo12:dyn_v + 4088]
> +
> +	adrp	x0, dyn_v + 4096
> +	add	x0, x0, :lo12:dyn_v + 4096
> +	ldr	x0, [x0, :lo12:dyn_v + 4096]
> +
> +	adrp	x0, dyn_v + 900012
> +	add	x0, x0, :lo12:dyn_v + 900012
> +	ldr	x0, [x0, :lo12:dyn_v + 900016]
> +
> +	adrp	x0, dyn_v + 1048575
> +	add	x0, x0, :lo12:dyn_v + 1048575
> +	ldr	x0, [x0, :lo12:dyn_v + 1048568]
> +
> +	adrp	x0, dyn_v - 2
> +	add	x0, x0, :lo12:dyn_v - 2
> +	ldr	x0, [x0, :lo12:dyn_v - 8]
> +
> +	adrp	x0, dyn_v - 4095
> +	add	x0, x0, :lo12:dyn_v - 4095
> +	ldr	x0, [x0, :lo12:dyn_v - 4088]
> +
> +	adrp	x0, dyn_v - 4096
> +	add	x0, x0, :lo12:dyn_v - 4096
> +	ldr	x0, [x0, :lo12:dyn_v - 4096]
> +
> +	adrp	x0, dyn_v - 900012
> +	add	x0, x0, :lo12:dyn_v - 900012
> +	ldr	x0, [x0, :lo12:dyn_v - 900016]
> +
> +	adrp	x0, dyn_v - 1048576
> +	add	x0, x0, :lo12:dyn_v - 1048576
> +	ldr	x0, [x0, :lo12:dyn_v - 1048576]
> +
> +	adrp	x1, dyn_v + 2
> +	add	x1, x1, :lo12:dyn_v + 2
> +	ldr	x1, [x1, :lo12:dyn_v + 8]
> +
> +	adrp	x1, dyn_v + 2
> +	add	x0, x1, :lo12:dyn_v + 2
> +	ldr	x0, [x1, :lo12:dyn_v + 8]
> +
> +	adrp	x1, dyn_v - 2
> +	add	x1, x1, :lo12:dyn_v - 2
> +	ldr	x1, [x1, :lo12:dyn_v - 8]

These tests currently uses invalid combinations of symbol references:
- adding a :lo12: value to x0 and then adding another :lo12: value to the
  result;
- using different addends in the adrp and ldr relocations when these might not
  be on the same page.

You're not trying to test behaviour on invalid input, so you should change the
tests to use valid combinations of symbol references.

> +
> +	b init_dyn_v
> +	bl init_dyn_v
> diff --git a/ld/testsuite/ld-pe/auto-import-dll-aarch64.s b/ld/testsuite/ld-pe/auto-import-dll-aarch64.s
> new file mode 100644
> index 00000000000..dc9314273fa
> --- /dev/null
> +++ b/ld/testsuite/ld-pe/auto-import-dll-aarch64.s
> @@ -0,0 +1,13 @@
> +	.data
> +	.global	dyn_v
> +	.align	3
> +	.def	dyn_v;	.scl	2;	.type	0;	.endef
> +dyn_v:
> +	.space	8
> +
> +	.text
> +	.align	2
> +	.global	init_dyn_v
> +	.def	init_dyn_v;	.scl	2;	.type	32;	.endef
> +init_dyn_v:
> +	ret
> diff --git a/ld/testsuite/ld-pe/pe.exp b/ld/testsuite/ld-pe/pe.exp
> index b95f61b8578..53b04bb6757 100644
> --- a/ld/testsuite/ld-pe/pe.exp
> +++ b/ld/testsuite/ld-pe/pe.exp
> @@ -121,6 +121,17 @@ if {[istarget "aarch64-*-pe*"] || [istarget "aarch64-*-mingw*"]} {
>      }
>  
>      run_ld_link_tests $pe_tests
> +
> +    set auto_import_aarch64_test "auto-import-aarch64"
> +    if { [ld_assemble $as $srcdir/$subdir/auto-import-dll-aarch64.s tmpdir/auto-import-dll-aarch64.o]
> +	 && [ld_assemble $as $srcdir/$subdir/auto-import-aarch64.s tmpdir/auto-import-aarch64.o]
> +	 && [ld_link $ld "tmpdir/auto-import-dll.dll" "-shared tmpdir/auto-import-dll-aarch64.o --out-implib tmpdir/libauto-import-dll-aarch64.a"]
> +	 && [ld_link $ld "tmpdir/auto-import-aarch64.exe" "tmpdir/auto-import-aarch64.o tmpdir/libauto-import-dll-aarch64.a"]
> +	 && [regexp [file_contents "$srcdir/$subdir/auto-import-aarch64.d"] [run_host_cmd "$objdump" "-d tmpdir/auto-import-aarch64.exe"]] } {
> +	pass $auto_import_aarch64_test
> +    } else {
> +	fail $auto_import_aarch64_test
> +    }
>  }
>  
>  run_dump_test "image_size"
> @@ -185,10 +196,10 @@ if [check_shared_lib_support] {
>      }
>      run_dump_test "symbols-ordinals-hints-exports-ld"
>      # no dlltool for these two
> -    setup_xfail aarch64-*-* sh-*-*
> +    setup_xfail sh-*-*
>      run_dump_test "symbols-ordinals-hints-exports-dlltool"
>      run_dump_test "symbols-ordinals-hints-imports-ld"
> -    setup_xfail aarch64-*-* sh-*-*
> +    setup_xfail sh-*-*
>      run_dump_test "symbols-ordinals-hints-imports-dlltool"
>      set ASFLAGS $old_ASFLAGS
>  }


More information about the Binutils mailing list