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-obj \
dl-early_allocate \
dl-find_object \
dl-iteratephdr \
dl-libc \
dl-origin \
@ -60,7 +61,6 @@ dl-routines = \
dl-deps \
dl-exception \
dl-execstack \
dl-find_object \
dl-fini \
dl-init \
dl-load \

View File

@ -356,7 +356,7 @@ _dlfo_lookup (uintptr_t pc, struct dl_find_object_internal *first1, size_t size)
}
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;
@ -463,7 +463,8 @@ _dl_find_object (void *pc1, struct dl_find_object *result)
return -1;
} /* 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
sizes from the initial loaded mappings. Second to fill in the

View File

@ -4,7 +4,8 @@
#include <link.h> /* For ElfW. */
#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. */
#define __RTLD_DLOPEN 0x80000000

View File

@ -16,64 +16,15 @@
<https://www.gnu.org/licenses/>. */
#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. */
_Unwind_Ptr
__gnu_Unwind_Find_exidx (_Unwind_Ptr pc, int * pcount)
{
struct unw_eh_callback_data data;
data.pc = pc;
data.exidx_start = 0;
if (__dl_iterate_phdr (find_exidx_callback, &data) <= 0)
struct dl_find_object data;
if (__dl_find_object ((void *) pc, &data) < 0)
return 0;
*pcount = data.exidx_len / 8;
return data.exidx_start;
*pcount = data.dlfo_eh_count;
return (_Unwind_Ptr) data.dlfo_eh_frame;
}