[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