arm: Use _dl_find_object on __gnu_Unwind_Find_exidx (BZ 31405)

Instead of __dl_iterate_phdr. On ARM dlfo_eh_frame/dlfo_eh_count
maps to PT_ARM_EXIDX vaddr start / length.

On a Neoverse N1 machine with 160 cores, the following program:

  $ cat test.c
  #include <stdlib.h>
  #include <pthread.h>
  #include <assert.h>

  enum {
    niter = 1024,
    ntimes = 128,
  };

  static void *
  tf (void *arg)
  {
    int a = (int) arg;

    for (int i = 0; i < niter; i++)
      {
        void *p[ntimes];
        for (int j = 0; j < ntimes; j++)
  	p[j] = malloc (a * 128);
        for (int j = 0; j < ntimes; j++)
  	free (p[j]);
      }

    return NULL;
  }

  int main (int argc, char *argv[])
  {
    enum { nthreads = 16 };
    pthread_t t[nthreads];

    for (int i = 0; i < nthreads; i ++)
      assert (pthread_create (&t[i], NULL, tf, (void *) i) == 0);

    for (int i = 0; i < nthreads; i++)
      {
        void *r;
        assert (pthread_join (t[i], &r) == 0);
        assert (r == NULL);
      }

    return 0;
  }
  $ arm-linux-gnueabihf-gcc -fsanitize=address test.c -o test

Improves from ~15s to 0.5s.

Checked on arm-linux-gnueabihf.
This commit is contained in:
Adhemerval Zanella 2024-02-22 10:42:55 -03:00
parent e2a65ecc4b
commit f4c142bb9f
4 changed files with 10 additions and 57 deletions

View file

@ -34,6 +34,7 @@ routines = \
dl-addr \ dl-addr \
dl-addr-obj \ dl-addr-obj \
dl-early_allocate \ dl-early_allocate \
dl-find_object \
dl-iteratephdr \ dl-iteratephdr \
dl-libc \ dl-libc \
dl-origin \ dl-origin \
@ -60,7 +61,6 @@ dl-routines = \
dl-deps \ dl-deps \
dl-exception \ dl-exception \
dl-execstack \ dl-execstack \
dl-find_object \
dl-fini \ dl-fini \
dl-init \ dl-init \
dl-load \ dl-load \

View file

@ -356,7 +356,7 @@ _dlfo_lookup (uintptr_t pc, struct dl_find_object_internal *first1, size_t size)
} }
int int
_dl_find_object (void *pc1, struct dl_find_object *result) __dl_find_object (void *pc1, struct dl_find_object *result)
{ {
uintptr_t pc = (uintptr_t) pc1; uintptr_t pc = (uintptr_t) pc1;
@ -463,7 +463,8 @@ _dl_find_object (void *pc1, struct dl_find_object *result)
return -1; return -1;
} /* Transaction retry loop. */ } /* Transaction retry loop. */
} }
rtld_hidden_def (_dl_find_object) hidden_def (__dl_find_object)
weak_alias (__dl_find_object, _dl_find_object)
/* _dlfo_process_initial is called twice. First to compute the array /* _dlfo_process_initial is called twice. First to compute the array
sizes from the initial loaded mappings. Second to fill in the sizes from the initial loaded mappings. Second to fill in the

View file

@ -4,7 +4,8 @@
#include <link.h> /* For ElfW. */ #include <link.h> /* For ElfW. */
#include <stdbool.h> #include <stdbool.h>
rtld_hidden_proto (_dl_find_object) extern __typeof (_dl_find_object) __dl_find_object;
hidden_proto (__dl_find_object)
/* Internally used flag. */ /* Internally used flag. */
#define __RTLD_DLOPEN 0x80000000 #define __RTLD_DLOPEN 0x80000000

View file

@ -16,64 +16,15 @@
<https://www.gnu.org/licenses/>. */ <https://www.gnu.org/licenses/>. */
#include <link.h> #include <link.h>
#include <unwind.h>
struct unw_eh_callback_data
{
_Unwind_Ptr pc;
_Unwind_Ptr exidx_start;
int exidx_len;
};
/* Callback to determines if the PC lies within an object, and remember the
location of the exception index table if it does. */
static int
find_exidx_callback (struct dl_phdr_info * info, size_t size, void * ptr)
{
struct unw_eh_callback_data * data;
const ElfW(Phdr) *phdr;
int i;
int match;
_Unwind_Ptr load_base;
data = (struct unw_eh_callback_data *) ptr;
load_base = info->dlpi_addr;
phdr = info->dlpi_phdr;
match = 0;
for (i = info->dlpi_phnum; i > 0; i--, phdr++)
{
if (phdr->p_type == PT_LOAD)
{
_Unwind_Ptr vaddr = phdr->p_vaddr + load_base;
if (data->pc >= vaddr && data->pc < vaddr + phdr->p_memsz)
match = 1;
}
else if (phdr->p_type == PT_ARM_EXIDX)
{
data->exidx_start = (_Unwind_Ptr) (phdr->p_vaddr + load_base);
data->exidx_len = phdr->p_memsz;
}
}
return match;
}
/* Find the exception index table containing PC. */ /* Find the exception index table containing PC. */
_Unwind_Ptr _Unwind_Ptr
__gnu_Unwind_Find_exidx (_Unwind_Ptr pc, int * pcount) __gnu_Unwind_Find_exidx (_Unwind_Ptr pc, int * pcount)
{ {
struct unw_eh_callback_data data; struct dl_find_object data;
if (__dl_find_object ((void *) pc, &data) < 0)
data.pc = pc;
data.exidx_start = 0;
if (__dl_iterate_phdr (find_exidx_callback, &data) <= 0)
return 0; return 0;
*pcount = data.dlfo_eh_count;
*pcount = data.exidx_len / 8; return (_Unwind_Ptr) data.dlfo_eh_frame;
return data.exidx_start;
} }