]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
LoongArch: Call elf_ifunc_invoke for R_LARCH_IRELATIVE in elf_machine_rela
authorXi Ruoyao <xry111@xry111.site>
Fri, 7 Nov 2025 15:49:22 +0000 (23:49 +0800)
committercaiyinyu <caiyinyu@loongson.cn>
Wed, 12 Nov 2025 01:12:48 +0000 (09:12 +0800)
When R_LARCH_IRELATIVE is resolved by apply_irel, the ifunc resolver is
called via elf_ifunc_invoke so it can read HWCAP from the __ifunc_arg_t
argument.  But when R_LARCH_IRELATIVE is resolved by elf_machine_rela (it
will happen if we dlopen() a shared object containing R_LARCH_IRELATIVE),
the ifunc resolver is invoked directly with no or different argument.
This causes a segfault if the resolver uses the __ifunc_arg_t.

Despite the LoongArch psABI does not specify this argument, IMO it's
more convenient to have this argument IMO and per hyrum's rule there may
be objects in wild which already relies on this argument (they just
didn't blow up because they are not dlopen()ed yet).  So make the
behavior handling R_LARCH_IRELATIVE of elf_machine_rela same as
apply_irel.

This fixes BZ #33610.

Signed-off-by: Xi Ruoyao <xry111@xry111.site>
sysdeps/loongarch/dl-machine.h

index a956590ea9aca8a59bcd6c92e69b7ec647d8270e..b01d9339a45c6c8a40da6c7cbad977e15c771e26 100644 (file)
@@ -27,6 +27,7 @@
 #include <sys/asm.h>
 #include <dl-tlsdesc.h>
 #include <dl-static-tls.h>
+#include <dl-irel.h>
 #include <dl-machine-rel.h>
 
 #include <cpu-features.c>
@@ -179,7 +180,7 @@ elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
       && __glibc_unlikely (ELFW (ST_TYPE) (sym->st_info) == STT_GNU_IFUNC)
       && __glibc_likely (sym->st_shndx != SHN_UNDEF)
       && __glibc_likely (!skip_ifunc))
-    value = ((ElfW (Addr) (*) (int)) value) (GLRO (dl_hwcap));
+    value = elf_ifunc_invoke (value);
 
   switch (r_type)
     {
@@ -273,7 +274,7 @@ elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
     case R_LARCH_IRELATIVE:
       value = map->l_addr + reloc->r_addend;
       if (__glibc_likely (!skip_ifunc))
-       value = ((ElfW (Addr) (*) (void)) value) ();
+       value = elf_ifunc_invoke (value);
       *addr_field = value;
       break;