[PATCH] aarch64: Add auto-import support
Evgeny Karpov
evgeny@kmaps.co
Thu Nov 13 20:57:30 GMT 2025
-------------- next part --------------
From: Evgeny Karpov <evgeny@kmaps.co>
Subject: [PATCH] aarch64: Add auto-import support
The patch implements the required changes to support runtime relocations in
MinGW/Cygwin. For 26-bit relocations, the linker generates a jump stub, as
a single opcode is not sufficient for relocation.
This is how it is handled in Cygwin, for instance.
https://cygwin.com/pipermail/cygwin-patches/2025q4/014332.html .
Signed-off-by: Evgeny Karpov <evgeny@kmaps.co>
---
bfd/coff-aarch64.c | 13 +++++--
ld/emultempl/pep.em | 22 ++++++++++++
ld/pe-dll.c | 83 ++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 115 insertions(+), 3 deletions(-)
diff --git a/bfd/coff-aarch64.c b/bfd/coff-aarch64.c
index 0792306cfa0..ac4226432e2 100644
--- a/bfd/coff-aarch64.c
+++ b/bfd/coff-aarch64.c
@@ -266,17 +266,26 @@ static const reloc_howto_type arm64_reloc_howto_branch26
= HOW (IMAGE_REL_ARM64_BRANCH26,
2, 4, 26, true, 0, signed, NULL, 0x3ffffff);
+/* On AArch64 COFF, a custom relocation, such as
+ coff_aarch64_rel21_reloc func, is used.
+ The reloc_howto_struct is not used in the usual way.
+ The mask is set to 0 to avoid issues during dynamic linking. */
static const reloc_howto_type arm64_reloc_howto_page21
= HOW (IMAGE_REL_ARM64_PAGEBASE_REL21,
- 12, 4, 21, true, 0, signed, rel21_reloc, 0x1fffff);
+ 12, 4, 21, true, 0, signed, rel21_reloc, 0);
static const reloc_howto_type arm64_reloc_howto_lo21
= HOW (IMAGE_REL_ARM64_REL21,
0, 4, 21, true, 0, signed, rel21_reloc, 0x1fffff);
+/* Similar to IMAGE_REL_ARM64_PAGEBASE_REL21.
+ On AArch64 COFF, a custom relocation, such as
+ coff_aarch64_po12l_reloc func, is used.
+ The reloc_howto_struct is not used in the usual way.
+ The overflow func is set to dont to avoid issues during dynamic linking. */
static const reloc_howto_type arm64_reloc_howto_pgoff12l
= HOW (IMAGE_REL_ARM64_PAGEOFFSET_12L,
- 0, 4, 12, true, 10, signed, po12l_reloc, 0x3ffc00);
+ 0, 4, 12, true, 10, dont, po12l_reloc, 0x3ffc00);
static const reloc_howto_type arm64_reloc_howto_branch19
= HOW (IMAGE_REL_ARM64_BRANCH19,
diff --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em
index 0d059fb6400..f6c15927e2e 100644
--- a/ld/emultempl/pep.em
+++ b/ld/emultempl/pep.em
@@ -1165,6 +1165,28 @@ read_addend (arelent *rel, asection *s)
switch (rel->howto->bitsize)
{
+#if defined (COFF_WITH_peAArch64)
+ case 12:
+ ok = bfd_get_section_contents (s->owner, s, &addend, rel->address, 4);
+ if (!ok)
+ break;
+ addend = (addend >> 10) & ((1 << 12) - 1);
+ break;
+ case 21:
+ ok = bfd_get_section_contents (s->owner, s, &addend, rel->address, 4);
+ if (!ok)
+ break;
+ addend = (((addend >> 5) & ((1 << 19) - 1)) << 2) | ((addend >> 29) & ((1 << 2) - 1));
+ addend <<= 12;
+ break;
+ case 26:
+ ok = bfd_get_section_contents (s->owner, s, &addend, rel->address, 4);
+ if (!ok)
+ break;
+ addend = addend & ((1 << 12) - 1);
+ addend <<= 2;
+ break;
+#endif
case 8:
ok = bfd_get_section_contents (s->owner, s, buf, rel->address, 1);
if (ok)
diff --git a/ld/pe-dll.c b/ld/pe-dll.c
index 853425dc287..9daf1f228d4 100644
--- a/ld/pe-dll.c
+++ b/ld/pe-dll.c
@@ -1518,10 +1518,15 @@ pe_find_data_imports (const char *symhead,
undef->u.def.value = sym->u.def.value;
undef->u.def.section = sym->u.def.section;
+#if !defined (COFF_WITH_peAArch64)
/* We replace the original name with the __imp_ prefixed one, this
1) may trash memory 2) leads to duplicate symbols. But this is
- better than having a misleading name that can confuse GDB. */
+ better than having a misleading name that can confuse GDB.
+
+ On AArch64, it should not be changed, as a jump stub will be generated
+ for the same function name. */
undef->root.string = sym->root.string;
+#endif
if (link_info.pei386_auto_import == -1)
{
@@ -2822,6 +2827,71 @@ pe_create_runtime_relocator_reference (bfd *parent)
return abfd;
}
+#if defined (COFF_WITH_peAArch64)
+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);
+
+ 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);
+
+ asection *tx;
+ unsigned char *td = NULL;
+ char *oname;
+ bfd *abfd;
+ const unsigned char *jmp_bytes = NULL;
+ int jmp_byte_count = 0;
+ jmp_bytes = jmp_aarch64_bytes;
+ jmp_byte_count = sizeof (jmp_aarch64_bytes);
+ static int tmp_stub_seq = 0;
+
+ oname = xasprintf ("jump_stub_d%06d.o", tmp_stub_seq);
+ ++tmp_stub_seq;
+
+ 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 *));
+
+ 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);
+
+ bfd_set_section_size (tx, jmp_byte_count);
+ td = xmalloc (jmp_byte_count);
+ tx->contents = td;
+ memcpy (td, jmp_bytes, jmp_byte_count);
+
+ quick_reloc (abfd, 0, BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL, 2);
+ 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);
+}
+#endif
+
void
pe_create_import_fixup (arelent *rel, asection *s, bfd_vma addend, char *name,
const char *symname)
@@ -2865,6 +2935,17 @@ pe_create_import_fixup (arelent *rel, asection *s, bfd_vma addend, char *name,
if ((addend != 0 && link_info.pei386_runtime_pseudo_reloc == 1)
|| link_info.pei386_runtime_pseudo_reloc == 2)
{
+#if defined (COFF_WITH_peAArch64)
+
+ 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;
+ }
+#endif
+
if (pe_dll_extra_pe_debug)
printf ("creating runtime pseudo-reloc entry for %s (addend=%d)\n",
fixup_name, (int) addend);
--
2.50.1 (Apple Git-155)
More information about the Binutils
mailing list