summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2004-08-26 23:39:02 +0000
committerEric Andersen <andersen@codepoet.org>2004-08-26 23:39:02 +0000
commit6cd34f77ff5044e6aeb1cf01f02a8403351c4ad1 (patch)
treee5e7e8c0728a3fd3cd09cabd85ef736db3482bd7
parent73fdcf0b9ce22a0fe993689c8f9e13d2c95a806c (diff)
Partial patch from Alexandre Oliva to update the frv port
-rw-r--r--ldso/ldso/frv/dl-inlines.h471
-rw-r--r--ldso/ldso/frv/dl-sysdep.h437
-rw-r--r--ldso/ldso/frv/elfinterp.c16
3 files changed, 501 insertions, 423 deletions
diff --git a/ldso/ldso/frv/dl-inlines.h b/ldso/ldso/frv/dl-inlines.h
new file mode 100644
index 000000000..f09c8b93a
--- /dev/null
+++ b/ldso/ldso/frv/dl-inlines.h
@@ -0,0 +1,471 @@
+ /* Copyright (C) 2003, 2004 Red Hat, Inc.
+ Contributed by Alexandre Oliva <aoliva@redhat.com>
+
+This file is part of uClibc.
+
+uClibc 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.
+
+uClibc 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with uClibc; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+USA. */
+
+
+#ifndef _dl_assert
+# define _dl_assert(expr)
+#endif
+
+/* Initialize a DL_LOADADDR_TYPE given a got pointer and a complete
+ load map. */
+inline static void
+__dl_init_loadaddr_map (struct elf32_fdpic_loadaddr *loadaddr, void *got_value,
+ struct elf32_fdpic_loadmap *map)
+{
+ if (map->version != 0)
+ {
+ SEND_EARLY_STDERR ("Invalid loadmap version number\n");
+ _dl_exit(-1);
+ }
+ if (map->nsegs == 0)
+ {
+ SEND_EARLY_STDERR ("Invalid segment count in loadmap\n");
+ _dl_exit(-1);
+ }
+ loadaddr->got_value = got_value;
+ loadaddr->map = map;
+}
+
+/* Figure out how many LOAD segments there are in the given headers,
+ and allocate a block for the load map big enough for them.
+ got_value will be properly initialized later on, with INIT_GOT. */
+inline static int
+__dl_init_loadaddr (struct elf32_fdpic_loadaddr *loadaddr, Elf32_Phdr *ppnt,
+ int pcnt)
+{
+ int count = 0, i;
+ size_t size;
+
+ for (i = 0; i < pcnt; i++)
+ if (ppnt[i].p_type == PT_LOAD)
+ count++;
+
+ loadaddr->got_value = 0;
+
+ size = sizeof (struct elf32_fdpic_loadmap)
+ + sizeof (struct elf32_fdpic_loadseg) * count;
+ loadaddr->map = _dl_malloc (size);
+ if (! loadaddr->map)
+ _dl_exit (-1);
+
+ loadaddr->map->version = 0;
+ loadaddr->map->nsegs = 0;
+
+ return count;
+}
+
+/* Incrementally initialize a load map. */
+inline static void
+__dl_init_loadaddr_hdr (struct elf32_fdpic_loadaddr loadaddr, void *addr,
+ Elf32_Phdr *phdr, int maxsegs)
+{
+ struct elf32_fdpic_loadseg *segdata;
+
+ if (loadaddr.map->nsegs == maxsegs)
+ _dl_exit (-1);
+
+ segdata = &loadaddr.map->segs[loadaddr.map->nsegs++];
+ segdata->addr = (Elf32_Addr) addr;
+ segdata->p_vaddr = phdr->p_vaddr;
+ segdata->p_memsz = phdr->p_memsz;
+
+#if defined (__SUPPORT_LD_DEBUG__)
+ {
+ extern char *_dl_debug;
+ extern int _dl_debug_file;
+ if (_dl_debug)
+ _dl_dprintf(_dl_debug_file, "%i: mapped %x at %x, size %x\n",
+ loadaddr.map->nsegs-1,
+ segdata->p_vaddr, segdata->addr, segdata->p_memsz);
+ }
+#endif
+}
+
+inline static void __dl_loadaddr_unmap
+(struct elf32_fdpic_loadaddr loadaddr, struct funcdesc_ht *funcdesc_ht);
+
+/* Figure out whether the given address is in one of the mapped
+ segments. */
+inline static int
+__dl_addr_in_loadaddr (void *p, struct elf32_fdpic_loadaddr loadaddr)
+{
+ struct elf32_fdpic_loadmap *map = loadaddr.map;
+ int c;
+
+ for (c = 0; c < map->nsegs; c++)
+ if ((void*)map->segs[c].addr <= p
+ && (char*)p < (char*)map->segs[c].addr + map->segs[c].p_memsz)
+ return 1;
+
+ return 0;
+}
+
+inline static void * _dl_funcdesc_for (void *entry_point, void *got_value);
+
+/* The hashcode handling code below is heavily inspired in libiberty's
+ hashtab code, but with most adaptation points and support for
+ deleting elements removed.
+
+ Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ Contributed by Vladimir Makarov (vmakarov@cygnus.com). */
+
+inline static unsigned long
+higher_prime_number (unsigned long n)
+{
+ /* These are primes that are near, but slightly smaller than, a
+ power of two. */
+ static const unsigned long primes[] = {
+ (unsigned long) 7,
+ (unsigned long) 13,
+ (unsigned long) 31,
+ (unsigned long) 61,
+ (unsigned long) 127,
+ (unsigned long) 251,
+ (unsigned long) 509,
+ (unsigned long) 1021,
+ (unsigned long) 2039,
+ (unsigned long) 4093,
+ (unsigned long) 8191,
+ (unsigned long) 16381,
+ (unsigned long) 32749,
+ (unsigned long) 65521,
+ (unsigned long) 131071,
+ (unsigned long) 262139,
+ (unsigned long) 524287,
+ (unsigned long) 1048573,
+ (unsigned long) 2097143,
+ (unsigned long) 4194301,
+ (unsigned long) 8388593,
+ (unsigned long) 16777213,
+ (unsigned long) 33554393,
+ (unsigned long) 67108859,
+ (unsigned long) 134217689,
+ (unsigned long) 268435399,
+ (unsigned long) 536870909,
+ (unsigned long) 1073741789,
+ (unsigned long) 2147483647,
+ /* 4294967291L */
+ ((unsigned long) 2147483647) + ((unsigned long) 2147483644),
+ };
+
+ const unsigned long *low = &primes[0];
+ const unsigned long *high = &primes[sizeof(primes) / sizeof(primes[0])];
+
+ while (low != high)
+ {
+ const unsigned long *mid = low + (high - low) / 2;
+ if (n > *mid)
+ low = mid + 1;
+ else
+ high = mid;
+ }
+
+#if 0
+ /* If we've run out of primes, abort. */
+ if (n > *low)
+ {
+ fprintf (stderr, "Cannot find prime bigger than %lu\n", n);
+ abort ();
+ }
+#endif
+
+ return *low;
+}
+
+struct funcdesc_ht
+{
+ /* Table itself. */
+ struct funcdesc_value **entries;
+
+ /* Current size (in entries) of the hash table */
+ size_t size;
+
+ /* Current number of elements. */
+ size_t n_elements;
+};
+
+inline static int
+hash_pointer (const void *p)
+{
+ return (int) ((long)p >> 3);
+}
+
+inline static struct funcdesc_ht *
+htab_create (void)
+{
+ struct funcdesc_ht *ht = _dl_malloc (sizeof (struct funcdesc_ht));
+
+ if (! ht)
+ return NULL;
+ ht->size = 3;
+ ht->entries = _dl_malloc (sizeof (struct funcdesc_ht_value *) * ht->size);
+ if (! ht->entries)
+ return NULL;
+
+ ht->n_elements = 0;
+
+ _dl_memset (ht->entries, 0, sizeof (struct funcdesc_ht_value *) * ht->size);
+
+ return ht;
+}
+
+/* This is only called from _dl_loadaddr_unmap, so it's safe to call
+ _dl_free(). See the discussion below. */
+inline static void
+htab_delete (struct funcdesc_ht *htab)
+{
+ int i;
+
+ for (i = htab->size - 1; i >= 0; i--)
+ if (htab->entries[i])
+ _dl_free (htab->entries[i]);
+
+ _dl_free (htab->entries);
+ _dl_free (htab);
+}
+
+/* Similar to htab_find_slot, but without several unwanted side effects:
+ - Does not call htab->eq_f when it finds an existing entry.
+ - Does not change the count of elements/searches/collisions in the
+ hash table.
+ This function also assumes there are no deleted entries in the table.
+ HASH is the hash value for the element to be inserted. */
+
+inline static struct funcdesc_value **
+find_empty_slot_for_expand (struct funcdesc_ht *htab, int hash)
+{
+ size_t size = htab->size;
+ unsigned int index = hash % size;
+ struct funcdesc_value **slot = htab->entries + index;
+ int hash2;
+
+ if (! *slot)
+ return slot;
+
+ hash2 = 1 + hash % (size - 2);
+ for (;;)
+ {
+ index += hash2;
+ if (index >= size)
+ index -= size;
+
+ slot = htab->entries + index;
+ if (! *slot)
+ return slot;
+ }
+}
+
+/* The following function changes size of memory allocated for the
+ entries and repeatedly inserts the table elements. The occupancy
+ of the table after the call will be about 50%. Naturally the hash
+ table must already exist. Remember also that the place of the
+ table entries is changed. If memory allocation failures are allowed,
+ this function will return zero, indicating that the table could not be
+ expanded. If all goes well, it will return a non-zero value. */
+
+inline static int
+htab_expand (struct funcdesc_ht *htab)
+{
+ struct funcdesc_value **oentries;
+ struct funcdesc_value **olimit;
+ struct funcdesc_value **p;
+ struct funcdesc_value **nentries;
+ size_t nsize;
+
+ oentries = htab->entries;
+ olimit = oentries + htab->size;
+
+ /* Resize only when table after removal of unused elements is either
+ too full or too empty. */
+ if (htab->n_elements * 2 > htab->size)
+ nsize = higher_prime_number (htab->n_elements * 2);
+ else
+ nsize = htab->size;
+
+ nentries = _dl_malloc (sizeof (struct funcdesc_value *) * nsize);
+ _dl_memset (nentries, 0, sizeof (struct funcdesc_value *) * nsize);
+ if (nentries == NULL)
+ return 0;
+ htab->entries = nentries;
+ htab->size = nsize;
+
+ p = oentries;
+ do
+ {
+ if (*p)
+ *find_empty_slot_for_expand (htab, hash_pointer ((*p)->entry_point))
+ = *p;
+
+ p++;
+ }
+ while (p < olimit);
+
+#if 0 /* We can't tell whether this was allocated by the _dl_malloc()
+ built into ld.so or malloc() in the main executable or libc,
+ and calling free() for something that wasn't malloc()ed could
+ do Very Bad Things (TM). Take the conservative approach
+ here, potentially wasting as much memory as actually used by
+ the hash table, even if multiple growths occur. That's not
+ so bad as to require some overengineered solution that would
+ enable us to keep track of how it was allocated. */
+ _dl_free (oentries);
+#endif
+ return 1;
+}
+
+/* This function searches for a hash table slot containing an entry
+ equal to the given element. To delete an entry, call this with
+ INSERT = 0, then call htab_clear_slot on the slot returned (possibly
+ after doing some checks). To insert an entry, call this with
+ INSERT = 1, then write the value you want into the returned slot.
+ When inserting an entry, NULL may be returned if memory allocation
+ fails. */
+
+inline static struct funcdesc_value **
+htab_find_slot (struct funcdesc_ht *htab, void *ptr, int insert)
+{
+ unsigned int index;
+ int hash, hash2;
+ size_t size;
+ struct funcdesc_value **entry;
+
+ if (htab->size * 3 <= htab->n_elements * 4
+ && htab_expand (htab) == 0)
+ return NULL;
+
+ hash = hash_pointer (ptr);
+
+ size = htab->size;
+ index = hash % size;
+
+ entry = &htab->entries[index];
+ if (!*entry)
+ goto empty_entry;
+ else if ((*entry)->entry_point == ptr)
+ return entry;
+
+ hash2 = 1 + hash % (size - 2);
+ for (;;)
+ {
+ index += hash2;
+ if (index >= size)
+ index -= size;
+
+ entry = &htab->entries[index];
+ if (!*entry)
+ goto empty_entry;
+ else if ((*entry)->entry_point == ptr)
+ return entry;
+ }
+
+ empty_entry:
+ if (!insert)
+ return NULL;
+
+ htab->n_elements++;
+ return entry;
+}
+
+void *
+_dl_funcdesc_for (void *entry_point, void *got_value)
+{
+ struct elf_resolve *tpnt = ((void**)got_value)[2];
+ struct funcdesc_ht *ht = tpnt->funcdesc_ht;
+ struct funcdesc_value **entry;
+
+ _dl_assert (got_value == tpnt->loadaddr.got_value);
+
+ if (! ht)
+ {
+ ht = htab_create ();
+ if (! ht)
+ return (void*)-1;
+ tpnt->funcdesc_ht = ht;
+ }
+
+ entry = htab_find_slot (ht, entry_point, 1);
+ if (*entry)
+ {
+ _dl_assert ((*entry)->entry_point == entry_point);
+ return _dl_stabilize_funcdesc (*entry);
+ }
+
+ *entry = _dl_malloc (sizeof (struct funcdesc_value));
+ (*entry)->entry_point = entry_point;
+ (*entry)->got_value = got_value;
+
+ return _dl_stabilize_funcdesc (*entry);
+}
+
+inline static void *
+_dl_lookup_address (void *address)
+{
+ struct elf_resolve *rpnt;
+ struct funcdesc_value *fd;
+
+ /* Make sure we don't make assumptions about its alignment. */
+ asm ("" : "+r" (address));
+
+ if ((Elf32_Addr)address & 7)
+ /* It's not a function descriptor. */
+ return address;
+
+ fd = (struct funcdesc_value *)address;
+
+ for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next)
+ {
+ if (! rpnt->funcdesc_ht)
+ continue;
+
+ if (fd->got_value != rpnt->loadaddr.got_value)
+ continue;
+
+ address = htab_find_slot (rpnt->funcdesc_ht, (void*)fd->entry_point, 0);
+
+ if (address && *(struct funcdesc_value **)address == fd)
+ {
+ address = (*(struct funcdesc_value **)address)->entry_point;
+ break;
+ }
+ else
+ address = fd;
+ }
+
+ return address;
+}
+
+void
+__dl_loadaddr_unmap (struct elf32_fdpic_loadaddr loadaddr,
+ struct funcdesc_ht *funcdesc_ht)
+{
+ int i;
+
+ for (i = 0; i < loadaddr.map->nsegs; i++)
+ _dl_munmap ((void*)loadaddr.map->segs[i].addr,
+ loadaddr.map->segs[i].p_memsz);
+
+ /* _dl_unmap is only called for dlopen()ed libraries, for which
+ calling free() is safe, or before we've completed the initial
+ relocation, in which case calling free() is probably pointless,
+ but still safe. */
+ _dl_free (loadaddr.map);
+ if (funcdesc_ht)
+ htab_delete (funcdesc_ht);
+}
diff --git a/ldso/ldso/frv/dl-sysdep.h b/ldso/ldso/frv/dl-sysdep.h
index 46f8461f7..b121a934c 100644
--- a/ldso/ldso/frv/dl-sysdep.h
+++ b/ldso/ldso/frv/dl-sysdep.h
@@ -29,6 +29,9 @@ USA. */
*/
#undef ELF_USES_RELOCA
+/* JMPREL relocs are inside the DT_RELA table. */
+#define ELF_MACHINE_PLTREL_OVERLAP
+
#define DL_NO_COPY_RELOCS
/*
@@ -76,127 +79,10 @@ struct funcdesc_ht;
segment, such that they are referenced with GOTOFF instead of
GPREL, because GPREL needs the GOT to have already been
relocated. */
+#undef SEND_EARLY_STDERR
#define SEND_EARLY_STDERR(S) \
do { static char __s[] = (S); SEND_STDERR (__s); } while (0)
-#include <bits/elf-fdpic.h>
-#ifdef __USE_GNU
-# include <link.h>
-#else
-# define __USE_GNU
-# include <link.h>
-# undef __USE_GNU
-#endif
-#include <dl-syscall.h>
-#include <dl-string.h>
-
-/* These are declared in ldso.h, after it includes dl-elf.h that
- includes ourselves. */
-extern void *_dl_malloc(int size);
-extern void _dl_free(void *);
-extern void _dl_dprintf(int, const char *, ...);
-
-
-#ifndef _dl_assert
-# define _dl_assert(expr)
-#endif
-
-/* Initialize a DL_LOADADDR_TYPE given a got pointer and a complete
- load map. */
-inline static void
-__dl_init_loadaddr_map (struct elf32_fdpic_loadaddr *loadaddr, void *got_value,
- struct elf32_fdpic_loadmap *map)
-{
- if (map->version != 0)
- {
- SEND_EARLY_STDERR ("Invalid loadmap version number\n");
- _dl_exit(-1);
- }
- if (map->nsegs == 0)
- {
- SEND_EARLY_STDERR ("Invalid segment count in loadmap\n");
- _dl_exit(-1);
- }
- loadaddr->got_value = got_value;
- loadaddr->map = map;
-}
-
-/* Figure out how many LOAD segments there are in the given headers,
- and allocate a block for the load map big enough for them.
- got_value will be properly initialized later on, with INIT_GOT. */
-inline static int
-__dl_init_loadaddr (struct elf32_fdpic_loadaddr *loadaddr, Elf32_Phdr *ppnt,
- int pcnt)
-{
- int count = 0, i;
- size_t size;
-
- for (i = 0; i < pcnt; i++)
- if (ppnt[i].p_type == PT_LOAD)
- count++;
-
- loadaddr->got_value = 0;
-
- size = sizeof (struct elf32_fdpic_loadmap)
- + sizeof (struct elf32_fdpic_loadseg) * count;
- loadaddr->map = _dl_malloc (size);
- if (! loadaddr->map)
- _dl_exit (-1);
-
- loadaddr->map->version = 0;
- loadaddr->map->nsegs = 0;
-
- return count;
-}
-
-/* Incrementally initialize a load map. */
-inline static void
-__dl_init_loadaddr_hdr (struct elf32_fdpic_loadaddr loadaddr, void *addr,
- Elf32_Phdr *phdr, int maxsegs)
-{
- struct elf32_fdpic_loadseg *segdata;
-
- if (loadaddr.map->nsegs == maxsegs)
- _dl_exit (-1);
-
- segdata = &loadaddr.map->segs[loadaddr.map->nsegs++];
- segdata->addr = (Elf32_Addr) addr;
- segdata->p_vaddr = phdr->p_vaddr;
- segdata->p_memsz = phdr->p_memsz;
-
-#if defined (__SUPPORT_LD_DEBUG__)
- {
- extern char *_dl_debug;
- extern int _dl_debug_file;
- if (_dl_debug)
- _dl_dprintf(_dl_debug_file, "%i: mapped %x at %x, size %x\n",
- loadaddr.map->nsegs-1,
- segdata->p_vaddr, segdata->addr, segdata->p_memsz);
- }
-#endif
-}
-
-inline static void __dl_loadaddr_unmap
-(struct elf32_fdpic_loadaddr loadaddr, struct funcdesc_ht *funcdesc_ht);
-
-/* Figure out whether the given address is in one of the mapped
- segments. */
-inline static int
-__dl_addr_in_loadaddr (void *p, struct elf32_fdpic_loadaddr loadaddr)
-{
- struct elf32_fdpic_loadmap *map = loadaddr.map;
- int c;
-
- for (c = 0; c < map->nsegs; c++)
- if ((void*)map->segs[c].addr <= p
- && (char*)p < (char*)map->segs[c].addr + map->segs[c].p_memsz)
- return 1;
-
- return 0;
-}
-
-inline static void * _dl_funcdesc_for (void *entry_point, void *got_value);
-
#define DL_LOADADDR_TYPE struct elf32_fdpic_loadaddr
#define DL_RELOC_ADDR(ADDR, LOADADDR) \
@@ -235,6 +121,11 @@ inline static void * _dl_funcdesc_for (void *entry_point, void *got_value);
#define DL_LOADADDR_BASE(LOADADDR) \
((LOADADDR).got_value)
+/* This is called from dladdr(), such that we map a function
+ descriptor's address to the function's entry point before trying to
+ find in which library it's defined. */
+#define DL_LOOKUP_ADDRESS(ADDRESS) (_dl_lookup_address (ADDRESS))
+
#define DL_ADDR_IN_LOADADDR(ADDR, TPNT, TFROM) \
(! (TFROM) && __dl_addr_in_loadaddr ((void*)(ADDR), (TPNT)->loadaddr))
@@ -272,300 +163,20 @@ while (0)
(_dl_pread((FD), (BUF), (SIZE), (OFFSET)))
#endif
-#include <dl-hash.h>
+/* We want to return to dlsym() a function descriptor if the symbol
+ turns out to be a function. */
+#define DL_FIND_HASH_VALUE(TPNT, TYPE_CLASS, SYM) \
+ (((TYPE_CLASS) & ELF_RTYPE_CLASS_DLSYM) \
+ && ELF32_ST_TYPE((SYM)->st_info) == STT_FUNC \
+ ? _dl_funcdesc_for (DL_RELOC_ADDR ((SYM)->st_value, (TPNT)->loadaddr), \
+ (TPNT)->loadaddr.got_value) \
+ : DL_RELOC_ADDR ((SYM)->st_value, (TPNT)->loadaddr))
-/* The hashcode handling code below is heavily inspired in libiberty's
- hashtab code, but with most adaptation points and support for
- deleting elements removed.
-
- Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
- Contributed by Vladimir Makarov (vmakarov@cygnus.com). */
-
-inline static unsigned long
-higher_prime_number (unsigned long n)
-{
- /* These are primes that are near, but slightly smaller than, a
- power of two. */
- static const unsigned long primes[] = {
- (unsigned long) 7,
- (unsigned long) 13,
- (unsigned long) 31,
- (unsigned long) 61,
- (unsigned long) 127,
- (unsigned long) 251,
- (unsigned long) 509,
- (unsigned long) 1021,
- (unsigned long) 2039,
- (unsigned long) 4093,
- (unsigned long) 8191,
- (unsigned long) 16381,
- (unsigned long) 32749,
- (unsigned long) 65521,
- (unsigned long) 131071,
- (unsigned long) 262139,
- (unsigned long) 524287,
- (unsigned long) 1048573,
- (unsigned long) 2097143,
- (unsigned long) 4194301,
- (unsigned long) 8388593,
- (unsigned long) 16777213,
- (unsigned long) 33554393,
- (unsigned long) 67108859,
- (unsigned long) 134217689,
- (unsigned long) 268435399,
- (unsigned long) 536870909,
- (unsigned long) 1073741789,
- (unsigned long) 2147483647,
- /* 4294967291L */
- ((unsigned long) 2147483647) + ((unsigned long) 2147483644),
- };
-
- const unsigned long *low = &primes[0];
- const unsigned long *high = &primes[sizeof(primes) / sizeof(primes[0])];
-
- while (low != high)
- {
- const unsigned long *mid = low + (high - low) / 2;
- if (n > *mid)
- low = mid + 1;
- else
- high = mid;
- }
-
-#if 0
- /* If we've run out of primes, abort. */
- if (n > *low)
- {
- fprintf (stderr, "Cannot find prime bigger than %lu\n", n);
- abort ();
- }
+/* Make sure dl_iterate_phdr is defined. */
+#ifdef __USE_GNU
+# include <link.h>
+#else
+# define __USE_GNU
+# include <link.h>
+# undef __USE_GNU
#endif
-
- return *low;
-}
-
-struct funcdesc_ht
-{
- /* Table itself. */
- struct funcdesc_value **entries;
-
- /* Current size (in entries) of the hash table */
- size_t size;
-
- /* Current number of elements. */
- size_t n_elements;
-};
-
-inline static int
-hash_pointer (const void *p)
-{
- return (int) ((long)p >> 3);
-}
-
-inline static struct funcdesc_ht *
-htab_create (void)
-{
- struct funcdesc_ht *ht = _dl_malloc (sizeof (struct funcdesc_ht));
-
- if (! ht)
- return NULL;
- ht->size = 3;
- ht->entries = _dl_malloc (sizeof (struct funcdesc_ht_value *) * ht->size);
- if (! ht->entries)
- return NULL;
-
- ht->n_elements = 0;
-
- _dl_memset (ht->entries, 0, sizeof (struct funcdesc_ht_value *) * ht->size);
-
- return ht;
-}
-
-inline static void
-htab_delete (struct funcdesc_ht *htab)
-{
- int i;
-
- for (i = htab->size - 1; i >= 0; i--)
- if (htab->entries[i])
- _dl_free (htab->entries[i]);
-
- _dl_free (htab->entries);
- _dl_free (htab);
-}
-
-/* Similar to htab_find_slot, but without several unwanted side effects:
- - Does not call htab->eq_f when it finds an existing entry.
- - Does not change the count of elements/searches/collisions in the
- hash table.
- This function also assumes there are no deleted entries in the table.
- HASH is the hash value for the element to be inserted. */
-
-inline static struct funcdesc_value **
-find_empty_slot_for_expand (struct funcdesc_ht *htab, int hash)
-{
- size_t size = htab->size;
- unsigned int index = hash % size;
- struct funcdesc_value **slot = htab->entries + index;
- int hash2;
-
- if (! *slot)
- return slot;
-
- hash2 = 1 + hash % (size - 2);
- for (;;)
- {
- index += hash2;
- if (index >= size)
- index -= size;
-
- slot = htab->entries + index;
- if (! *slot)
- return slot;
- }
-}
-
-/* The following function changes size of memory allocated for the
- entries and repeatedly inserts the table elements. The occupancy
- of the table after the call will be about 50%. Naturally the hash
- table must already exist. Remember also that the place of the
- table entries is changed. If memory allocation failures are allowed,
- this function will return zero, indicating that the table could not be
- expanded. If all goes well, it will return a non-zero value. */
-
-inline static int
-htab_expand (struct funcdesc_ht *htab)
-{
- struct funcdesc_value **oentries;
- struct funcdesc_value **olimit;
- struct funcdesc_value **p;
- struct funcdesc_value **nentries;
- size_t nsize;
-
- oentries = htab->entries;
- olimit = oentries + htab->size;
-
- /* Resize only when table after removal of unused elements is either
- too full or too empty. */
- if (htab->n_elements * 2 > htab->size)
- nsize = higher_prime_number (htab->n_elements * 2);
- else
- nsize = htab->size;
-
- nentries = _dl_malloc (sizeof (struct funcdesc_value *) * nsize);
- _dl_memset (nentries, 0, sizeof (struct funcdesc_value *) * nsize);
- if (nentries == NULL)
- return 0;
- htab->entries = nentries;
- htab->size = nsize;
-
- p = oentries;
- do
- {
- if (*p)
- *find_empty_slot_for_expand (htab, hash_pointer ((*p)->entry_point))
- = *p;
-
- p++;
- }
- while (p < olimit);
-
- _dl_free (oentries);
- return 1;
-}
-
-/* This function searches for a hash table slot containing an entry
- equal to the given element. To delete an entry, call this with
- INSERT = 0, then call htab_clear_slot on the slot returned (possibly
- after doing some checks). To insert an entry, call this with
- INSERT = 1, then write the value you want into the returned slot.
- When inserting an entry, NULL may be returned if memory allocation
- fails. */
-
-inline static struct funcdesc_value **
-htab_find_slot (struct funcdesc_ht *htab, void *ptr)
-{
- unsigned int index;
- int hash, hash2;
- size_t size;
- struct funcdesc_value **entry;
-
- if (htab->size * 3 <= htab->n_elements * 4
- && htab_expand (htab) == 0)
- return NULL;
-
- hash = hash_pointer (ptr);
-
- size = htab->size;
- index = hash % size;
-
- entry = &htab->entries[index];
- if (!*entry)
- goto empty_entry;
- else if ((*entry)->entry_point == ptr)
- return entry;
-
- hash2 = 1 + hash % (size - 2);
- for (;;)
- {
- index += hash2;
- if (index >= size)
- index -= size;
-
- entry = &htab->entries[index];
- if (!*entry)
- goto empty_entry;
- else if ((*entry)->entry_point == ptr)
- return entry;
- }
-
- empty_entry:
- htab->n_elements++;
- return entry;
-}
-
-void *
-_dl_funcdesc_for (void *entry_point, void *got_value)
-{
- struct elf_resolve *tpnt = ((void**)got_value)[2];
- struct funcdesc_ht *ht = tpnt->funcdesc_ht;
- struct funcdesc_value **entry;
-
- _dl_assert (got_value == tpnt->loadaddr.got_value);
-
- if (! ht)
- {
- ht = htab_create ();
- if (! ht)
- return (void*)-1;
- tpnt->funcdesc_ht = ht;
- }
-
- entry = htab_find_slot (ht, entry_point);
- if (*entry)
- {
- _dl_assert ((*entry)->entry_point == entry_point);
- return _dl_stabilize_funcdesc (*entry);
- }
-
- *entry = _dl_malloc (sizeof (struct funcdesc_value));
- (*entry)->entry_point = entry_point;
- (*entry)->got_value = got_value;
-
- return _dl_stabilize_funcdesc (*entry);
-}
-
-void
-__dl_loadaddr_unmap (struct elf32_fdpic_loadaddr loadaddr,
- struct funcdesc_ht *funcdesc_ht)
-{
- int i;
-
- for (i = 0; i < loadaddr.map->nsegs; i++)
- _dl_munmap ((void*)loadaddr.map->segs[i].addr,
- loadaddr.map->segs[i].p_memsz);
-
- _dl_free (loadaddr.map);
- if (funcdesc_ht)
- htab_delete (funcdesc_ht);
-}
diff --git a/ldso/ldso/frv/elfinterp.c b/ldso/ldso/frv/elfinterp.c
index dabd84a56..f69f70b7e 100644
--- a/ldso/ldso/frv/elfinterp.c
+++ b/ldso/ldso/frv/elfinterp.c
@@ -1,5 +1,5 @@
/* FR-V FDPIC ELF shared library loader suppport
- Copyright (C) 2003 Red Hat, Inc.
+ Copyright (C) 2003, 2004 Red Hat, Inc.
Contributed by Alexandre Oliva <aoliva@redhat.com>
Lots of code copied from ../i386/elfinterp.c, so:
Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
@@ -153,11 +153,10 @@ _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
DL_RELOC_ADDR (this_reloc->r_offset, tpnt->loadaddr);
/* Get the address to be used to fill in the GOT entry. */
- new_addr = __dl_find_hash(symname, tpnt->symbol_scope, tpnt, resolver,
- &new_tpnt);
+ new_addr = _dl_find_hash_mod(symname, tpnt->symbol_scope, 0,
+ &new_tpnt);
if (!new_addr) {
- new_addr = __dl_find_hash(symname, NULL, NULL, resolver,
- &new_tpnt);
+ new_addr = _dl_find_hash_mod(symname, NULL, 0, &new_tpnt);
if (!new_addr) {
_dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
_dl_progname, symname);
@@ -279,10 +278,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
} else {
symbol_addr = (unsigned long)
- __dl_find_hash(symname, scope,
- (reloc_type == R_FRV_FUNCDESC_VALUE
- ? tpnt : NULL), symbolrel,
- &symbol_tpnt);
+ _dl_find_hash_mod(symname, scope, 0, &symbol_tpnt);
/*
* We want to allow undefined references to weak symbols - this might
@@ -338,7 +334,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
funcval.got_value = 0;
asm ("std%I0\t%1, %M0"
: "=m" (*(struct funcdesc_value *)reloc_addr)
- : "r" (funcval));
+ : "e" (funcval));
break;
case R_FRV_FUNCDESC:
if ((long)reloc_addr_packed & 3)