public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] RFC: Provide a function to reset IFUNC PLTs
@ 2023-03-06  8:04 Jan Kratochvil
  2023-03-07  8:40 ` Florian Weimer
  0 siblings, 1 reply; 19+ messages in thread
From: Jan Kratochvil @ 2023-03-06  8:04 UTC (permalink / raw)
  To: libc-alpha; +Cc: Anton Kozlov

Some projects snapshot+restore process images to migrate them to
a different machine. The target machine may have different (particularly
lower) set of CPU features. Restored process does crash in glibc IFUNC
functions which have been already set in PLTs due to the former more
rich CPU features on the snapshotting machine.

Providing a glibc function which can be called during the restore.

I understand the code may need more adjustments before its upstreaming
but is this an acceptable approach?

An example of the problem reproducibility with: http://criu.org

int main(void) {
  setbuf(stdout, NULL);
  for (;;) {
    time_t t = time(NULL);
    fputs(ctime(&t), stdout);
    sleep(strcmp("hello", "world") != 0);
  }
}

newcpu$ gcc -o strcmper strcmper.c -Wall -g
newcpu$ rm -rf dir;mkdir dir;./strcmper &p=$!;sleep 1;sudo criu dump --shell-job -t $p -D dir
oldcpu$ sudo criu restore --shell-job -D dir
Segmentation fault

newcpu$ gcc -o strcmper strcmper.c -Wall -g glibc/ld-linux-x86-64.so.2 glibc/libc.so.6 # patched files are in glibc/
newcpu$ rm -rf dir;mkdir dir;LD_LIBRARY_PATH=glibc ./glibc/ld-linux-x86-64.so.2 ./strcmper &p=$!;sleep 1;sudo criu dump --shell-job -t $p -D dir
oldcpu$ sudo criu restore --shell-job -D dir
running...
---
 elf/Makefile                       |   2 +
 elf/Versions                       |   9 +
 elf/dl-reloc.c                     |   2 +
 elf/dl-reset-ifunc.c               | 392 +++++++++++++++++++++++++++++
 elf/dl-tunables.c                  |  14 ++
 elf/dl-tunables.h                  |   4 +
 elf/link.h                         |   2 +
 elf/tst-reset-ifunc.c              |  70 ++++++
 sysdeps/generic/ldsodefs.h         |   4 +-
 sysdeps/x86/dl-get-cpu-features.c  |   1 +
 sysdeps/x86/include/cpu-features.h |   3 +-
 11 files changed, 500 insertions(+), 3 deletions(-)
 create mode 100644 elf/dl-reset-ifunc.c
 create mode 100644 elf/tst-reset-ifunc.c

diff --git a/elf/Makefile b/elf/Makefile
index 0d19964d42..1948d51407 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -39,6 +39,7 @@ routines = \
   dl-origin \
   dl-profstub \
   dl-reloc-static-pie \
+  dl-reset-ifunc \
   dl-support \
   dl-sym \
   dl-sysdep \
@@ -309,6 +310,7 @@ tests := \
   tst-auxv \
   tst-dl-hash \
   tst-leaks1 \
+  tst-reset-ifunc \
   tst-stringtable \
   tst-tls9 \
   # tests
diff --git a/elf/Versions b/elf/Versions
index 4614acea3e..f04f81efbf 100644
--- a/elf/Versions
+++ b/elf/Versions
@@ -23,6 +23,9 @@ libc {
   GLIBC_2.35 {
     _dl_find_object;
   }
+  GLIBC_2.38 {
+    _dl_reset_ifunc;
+  }
   GLIBC_ABI_DT_RELR {
     # This symbol is used only for empty version map and will be removed
     # by scripts/versions.awk.
@@ -78,5 +81,11 @@ ld {
 
     # Set value of a tunable.
     __tunable_get_val;
+
+    # For dl-reset-ifunc.c.
+    __tunable_get_start;
+    __tunable_get_end;
+    _dl_relocate_object;
+    _dl_x86_init_cpu_features;
   }
 }
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 1d558c1e0c..7aed2d44fa 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -349,6 +349,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
     _dl_protect_relro (l);
 }
 
+rtld_hidden_def (_dl_relocate_object)
+
 
 void
 _dl_protect_relro (struct link_map *l)
diff --git a/elf/dl-reset-ifunc.c b/elf/dl-reset-ifunc.c
new file mode 100644
index 0000000000..04a17088e4
--- /dev/null
+++ b/elf/dl-reset-ifunc.c
@@ -0,0 +1,392 @@
+/* Reset IFUNC symbols for their new detection.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/* Very special case: This object is built into the static libc, but
+   must know the layout of _rtld_global_ro.  */
+#undef SHARED
+#define SHARED
+#include <ldsodefs.h>
+
+#include <cpu-features.h>
+
+#if HAVE_TUNABLES
+# define TUNABLES_INTERNAL 1
+# include "dl-tunables.h"
+static tunable_t tunable_list[] attribute_relro __attribute_maybe_unused__;
+#endif // HAVE_TUNABLES
+
+#define strcmp strcmp_local
+static int strcmp_local(const char *s1, const char *s2) {
+  const unsigned char *a = (const unsigned char *) s1;
+  const unsigned char *b = (const unsigned char *) s2;
+  for (;; ++a, ++b) {
+    if (*a != *b)
+      return *b > *a ? +1 : -1;
+    if (*a == 0)
+      return 0;
+  }
+}
+
+#define strchr strchr_local
+static char *strchr_local(const char *s, int c) {
+  for (; *s; ++s)
+    if ((uint8_t)*s == (uint8_t)c)
+      return (char *)s;
+  return NULL;
+}
+
+#define strlen strlen_local
+__attribute__ ((optimize(0))) // otherwise GCC will replace the function by system strlen() again
+static size_t strlen_local(const char *cs) {
+  size_t retval = 0;
+  while (*cs++)
+    ++retval;
+  return retval;
+}
+
+// FIXME: Why volatile?
+#define memset memset_local
+static volatile void *memset_local(volatile void *m, int c, size_t n) {
+  for (volatile uint8_t *d = (volatile uint8_t *)m; n--; ++d)
+    *d = c;
+  return m;
+}
+
+static char *file_read(const char *fn) {
+  int fd = open(fn, O_RDONLY);
+  assert(fd != -1);
+  // realloc() calls memmove().
+  size_t buf_size = 0x100000;
+  char *buf = (char *)malloc(buf_size);
+  assert(buf);
+  size_t buf_have = 0;
+  for (;;) {
+    assert(buf_have < buf_size);
+    ssize_t got = read(fd, buf + buf_have, buf_size - buf_have);
+    assert(got != -1);
+    if (got == 0)
+      break;
+    assert(got > 0);
+    assert(buf_have + got <= buf_size);
+    buf_have += got;
+  }
+  assert(buf_have < buf_size);
+  buf[buf_have] = 0;
+  assert(strlen(buf) == buf_have);
+  return buf;
+}
+
+static uint64_t read_hex(const char **cs_p) {
+  uint64_t retval = 0;
+  for (;;)
+#define cs (*cs_p)
+    switch (*cs) {
+    case '0' ... '9':
+      retval <<= 4;
+      retval |= *cs++ - '0';
+      continue;
+    case 'a' ... 'f':
+      retval <<= 4;
+      retval |= *cs++ - 'a' + 0xa;
+      continue;
+    default:
+      return retval;
+      break;
+    }
+#undef cs
+}
+
+static int mprotect_read(const void *addr, const void **addr_end_return) {
+  uint64_t addr_u = (uintptr_t)addr;
+  char *file = file_read("/proc/self/maps");
+  int retval = -1;
+  for (const char *cs = file; *cs;) {
+    // sscanf() calls rawmemchr().
+    uint64_t start = read_hex(&cs);
+    assert(*cs == '-');
+    ++cs;
+    uint64_t end = read_hex(&cs);
+    assert(*cs == ' ');
+    ++cs;
+    assert(start < end);
+    int rwxp = 0;
+    assert(*cs == 'r' || *cs == '-');
+    if (*cs++ == 'r')
+      rwxp |= 04;
+    assert(*cs == 'w' || *cs == '-');
+    if (*cs++ == 'w')
+      rwxp |= 02;
+    assert(*cs == 'x' || *cs == '-');
+    if (*cs++ == 'x')
+      rwxp |= 01;
+    assert(*cs == 's' || *cs == 'p');
+    ++cs;
+    assert(*cs == ' ');
+    ++cs;
+    if (start <= addr_u && addr_u < end) {
+      if (addr_end_return)
+        *addr_end_return = (const void *)(uintptr_t)end;
+      retval = rwxp;
+      break;
+    }
+    cs = strchr(cs, '\n');
+    assert(cs);
+    ++cs;
+  }
+  if (retval == -1) {
+    fprintf(stderr, "Not found an address: %p\n", addr);
+    assert(0);
+  }
+  free(file);
+  return retval;
+}
+
+static void verify_rwxp(const void *start, const void *end, int rwxp_want) {
+  assert((((uintptr_t)start) & (PAGE_SIZE - 1)) == 0);
+  assert((((uintptr_t)end  ) & (PAGE_SIZE - 1)) == 0);
+  assert(start < end);
+  while (start < end) {
+    int rwxp_found = mprotect_read(start, &start);
+    if (rwxp_found != rwxp_want) { printf("sudo gdb -p %d\n",getpid()); pause(); }
+    assert(rwxp_found == rwxp_want);
+  }
+}
+
+const struct link_map *phdr_info_to_link_map(struct dl_phdr_info *phdr_info) {
+  Dl_info info;
+  const struct link_map *link_map = NULL;
+  int err = dladdr1(phdr_info->dlpi_phdr, &info, (void **)&link_map, RTLD_DL_LINKMAP);
+  assert(err == 1);
+  assert(link_map);
+  return link_map;
+}
+
+static void page_align(const void **start_p, const void **end_p) {
+  *start_p = (const void *)(((uintptr_t)*start_p) & -PAGE_SIZE);
+  assert(*start_p);
+  *end_p = (const void *)((((uintptr_t)*end_p) + PAGE_SIZE - 1) & -PAGE_SIZE);
+}
+
+static void readonly_unset(const void *start, const void *end) {
+  assert((((uintptr_t)start) & (PAGE_SIZE - 1)) == 0);
+  assert((((uintptr_t)end  ) & (PAGE_SIZE - 1)) == 0);
+  assert(start <= end);
+  if (start == end)
+    return;
+  verify_rwxp(start, end, 04/*r--*/);
+  int err = mprotect((void *)start, (const uint8_t *)end - (const uint8_t *)start, PROT_READ | PROT_WRITE);
+  assert(!err);
+  verify_rwxp(start, end, 06/*rw-*/);
+}
+
+static void readonly_reset(const void *start, const void *end) {
+  assert((((uintptr_t)start) & (PAGE_SIZE - 1)) == 0);
+  assert((((uintptr_t)end  ) & (PAGE_SIZE - 1)) == 0);
+  assert(start <= end);
+  if (start == end)
+    return;
+  verify_rwxp(start, end, 06/*rw-*/);
+  int err = mprotect((void *)start, (const uint8_t *)end - (const uint8_t *)start, PROT_READ);
+  assert(!err);
+  verify_rwxp(start, end, 04/*r--*/);
+}
+
+static void swap(const void **a_p, const void **b_p) {
+  const void *p = *a_p;
+  *a_p = *b_p;
+  *b_p = p;
+}
+
+static void intersect(const void **first_start_p, const void **first_end_p, const void **second_start_p, const void **second_end_p) {
+  assert((((uintptr_t)*first_start_p) & (PAGE_SIZE - 1)) == 0);
+  assert((((uintptr_t)*first_end_p  ) & (PAGE_SIZE - 1)) == 0);
+  assert(*first_start_p <= *first_end_p);
+  assert((((uintptr_t)*second_start_p) & (PAGE_SIZE - 1)) == 0);
+  assert((((uintptr_t)*second_end_p  ) & (PAGE_SIZE - 1)) == 0);
+  assert(*second_start_p <= *second_end_p);
+  if (*first_start_p > *second_start_p) {
+    swap(first_start_p, second_start_p);
+    swap(second_start_p, second_start_p);
+  }
+  if (*second_start_p < *first_end_p) {
+    *second_start_p = *first_end_p;
+    if (*second_start_p > *second_end_p)
+      *second_end_p = *second_start_p;
+  }
+}
+
+static int reset_ifunc_iterate_phdr(struct dl_phdr_info *info, size_t size, void *data_unused) {
+  if (strcmp(info->dlpi_name, "/lib64/ld-linux-x86-64.so.2") == 0) // _dl_relocate_object would crash on scope == NULL.
+    return 0; // unused
+  const void *relro = NULL;
+  const void *relro_end = NULL;
+  assert(size >= offsetof(struct dl_phdr_info, dlpi_adds));
+  for (size_t phdr_ix = 0; phdr_ix < info->dlpi_phnum; ++phdr_ix) {
+    const Elf64_Phdr *phdr = info->dlpi_phdr + phdr_ix;
+    if (phdr->p_type == PT_GNU_RELRO) {
+      // It does not apply: assert(phdr->p_offset == phdr->p_vaddr);
+      assert(phdr->p_paddr == phdr->p_vaddr);
+      // /lib64/libz.so.1: p_filesz=0x538 > p_memsz=0x550
+      assert(!relro);
+      relro = (const void *)(uintptr_t)(phdr->p_vaddr + info->dlpi_addr);
+      relro_end = (const void *)(((const uint8_t *)relro) + phdr->p_memsz);
+      page_align(&relro, &relro_end);
+      assert(relro);
+    }
+  }
+  if (relro)
+    readonly_unset(relro, relro_end);
+  const struct link_map *map = phdr_info_to_link_map(info);
+  Elf64_Dyn *dynamic = map->l_ld;
+  Elf64_Xword *relxsz_p = NULL;
+  Elf64_Xword *relrsz_p = NULL;
+  Elf64_Xword *relxcount_p = NULL;
+  for (; dynamic->d_tag != DT_NULL; ++dynamic)
+    switch (dynamic->d_tag) {
+    case DT_RELASZ:
+    case DT_RELSZ:
+      assert(!relxsz_p);
+      relxsz_p = &dynamic->d_un.d_val;
+      break;
+    case DT_RELRSZ:
+      assert(!relrsz_p);
+      relrsz_p = &dynamic->d_un.d_val;
+      break;
+    case DT_RELCOUNT:
+    case DT_RELACOUNT:
+      assert(!relxcount_p);
+      relxcount_p = &dynamic->d_un.d_val;
+      break;
+    case DT_PLTREL:
+      // It is impossible to relocate DT_REL twice.
+      assert(dynamic->d_un.d_val == DT_RELA);
+      break;
+    }
+  Elf64_Xword relxsz_saved = -1; // may be used uninitialized [-Werror=maybe-uninitialized]
+  if (relxsz_p) {
+    relxsz_saved = *relxsz_p;
+    *relxsz_p = 0;
+  }
+  Elf64_Xword relrsz_saved = -1; // may be used uninitialized [-Werror=maybe-uninitialized]
+  if (relrsz_p) {
+    relrsz_saved = *relrsz_p;
+    *relrsz_p = 0;
+  }
+  Elf64_Xword relxcount_saved = -1; // may be used uninitialized [-Werror=maybe-uninitialized]
+  if (relxcount_p) {
+    relxcount_saved = *relxcount_p;
+    *relxcount_p = 0;
+  }
+  struct link_map *link_map_p = (struct link_map *)map;
+  assert(link_map_p->l_relocated);
+  link_map_p->l_relocated = 0;
+  // FIXME: skip ifuncs
+  _dl_relocate_object((struct link_map *)map, link_map_p->l_scope, 0/*lazy*/, 0/*consider_profiling*/);
+  // It was read/write before but _dl_relocate_object made it read-only.
+  const void *dynamic_start = NULL;
+  const void *dynamic_end;
+  if (relxsz_p) {
+    dynamic_start = relxsz_p;
+    dynamic_end = relxsz_p + 1;
+  }
+  if (relrsz_p) {
+    if (!dynamic_start) {
+      dynamic_start = relrsz_p;
+      dynamic_end = relrsz_p + 1;
+    } else {
+      if (dynamic_start > (const void *)relrsz_p)
+        dynamic_start = relrsz_p;
+      if (dynamic_end < (const void *)(relrsz_p + 1))
+        dynamic_end = relrsz_p + 1;
+    }
+  }
+  if (relxcount_p) {
+    if (!dynamic_start) {
+      dynamic_start = relxcount_p;
+      dynamic_end = relxcount_p + 1;
+    } else {
+      if (dynamic_start > (const void *)relxcount_p)
+        dynamic_start = relxcount_p;
+      if (dynamic_end < (const void *)(relxcount_p + 1))
+        dynamic_end = relxcount_p + 1;
+    }
+  }
+  if (dynamic_start) {
+    page_align(&dynamic_start, &dynamic_end);
+    // _dl_relocate_object made it already readonly: readonly_reset(relro, relro_end);
+    intersect(&relro, &relro_end, &dynamic_start, &dynamic_end);
+    readonly_unset(relro, relro_end);
+    readonly_unset(dynamic_start, dynamic_end);
+  }
+  if (relxsz_p)
+    *relxsz_p = relxsz_saved;
+  if (relrsz_p)
+    *relrsz_p = relrsz_saved;
+  if (relxcount_p)
+    *relxcount_p = relxcount_saved;
+  if (dynamic_start)
+    readonly_reset(dynamic_start, dynamic_end);
+  if (relro)
+    readonly_reset(relro, relro_end);
+  return 0; // unused
+}
+
+static void reset_glibc(void) {
+  const void *rtld_global_ro = &_rtld_global_ro;
+  const void *rtld_global_ro_end = &_rtld_global_ro + 1;
+  page_align(&rtld_global_ro, &rtld_global_ro_end);
+#if HAVE_TUNABLES
+  const void *tunable_list = __tunable_get_start();
+  const void *tunable_list_end = __tunable_get_end();
+  page_align(&tunable_list, &tunable_list_end);
+  intersect(&rtld_global_ro, &rtld_global_ro_end, &tunable_list, &tunable_list_end);
+  readonly_unset(tunable_list, tunable_list_end);
+#endif
+  readonly_unset(rtld_global_ro, rtld_global_ro_end);
+  const struct cpu_features *cpu_features_const = &GLRO(dl_x86_cpu_features);
+  // FIXME: Why volatile?
+  volatile struct cpu_features *cpu_features = (struct cpu_features *)cpu_features_const;
+  assert(cpu_features->basic.kind != arch_kind_unknown);
+  unsigned long int xsave_state_size = cpu_features->xsave_state_size;
+  unsigned int xsave_state_full_size = cpu_features->xsave_state_full_size;
+  memset((volatile uint8_t *)cpu_features, 0, sizeof(*cpu_features));
+  cpu_features->xsave_state_size = xsave_state_size;
+  cpu_features->xsave_state_full_size = xsave_state_full_size;
+  assert(cpu_features->basic.kind == arch_kind_unknown);
+  _dl_x86_init_cpu_features();
+  assert(cpu_features->basic.kind != arch_kind_unknown);
+  readonly_reset(rtld_global_ro, rtld_global_ro_end);
+#if HAVE_TUNABLES
+  readonly_reset(tunable_list, tunable_list_end);
+#endif
+}
+
+void
+_dl_reset_ifunc(void)
+{
+  // _dl_relocate_object() from reset_ifunc_iterate_phdr may be calling glibc ifunc resolvers already.
+  reset_glibc();
+  int i = dl_iterate_phdr(reset_ifunc_iterate_phdr, NULL/*data*/);
+  assert(!i);
+}
+rtld_hidden_def (_dl_reset_ifunc)
diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
index 327b9eb52f..d8c0617bd1 100644
--- a/elf/dl-tunables.c
+++ b/elf/dl-tunables.c
@@ -433,3 +433,17 @@ __tunable_get_val (tunable_id_t id, void *valp, tunable_callback_t callback)
 }
 
 rtld_hidden_def (__tunable_get_val)
+
+const void *
+__tunable_get_start(void)
+{
+  return &tunable_list;
+}
+rtld_hidden_def (__tunable_get_start)
+
+const void *
+__tunable_get_end(void)
+{
+  return tunable_list + sizeof (tunable_list) / sizeof (tunable_t);
+}
+rtld_hidden_def (__tunable_get_end)
diff --git a/elf/dl-tunables.h b/elf/dl-tunables.h
index ae6e014b95..3e3783b9f7 100644
--- a/elf/dl-tunables.h
+++ b/elf/dl-tunables.h
@@ -56,10 +56,14 @@ extern void __tunables_print (void);
 extern void __tunable_get_val (tunable_id_t, void *, tunable_callback_t);
 extern void __tunable_set_val (tunable_id_t, tunable_val_t *, tunable_num_t *,
 			       tunable_num_t *);
+extern const void *__tunable_get_start (void);
+extern const void *__tunable_get_end (void);
 rtld_hidden_proto (__tunables_init)
 rtld_hidden_proto (__tunables_print)
 rtld_hidden_proto (__tunable_get_val)
 rtld_hidden_proto (__tunable_set_val)
+rtld_hidden_proto (__tunable_get_start)
+rtld_hidden_proto (__tunable_get_end)
 
 /* Define TUNABLE_GET and TUNABLE_SET in short form if TOP_NAMESPACE and
    TUNABLE_NAMESPACE are defined.  This is useful shorthand to get and set
diff --git a/elf/link.h b/elf/link.h
index 3b5954d981..b30a736191 100644
--- a/elf/link.h
+++ b/elf/link.h
@@ -185,6 +185,8 @@ extern int dl_iterate_phdr (int (*__callback) (struct dl_phdr_info *,
 					       size_t, void *),
 			    void *__data);
 
+extern void _dl_reset_ifunc (void);
+
 
 /* Prototypes for the ld.so auditing interfaces.  These are not
    defined anywhere in ld.so but instead have to be provided by the
diff --git a/elf/tst-reset-ifunc.c b/elf/tst-reset-ifunc.c
new file mode 100644
index 0000000000..8c185e269d
--- /dev/null
+++ b/elf/tst-reset-ifunc.c
@@ -0,0 +1,70 @@
+/* Test resetting of IFUNC symbols for their new detection.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/check.h>
+#include <link.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <assert.h>
+
+static int func_count;
+
+void
+my_testifunc (void)
+{
+  puts ("my_testifunc");
+  ++func_count;
+}
+
+static int resolve_count;
+
+static void (*
+resolve_testifunc (void)) (void)
+{
+  puts ("resolve_testifunc");
+  ++resolve_count;
+  return (void (*)(void)) my_testifunc; // we'll just always select this routine
+}
+
+void testifunc (void) __attribute__ ((ifunc ("resolve_testifunc")));
+
+static int
+do_test (void)
+{
+  // resolver could be called or not yet.
+  assert (func_count == 0);
+  puts("testifunc");
+  testifunc ();
+  assert (resolve_count == 1);
+  assert (func_count == 1);
+  puts("_dl_reset_ifunc");
+  _dl_reset_ifunc ();
+  // resolver could be called or not yet.
+  assert (func_count == 1);
+  puts("testifunc");
+  testifunc ();
+  assert (resolve_count == 2);
+  assert (func_count == 2);
+  puts("testifunc");
+  testifunc ();
+  assert (resolve_count == 2);
+  assert (func_count == 3);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index c99dad77cc..5cf15a797d 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1015,8 +1015,8 @@ extern struct link_map *_dl_new_object (char *realname, const char *libname,
    If RTLD_LAZY is set in RELOC-MODE, don't relocate its PLT.  */
 extern void _dl_relocate_object (struct link_map *map,
 				 struct r_scope_elem *scope[],
-				 int reloc_mode, int consider_profiling)
-     attribute_hidden;
+				 int reloc_mode, int consider_profiling);
+rtld_hidden_proto (_dl_relocate_object)
 
 /* Protect PT_GNU_RELRO area.  */
 extern void _dl_protect_relro (struct link_map *map) attribute_hidden;
diff --git a/sysdeps/x86/dl-get-cpu-features.c b/sysdeps/x86/dl-get-cpu-features.c
index 5e3bb04d11..46fba307f0 100644
--- a/sysdeps/x86/dl-get-cpu-features.c
+++ b/sysdeps/x86/dl-get-cpu-features.c
@@ -68,6 +68,7 @@ Fatal glibc error: CPU does not support x86-64-v%d\n", 4);
     }
 }
 
+rtld_hidden_def (_dl_x86_init_cpu_features)
 __ifunc (__x86_cpu_features, __x86_cpu_features, NULL, void,
 	 _dl_x86_init_cpu_features);
 #endif
diff --git a/sysdeps/x86/include/cpu-features.h b/sysdeps/x86/include/cpu-features.h
index fa91a23129..ad2bcc883f 100644
--- a/sysdeps/x86/include/cpu-features.h
+++ b/sysdeps/x86/include/cpu-features.h
@@ -929,7 +929,8 @@ extern const struct cpu_features *_dl_x86_get_cpu_features (void)
 /* Unused for x86.  */
 # define INIT_ARCH()
 # define _dl_x86_get_cpu_features() (&GLRO(dl_x86_cpu_features))
-extern void _dl_x86_init_cpu_features (void) attribute_hidden;
+extern void _dl_x86_init_cpu_features (void);
+rtld_hidden_proto (_dl_x86_init_cpu_features)
 #endif
 
 #ifdef __x86_64__

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2023-03-29 13:14 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-06  8:04 [PATCH] RFC: Provide a function to reset IFUNC PLTs Jan Kratochvil
2023-03-07  8:40 ` Florian Weimer
2023-03-07 13:07   ` Adhemerval Zanella Netto
2023-03-08 10:21     ` Jan Kratochvil
2023-03-08 13:04       ` Adhemerval Zanella Netto
2023-03-09 11:32         ` Jan Kratochvil
2023-03-09 15:47           ` Adhemerval Zanella Netto
2023-03-09 17:43             ` Adhemerval Zanella Netto
2023-03-16 14:38             ` Jan Kratochvil
2023-03-20 16:47               ` Adhemerval Zanella Netto
2023-03-29 12:12                 ` Jan Kratochvil
2023-03-29 13:14                   ` Adhemerval Zanella Netto
2023-03-13 13:59           ` Florian Weimer
2023-03-14 12:55             ` Jan Kratochvil
2023-03-14 14:49               ` Florian Weimer
2023-03-14 15:06                 ` Jan Kratochvil
2023-03-08 10:23   ` Jan Kratochvil
2023-03-08 10:44     ` Florian Weimer
2023-03-08 11:03       ` Jan Kratochvil

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).