Index: sys/arm64/arm64/elf_machdep.c =================================================================== --- sys/arm64/arm64/elf_machdep.c +++ sys/arm64/arm64/elf_machdep.c @@ -143,8 +143,10 @@ */ static int elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, - int type, int local, elf_lookup_fn lookup) + int type, int flags, elf_lookup_fn lookup) { +#define ARM64_ELF_RELOC_LOCAL (1 << 0) +#define ARM64_ELF_RELOC_LATE_IFUNC (1 << 1) Elf_Addr *where, addr, addend, val; Elf_Word rtype, symidx; const Elf_Rel *rel; @@ -170,7 +172,14 @@ panic("unknown reloc type %d\n", type); } - if (local) { + if ((flags & ARM64_ELF_RELOC_LATE_IFUNC) != 0) { + KASSERT(type == ELF_RELOC_RELA, + ("Only RELA ifunc relocations are supported")); + if (rtype != R_AARCH64_IRELATIVE) + return (0); + } + + if ((flags & ARM64_ELF_RELOC_LOCAL) != 0) { if (rtype == R_AARCH64_RELATIVE) *where = elf_relocaddr(lf, relocbase + addend); return (0); @@ -229,7 +238,8 @@ int type, elf_lookup_fn lookup) { - return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup)); + return (elf_reloc_internal(lf, relocbase, data, type, + ARM64_ELF_RELOC_LOCAL, lookup)); } /* Process one elf relocation with addend. */ @@ -241,6 +251,15 @@ return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup)); } +int +elf_reloc_late(linker_file_t lf, Elf_Addr relocbase, const void *data, + int type, elf_lookup_fn lookup) +{ + + return (elf_reloc_internal(lf, relocbase, data, type, + ARM64_ELF_RELOC_LATE_IFUNC, lookup)); +} + int elf_cpu_load_file(linker_file_t lf) { Index: sys/arm64/arm64/machdep.c =================================================================== --- sys/arm64/arm64/machdep.c +++ sys/arm64/arm64/machdep.c @@ -181,6 +181,13 @@ SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL); +static void +late_ifunc_resolve(void *dummy __unused) +{ + link_elf_late_ireloc(); +} +SYSINIT(late_ifunc_resolve, SI_SUB_CPU, SI_ORDER_ANY, late_ifunc_resolve, NULL); + int cpu_idle_wakeup(int cpu) { Index: sys/kern/link_elf.c =================================================================== --- sys/kern/link_elf.c +++ sys/kern/link_elf.c @@ -1925,4 +1925,18 @@ link_elf_preload_parse_symbols(ef); relocate_file1(ef, elf_lookup_ifunc, elf_reloc, true); } + +#if defined(__aarch64__) +void +link_elf_late_ireloc(void) +{ + elf_file_t ef; + + KASSERT(linker_kernel_file != NULL, + ("link_elf_late_ireloc: No kernel linker file found")); + ef = (elf_file_t)linker_kernel_file; + + relocate_file1(ef, elf_lookup_ifunc, elf_reloc_late, true); +} +#endif #endif Index: sys/sys/linker.h =================================================================== --- sys/sys/linker.h +++ sys/sys/linker.h @@ -289,6 +289,12 @@ const char *elf_get_symname(linker_file_t _lf, Elf_Size _symidx); void link_elf_ireloc(caddr_t kmdp); +#if defined(__aarch64__) +int elf_reloc_late(linker_file_t _lf, Elf_Addr base, const void *_rel, + int _type, elf_lookup_fn _lu); +void link_elf_late_ireloc(void); +#endif + typedef struct linker_ctf { const uint8_t *ctftab; /* Decompressed CTF data. */ int ctfcnt; /* Number of CTF data bytes. */